mirror of https://github.com/docker/docs.git
driver: exoscale driver
Add support for exoscale, a Swiss cloud provider. This pull "egoscale", a Go binding for exoscale, in godeps. Signed-off-by: Vincent Bernat <Vincent.Bernat@exoscale.ch>
This commit is contained in:
parent
7dcd4c2dfd
commit
fd569c8fdf
|
|
@ -130,6 +130,10 @@
|
||||||
"ImportPath": "github.com/stretchr/testify/assert",
|
"ImportPath": "github.com/stretchr/testify/assert",
|
||||||
"Rev": "e4ec8152c15fc46bd5056ce65997a07c7d415325"
|
"Rev": "e4ec8152c15fc46bd5056ce65997a07c7d415325"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/pyr/egoscale/src/egoscale",
|
||||||
|
"Rev": "8bdfe1d0420634bdd37d73d00d51f86f8d08e481"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/tent/http-link-go",
|
"ImportPath": "github.com/tent/http-link-go",
|
||||||
"Rev": "ac974c61c2f990f4115b119354b5e0b47550e888"
|
"Rev": "ac974c61c2f990f4115b119354b5e0b47550e888"
|
||||||
|
|
|
||||||
36
Godeps/_workspace/src/github.com/pyr/egoscale/src/egoscale/async.go
generated
vendored
Normal file
36
Godeps/_workspace/src/github.com/pyr/egoscale/src/egoscale/async.go
generated
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
package egoscale
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (exo *Client) PollAsyncJob(jobid string) (*QueryAsyncJobResultResponse, error) {
|
||||||
|
params := url.Values{}
|
||||||
|
|
||||||
|
params.Set("jobid", jobid)
|
||||||
|
|
||||||
|
resp, err := exo.Request("queryAsyncJobResult", params)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var r QueryAsyncJobResultResponse
|
||||||
|
|
||||||
|
if err := json.Unmarshal(resp, &r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exo *Client) AsyncToVirtualMachine(resp QueryAsyncJobResultResponse) (*DeployVirtualMachineResponse, error) {
|
||||||
|
var r DeployVirtualMachineWrappedResponse
|
||||||
|
|
||||||
|
if err := json.Unmarshal(resp.Jobresult, &r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &r.Wrapped, nil
|
||||||
|
}
|
||||||
9
Godeps/_workspace/src/github.com/pyr/egoscale/src/egoscale/error.go
generated
vendored
Normal file
9
Godeps/_workspace/src/github.com/pyr/egoscale/src/egoscale/error.go
generated
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
package egoscale
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e *Error) Error() error {
|
||||||
|
return fmt.Errorf("exoscale API error %d (internal code: %d): %s", e.ErrorCode, e.CSErrorCode, e.ErrorText)
|
||||||
|
}
|
||||||
105
Godeps/_workspace/src/github.com/pyr/egoscale/src/egoscale/groups.go
generated
vendored
Normal file
105
Godeps/_workspace/src/github.com/pyr/egoscale/src/egoscale/groups.go
generated
vendored
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
package egoscale
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (exo *Client) CreateEgressRule(rule SecurityGroupRule) (*AuthorizeSecurityGroupEgressResponse, error) {
|
||||||
|
|
||||||
|
params := url.Values{}
|
||||||
|
params.Set("securitygroupid", rule.SecurityGroupId)
|
||||||
|
params.Set("cidrlist", rule.Cidr)
|
||||||
|
params.Set("protocol", rule.Protocol)
|
||||||
|
|
||||||
|
if rule.Protocol == "ICMP" {
|
||||||
|
params.Set("icmpcode", fmt.Sprintf("%d", rule.IcmpCode))
|
||||||
|
params.Set("icmptype", fmt.Sprintf("%d", rule.IcmpType))
|
||||||
|
} else if (rule.Protocol == "TCP" || rule.Protocol == "UDP") {
|
||||||
|
params.Set("startport", fmt.Sprintf("%d", rule.Port))
|
||||||
|
params.Set("endport", fmt.Sprintf("%d", rule.Port))
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("Invalid Egress rule Protocol: %s", rule.Protocol)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := exo.Request("authorizeSecurityGroupEgress", params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var r AuthorizeSecurityGroupEgressResponse
|
||||||
|
if err := json.Unmarshal(resp, &r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exo *Client) CreateIngressRule(rule SecurityGroupRule) (*AuthorizeSecurityGroupIngressResponse, error) {
|
||||||
|
|
||||||
|
params := url.Values{}
|
||||||
|
params.Set("securitygroupid", rule.SecurityGroupId)
|
||||||
|
params.Set("cidrlist", rule.Cidr)
|
||||||
|
params.Set("protocol", rule.Protocol)
|
||||||
|
|
||||||
|
if rule.Protocol == "ICMP" {
|
||||||
|
params.Set("icmpcode", fmt.Sprintf("%d", rule.IcmpCode))
|
||||||
|
params.Set("icmptype", fmt.Sprintf("%d", rule.IcmpType))
|
||||||
|
} else if (rule.Protocol == "TCP" || rule.Protocol == "UDP") {
|
||||||
|
params.Set("startport", fmt.Sprintf("%d", rule.Port))
|
||||||
|
params.Set("endport", fmt.Sprintf("%d", rule.Port))
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("Invalid Egress rule Protocol: %s", rule.Protocol)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := exo.Request("authorizeSecurityGroupIngress", params)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var r AuthorizeSecurityGroupIngressResponse
|
||||||
|
if err := json.Unmarshal(resp, &r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exo *Client) CreateSecurityGroupWithRules(name string, ingress []SecurityGroupRule, egress []SecurityGroupRule) (*CreateSecurityGroupResponse, error) {
|
||||||
|
|
||||||
|
params := url.Values{}
|
||||||
|
params.Set("name", name)
|
||||||
|
|
||||||
|
resp, err := exo.Request("createSecurityGroup", params)
|
||||||
|
|
||||||
|
var r CreateSecurityGroupResponseWrapper
|
||||||
|
if err := json.Unmarshal(resp, &r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sgid := r.Wrapped.Id
|
||||||
|
|
||||||
|
for _, erule := range(egress) {
|
||||||
|
erule.SecurityGroupId = sgid
|
||||||
|
_, err = exo.CreateEgressRule(erule)
|
||||||
|
if (err != nil) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, inrule := range(ingress) {
|
||||||
|
inrule.SecurityGroupId = sgid
|
||||||
|
_, err = exo.CreateIngressRule(inrule)
|
||||||
|
if (err != nil) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &r.Wrapped, nil
|
||||||
|
}
|
||||||
21
Godeps/_workspace/src/github.com/pyr/egoscale/src/egoscale/init.go
generated
vendored
Normal file
21
Godeps/_workspace/src/github.com/pyr/egoscale/src/egoscale/init.go
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
package egoscale
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"crypto/tls"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewClient(endpoint string, apiKey string, apiSecret string) *Client {
|
||||||
|
cs := &Client {
|
||||||
|
client: &http.Client {
|
||||||
|
Transport: &http.Transport {
|
||||||
|
Proxy: http.ProxyFromEnvironment,
|
||||||
|
TLSClientConfig: &tls.Config { InsecureSkipVerify: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
endpoint: endpoint,
|
||||||
|
apiKey: apiKey,
|
||||||
|
apiSecret: apiSecret,
|
||||||
|
}
|
||||||
|
return cs
|
||||||
|
}
|
||||||
23
Godeps/_workspace/src/github.com/pyr/egoscale/src/egoscale/keypair.go
generated
vendored
Normal file
23
Godeps/_workspace/src/github.com/pyr/egoscale/src/egoscale/keypair.go
generated
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
package egoscale
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (exo *Client) CreateKeypair(name string) (*CreateSSHKeyPairResponse, error) {
|
||||||
|
params := url.Values{}
|
||||||
|
params.Set("name", name)
|
||||||
|
|
||||||
|
resp, err := exo.Request("createSSHKeyPair", params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var r CreateSSHKeyPairWrappedResponse
|
||||||
|
if err := json.Unmarshal(resp, &r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &r.Wrapped, nil
|
||||||
|
}
|
||||||
65
Godeps/_workspace/src/github.com/pyr/egoscale/src/egoscale/request.go
generated
vendored
Normal file
65
Godeps/_workspace/src/github.com/pyr/egoscale/src/egoscale/request.go
generated
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
package egoscale
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func rawValue(b json.RawMessage) (json.RawMessage, error) {
|
||||||
|
var m map[string]json.RawMessage
|
||||||
|
|
||||||
|
if err := json.Unmarshal(b, &m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, v := range m {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("Unable to extract raw value from:\n\n%s\n\n", string(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exo *Client) Request (command string, params url.Values) (json.RawMessage, error) {
|
||||||
|
|
||||||
|
mac := hmac.New(sha1.New, []byte(exo.apiSecret))
|
||||||
|
|
||||||
|
params.Set("apikey", exo.apiKey)
|
||||||
|
params.Set("command", command)
|
||||||
|
params.Set("response", "json")
|
||||||
|
|
||||||
|
s := strings.Replace(strings.ToLower(params.Encode()), "+", "%20", -1)
|
||||||
|
mac.Write([]byte(s))
|
||||||
|
signature := url.QueryEscape(base64.StdEncoding.EncodeToString(mac.Sum(nil)))
|
||||||
|
|
||||||
|
s = params.Encode()
|
||||||
|
url := exo.endpoint + "?" + s + "&signature=" + signature
|
||||||
|
|
||||||
|
resp, err := exo.client.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := ioutil.ReadAll(resp.Body)
|
||||||
|
resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err = rawValue(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
var e Error
|
||||||
|
if err := json.Unmarshal(b, &e); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, e.Error()
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
170
Godeps/_workspace/src/github.com/pyr/egoscale/src/egoscale/topology.go
generated
vendored
Normal file
170
Godeps/_workspace/src/github.com/pyr/egoscale/src/egoscale/topology.go
generated
vendored
Normal file
|
|
@ -0,0 +1,170 @@
|
||||||
|
package egoscale
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (exo *Client) GetSecurityGroups() (map[string]string, error) {
|
||||||
|
var sgs map[string]string
|
||||||
|
params := url.Values{}
|
||||||
|
resp, err := exo.Request("listSecurityGroups", params)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var r ListSecurityGroupsResponse
|
||||||
|
if err := json.Unmarshal(resp, &r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sgs = make(map[string]string)
|
||||||
|
for _, sg := range(r.SecurityGroups) {
|
||||||
|
sgs[sg.Name] = sg.Id
|
||||||
|
}
|
||||||
|
return sgs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exo *Client) GetZones() (map[string]string, error) {
|
||||||
|
var zones map[string]string
|
||||||
|
params := url.Values{}
|
||||||
|
resp, err := exo.Request("listZones", params)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var r ListZonesResponse
|
||||||
|
if err := json.Unmarshal(resp, &r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
zones = make(map[string]string)
|
||||||
|
for _, zone := range(r.Zones) {
|
||||||
|
zones[zone.Name] = zone.Id
|
||||||
|
}
|
||||||
|
return zones, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exo *Client) GetProfiles() (map[string]string, error) {
|
||||||
|
|
||||||
|
var profiles map[string]string
|
||||||
|
params := url.Values{}
|
||||||
|
resp, err := exo.Request("listServiceOfferings", params)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var r ListServiceOfferingsResponse
|
||||||
|
if err := json.Unmarshal(resp, &r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
profiles = make(map[string]string)
|
||||||
|
for _, offering := range(r.ServiceOfferings) {
|
||||||
|
profiles[strings.ToLower(offering.Name)] = offering.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
return profiles, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exo *Client) GetKeypairs() ([]string, error) {
|
||||||
|
|
||||||
|
var keypairs []string
|
||||||
|
params := url.Values{}
|
||||||
|
|
||||||
|
resp, err := exo.Request("listSSHKeyPairs", params)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var r ListSSHKeyPairsResponse
|
||||||
|
if err := json.Unmarshal(resp, &r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
keypairs = make([]string, r.Count, r.Count)
|
||||||
|
for i, keypair := range(r.SSHKeyPairs) {
|
||||||
|
keypairs[i] = keypair.Name
|
||||||
|
}
|
||||||
|
return keypairs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exo *Client) GetImages() (map[string]map[int]string, error) {
|
||||||
|
var images map[string]map[int]string
|
||||||
|
images = make(map[string]map[int]string)
|
||||||
|
|
||||||
|
params := url.Values{}
|
||||||
|
params.Set("templatefilter", "featured")
|
||||||
|
|
||||||
|
resp, err := exo.Request("listTemplates", params)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var r ListTemplatesResponse
|
||||||
|
if err := json.Unmarshal(resp, &r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
re := regexp.MustCompile(`^Linux (?P<name>Ubuntu|Debian) (?P<version>[0-9.]+).*$`)
|
||||||
|
for _, template := range(r.Templates) {
|
||||||
|
size := template.Size / (1024 * 1024 * 1024)
|
||||||
|
submatch := re.FindStringSubmatch(template.Name)
|
||||||
|
if len(submatch) > 0 {
|
||||||
|
name := strings.ToLower(submatch[1])
|
||||||
|
version := submatch[2]
|
||||||
|
image := fmt.Sprintf("%s-%s", name, version)
|
||||||
|
|
||||||
|
_, present := images[image]
|
||||||
|
if (!present) {
|
||||||
|
images[image] = make(map[int]string)
|
||||||
|
}
|
||||||
|
images[image][size] = template.Id
|
||||||
|
|
||||||
|
images[fmt.Sprintf("%s-%s", name, version)][size] = template.Id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return images, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exo *Client) GetTopology() (*Topology, error) {
|
||||||
|
|
||||||
|
zones, err := exo.GetZones()
|
||||||
|
if (err != nil) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
images, err := exo.GetImages()
|
||||||
|
if (err != nil) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
groups, err := exo.GetSecurityGroups()
|
||||||
|
if (err != nil) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
keypairs, err := exo.GetKeypairs()
|
||||||
|
if (err != nil) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
profiles, err := exo.GetProfiles()
|
||||||
|
if (err != nil) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
topo := &Topology{
|
||||||
|
Zones: zones,
|
||||||
|
Profiles: profiles,
|
||||||
|
Images: images,
|
||||||
|
Keypairs: keypairs,
|
||||||
|
SecurityGroups: groups,
|
||||||
|
}
|
||||||
|
|
||||||
|
return topo, nil
|
||||||
|
}
|
||||||
404
Godeps/_workspace/src/github.com/pyr/egoscale/src/egoscale/types.go
generated
vendored
Normal file
404
Godeps/_workspace/src/github.com/pyr/egoscale/src/egoscale/types.go
generated
vendored
Normal file
|
|
@ -0,0 +1,404 @@
|
||||||
|
package egoscale
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
client *http.Client
|
||||||
|
endpoint string
|
||||||
|
apiKey string
|
||||||
|
apiSecret string
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Error struct {
|
||||||
|
ErrorCode int `json:"errorcode"`
|
||||||
|
CSErrorCode int `json:"cserrorcode"`
|
||||||
|
ErrorText string `json:"errortext"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Topology struct {
|
||||||
|
Zones map[string]string
|
||||||
|
Images map[string]map[int]string
|
||||||
|
Profiles map[string]string
|
||||||
|
Keypairs []string
|
||||||
|
SecurityGroups map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecurityGroupRule struct {
|
||||||
|
Cidr string
|
||||||
|
IcmpType int
|
||||||
|
IcmpCode int
|
||||||
|
Port int
|
||||||
|
Protocol string
|
||||||
|
SecurityGroupId string
|
||||||
|
}
|
||||||
|
|
||||||
|
type MachineProfile struct {
|
||||||
|
Name string
|
||||||
|
SecurityGroups []string
|
||||||
|
Keypair string
|
||||||
|
Userdata string
|
||||||
|
ServiceOffering string
|
||||||
|
Template string
|
||||||
|
Zone string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListZonesResponse struct {
|
||||||
|
Count int `json:"count"`
|
||||||
|
Zones []*Zone `json:"zone"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Zone struct {
|
||||||
|
Allocationstate string `json:"allocationstate,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Displaytext string `json:"displaytext,omitempty"`
|
||||||
|
Domain string `json:"domain,omitempty"`
|
||||||
|
Domainid string `json:"domainid,omitempty"`
|
||||||
|
Domainname string `json:"domainname,omitempty"`
|
||||||
|
Id string `json:"id,omitempty"`
|
||||||
|
Internaldns1 string `json:"internaldns1,omitempty"`
|
||||||
|
Internaldns2 string `json:"internaldns2,omitempty"`
|
||||||
|
Ip6dns1 string `json:"ip6dns1,omitempty"`
|
||||||
|
Ip6dns2 string `json:"ip6dns2,omitempty"`
|
||||||
|
Localstorageenabled bool `json:"localstorageenabled,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Networktype string `json:"networktype,omitempty"`
|
||||||
|
Resourcedetails map[string]string `json:"resourcedetails,omitempty"`
|
||||||
|
Securitygroupsenabled bool `json:"securitygroupsenabled,omitempty"`
|
||||||
|
Vlan string `json:"vlan,omitempty"`
|
||||||
|
Zonetoken string `json:"zonetoken,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListServiceOfferingsResponse struct {
|
||||||
|
Count int `json:"count"`
|
||||||
|
ServiceOfferings []*ServiceOffering `json:"serviceoffering"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceOffering struct {
|
||||||
|
Cpunumber int `json:"cpunumber,omitempty"`
|
||||||
|
Cpuspeed int `json:"cpuspeed,omitempty"`
|
||||||
|
Displaytext string `json:"displaytext,omitempty"`
|
||||||
|
Domain string `json:"domain,omitempty"`
|
||||||
|
Domainid string `json:"domainid,omitempty"`
|
||||||
|
Hosttags string `json:"hosttags,omitempty"`
|
||||||
|
Id string `json:"id,omitempty"`
|
||||||
|
Iscustomized bool `json:"iscustomized,omitempty"`
|
||||||
|
Issystem bool `json:"issystem,omitempty"`
|
||||||
|
Isvolatile bool `json:"isvolatile,omitempty"`
|
||||||
|
Memory int `json:"memory,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Networkrate int `json:"networkrate,omitempty"`
|
||||||
|
Serviceofferingdetails map[string]string `json:"serviceofferingdetails,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListTemplatesResponse struct {
|
||||||
|
Count int `json:"count"`
|
||||||
|
Templates []*Template `json:"template"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Template struct {
|
||||||
|
Account string `json:"account,omitempty"`
|
||||||
|
Accountid string `json:"accountid,omitempty"`
|
||||||
|
Bootable bool `json:"bootable,omitempty"`
|
||||||
|
Checksum string `json:"checksum,omitempty"`
|
||||||
|
Created string `json:"created,omitempty"`
|
||||||
|
CrossZones bool `json:"crossZones,omitempty"`
|
||||||
|
Details map[string]string `json:"details,omitempty"`
|
||||||
|
Displaytext string `json:"displaytext,omitempty"`
|
||||||
|
Domain string `json:"domain,omitempty"`
|
||||||
|
Domainid string `json:"domainid,omitempty"`
|
||||||
|
Format string `json:"format,omitempty"`
|
||||||
|
Hostid string `json:"hostid,omitempty"`
|
||||||
|
Hostname string `json:"hostname,omitempty"`
|
||||||
|
Hypervisor string `json:"hypervisor,omitempty"`
|
||||||
|
Id string `json:"id,omitempty"`
|
||||||
|
Isdynamicallyscalable bool `json:"isdynamicallyscalable,omitempty"`
|
||||||
|
Isextractable bool `json:"isextractable,omitempty"`
|
||||||
|
Isfeatured bool `json:"isfeatured,omitempty"`
|
||||||
|
Ispublic bool `json:"ispublic,omitempty"`
|
||||||
|
Isready bool `json:"isready,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Ostypeid string `json:"ostypeid,omitempty"`
|
||||||
|
Ostypename string `json:"ostypename,omitempty"`
|
||||||
|
Passwordenabled bool `json:"passwordenabled,omitempty"`
|
||||||
|
Project string `json:"project,omitempty"`
|
||||||
|
Projectid string `json:"projectid,omitempty"`
|
||||||
|
Removed string `json:"removed,omitempty"`
|
||||||
|
Size int `json:"size,omitempty"`
|
||||||
|
Sourcetemplateid string `json:"sourcetemplateid,omitempty"`
|
||||||
|
Sshkeyenabled bool `json:"sshkeyenabled,omitempty"`
|
||||||
|
Status string `json:"status,omitempty"`
|
||||||
|
Zoneid string `json:"zoneid,omitempty"`
|
||||||
|
Zonename string `json:"zonename,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListSSHKeyPairsResponse struct {
|
||||||
|
Count int `json:"count"`
|
||||||
|
SSHKeyPairs []*SSHKeyPair `json:"sshkeypair"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SSHKeyPair struct {
|
||||||
|
Fingerprint string `json:"fingerprint,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type ListSecurityGroupsResponse struct {
|
||||||
|
Count int `json:"count"`
|
||||||
|
SecurityGroups []*SecurityGroup `json:"securitygroup"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecurityGroup struct {
|
||||||
|
Account string `json:"account,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Domain string `json:"domain,omitempty"`
|
||||||
|
Domainid string `json:"domainid,omitempty"`
|
||||||
|
Id string `json:"id,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Project string `json:"project,omitempty"`
|
||||||
|
Projectid string `json:"projectid,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateSecurityGroupResponseWrapper struct {
|
||||||
|
Wrapped CreateSecurityGroupResponse `json:"securitygroup"`
|
||||||
|
}
|
||||||
|
type CreateSecurityGroupResponse struct {
|
||||||
|
Account string `json:"account,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Domain string `json:"domain,omitempty"`
|
||||||
|
Domainid string `json:"domainid,omitempty"`
|
||||||
|
Id string `json:"id,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Project string `json:"project,omitempty"`
|
||||||
|
Projectid string `json:"projectid,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AuthorizeSecurityGroupIngressResponse struct {
|
||||||
|
JobID string `json:"jobid,omitempty"`
|
||||||
|
Account string `json:"account,omitempty"`
|
||||||
|
Cidr string `json:"cidr,omitempty"`
|
||||||
|
Endport int `json:"endport,omitempty"`
|
||||||
|
Icmpcode int `json:"icmpcode,omitempty"`
|
||||||
|
Icmptype int `json:"icmptype,omitempty"`
|
||||||
|
Protocol string `json:"protocol,omitempty"`
|
||||||
|
Ruleid string `json:"ruleid,omitempty"`
|
||||||
|
Securitygroupname string `json:"securitygroupname,omitempty"`
|
||||||
|
Startport int `json:"startport,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AuthorizeSecurityGroupEgressResponse struct {
|
||||||
|
JobID string `json:"jobid,omitempty"`
|
||||||
|
Account string `json:"account,omitempty"`
|
||||||
|
Cidr string `json:"cidr,omitempty"`
|
||||||
|
Endport int `json:"endport,omitempty"`
|
||||||
|
Icmpcode int `json:"icmpcode,omitempty"`
|
||||||
|
Icmptype int `json:"icmptype,omitempty"`
|
||||||
|
Protocol string `json:"protocol,omitempty"`
|
||||||
|
Ruleid string `json:"ruleid,omitempty"`
|
||||||
|
Securitygroupname string `json:"securitygroupname,omitempty"`
|
||||||
|
Startport int `json:"startport,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeployVirtualMachineWrappedResponse struct {
|
||||||
|
Wrapped DeployVirtualMachineResponse `json:"virtualmachine"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeployVirtualMachineResponse struct {
|
||||||
|
JobID string `json:"jobid,omitempty"`
|
||||||
|
Account string `json:"account,omitempty"`
|
||||||
|
Affinitygroup []struct {
|
||||||
|
Account string `json:"account,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Domain string `json:"domain,omitempty"`
|
||||||
|
Domainid string `json:"domainid,omitempty"`
|
||||||
|
Id string `json:"id,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
VirtualmachineIds []string `json:"virtualmachineIds,omitempty"`
|
||||||
|
|
||||||
|
} `json:"affinitygroup,omitempty"`
|
||||||
|
Cpunumber int `json:"cpunumber,omitempty"`
|
||||||
|
Cpuspeed int `json:"cpuspeed,omitempty"`
|
||||||
|
Cpuused string `json:"cpuused,omitempty"`
|
||||||
|
Created string `json:"created,omitempty"`
|
||||||
|
Details map[string]string `json:"details,omitempty"`
|
||||||
|
Diskioread int `json:"diskioread,omitempty"`
|
||||||
|
Diskiowrite int `json:"diskiowrite,omitempty"`
|
||||||
|
Diskkbsread int `json:"diskkbsread,omitempty"`
|
||||||
|
Diskkbswrite int `json:"diskkbswrite,omitempty"`
|
||||||
|
Displayname string `json:"displayname,omitempty"`
|
||||||
|
Displayvm bool `json:"displayvm,omitempty"`
|
||||||
|
Domain string `json:"domain,omitempty"`
|
||||||
|
Domainid string `json:"domainid,omitempty"`
|
||||||
|
Forvirtualnetwork bool `json:"forvirtualnetwork,omitempty"`
|
||||||
|
Group string `json:"group,omitempty"`
|
||||||
|
Groupid string `json:"groupid,omitempty"`
|
||||||
|
Guestosid string `json:"guestosid,omitempty"`
|
||||||
|
Haenable bool `json:"haenable,omitempty"`
|
||||||
|
Hostid string `json:"hostid,omitempty"`
|
||||||
|
Hostname string `json:"hostname,omitempty"`
|
||||||
|
Hypervisor string `json:"hypervisor,omitempty"`
|
||||||
|
Id string `json:"id,omitempty"`
|
||||||
|
Instancename string `json:"instancename,omitempty"`
|
||||||
|
Isdynamicallyscalable bool `json:"isdynamicallyscalable,omitempty"`
|
||||||
|
Isodisplaytext string `json:"isodisplaytext,omitempty"`
|
||||||
|
Isoid string `json:"isoid,omitempty"`
|
||||||
|
Isoname string `json:"isoname,omitempty"`
|
||||||
|
Keypair string `json:"keypair,omitempty"`
|
||||||
|
Memory int `json:"memory,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Networkkbsread int `json:"networkkbsread,omitempty"`
|
||||||
|
Networkkbswrite int `json:"networkkbswrite,omitempty"`
|
||||||
|
Nic []struct {
|
||||||
|
Broadcasturi string `json:"broadcasturi,omitempty"`
|
||||||
|
Gateway string `json:"gateway,omitempty"`
|
||||||
|
Id string `json:"id,omitempty"`
|
||||||
|
Ipaddress string `json:"ipaddress,omitempty"`
|
||||||
|
Isdefault bool `json:"isdefault,omitempty"`
|
||||||
|
Isolationuri string `json:"isolationuri,omitempty"`
|
||||||
|
Macaddress string `json:"macaddress,omitempty"`
|
||||||
|
Netmask string `json:"netmask,omitempty"`
|
||||||
|
Networkid string `json:"networkid,omitempty"`
|
||||||
|
Networkname string `json:"networkname,omitempty"`
|
||||||
|
Secondaryip []string `json:"secondaryip,omitempty"`
|
||||||
|
Traffictype string `json:"traffictype,omitempty"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
} `json:"nic,omitempty"`
|
||||||
|
Password string `json:"password,omitempty"`
|
||||||
|
Passwordenabled bool `json:"passwordenabled,omitempty"`
|
||||||
|
Project string `json:"project,omitempty"`
|
||||||
|
Projectid string `json:"projectid,omitempty"`
|
||||||
|
Publicip string `json:"publicip,omitempty"`
|
||||||
|
Publicipid string `json:"publicipid,omitempty"`
|
||||||
|
Rootdeviceid int `json:"rootdeviceid,omitempty"`
|
||||||
|
Rootdevicetype string `json:"rootdevicetype,omitempty"`
|
||||||
|
Serviceofferingid string `json:"serviceofferingid,omitempty"`
|
||||||
|
Serviceofferingname string `json:"serviceofferingname,omitempty"`
|
||||||
|
Servicestate string `json:"servicestate,omitempty"`
|
||||||
|
State string `json:"state,omitempty"`
|
||||||
|
Templatedisplaytext string `json:"templatedisplaytext,omitempty"`
|
||||||
|
Templateid string `json:"templateid,omitempty"`
|
||||||
|
Templatename string `json:"templatename,omitempty"`
|
||||||
|
Zoneid string `json:"zoneid,omitempty"`
|
||||||
|
Zonename string `json:"zonename,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type QueryAsyncJobResultResponse struct {
|
||||||
|
Accountid string `json:"accountid,omitempty"`
|
||||||
|
Cmd string `json:"cmd,omitempty"`
|
||||||
|
Created string `json:"created,omitempty"`
|
||||||
|
Jobinstanceid string `json:"jobinstanceid,omitempty"`
|
||||||
|
Jobinstancetype string `json:"jobinstancetype,omitempty"`
|
||||||
|
Jobprocstatus int `json:"jobprocstatus,omitempty"`
|
||||||
|
Jobresult json.RawMessage `json:"jobresult,omitempty"`
|
||||||
|
Jobresultcode int `json:"jobresultcode,omitempty"`
|
||||||
|
Jobresulttype string `json:"jobresulttype,omitempty"`
|
||||||
|
Jobstatus int `json:"jobstatus,omitempty"`
|
||||||
|
Userid string `json:"userid,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListVirtualMachinesResponse struct {
|
||||||
|
Count int `json:"count"`
|
||||||
|
VirtualMachines []*VirtualMachine `json:"virtualmachine"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type VirtualMachine struct {
|
||||||
|
Account string `json:"account,omitempty"`
|
||||||
|
Cpunumber int `json:"cpunumber,omitempty"`
|
||||||
|
Cpuspeed int `json:"cpuspeed,omitempty"`
|
||||||
|
Cpuused string `json:"cpuused,omitempty"`
|
||||||
|
Created string `json:"created,omitempty"`
|
||||||
|
Details map[string]string `json:"details,omitempty"`
|
||||||
|
Diskioread int `json:"diskioread,omitempty"`
|
||||||
|
Diskiowrite int `json:"diskiowrite,omitempty"`
|
||||||
|
Diskkbsread int `json:"diskkbsread,omitempty"`
|
||||||
|
Diskkbswrite int `json:"diskkbswrite,omitempty"`
|
||||||
|
Displayname string `json:"displayname,omitempty"`
|
||||||
|
Displayvm bool `json:"displayvm,omitempty"`
|
||||||
|
Domain string `json:"domain,omitempty"`
|
||||||
|
Domainid string `json:"domainid,omitempty"`
|
||||||
|
Forvirtualnetwork bool `json:"forvirtualnetwork,omitempty"`
|
||||||
|
Group string `json:"group,omitempty"`
|
||||||
|
Groupid string `json:"groupid,omitempty"`
|
||||||
|
Guestosid string `json:"guestosid,omitempty"`
|
||||||
|
Haenable bool `json:"haenable,omitempty"`
|
||||||
|
Hostid string `json:"hostid,omitempty"`
|
||||||
|
Hostname string `json:"hostname,omitempty"`
|
||||||
|
Hypervisor string `json:"hypervisor,omitempty"`
|
||||||
|
Id string `json:"id,omitempty"`
|
||||||
|
Instancename string `json:"instancename,omitempty"`
|
||||||
|
Isdynamicallyscalable bool `json:"isdynamicallyscalable,omitempty"`
|
||||||
|
Isodisplaytext string `json:"isodisplaytext,omitempty"`
|
||||||
|
Isoid string `json:"isoid,omitempty"`
|
||||||
|
Isoname string `json:"isoname,omitempty"`
|
||||||
|
Keypair string `json:"keypair,omitempty"`
|
||||||
|
Memory int `json:"memory,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Networkkbsread int `json:"networkkbsread,omitempty"`
|
||||||
|
Networkkbswrite int `json:"networkkbswrite,omitempty"`
|
||||||
|
Nic []struct {
|
||||||
|
Broadcasturi string `json:"broadcasturi,omitempty"`
|
||||||
|
Gateway string `json:"gateway,omitempty"`
|
||||||
|
Id string `json:"id,omitempty"`
|
||||||
|
Ip6address string `json:"ip6address,omitempty"`
|
||||||
|
Ip6cidr string `json:"ip6cidr,omitempty"`
|
||||||
|
Ip6gateway string `json:"ip6gateway,omitempty"`
|
||||||
|
Ipaddress string `json:"ipaddress,omitempty"`
|
||||||
|
Isdefault bool `json:"isdefault,omitempty"`
|
||||||
|
Isolationuri string `json:"isolationuri,omitempty"`
|
||||||
|
Macaddress string `json:"macaddress,omitempty"`
|
||||||
|
Netmask string `json:"netmask,omitempty"`
|
||||||
|
Networkid string `json:"networkid,omitempty"`
|
||||||
|
Networkname string `json:"networkname,omitempty"`
|
||||||
|
Secondaryip []string `json:"secondaryip,omitempty"`
|
||||||
|
Traffictype string `json:"traffictype,omitempty"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
|
||||||
|
} `json:"nic,omitempty"`
|
||||||
|
Password string `json:"password,omitempty"`
|
||||||
|
Passwordenabled bool `json:"passwordenabled,omitempty"`
|
||||||
|
Project string `json:"project,omitempty"`
|
||||||
|
Projectid string `json:"projectid,omitempty"`
|
||||||
|
Publicip string `json:"publicip,omitempty"`
|
||||||
|
Publicipid string `json:"publicipid,omitempty"`
|
||||||
|
Rootdeviceid int `json:"rootdeviceid,omitempty"`
|
||||||
|
Rootdevicetype string `json:"rootdevicetype,omitempty"`
|
||||||
|
Serviceofferingid string `json:"serviceofferingid,omitempty"`
|
||||||
|
Serviceofferingname string `json:"serviceofferingname,omitempty"`
|
||||||
|
Servicestate string `json:"servicestate,omitempty"`
|
||||||
|
State string `json:"state,omitempty"`
|
||||||
|
Templatedisplaytext string `json:"templatedisplaytext,omitempty"`
|
||||||
|
Templateid string `json:"templateid,omitempty"`
|
||||||
|
Templatename string `json:"templatename,omitempty"`
|
||||||
|
Zoneid string `json:"zoneid,omitempty"`
|
||||||
|
Zonename string `json:"zonename,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type StartVirtualMachineResponse struct {
|
||||||
|
JobID string `json:"jobid,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StopVirtualMachineResponse struct {
|
||||||
|
JobID string `json:"jobid,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DestroyVirtualMachineResponse struct {
|
||||||
|
JobID string `json:"jobid,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type RebootVirtualMachineResponse struct {
|
||||||
|
JobID string `json:"jobid,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateSSHKeyPairWrappedResponse struct {
|
||||||
|
Wrapped CreateSSHKeyPairResponse `json:"keypair,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateSSHKeyPairResponse struct {
|
||||||
|
Privatekey string `json:"privatekey,omitempty"`
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
package egoscale
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (exo *Client) CreateVirtualMachine(p MachineProfile) (string, error) {
|
||||||
|
|
||||||
|
params := url.Values{}
|
||||||
|
params.Set("serviceofferingid", p.ServiceOffering)
|
||||||
|
params.Set("templateid", p.Template)
|
||||||
|
params.Set("zoneid", p.Zone)
|
||||||
|
|
||||||
|
params.Set("displayname", p.Name)
|
||||||
|
if len(p.Userdata) > 0 {
|
||||||
|
params.Set("userdata", base64.StdEncoding.EncodeToString([]byte(p.Userdata)))
|
||||||
|
}
|
||||||
|
if len(p.Keypair) > 0 {
|
||||||
|
params.Set("keypair", p.Keypair)
|
||||||
|
}
|
||||||
|
|
||||||
|
params.Set("securitygroupids", strings.Join(p.SecurityGroups, ","))
|
||||||
|
|
||||||
|
resp, err := exo.Request("deployVirtualMachine", params)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var r DeployVirtualMachineResponse
|
||||||
|
|
||||||
|
if err := json.Unmarshal(resp, &r); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.JobID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exo *Client) StartVirtualMachine(id string) (string, error) {
|
||||||
|
params := url.Values{}
|
||||||
|
params.Set("id", id)
|
||||||
|
|
||||||
|
resp, err := exo.Request("startVirtualMachine", params)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var r StartVirtualMachineResponse
|
||||||
|
|
||||||
|
if err := json.Unmarshal(resp, &r); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.JobID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exo *Client) StopVirtualMachine(id string) (string, error) {
|
||||||
|
params := url.Values{}
|
||||||
|
params.Set("id", id)
|
||||||
|
|
||||||
|
resp, err := exo.Request("stopVirtualMachine", params)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var r StopVirtualMachineResponse
|
||||||
|
|
||||||
|
if err := json.Unmarshal(resp, &r); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.JobID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exo *Client) RebootVirtualMachine(id string) (string, error) {
|
||||||
|
params := url.Values{}
|
||||||
|
params.Set("id", id)
|
||||||
|
|
||||||
|
resp, err := exo.Request("rebootVirtualMachine", params)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var r RebootVirtualMachineResponse
|
||||||
|
|
||||||
|
if err := json.Unmarshal(resp, &r); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.JobID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exo *Client) DestroyVirtualMachine(id string) (string, error) {
|
||||||
|
params := url.Values{}
|
||||||
|
params.Set("id", id)
|
||||||
|
|
||||||
|
resp, err := exo.Request("destroyVirtualMachine", params)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var r DestroyVirtualMachineResponse
|
||||||
|
|
||||||
|
if err := json.Unmarshal(resp, &r); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.JobID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (exo *Client) GetVirtualMachine(id string) (*VirtualMachine, error) {
|
||||||
|
|
||||||
|
params := url.Values{}
|
||||||
|
params.Set("id", id)
|
||||||
|
|
||||||
|
resp, err := exo.Request("listVirtualMachines", params)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var r ListVirtualMachinesResponse
|
||||||
|
|
||||||
|
if err := json.Unmarshal(resp, &r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(r.VirtualMachines) == 1 {
|
||||||
|
machine := r.VirtualMachines[0]
|
||||||
|
return machine, nil
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("cannot retrieve virtualmachine with id %s", id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,6 +16,7 @@ import (
|
||||||
_ "github.com/docker/machine/drivers/amazonec2"
|
_ "github.com/docker/machine/drivers/amazonec2"
|
||||||
_ "github.com/docker/machine/drivers/azure"
|
_ "github.com/docker/machine/drivers/azure"
|
||||||
_ "github.com/docker/machine/drivers/digitalocean"
|
_ "github.com/docker/machine/drivers/digitalocean"
|
||||||
|
_ "github.com/docker/machine/drivers/exoscale"
|
||||||
_ "github.com/docker/machine/drivers/google"
|
_ "github.com/docker/machine/drivers/google"
|
||||||
_ "github.com/docker/machine/drivers/hyperv"
|
_ "github.com/docker/machine/drivers/hyperv"
|
||||||
_ "github.com/docker/machine/drivers/none"
|
_ "github.com/docker/machine/drivers/none"
|
||||||
|
|
|
||||||
|
|
@ -1120,6 +1120,21 @@ Options:
|
||||||
|
|
||||||
The VMware vSphere driver uses the latest boot2docker image.
|
The VMware vSphere driver uses the latest boot2docker image.
|
||||||
|
|
||||||
|
#### exoscale
|
||||||
|
Create machines on [exoscale](https://www.exoscale.ch/).
|
||||||
|
|
||||||
|
Get your API key and API secret key from [API details](https://portal.exoscale.ch/account/api) and pass them to `machine create` with the `--exoscale-api-key` and `--exoscale-api-secret-key` options.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
- `--exoscale-api-key`: Your API key.
|
||||||
|
- `--exoscale-api-secret-key`: Your API secret key.
|
||||||
|
- `--exoscale-instance-profile`: Instance profile. Default: `small`.
|
||||||
|
- `--exoscale-disk-size`: Disk size for the host in GB. Default: `50`.
|
||||||
|
- `--exoscale-security-group`: Security group. It will be created if it doesn't exist. Default: `docker-machine`.
|
||||||
|
|
||||||
|
If a custom security group is provided, you need to ensure that you allow TCP port 2376 in an ingress rule.
|
||||||
|
|
||||||
## Release Notes
|
## Release Notes
|
||||||
|
|
||||||
### Version 0.2.0 (April 16, 2015)
|
### Version 0.2.0 (April 16, 2015)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,470 @@
|
||||||
|
package exoscale
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
"github.com/docker/machine/drivers"
|
||||||
|
"github.com/docker/machine/log"
|
||||||
|
"github.com/docker/machine/provider"
|
||||||
|
"github.com/docker/machine/state"
|
||||||
|
"github.com/pyr/egoscale/src/egoscale"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Driver struct {
|
||||||
|
URL string
|
||||||
|
ApiKey string
|
||||||
|
ApiSecretKey string
|
||||||
|
InstanceProfile string
|
||||||
|
DiskSize int
|
||||||
|
Image string
|
||||||
|
SecurityGroup string
|
||||||
|
AvailabilityZone string
|
||||||
|
MachineName string
|
||||||
|
KeyPair string
|
||||||
|
IPAddress string
|
||||||
|
PublicKey string
|
||||||
|
Id string
|
||||||
|
CaCertPath string
|
||||||
|
PrivateKeyPath string
|
||||||
|
DriverKeyPath string
|
||||||
|
SwarmMaster bool
|
||||||
|
SwarmHost string
|
||||||
|
SwarmDiscovery string
|
||||||
|
storePath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
drivers.Register("exoscale", &drivers.RegisteredDriver{
|
||||||
|
New: NewDriver,
|
||||||
|
GetCreateFlags: GetCreateFlags,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterCreateFlags registers the flags this driver adds to
|
||||||
|
// "docker hosts create"
|
||||||
|
func GetCreateFlags() []cli.Flag {
|
||||||
|
return []cli.Flag{
|
||||||
|
cli.StringFlag{
|
||||||
|
EnvVar: "EXOSCALE_ENDPOINT",
|
||||||
|
Name: "exoscale-url",
|
||||||
|
Usage: "exoscale API endpoint",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
EnvVar: "EXOSCALE_API_KEY",
|
||||||
|
Name: "exoscale-api-key",
|
||||||
|
Usage: "exoscale API key",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
EnvVar: "EXOSCALE_API_SECRET",
|
||||||
|
Name: "exoscale-api-secret-key",
|
||||||
|
Usage: "exoscale API secret key",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
EnvVar: "EXOSCALE_INSTANCE_PROFILE",
|
||||||
|
Name: "exoscale-instance-profile",
|
||||||
|
Value: "small",
|
||||||
|
Usage: "exoscale instance profile (small, medium, large, ...)",
|
||||||
|
},
|
||||||
|
cli.IntFlag{
|
||||||
|
EnvVar: "EXOSCALE_DISK_SIZE",
|
||||||
|
Name: "exoscale-disk-size",
|
||||||
|
Value: 50,
|
||||||
|
Usage: "exoscale disk size (10, 50, 100, 200, 400)",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
EnvVar: "EXSOCALE_IMAGE",
|
||||||
|
Name: "exoscale-image",
|
||||||
|
Value: "ubuntu-14.04",
|
||||||
|
Usage: "exoscale image template",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
EnvVar: "EXOSCALE_SECURITY_GROUP",
|
||||||
|
Name: "exoscale-security-group",
|
||||||
|
Value: "docker-machine",
|
||||||
|
Usage: "exoscale security group",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
EnvVar: "EXOSCALE_AVAILABILITY_ZONE",
|
||||||
|
Name: "exoscale-availability-zone",
|
||||||
|
Value: "ch-gva-2",
|
||||||
|
Usage: "exoscale availibility zone",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
EnvVar: "EXOSCALE_KEYPAIR",
|
||||||
|
Name: "exoscale-keypair",
|
||||||
|
Usage: "exoscale keypair name",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDriver(machineName string, storePath string, caCert string, privateKey string) (drivers.Driver, error) {
|
||||||
|
return &Driver{MachineName: machineName, storePath: storePath, CaCertPath: caCert, PrivateKeyPath: privateKey}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) AuthorizePort(ports []*drivers.Port) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) DeauthorizePort(ports []*drivers.Port) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) GetMachineName() string {
|
||||||
|
return d.MachineName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) GetSSHHostname() (string, error) {
|
||||||
|
return d.GetIP()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) GetSSHKeyPath() string {
|
||||||
|
return filepath.Join(d.storePath, "id_rsa")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) GetSSHPort() (int, error) {
|
||||||
|
return 22, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) GetSSHUsername() string {
|
||||||
|
return "ubuntu"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) GetProviderType() provider.ProviderType {
|
||||||
|
return provider.Remote
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) DriverName() string {
|
||||||
|
return "exoscale"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
|
||||||
|
d.URL = flags.String("exoscale-endpoint")
|
||||||
|
d.ApiKey = flags.String("exoscale-api-key")
|
||||||
|
d.ApiSecretKey = flags.String("exoscale-api-secret-key")
|
||||||
|
d.InstanceProfile = flags.String("exoscale-instance-profile")
|
||||||
|
d.DiskSize = flags.Int("exoscale-disk-size")
|
||||||
|
d.Image = flags.String("exoscale-image")
|
||||||
|
d.SecurityGroup = flags.String("exoscale-security-group")
|
||||||
|
d.AvailabilityZone = flags.String("exoscale-availability-zone")
|
||||||
|
d.KeyPair = flags.String("exoscale-keypair")
|
||||||
|
d.SwarmMaster = flags.Bool("swarm-master")
|
||||||
|
d.SwarmHost = flags.String("swarm-host")
|
||||||
|
d.SwarmDiscovery = flags.String("swarm-discovery")
|
||||||
|
|
||||||
|
if d.URL == "" {
|
||||||
|
d.URL = "https://api.exoscale.ch/compute"
|
||||||
|
}
|
||||||
|
if d.ApiKey == "" || d.ApiSecretKey == "" {
|
||||||
|
return fmt.Errorf("Please specify an API key (--exoscale-api-key) and an API secret key (--exoscale-api-secret-key).")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) GetURL() (string, error) {
|
||||||
|
ip, err := d.GetIP()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("tcp://%s:2376", ip), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) GetIP() (string, error) {
|
||||||
|
if d.IPAddress == "" {
|
||||||
|
return "", fmt.Errorf("IP address is not set")
|
||||||
|
}
|
||||||
|
return d.IPAddress, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) GetState() (state.State, error) {
|
||||||
|
client := egoscale.NewClient(d.URL, d.ApiKey, d.ApiSecretKey)
|
||||||
|
vm, err := client.GetVirtualMachine(d.Id)
|
||||||
|
if err != nil {
|
||||||
|
return state.Error, err
|
||||||
|
}
|
||||||
|
switch vm.State {
|
||||||
|
case "Starting":
|
||||||
|
return state.Starting, nil
|
||||||
|
case "Running":
|
||||||
|
return state.Running, nil
|
||||||
|
case "Stopping":
|
||||||
|
return state.Running, nil
|
||||||
|
case "Stopped":
|
||||||
|
return state.Stopped, nil
|
||||||
|
case "Destroyed":
|
||||||
|
return state.Stopped, nil
|
||||||
|
case "Expunging":
|
||||||
|
return state.Stopped, nil
|
||||||
|
case "Migrating":
|
||||||
|
return state.Paused, nil
|
||||||
|
case "Error":
|
||||||
|
return state.Error, nil
|
||||||
|
case "Unknown":
|
||||||
|
return state.Error, nil
|
||||||
|
case "Shutdowned":
|
||||||
|
return state.Stopped, nil
|
||||||
|
}
|
||||||
|
return state.None, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) PreCreateCheck() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) Create() error {
|
||||||
|
log.Infof("Querying exoscale for the requested parameters...")
|
||||||
|
client := egoscale.NewClient(d.URL, d.ApiKey, d.ApiSecretKey)
|
||||||
|
topology, err := client.GetTopology()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Availability zone UUID
|
||||||
|
zone, ok := topology.Zones[d.AvailabilityZone]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Availability zone %v doesn't exist",
|
||||||
|
d.AvailabilityZone)
|
||||||
|
}
|
||||||
|
log.Debugf("Availability zone %v = %s", d.AvailabilityZone, zone)
|
||||||
|
|
||||||
|
// Image UUID
|
||||||
|
var tpl string
|
||||||
|
images, ok := topology.Images[strings.ToLower(d.Image)]
|
||||||
|
if ok {
|
||||||
|
tpl, ok = images[d.DiskSize]
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Unable to find image %v with size %d",
|
||||||
|
d.Image, d.DiskSize)
|
||||||
|
}
|
||||||
|
log.Debugf("Image %v(%d) = %s", d.Image, d.DiskSize, tpl)
|
||||||
|
|
||||||
|
// Profile UUID
|
||||||
|
profile, ok := topology.Profiles[strings.ToLower(d.InstanceProfile)]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Unable to find the %s profile",
|
||||||
|
d.InstanceProfile)
|
||||||
|
}
|
||||||
|
log.Debugf("Profile %v = %s", d.InstanceProfile, profile)
|
||||||
|
|
||||||
|
// Security group
|
||||||
|
sg, ok := topology.SecurityGroups[d.SecurityGroup]
|
||||||
|
if !ok {
|
||||||
|
log.Infof("Security group %v does not exist, create it",
|
||||||
|
d.SecurityGroup)
|
||||||
|
rules := []egoscale.SecurityGroupRule{
|
||||||
|
{
|
||||||
|
SecurityGroupId: "",
|
||||||
|
Cidr: "0.0.0.0/0",
|
||||||
|
Protocol: "TCP",
|
||||||
|
Port: 22,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SecurityGroupId: "",
|
||||||
|
Cidr: "0.0.0.0/0",
|
||||||
|
Protocol: "TCP",
|
||||||
|
Port: 2376,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SecurityGroupId: "",
|
||||||
|
Cidr: "0.0.0.0/0",
|
||||||
|
Protocol: "ICMP",
|
||||||
|
IcmpType: 8,
|
||||||
|
IcmpCode: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
sgresp, err := client.CreateSecurityGroupWithRules(d.SecurityGroup,
|
||||||
|
rules,
|
||||||
|
make([]egoscale.SecurityGroupRule, 0, 0))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sg = sgresp.Id
|
||||||
|
}
|
||||||
|
log.Debugf("Security group %v = %s", d.SecurityGroup, sg)
|
||||||
|
|
||||||
|
if d.KeyPair == "" {
|
||||||
|
log.Infof("Generate an SSH keypair...")
|
||||||
|
kpresp, err := client.CreateKeypair(d.MachineName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = ioutil.WriteFile(d.GetSSHKeyPath(), []byte(kpresp.Privatekey), 0600)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.KeyPair = d.MachineName
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("Spawn exoscale host...")
|
||||||
|
|
||||||
|
userdata, err := d.getCloudInit()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Debugf("Using the following cloud-init file:")
|
||||||
|
log.Debugf("%s", userdata)
|
||||||
|
|
||||||
|
machineProfile := egoscale.MachineProfile{
|
||||||
|
Template: tpl,
|
||||||
|
ServiceOffering: profile,
|
||||||
|
SecurityGroups: []string{sg},
|
||||||
|
Userdata: userdata,
|
||||||
|
Zone: zone,
|
||||||
|
Keypair: d.KeyPair,
|
||||||
|
Name: d.MachineName,
|
||||||
|
}
|
||||||
|
|
||||||
|
cvmresp, err := client.CreateVirtualMachine(machineProfile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
vm, err := d.waitForVM(client, cvmresp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.IPAddress = vm.Nic[0].Ipaddress
|
||||||
|
d.Id = vm.Id
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) Start() error {
|
||||||
|
vmstate, err := d.GetState()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if vmstate == state.Running || vmstate == state.Starting {
|
||||||
|
log.Infof("Host is already running or starting")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
client := egoscale.NewClient(d.URL, d.ApiKey, d.ApiSecretKey)
|
||||||
|
svmresp, err := client.StartVirtualMachine(d.Id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = d.waitForVM(client, svmresp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) Stop() error {
|
||||||
|
vmstate, err := d.GetState()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if vmstate == state.Stopped {
|
||||||
|
log.Infof("Host is already stopped")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
client := egoscale.NewClient(d.URL, d.ApiKey, d.ApiSecretKey)
|
||||||
|
svmresp, err := client.StopVirtualMachine(d.Id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = d.waitForVM(client, svmresp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) Remove() error {
|
||||||
|
client := egoscale.NewClient(d.URL, d.ApiKey, d.ApiSecretKey)
|
||||||
|
dvmresp, err := client.DestroyVirtualMachine(d.Id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = d.waitForVM(client, dvmresp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) Restart() error {
|
||||||
|
vmstate, err := d.GetState()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if vmstate == state.Stopped {
|
||||||
|
return fmt.Errorf("Host is stopped, use start command to start it")
|
||||||
|
}
|
||||||
|
|
||||||
|
client := egoscale.NewClient(d.URL, d.ApiKey, d.ApiSecretKey)
|
||||||
|
svmresp, err := client.RebootVirtualMachine(d.Id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = d.waitForVM(client, svmresp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) Kill() error {
|
||||||
|
return d.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) waitForVM(client *egoscale.Client, jobid string) (*egoscale.DeployVirtualMachineResponse, error) {
|
||||||
|
log.Infof("Waiting for VM...")
|
||||||
|
maxRepeats := 60
|
||||||
|
i := 0
|
||||||
|
var resp *egoscale.QueryAsyncJobResultResponse
|
||||||
|
var err error
|
||||||
|
for ; i < maxRepeats; i++ {
|
||||||
|
resp, err = client.PollAsyncJob(jobid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Jobstatus == 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
}
|
||||||
|
if i == maxRepeats {
|
||||||
|
return nil, fmt.Errorf("Timeout while waiting for VM")
|
||||||
|
}
|
||||||
|
vm, err := client.AsyncToVirtualMachine(*resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return vm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a cloud-init user data string that will install and run
|
||||||
|
// docker.
|
||||||
|
func (d *Driver) getCloudInit() (string, error) {
|
||||||
|
const tpl = `#cloud-config
|
||||||
|
manage_etc_hosts: true
|
||||||
|
fqdn: {{ .MachineName }}
|
||||||
|
resize_rootfs: true
|
||||||
|
`
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
|
||||||
|
tmpl, err := template.New("cloud-init").Parse(tpl)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
err = tmpl.Execute(&buffer, d)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return buffer.String(), nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package exoscale
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
load helpers
|
||||||
|
|
||||||
|
export DRIVER=exoscale
|
||||||
|
export NAME="bats-$DRIVER-test"
|
||||||
|
export MACHINE_STORAGE_PATH=/tmp/machine-bats-test-$DRIVER
|
||||||
|
|
||||||
|
@test "$DRIVER: machine should not exist" {
|
||||||
|
run machine active $NAME
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: create" {
|
||||||
|
run machine create -d $DRIVER $NAME
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: active" {
|
||||||
|
run machine active $NAME
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: ls" {
|
||||||
|
run machine ls
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ ${lines[1]} == *"$NAME"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: run busybox container" {
|
||||||
|
run docker $(machine config $NAME) run busybox echo hello world
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: url" {
|
||||||
|
run machine url $NAME
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: ip" {
|
||||||
|
run machine ip $NAME
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: ssh" {
|
||||||
|
run machine ssh $NAME -- ls -lah /
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ ${lines[0]} =~ "total" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: docker commands with the socket should work" {
|
||||||
|
run machine ssh $NAME -- docker version
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: stop" {
|
||||||
|
run machine stop $NAME
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: machine should show stopped after stop" {
|
||||||
|
run machine ls
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ ${lines[1]} == *"Stopped"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: start" {
|
||||||
|
run machine start $NAME
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: machine should show running after start" {
|
||||||
|
run machine ls
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ ${lines[1]} == *"Running"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: kill" {
|
||||||
|
run machine kill $NAME
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: machine should show stopped after kill" {
|
||||||
|
run machine ls
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ ${lines[1]} == *"Stopped"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: restart" {
|
||||||
|
run machine restart $NAME
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: machine should show running after restart" {
|
||||||
|
run machine ls
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ ${lines[1]} == *"Running"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: remove" {
|
||||||
|
run sleep 20
|
||||||
|
run machine rm -f $NAME
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: machine should not exist" {
|
||||||
|
run machine active $NAME
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: cleanup" {
|
||||||
|
run rm -rf $MACHINE_STORAGE_PATH
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in New Issue