diff --git a/compute/droplet/instance.go b/compute/droplet/instance.go index 024c9c3..601221b 100644 --- a/compute/droplet/instance.go +++ b/compute/droplet/instance.go @@ -5,10 +5,11 @@ import ( "encoding/json" "errors" "fmt" - digioceanAuth "github.com/cloudlibz/gocloud/digioceanauth" "io/ioutil" "net/http" "strconv" + + digioceanAuth "github.com/cloudlibz/gocloud/digioceanauth" ) // dropletBasePath is the endpoint URL for digitalocean API. diff --git a/compute/rackspacecompute/instance.go b/compute/rackspacecompute/instance.go index 9bec522..5ba39fe 100644 --- a/compute/rackspacecompute/instance.go +++ b/compute/rackspacecompute/instance.go @@ -1,7 +1,83 @@ package rackspacecompute +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + + "github.com/cloudlibz/gocloud/rackspaceauth" +) + +var cloudserverEndpoints = rackspaceauth.Token.Endpoints["cloudServer"] + // CreateNode function creates a new rackspacecompute instance. func (rackspacecompute *Rackspacecompute) CreateNode(request interface{}) (resp interface{}, err error) { + var cloudserverInstance Cloudserver // Initialize Cloudserver struct + var region string + rackSpaceAuthToken := rackspaceauth.Token.RackSpaceAuthToken // Fetch the DigiOceanAccessToken + + param := request.(map[string]interface{}) + + for key, value := range param { + + switch key { + + case "Name": + name, _ := value.(string) + cloudserverInstance.Name = name + + case "ImageRef": + imageparam, _ := value.(string) + cloudserverInstance.ImageRef = imageparam + + case "FlavourRef": + flavourparam, _ := value.(string) + cloudserverInstance.FlavorRef = flavourparam + + case "Region": + region, _ = value.(string) + } // Closes switch-case + + } // Closes for loop + + rackspacecompute.Server = cloudserverInstance + rackspacecomputeJSON, _ := json.Marshal(rackspacecompute) + + var cloudserverEndpoint string + flag := 0 + for _, endpoint := range cloudserverEndpoints { + if endpoint.Region == region { + cloudserverEndpoint = endpoint.URL + flag = 1 + break + } + } + if flag == 0 { + return nil, fmt.Errorf("Could not find a endpoint for the giver region : %s", region) + } + + createNodereq, err := http.NewRequest("POST", cloudserverEndpoint, bytes.NewBuffer(rackspacecomputeJSON)) + if err != nil { + fmt.Println(err) + } + createNodereq.Header.Set("Content-Type", "application/json") + createNodereq.Header.Set("X-Auth-Token", rackSpaceAuthToken) + + createNoderesp, err := http.DefaultClient.Do(createNodereq) + if err != nil { + fmt.Println(err) + } + + defer createNoderesp.Body.Close() + + responseBody, err := ioutil.ReadAll(createNoderesp.Body) + createNoderesponse := make(map[string]interface{}) + createNoderesponse["status"] = createNoderesp.StatusCode + createNoderesponse["body"] = string(responseBody) + resp = createNoderesponse + return resp, err } diff --git a/compute/rackspacecompute/instance_test.go b/compute/rackspacecompute/instance_test.go new file mode 100644 index 0000000..c086806 --- /dev/null +++ b/compute/rackspacecompute/instance_test.go @@ -0,0 +1,20 @@ +package rackspacecompute + +import "testing" + +func TestCreateNode(t *testing.T) { + + var rackspacecompute Rackspacecompute + + request := map[string]interface{}{ + "Name": "testcloudserver", + "ImageRef": "3afe97b2-26dc-49c5-a2cc-a2fc8d80c001", + "FlavourRef": "2", + "Region": "DFW", + } + _, err := rackspacecompute.CreateNode(request) + + if err != nil { + t.Errorf("Test Fail") + } +} diff --git a/compute/rackspacecompute/rackspacecompute.go b/compute/rackspacecompute/rackspacecompute.go index 0e450d6..64c3bea 100644 --- a/compute/rackspacecompute/rackspacecompute.go +++ b/compute/rackspacecompute/rackspacecompute.go @@ -2,4 +2,12 @@ package rackspacecompute // Rackspacecompute represents a request to create a Rackspace compute instance. type Rackspacecompute struct { + Server Cloudserver `json:"server"` +} + +// Cloudserver represents a node of cloud server on rackspace +type Cloudserver struct { + Name string `json:"name"` + ImageRef string `json:"imageRef"` + FlavorRef string `json:"flavorRef"` } diff --git a/gocloud/gocloud.go b/gocloud/gocloud.go index 75f2ecb..29ac7d4 100644 --- a/gocloud/gocloud.go +++ b/gocloud/gocloud.go @@ -2,6 +2,7 @@ package gocloud import ( "fmt" + "github.com/cloudlibz/gocloud/ali" aliAuth "github.com/cloudlibz/gocloud/aliauth" awsAuth "github.com/cloudlibz/gocloud/auth" @@ -12,6 +13,7 @@ import ( "github.com/cloudlibz/gocloud/google" "github.com/cloudlibz/gocloud/openstack" "github.com/cloudlibz/gocloud/rackspace" + "github.com/cloudlibz/gocloud/rackspaceauth" "github.com/cloudlibz/gocloud/vultr" "github.com/cloudlibz/gocloud/vultrauth" ) @@ -112,6 +114,7 @@ func CloudProvider(provider string) (Gocloud, error) { return new(ali.Ali), nil case Rackspaceprovider: + rackspaceauth.LoadConfigAndAuthenticate() return new(rackspace.Rackspace), nil case Vultrprovider: diff --git a/rackspaceauth/rackspaceauth.go b/rackspaceauth/rackspaceauth.go new file mode 100644 index 0000000..88eb64b --- /dev/null +++ b/rackspaceauth/rackspaceauth.go @@ -0,0 +1,106 @@ +package rackspaceauth + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "log" + "net/http" + "os" +) + +// TokenSource struct for representing RackSpace credentials. +type TokenSource struct { + RackSpaceTenantID string + RackSpaceTenantName string + RackSpaceAuthToken string + RackSpaceAPIKey string + RackSpaceUsername string + Endpoints map[string][]Endpoint +} + +// Endpoint represents the enpoint of a particular service +type Endpoint struct { + URL string `json:"publicURL"` + Region string `json:"region"` +} + +// Token is a variable of type TokenSource. +var Token TokenSource + +// LoadConfigAndAuthenticate loads the RackSpace credentials. +func LoadConfigAndAuthenticate() { + + // Read from file first. + var home = os.Getenv("HOME") + file, _ := os.Open(home + "/.gocloud" + "/rackspacecloudconfig.json") + + // Defer the closing of our file so that we can parse it later on. + defer file.Close() + + // We initialize TokenSource struct. + decoder := json.NewDecoder(file) + Token = TokenSource{} + _ = decoder.Decode(&Token) + + if Token.RackSpaceAPIKey == "" || Token.RackSpaceUsername == "" { + // If digioceancloudconfig.json doesn't exist, look for credentials as environment variables. + + Token.RackSpaceAPIKey = os.Getenv("RackSpaceAPIKey") + Token.RackSpaceUsername = os.Getenv("RackSpaceUsername") + if Token.RackSpaceAPIKey == "" || Token.RackSpaceUsername == "" { + log.Fatalln("Cannot get access token for RackSpace.") + } + } + + // prepare the authoriation request + url := "https://identity.api.rackspacecloud.com/v2.0/tokens" + authRequestData := map[string]interface{}{ + "auth": map[string]interface{}{ + "RAX-KSKEY:apiKeyCredentials": map[string]interface{}{ + "username": Token.RackSpaceUsername, + "apiKey": Token.RackSpaceAPIKey, + }, + }, + } + jsonStr, err := json.Marshal(authRequestData) + if err != nil { + log.Fatalln("Failed to marshal json") + } + req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr)) + if err != nil { + log.Fatalln("Failed to create the request") + } + req.Header.Set("Content-Type", "application/json") + + // make the authorization request + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + log.Fatalln("Failed to make the request") + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Fatalln("Failed to read the response body") + } + + // Extract the Auth Token and the tenant details + respJSON := make(map[string]interface{}) + err = json.Unmarshal(body, &respJSON) + if err != nil { + log.Fatalln("Failed to unmarshal response JSON") + } + accessJSON := respJSON["access"].(map[string]interface{}) + tokenJSON := accessJSON["token"].(map[string]interface{}) + serviceCatalogJSON := accessJSON["serviceCatalog"].([]map[string]interface{}) + for _, service := range serviceCatalogJSON { + endpointsBytes, _ := json.Marshal(service["endpoints"].([]map[string]interface{})) + serviceName := service["name"].(string) + json.Unmarshal(endpointsBytes, Token.Endpoints[serviceName]) + } + Token.RackSpaceAuthToken = tokenJSON["id"].(string) + tenantJSON := tokenJSON["tenant"].(map[string]interface{}) + Token.RackSpaceTenantID = tenantJSON["id"].(string) + Token.RackSpaceTenantName = tenantJSON["name"].(string) +}