23
README.md
23
README.md
@@ -241,6 +241,29 @@ variable and CLI option are provided the CLI option takes the precedence.
|
||||
| `OS_REGION_NAME` | `--rackspace-region` |
|
||||
| `OS_ENDPOINT_TYPE` | `--rackspace-endpoint-type` |
|
||||
|
||||
### Softlayer
|
||||
|
||||
Create machines on [Softlayer](http://softlayer.com).
|
||||
|
||||
You need to generate an API key in the softlayer control panel.
|
||||
[Retrieve your API key](http://knowledgelayer.softlayer.com/procedure/retrieve-your-api-key)
|
||||
|
||||
Options:
|
||||
- `--softlayer-api-endpoint=`: Change softlayer API endpoint
|
||||
- `--softlayer-user`: **required** username for your softlayer account, api key needs to match this user.
|
||||
- `--softlayer-api-key`: **required** API key for your user account
|
||||
- `--softlayer-cpu`: Number of CPU's for the machine.
|
||||
- `--softlayer-disk-size: Size of the disk in MB. `0` sets the softlayer default.
|
||||
- `--softlayer-domain`: **required** domain name for the machine
|
||||
- `--softlayer-hostname`: hostname for the machine
|
||||
- `--softlayer-hourly-billing`: Sets the hourly billing flag (default), otherwise uses monthly billing
|
||||
- `--softlayer-image`: OS Image to use
|
||||
- `--softlayer-install-script`: custom install script to use for installing Docker, other setup actions
|
||||
- `--softlayer-local-disk`: Use local machine disk instead of softlayer SAN.
|
||||
- `--softlayer-memory`: Memory for host in MB
|
||||
- `--softlayer-private-net-only`: Disable public networking
|
||||
- `--softlayer-region`: softlayer region
|
||||
|
||||
## Contributing
|
||||
|
||||
[](https://godoc.org/github.com/docker/machine)
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
_ "github.com/docker/machine/drivers/none"
|
||||
_ "github.com/docker/machine/drivers/openstack"
|
||||
_ "github.com/docker/machine/drivers/rackspace"
|
||||
_ "github.com/docker/machine/drivers/softlayer"
|
||||
_ "github.com/docker/machine/drivers/virtualbox"
|
||||
_ "github.com/docker/machine/drivers/vmwarefusion"
|
||||
_ "github.com/docker/machine/drivers/vmwarevcloudair"
|
||||
|
||||
452
drivers/softlayer/driver.go
Normal file
452
drivers/softlayer/driver.go
Normal file
@@ -0,0 +1,452 @@
|
||||
package softlayer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/docker/machine/drivers"
|
||||
"github.com/docker/machine/ssh"
|
||||
"github.com/docker/machine/state"
|
||||
)
|
||||
|
||||
const ApiEndpoint = "https://api.softlayer.com/rest/v3"
|
||||
const DockerInstallUrl = "https://get.docker.com"
|
||||
|
||||
type Driver struct {
|
||||
storePath string
|
||||
IPAddress string
|
||||
deviceConfig *deviceConfig
|
||||
Id int
|
||||
Client *Client
|
||||
}
|
||||
|
||||
type deviceConfig struct {
|
||||
DiskSize int
|
||||
Cpu int
|
||||
Hostname string
|
||||
Domain string
|
||||
Region string
|
||||
Memory int
|
||||
Image string
|
||||
HourlyBilling bool
|
||||
InstallScript string
|
||||
LocalDisk bool
|
||||
PrivateNet bool
|
||||
}
|
||||
|
||||
func init() {
|
||||
drivers.Register("softlayer", &drivers.RegisteredDriver{
|
||||
New: NewDriver,
|
||||
GetCreateFlags: GetCreateFlags,
|
||||
})
|
||||
}
|
||||
|
||||
func NewDriver(storePath string) (drivers.Driver, error) {
|
||||
return &Driver{storePath: storePath}, nil
|
||||
}
|
||||
|
||||
func GetCreateFlags() []cli.Flag {
|
||||
// Set hourly billing to true by default since codegangsta cli doesn't take default bool values
|
||||
if os.Getenv("SOFTLAYER_HOURLY_BILLING") == "" {
|
||||
os.Setenv("SOFTLAYER_HOURLY_BILLING", "true")
|
||||
}
|
||||
return []cli.Flag{
|
||||
cli.IntFlag{
|
||||
EnvVar: "SOFTLAYER_MEMORY",
|
||||
Name: "softlayer-memory",
|
||||
Usage: "Memory in MB for machine",
|
||||
Value: 1024,
|
||||
},
|
||||
cli.IntFlag{
|
||||
EnvVar: "SOFTLAYER_DISK_SIZE",
|
||||
Name: "softlayer-disk-size",
|
||||
Usage: "Disk size for machine, a value of 0 uses the default size on softlayer",
|
||||
Value: 0,
|
||||
},
|
||||
cli.StringFlag{
|
||||
EnvVar: "SOFTLAYER_USER",
|
||||
Name: "softlayer-user",
|
||||
Usage: "softlayer user account name",
|
||||
Value: "",
|
||||
},
|
||||
cli.StringFlag{
|
||||
EnvVar: "SOFTLAYER_API_KEY",
|
||||
Name: "softlayer-api-key",
|
||||
Usage: "softlayer user API key",
|
||||
Value: "",
|
||||
},
|
||||
cli.StringFlag{
|
||||
EnvVar: "SOFTLAYER_REGION",
|
||||
Name: "softlayer-region",
|
||||
Usage: "softlayer region for machine",
|
||||
Value: "dal01",
|
||||
},
|
||||
cli.IntFlag{
|
||||
EnvVar: "SOFTLAYER_CPU",
|
||||
Name: "softlayer-cpu",
|
||||
Usage: "number of CPU's for the machine",
|
||||
Value: 1,
|
||||
},
|
||||
cli.StringFlag{
|
||||
EnvVar: "SOFTLAYER_HOSTNAME",
|
||||
Name: "softlayer-hostname",
|
||||
Usage: "hostname for the machine",
|
||||
Value: "docker",
|
||||
},
|
||||
cli.StringFlag{
|
||||
EnvVar: "SOFTLAYER_DOMAIN",
|
||||
Name: "softlayer-domain",
|
||||
Usage: "domain name for machine",
|
||||
Value: "",
|
||||
},
|
||||
cli.StringFlag{
|
||||
EnvVar: "SOFTLAYER_API_ENDPOINT",
|
||||
Name: "softlayer-api-endpoint",
|
||||
Usage: "softlayer api endpoint to use",
|
||||
Value: ApiEndpoint,
|
||||
},
|
||||
cli.BoolFlag{
|
||||
EnvVar: "SOFTLAYER_HOURLY_BILLING",
|
||||
Name: "softlayer-hourly-billing",
|
||||
Usage: "set hourly billing for machine - on by default",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
EnvVar: "SOFTLAYER_LOCAL_DISK",
|
||||
Name: "softlayer-local-disk",
|
||||
Usage: "use machine local disk instead of softlayer SAN",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
EnvVar: "SOFTLAYER_PRIVATE_NET",
|
||||
Name: "softlayer-private-net-only",
|
||||
Usage: "Use only private networking",
|
||||
},
|
||||
cli.StringFlag{
|
||||
EnvVar: "SOFTLAYER_IMAGE",
|
||||
Name: "softlayer-image",
|
||||
Usage: "OS image for machine",
|
||||
Value: "UBUNTU_LATEST",
|
||||
},
|
||||
cli.StringFlag{
|
||||
EnvVar: "SOFTLAYER_INSTALL_SCRIPT",
|
||||
Name: "softlayer-install-script",
|
||||
Usage: "Install script to call after the machine is initialized (should install Docker)",
|
||||
Value: DockerInstallUrl,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func validateDeviceConfig(c *deviceConfig) error {
|
||||
if c.Hostname == "" {
|
||||
return fmt.Errorf("Missing required setting - --softlayer-hostname")
|
||||
}
|
||||
if c.Domain == "" {
|
||||
return fmt.Errorf("Missing required setting - --softlayer-domain")
|
||||
}
|
||||
|
||||
if c.Region == "" {
|
||||
return fmt.Errorf("Missing required setting - --softlayer-region")
|
||||
}
|
||||
if c.Cpu < 1 {
|
||||
return fmt.Errorf("Missing required setting - --softlayer-cpu")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateClientConfig(c *Client) error {
|
||||
if c.ApiKey == "" {
|
||||
return fmt.Errorf("Missing required setting - --softlayer-api-key")
|
||||
}
|
||||
|
||||
if c.User == "" {
|
||||
return fmt.Errorf("Missing required setting - --softlayer-user")
|
||||
}
|
||||
|
||||
if c.Endpoint == "" {
|
||||
return fmt.Errorf("Missing required setting - --softlayer-api-endpoint")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
|
||||
|
||||
d.Client = &Client{
|
||||
Endpoint: flags.String("softlayer-api-endpoint"),
|
||||
User: flags.String("softlayer-user"),
|
||||
ApiKey: flags.String("softlayer-api-key"),
|
||||
}
|
||||
|
||||
if err := validateClientConfig(d.Client); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.deviceConfig = &deviceConfig{
|
||||
Hostname: flags.String("softlayer-hostname"),
|
||||
DiskSize: flags.Int("softlayer-disk-size"),
|
||||
Cpu: flags.Int("softlayer-cpu"),
|
||||
Domain: flags.String("softlayer-domain"),
|
||||
Memory: flags.Int("softlayer-memory"),
|
||||
PrivateNet: flags.Bool("softlayer-private-net-only"),
|
||||
LocalDisk: flags.Bool("softlayer-local-disk"),
|
||||
HourlyBilling: flags.Bool("softlayer-hourly-billing"),
|
||||
InstallScript: flags.String("softlayer-install-script"),
|
||||
Image: "UBUNTU_LATEST",
|
||||
Region: flags.String("softlayer-region"),
|
||||
}
|
||||
return validateDeviceConfig(d.deviceConfig)
|
||||
}
|
||||
|
||||
func (d *Driver) getClient() *Client {
|
||||
return d.Client
|
||||
}
|
||||
|
||||
func (d *Driver) DriverName() string {
|
||||
return "softlayer"
|
||||
}
|
||||
|
||||
func (d *Driver) GetURL() (string, error) {
|
||||
ip, err := d.GetIP()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if ip == "" {
|
||||
return "", nil
|
||||
}
|
||||
return "tcp://" + ip + ":2376", nil
|
||||
}
|
||||
|
||||
func (d *Driver) GetIP() (string, error) {
|
||||
if d.IPAddress != "" {
|
||||
return d.IPAddress, nil
|
||||
}
|
||||
return d.getClient().VirtualGuest().GetPublicIp(d.Id)
|
||||
}
|
||||
|
||||
func (d *Driver) GetState() (state.State, error) {
|
||||
s, err := d.getClient().VirtualGuest().PowerState(d.Id)
|
||||
if err != nil {
|
||||
return state.None, err
|
||||
}
|
||||
var vmState state.State
|
||||
switch s {
|
||||
case "Running":
|
||||
vmState = state.Running
|
||||
case "Halted":
|
||||
vmState = state.Stopped
|
||||
default:
|
||||
vmState = state.None
|
||||
}
|
||||
return vmState, nil
|
||||
}
|
||||
|
||||
func (d *Driver) GetSSHCommand(args ...string) (*exec.Cmd, error) {
|
||||
return ssh.GetSSHCommand(d.IPAddress, 22, "root", d.sshKeyPath(), args...), nil
|
||||
}
|
||||
|
||||
func (d *Driver) Create() error {
|
||||
waitForStart := func() {
|
||||
log.Infof("Waiting for host to become available")
|
||||
for {
|
||||
s, err := d.GetState()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if s == state.Running {
|
||||
break
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
getIp := func() {
|
||||
log.Infof("Getting Host IP")
|
||||
for {
|
||||
var (
|
||||
ip string
|
||||
err error
|
||||
)
|
||||
if d.deviceConfig.PrivateNet {
|
||||
ip, err = d.getClient().VirtualGuest().GetPrivateIp(d.Id)
|
||||
} else {
|
||||
ip, err = d.getClient().VirtualGuest().GetPublicIp(d.Id)
|
||||
}
|
||||
if err != nil {
|
||||
time.Sleep(2 * time.Second)
|
||||
continue
|
||||
}
|
||||
// not a perfect regex, but should be just fine for our needs
|
||||
exp := regexp.MustCompile(`\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`)
|
||||
if exp.MatchString(ip) {
|
||||
d.IPAddress = ip
|
||||
break
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("Creating SSH key...")
|
||||
key, err := d.createSSHKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
spec := d.buildHostSpec()
|
||||
spec.SshKeys = []*SshKey{key}
|
||||
|
||||
id, err := d.getClient().VirtualGuest().Create(spec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating host: %q", err)
|
||||
}
|
||||
d.Id = id
|
||||
getIp()
|
||||
waitForStart()
|
||||
ssh.WaitForTCP(d.IPAddress + ":22")
|
||||
if err := d.setupHost(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error setting up host config: %q", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Driver) buildHostSpec() *HostSpec {
|
||||
spec := &HostSpec{
|
||||
Hostname: d.deviceConfig.Hostname,
|
||||
Domain: d.deviceConfig.Domain,
|
||||
Cpu: d.deviceConfig.Cpu,
|
||||
Memory: d.deviceConfig.Memory,
|
||||
Datacenter: Datacenter{Name: d.deviceConfig.Region},
|
||||
InstallScript: d.deviceConfig.InstallScript,
|
||||
Os: d.deviceConfig.Image,
|
||||
HourlyBilling: d.deviceConfig.HourlyBilling,
|
||||
PrivateNetOnly: d.deviceConfig.PrivateNet,
|
||||
}
|
||||
if d.deviceConfig.DiskSize > 0 {
|
||||
spec.BlockDevices = []BlockDevice{{Device: "0", DiskImage: DiskImage{Capacity: d.deviceConfig.DiskSize}}}
|
||||
}
|
||||
return spec
|
||||
}
|
||||
|
||||
func (d *Driver) createSSHKey() (*SshKey, error) {
|
||||
if err := ssh.GenerateSSHKey(d.sshKeyPath()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
publicKey, err := ioutil.ReadFile(d.publicSSHKeyPath())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, err := d.getClient().SshKey().Create(d.deviceConfig.Hostname, string(publicKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func (d *Driver) publicSSHKeyPath() string {
|
||||
return d.sshKeyPath() + ".pub"
|
||||
}
|
||||
|
||||
func (d *Driver) sshKeyPath() string {
|
||||
return path.Join(d.storePath, "id_rsa")
|
||||
}
|
||||
|
||||
func (d *Driver) Kill() error {
|
||||
return d.getClient().VirtualGuest().PowerOff(d.Id)
|
||||
}
|
||||
func (d *Driver) Remove() error {
|
||||
var err error
|
||||
for i := 0; i < 5; i++ {
|
||||
if err = d.getClient().VirtualGuest().Cancel(d.Id); err != nil {
|
||||
time.Sleep(2 * time.Second)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
return err
|
||||
}
|
||||
func (d *Driver) Restart() error {
|
||||
return d.getClient().VirtualGuest().Reboot(d.Id)
|
||||
}
|
||||
func (d *Driver) Start() error {
|
||||
return d.getClient().VirtualGuest().PowerOn(d.Id)
|
||||
}
|
||||
func (d *Driver) Stop() error {
|
||||
return d.getClient().VirtualGuest().PowerOff(d.Id)
|
||||
}
|
||||
|
||||
func (d *Driver) Upgrade() error {
|
||||
sshCmd, err := d.GetSSHCommand("curl -sSL https://get.docker.com/builds/Linux/x86_64/docker-latest > /tmp/docker && chmod +x /tmp/docker && mv /tmp/docker $(which docker)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sshCmd.Stdin = os.Stdin
|
||||
sshCmd.Stdout = os.Stdout
|
||||
sshCmd.Stderr = os.Stderr
|
||||
if err := sshCmd.Run(); err != nil {
|
||||
return fmt.Errorf("%s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Driver) setupHost() error {
|
||||
log.Infof("Configuring host OS")
|
||||
ssh.WaitForTCP(d.IPAddress + ":22")
|
||||
// Wait to make sure docker is installed
|
||||
for {
|
||||
cmd, err := d.GetSSHCommand(`[ -f "$(which docker)" ] && [ -f "/etc/default/docker" ] || exit 1`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.Run(); err == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
// Remove this once ID auth is released officialy
|
||||
cmd, err := d.GetSSHCommand("service docker stop")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
cmd, err = d.GetSSHCommand("dbin=$(which docker); wget -O $dbin https://bfirsh.s3.amazonaws.com/docker/docker-1.3.1-dev-identity-auth > /dev/null 2>&1 && chmod +x $dbin")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debugf("Updating /etc/default/docker to use identity auth...")
|
||||
|
||||
cmd, err = d.GetSSHCommand("echo 'export DOCKER_OPTS=\"--auth=identity --host=tcp://0.0.0.0:2376\"' >> /etc/default/docker")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debugf("Adding key to authorized-keys.d...")
|
||||
|
||||
if err := drivers.AddPublicKeyToAuthorizedHosts(d, "/.docker/authorized-keys.d"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd, err = d.GetSSHCommand("service docker start")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return cmd.Run()
|
||||
}
|
||||
308
drivers/softlayer/softlayer.go
Normal file
308
drivers/softlayer/softlayer.go
Normal file
@@ -0,0 +1,308 @@
|
||||
package softlayer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
User string
|
||||
ApiKey string
|
||||
Endpoint string
|
||||
}
|
||||
|
||||
type HostSpec struct {
|
||||
Hostname string `json:"hostname"`
|
||||
Domain string `json:"domain"`
|
||||
Cpu int `json:"startCpus"`
|
||||
Memory int `json:"maxMemory"`
|
||||
Datacenter Datacenter `json:"datacenter"`
|
||||
SshKeys []*SshKey `json:"sshKeys"`
|
||||
BlockDevices []BlockDevice `json:"blockDevices"`
|
||||
InstallScript string `json:"postInstallScriptUri"`
|
||||
PrivateNetOnly bool `json:"privateNetworkOnlyFlag"`
|
||||
Os string `json:"operatingSystemReferenceCode"`
|
||||
HourlyBilling bool `json:"hourlyBillingFlag"`
|
||||
LocalDisk bool `json:"localDiskFlag"`
|
||||
}
|
||||
|
||||
type SshKey struct {
|
||||
Key string `json:"key,omitempty"`
|
||||
Id int `json:"id,omitempty"`
|
||||
Label string `json:"label,omitempty"`
|
||||
}
|
||||
|
||||
type BlockDevice struct {
|
||||
Device string `json:"device"`
|
||||
DiskImage DiskImage `json:"diskImage"`
|
||||
}
|
||||
|
||||
type DiskImage struct {
|
||||
Capacity int `json:"capacity"`
|
||||
}
|
||||
|
||||
type Datacenter struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type sshKey struct {
|
||||
*Client
|
||||
}
|
||||
|
||||
type virtualGuest struct {
|
||||
*Client
|
||||
}
|
||||
|
||||
func NewClient(user, key, endpoint string) *Client {
|
||||
return &Client{User: user, ApiKey: key, Endpoint: endpoint}
|
||||
}
|
||||
|
||||
func (c *Client) isOkStatus(code int) bool {
|
||||
codes := map[int]bool{
|
||||
200: true,
|
||||
201: true,
|
||||
204: true,
|
||||
400: false,
|
||||
404: false,
|
||||
500: false,
|
||||
409: false,
|
||||
406: false,
|
||||
}
|
||||
|
||||
return codes[code]
|
||||
}
|
||||
|
||||
func (c *Client) newRequest(method, uri string, body interface{}) ([]byte, error) {
|
||||
var (
|
||||
client = &http.Client{}
|
||||
url = fmt.Sprintf("%s/%s", c.Endpoint, uri)
|
||||
err error
|
||||
req *http.Request
|
||||
)
|
||||
|
||||
if body != nil {
|
||||
bodyJson, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req, err = http.NewRequest(method, url, bytes.NewBuffer(bodyJson))
|
||||
} else {
|
||||
req, err = http.NewRequest(method, url, nil)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error with request: %v - %q", url, err)
|
||||
}
|
||||
|
||||
req.SetBasicAuth(c.User, c.ApiKey)
|
||||
req.Method = method
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
if !c.isOkStatus(resp.StatusCode) {
|
||||
type apiErr struct {
|
||||
Err string `json:"error"`
|
||||
}
|
||||
var outErr apiErr
|
||||
json.Unmarshal(data, &outErr)
|
||||
return nil, fmt.Errorf("Error in response: %s", outErr.Err)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (c *Client) SshKey() *sshKey {
|
||||
return &sshKey{c}
|
||||
}
|
||||
|
||||
func (c *sshKey) namespace() string {
|
||||
return "SoftLayer_Security_Ssh_Key"
|
||||
}
|
||||
|
||||
func (c *sshKey) Create(label, key string) (*SshKey, error) {
|
||||
var (
|
||||
method = "POST"
|
||||
uri = c.namespace()
|
||||
body = SshKey{Key: key, Label: label}
|
||||
)
|
||||
|
||||
data, err := c.newRequest(method, uri, map[string]interface{}{"parameters": []interface{}{body}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var k SshKey
|
||||
if err := json.Unmarshal(data, &k); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &k, nil
|
||||
}
|
||||
|
||||
func (c *Client) VirtualGuest() *virtualGuest {
|
||||
return &virtualGuest{c}
|
||||
}
|
||||
|
||||
func (c *virtualGuest) namespace() string {
|
||||
return "SoftLayer_Virtual_Guest"
|
||||
}
|
||||
|
||||
func (c *virtualGuest) PowerState(id int) (string, error) {
|
||||
type state struct {
|
||||
KeyName string `json:"keyName"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
var (
|
||||
method = "GET"
|
||||
uri = fmt.Sprintf("%s/%v/getPowerState.json", c.namespace(), id)
|
||||
)
|
||||
|
||||
data, err := c.newRequest(method, uri, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var s state
|
||||
if err := json.Unmarshal(data, &s); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return s.Name, nil
|
||||
}
|
||||
|
||||
func (c *virtualGuest) Create(spec *HostSpec) (int, error) {
|
||||
var (
|
||||
method = "POST"
|
||||
uri = c.namespace() + ".json"
|
||||
)
|
||||
|
||||
data, err := c.newRequest(method, uri, map[string]interface{}{"parameters": []interface{}{spec}})
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
type createResp struct {
|
||||
Id int `json:"id"`
|
||||
}
|
||||
|
||||
var r createResp
|
||||
if err := json.Unmarshal(data, &r); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
return r.Id, nil
|
||||
}
|
||||
|
||||
func (c *virtualGuest) Cancel(id int) error {
|
||||
var (
|
||||
method = "DELETE"
|
||||
uri = fmt.Sprintf("%s/%v", c.namespace(), id)
|
||||
)
|
||||
|
||||
_, err := c.newRequest(method, uri, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *virtualGuest) PowerOn(id int) error {
|
||||
var (
|
||||
method = "GET"
|
||||
uri = fmt.Sprintf("%s/%v/powerOn.json", c.namespace(), id)
|
||||
)
|
||||
|
||||
_, err := c.newRequest(method, uri, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *virtualGuest) PowerOff(id int) error {
|
||||
var (
|
||||
method = "GET"
|
||||
uri = fmt.Sprintf("%s/%v/powerOff.json", c.namespace(), id)
|
||||
)
|
||||
|
||||
_, err := c.newRequest(method, uri, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *virtualGuest) Pause(id int) error {
|
||||
var (
|
||||
method = "GET"
|
||||
uri = fmt.Sprintf("%s/%v/pause.json", c.namespace(), id)
|
||||
)
|
||||
|
||||
_, err := c.newRequest(method, uri, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *virtualGuest) Resume(id int) error {
|
||||
var (
|
||||
method = "GET"
|
||||
uri = fmt.Sprintf("%s/%v/resume.json", c.namespace(), id)
|
||||
)
|
||||
|
||||
_, err := c.newRequest(method, uri, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *virtualGuest) Reboot(id int) error {
|
||||
var (
|
||||
method = "GET"
|
||||
uri = fmt.Sprintf("%s/%v/rebootSoft.json", c.namespace(), id)
|
||||
)
|
||||
|
||||
_, err := c.newRequest(method, uri, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *virtualGuest) GetPublicIp(id int) (string, error) {
|
||||
var (
|
||||
method = "GET"
|
||||
uri = fmt.Sprintf("%s/%v/getPrimaryIpAddress.json", c.namespace(), id)
|
||||
)
|
||||
|
||||
data, err := c.newRequest(method, uri, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.Replace(string(data), "\"", "", -1), nil
|
||||
}
|
||||
|
||||
func (c *virtualGuest) GetPrivateIp(id int) (string, error) {
|
||||
var (
|
||||
method = "GET"
|
||||
uri = fmt.Sprintf("%s/%v/getPrimaryBackendIpAddress.json", c.namespace(), id)
|
||||
)
|
||||
|
||||
data, err := c.newRequest(method, uri, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.Replace(string(data), "\"", "", -1), nil
|
||||
}
|
||||
Reference in New Issue
Block a user