-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
293 additions
and
0 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 |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/* | ||
Package projects provides the ability to retrieve and manage projects through the | ||
Resell v2 API. | ||
Example of getting a single project referenced by its id | ||
project, _, err := projects.Get(context, resellClient, projectID) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
fmt.Println(project) | ||
*/ | ||
package projects |
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,33 @@ | ||
package projects | ||
|
||
import ( | ||
"context" | ||
"strings" | ||
|
||
"github.com/selectel/go-selvpcclient/selvpcclient" | ||
) | ||
|
||
const resourceURL = "projects" | ||
|
||
// Get returns a single project by its id. | ||
func Get(ctx context.Context, client *selvpcclient.ServiceClient, id string) (*Project, *selvpcclient.ResponseResult, error) { | ||
url := strings.Join([]string{client.Endpoint, resourceURL, id}, "/") | ||
responseResult, err := client.DoRequest(ctx, "GET", url, nil) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
if responseResult.Err != nil { | ||
return nil, responseResult, responseResult.Err | ||
} | ||
|
||
// Extract a project from the response body. | ||
var result struct { | ||
Project *Project `json:"project"` | ||
} | ||
err = responseResult.ExtractResult(&result) | ||
if err != nil { | ||
return nil, responseResult, err | ||
} | ||
|
||
return result.Project, responseResult, 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,88 @@ | ||
package projects | ||
|
||
import ( | ||
"encoding/json" | ||
|
||
"github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/quotas" | ||
) | ||
|
||
// Project represents a single Resell project. | ||
type Project struct { | ||
// ID is a unique id of a project. | ||
ID string `json:"-"` | ||
|
||
// Name is a human-readable name of a project. | ||
Name string `json:"-"` | ||
|
||
// URL is a public url of a project that is set by the admin API. | ||
URL string `json:"-"` | ||
|
||
// Enabled shows if project is active or it was disabled by the admin API. | ||
Enabled bool `json:"-"` | ||
|
||
// CustomURL is a public url of a project that can be set by a user. | ||
CustomURL string `json:"-"` | ||
|
||
// Theme represents project theme settings. | ||
Theme Theme `json:"-"` | ||
|
||
// Quotas contains information about project quotas. | ||
Quotas []quotas.Quota `json:"-"` | ||
} | ||
|
||
// UnmarshalJSON implements custom unmarshalling method for the Project type. | ||
func (result *Project) UnmarshalJSON(b []byte) error { | ||
// Populate temporary structure with resource quotas represented as maps. | ||
var s struct { | ||
ID string `json:"id"` | ||
Name string `json:"name"` | ||
URL string `json:"url"` | ||
Enabled bool `json:"enabled"` | ||
CustomURL string `json:"custom_url"` | ||
Theme Theme `json:"theme"` | ||
Quotas map[string][]quotas.ResourceQuotaEntity `json:"quotas"` | ||
} | ||
err := json.Unmarshal(b, &s) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Populate the result with the unmarshalled data. | ||
*result = Project{ | ||
ID: s.ID, | ||
Name: s.Name, | ||
URL: s.URL, | ||
Enabled: s.Enabled, | ||
CustomURL: s.CustomURL, | ||
Theme: s.Theme, | ||
} | ||
|
||
if len(s.Quotas) != 0 { | ||
// Convert resource quota maps to the slice of Quota types. | ||
// Here we're allocating memory in advance because we already know the length | ||
// of a result slice from the JSON bytearray. | ||
resourceQuotasSlice := make([]quotas.Quota, len(s.Quotas)) | ||
i := 0 | ||
for resourceName, resourceQuotas := range s.Quotas { | ||
resourceQuotasSlice[i] = quotas.Quota{ | ||
Name: resourceName, | ||
ResourceQuotasEntities: resourceQuotas, | ||
} | ||
i++ | ||
} | ||
|
||
// Add the unmarshalled quotas slice to the result. | ||
result.Quotas = resourceQuotasSlice | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Theme represents theme settings for a single project. | ||
type Theme struct { | ||
// Color is a hex string with a custom background color. | ||
Color string `json:"color"` | ||
|
||
// Logo contains url for the project custom header logotype. | ||
Logo string `json:"logo"` | ||
} |
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,102 @@ | ||
package testing | ||
|
||
import ( | ||
"github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/projects" | ||
"github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/quotas" | ||
) | ||
|
||
// TestGetProjectResponseRaw represents a raw response from the Get request. | ||
const TestGetProjectResponseRaw = ` | ||
{ | ||
"project": { | ||
"custom_url": null, | ||
"enabled": true, | ||
"id": "49338ac045f448e294b25d013f890317", | ||
"name": "Project1", | ||
"quotas": { | ||
"compute_cores": [ | ||
{ | ||
"region": "ru-1", | ||
"used": 2, | ||
"value": 10, | ||
"zone": "ru-1b" | ||
} | ||
], | ||
"compute_ram": [ | ||
{ | ||
"region": "ru-1", | ||
"used": 8192, | ||
"value": 10240, | ||
"zone": "ru-1b" | ||
} | ||
], | ||
"image_gigabytes": [ | ||
{ | ||
"region": "ru-1", | ||
"used": 4, | ||
"value": 12, | ||
"zone": null | ||
} | ||
] | ||
}, | ||
"theme": { | ||
"color": "#581845", | ||
"logo": null | ||
}, | ||
"url": "https://xxxxxx.selvpc.ru" | ||
} | ||
} | ||
` | ||
|
||
// TestGetProjectResponseSingleQuotaRaw represents a raw response with a single quota from the Get request. | ||
const TestGetProjectResponseSingleQuotaRaw = ` | ||
{ | ||
"project": { | ||
"custom_url": null, | ||
"enabled": true, | ||
"id": "49338ac045f448e294b25d013f890317", | ||
"name": "Project1", | ||
"quotas": { | ||
"compute_cores": [ | ||
{ | ||
"region": "ru-1", | ||
"used": 2, | ||
"value": 10, | ||
"zone": "ru-1b" | ||
} | ||
] | ||
}, | ||
"theme": { | ||
"color": "#581845", | ||
"logo": null | ||
}, | ||
"url": "https://xxxxxx.selvpc.ru" | ||
} | ||
} | ||
` | ||
|
||
// TestGetProjectSingleQuotaResponse represents the unmarshalled TestGetProjectResponseSingleQuotaRaw response. | ||
var TestGetProjectSingleQuotaResponse = &projects.Project{ | ||
ID: "49338ac045f448e294b25d013f890317", | ||
Name: "Project1", | ||
URL: "https://xxxxxx.selvpc.ru", | ||
Enabled: true, | ||
CustomURL: "", | ||
Theme: projects.Theme{ | ||
Color: "#581845", | ||
Logo: "", | ||
}, | ||
Quotas: []quotas.Quota{ | ||
{ | ||
Name: "compute_cores", | ||
ResourceQuotasEntities: []quotas.ResourceQuotaEntity{ | ||
{ | ||
Region: "ru-1", | ||
Used: 2, | ||
Value: 10, | ||
Zone: "ru-1b", | ||
}, | ||
}, | ||
}, | ||
}, | ||
} |
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,57 @@ | ||
package testing | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/projects" | ||
"github.com/selectel/go-selvpcclient/selvpcclient/testutils" | ||
) | ||
|
||
func TestGetProject(t *testing.T) { | ||
testEnv := testutils.SetupTestEnv() | ||
defer testEnv.TearDownTestEnv() | ||
testEnv.NewTestResellV2Client() | ||
testEnv.Mux.HandleFunc("/resell/v2/projects/49338ac045f448e294b25d013f890317", func(w http.ResponseWriter, r *http.Request) { | ||
w.Header().Add("Content-Type", "application/json") | ||
fmt.Fprintf(w, TestGetProjectResponseRaw) | ||
}) | ||
|
||
ctx := context.Background() | ||
actual, _, err := projects.Get(ctx, testEnv.Client, "49338ac045f448e294b25d013f890317") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
if actual == nil { | ||
t.Fatal("didn't get project") | ||
} | ||
if len(actual.Quotas) != 3 { | ||
t.Errorf("expected 3 quotas in project, but got %d", len(actual.Quotas)) | ||
} | ||
} | ||
|
||
func TestGetProjectSingleQuota(t *testing.T) { | ||
testEnv := testutils.SetupTestEnv() | ||
defer testEnv.TearDownTestEnv() | ||
testEnv.NewTestResellV2Client() | ||
testEnv.Mux.HandleFunc("/resell/v2/projects/49338ac045f448e294b25d013f890317", func(w http.ResponseWriter, r *http.Request) { | ||
w.Header().Add("Content-Type", "application/json") | ||
fmt.Fprintf(w, TestGetProjectResponseSingleQuotaRaw) | ||
}) | ||
|
||
ctx := context.Background() | ||
actual, _, err := projects.Get(ctx, testEnv.Client, "49338ac045f448e294b25d013f890317") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
expected := TestGetProjectSingleQuotaResponse | ||
|
||
if !reflect.DeepEqual(actual, expected) { | ||
t.Fatalf("expected %#v, but got %#v", expected, actual) | ||
} | ||
} |