-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implementing software installation via SSH
- Loading branch information
Showing
12 changed files
with
426 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
cm-grasshopper: | ||
listen: | ||
port: 8084 | ||
honeybee: | ||
server_address: 127.0.0.1 | ||
server_port: 8081 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package ssh | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"github.com/cloud-barista/cm-grasshopper/lib/config" | ||
"github.com/cloud-barista/cm-grasshopper/pkg/api/rest/common" | ||
honeybee "github.com/cloud-barista/cm-honeybee/server/pkg/api/rest/model" | ||
"github.com/melbahja/goph" | ||
"golang.org/x/crypto/ssh" | ||
"net" | ||
) | ||
|
||
type Client struct { | ||
*goph.Client | ||
ConnectionInfo honeybee.ConnectionInfo | ||
} | ||
|
||
func AddKnownHost(host string, remote net.Addr, key ssh.PublicKey) error { | ||
hostFound, err := goph.CheckKnownHost(host, remote, key, "") | ||
|
||
// Host in known hosts but key mismatch! | ||
// Maybe because of MAN IN THE MIDDLE ATTACK! | ||
if hostFound && err != nil { | ||
return err | ||
} | ||
|
||
if hostFound { | ||
return nil | ||
} | ||
|
||
return goph.AddKnownHost(host, remote, key, "") | ||
} | ||
|
||
func NewSSHClient(connectionInfoUUID string) (*Client, error) { | ||
data, err := common.GetHTTPRequest("http://" + config.CMGrasshopperConfig.CMGrasshopper.Honeybee.ServerAddress + | ||
":" + config.CMGrasshopperConfig.CMGrasshopper.Honeybee.ServerPort + | ||
"/connection_info/" + connectionInfoUUID) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var connectionInfo honeybee.ConnectionInfo | ||
err = json.Unmarshal(data, &connectionInfo) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var auth goph.Auth | ||
if connectionInfo.PrivateKey != "" { | ||
auth, err = goph.RawKey(connectionInfo.PrivateKey, "") | ||
if err != nil { | ||
return nil, err | ||
} | ||
} else if connectionInfo.Password != "" { | ||
auth = goph.Password(connectionInfo.Password) | ||
} else { | ||
return nil, errors.New("failed to determine auth method") | ||
} | ||
|
||
client, err := goph.NewConn(&goph.Config{ | ||
User: connectionInfo.User, | ||
Addr: connectionInfo.IPAddress, | ||
Port: uint(connectionInfo.SSHPort), | ||
Auth: auth, | ||
Timeout: goph.DefaultTimeout, | ||
Callback: AddKnownHost, | ||
}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return &Client{ | ||
client, | ||
connectionInfo, | ||
}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package ssh | ||
|
||
func (c Client) RunBash(cmd string) (string, error) { | ||
out, err := c.Run("bash -c '" + cmd + "'") | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return string(out), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,65 @@ | ||
package controller | ||
|
||
import ( | ||
"github.com/cloud-barista/cm-grasshopper/lib/ssh" | ||
"github.com/cloud-barista/cm-grasshopper/pkg/api/rest/common" | ||
"github.com/cloud-barista/cm-grasshopper/pkg/api/rest/model" | ||
"github.com/labstack/echo/v4" | ||
"net/http" | ||
"strings" | ||
) | ||
|
||
func SoftwareGetList(c echo.Context) error { | ||
uuid := c.QueryParam("uuid") | ||
if uuid == "" { | ||
return common.ReturnErrorMsg(c, "uuid is empty") | ||
// InstallSoftware godoc | ||
// | ||
// @Summary Install Software | ||
// @Description Install pieces of software to target. | ||
// @Tags [Software] | ||
// @Accept json | ||
// @Produce json | ||
// @Param softwareInstallReq body model.SoftwareInstallReq true "Software install request." | ||
// @Success 200 {object} model.SoftwareInstallRes "Successfully sent SSH command." | ||
// @Failure 400 {object} common.ErrorResponse "Sent bad request." | ||
// @Failure 500 {object} common.ErrorResponse "Failed to sent SSH command." | ||
// @Router /software/install [post] | ||
func InstallSoftware(c echo.Context) error { | ||
var err error | ||
|
||
softwareInstallReq := new(model.SoftwareInstallReq) | ||
err = c.Bind(softwareInstallReq) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
client, err := ssh.NewSSHClient(softwareInstallReq.ConnectionUUID) | ||
if err != nil { | ||
return common.ReturnErrorMsg(c, err.Error()) | ||
} | ||
|
||
var softwareInstallRes model.SoftwareInstallRes | ||
|
||
var packageNames string | ||
var out string | ||
|
||
for _, name := range softwareInstallReq.PackageNames { | ||
packageNames += " " + name | ||
} | ||
|
||
//data, err := common.GetHTTPRequest("http://XXX/software") | ||
//if err != nil { | ||
// return common.ReturnInternalError(c, err, "Error occurred while getting software list.") | ||
//} | ||
//err = json.Unmarshal(data, &XXX) | ||
//if err != nil { | ||
// return common.ReturnInternalError(c, err, "Error occurred while parsing software list.") | ||
//} | ||
// | ||
//return c.JSONPretty(http.StatusOK, softwareList, " ") | ||
|
||
return nil | ||
packageType := strings.ToLower(softwareInstallReq.PackageType) | ||
if packageType == "apt" { | ||
out, err = client.RunBash("echo " + client.ConnectionInfo.Password + " | sudo -S -k apt-get install" + packageNames) | ||
if err != nil { | ||
return common.ReturnErrorMsg(c, err.Error()) | ||
} | ||
} else if packageType == "yum" { | ||
out, err = client.RunBash("echo " + client.ConnectionInfo.Password + " | sudo -S -k yum install" + packageNames) | ||
if err != nil { | ||
return common.ReturnErrorMsg(c, err.Error()) | ||
} | ||
} else { | ||
return common.ReturnErrorMsg(c, "Invalid package type: "+softwareInstallReq.PackageType) | ||
} | ||
|
||
softwareInstallRes.Output = out | ||
|
||
return c.JSONPretty(http.StatusOK, softwareInstallRes, " ") | ||
} |
Oops, something went wrong.