Skip to content

Commit

Permalink
Merge pull request #944 from jtopjian/zun-merge
Browse files Browse the repository at this point in the history
Zun merge
  • Loading branch information
jtopjian committed Apr 24, 2018
2 parents c51806d + 10a32ce commit d240260
Show file tree
Hide file tree
Showing 11 changed files with 364 additions and 0 deletions.
19 changes: 19 additions & 0 deletions acceptance/clients/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,25 @@ func NewMessagingV2Client(clientID string) (*gophercloud.ServiceClient, error) {
})
}

// NewContainerV1Client returns a *ServiceClient for making calls
// to the OpenStack Container V1 API. An error will be returned
// if authentication or client creation was not possible.
func NewContainerV1Client() (*gophercloud.ServiceClient, error) {
ao, err := openstack.AuthOptionsFromEnv()
if err != nil {
return nil, err
}

client, err := openstack.AuthenticatedClient(ao)
if err != nil {
return nil, err
}

return openstack.NewContainerV1(client, gophercloud.EndpointOpts{
Region: os.Getenv("OS_REGION_NAME"),
})
}

// configureDebug will configure the provider client to print the API
// requests and responses if OS_DEBUG is enabled.
func configureDebug(client *gophercloud.ProviderClient) *gophercloud.ProviderClient {
Expand Down
28 changes: 28 additions & 0 deletions acceptance/openstack/container/v1/capsules_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package v1

import (
"testing"

"github.com/gophercloud/gophercloud/acceptance/clients"
"github.com/gophercloud/gophercloud/openstack/container/v1/capsules"
th "github.com/gophercloud/gophercloud/testhelper"
)

func TestCapsuleGet(t *testing.T) {
client, err := clients.NewContainerV1Client()
if err != nil {
t.Fatalf("Unable to create an container v1 client: %v", err)
}
th.AssertNoErr(t, err)
capsuleUUID := "e6c913bb-b4e4-409d-8b71-3e029f196458"
if capsuleUUID == "" {
t.Fatalf("In order to retrieve a capsule, the CapsuleUUID must be set")
}
capsule, err := capsules.Get(client, capsuleUUID).Extract()
// Get a capsule

th.AssertNoErr(t, err)
th.AssertEquals(t, capsule.Status, "Running")
th.AssertEquals(t, capsule.MetaName, "template")
th.AssertEquals(t, capsule.CPU, float64(2.0))
}
5 changes: 5 additions & 0 deletions openstack/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,3 +408,8 @@ func NewMessagingV2(client *gophercloud.ProviderClient, clientID string, eo goph
sc.MoreHeaders = map[string]string{"Client-ID": clientID}
return sc, err
}

// NewContainerV1 creates a ServiceClient that may be used with v1 container package
func NewContainerV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
return initClientOpts(client, eo, "container")
}
4 changes: 4 additions & 0 deletions openstack/container/v1/capsules/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Package capsules contains functionality for working with Zun capsule
// resources. A capsule is a container group, as the co-located and
// co-scheduled unit, is the same like pod in Kubernetes.
package capsules
13 changes: 13 additions & 0 deletions openstack/container/v1/capsules/requests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package capsules

import (
"github.com/gophercloud/gophercloud"
)

// Get requests details on a single capsule, by ID.
func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
_, r.Err = client.Get(getURL(client, id), &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200, 203},
})
return
}
107 changes: 107 additions & 0 deletions openstack/container/v1/capsules/results.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package capsules

import (
"encoding/json"
"time"

"github.com/gophercloud/gophercloud"
)

type commonResult struct {
gophercloud.Result
}

// Extract is a function that accepts a result and extracts a capsule resource.
func (r commonResult) Extract() (*Capsule, error) {
var s *Capsule
err := r.ExtractInto(&s)
return s, err
}

// GetResult represents the result of a get operation.
type GetResult struct {
commonResult
}

// Represents a Container Orchestration Engine Bay, i.e. a cluster
type Capsule struct {
// UUID for the capsule
UUID string `json:"uuid"`

// ID for the capsule
ID int `json:"id"`

// User ID for the capsule
UserID string `json:"user_id"`

// Project ID for the capsule
ProjectID string `json:"project_id"`

// cpu for the capsule
CPU float64 `json:"cpu"`

// Memory for the capsule
Memory string `json:"memory"`

// The name of the capsule
MetaName string `json:"meta_name"`

// Indicates whether capsule is currently operational. Possible values include:
// Running,
Status string `json:"status"`

// The created time of the capsule.
CreatedAt time.Time `json:"-"`

// The updated time of the capsule.
UpdatedAt time.Time `json:"-"`

// Links includes HTTP references to the itself, useful for passing along to
// other APIs that might want a server reference.
Links []interface{} `json:"links"`

// The capsule version
CapsuleVersion string `json:"capsule_version"`

// The capsule restart policy
RestartPolicy string `json:"restart_policy"`

// The capsule metadata labels
MetaLabels map[string]string `json:"meta_labels"`

// The list of containers uuids inside capsule.
ContainersUUIDs []string `json:"containers_uuids"`

// The capsule IP addresses
Addresses map[string][]Address `json:"addresses"`

// The capsule volume attached information
VolumesInfo map[string][]string `json:"volumes_info"`
}

type Address struct {
PreserveOnDelete bool `json:"preserve_on_delete"`
Addr string `json:"addr"`
Port string `json:"port"`
Version float64 `json:"version"`
SubnetID string `json:"subnet_id"`
}

func (r *Capsule) UnmarshalJSON(b []byte) error {
type tmp Capsule
var s struct {
tmp
CreatedAt gophercloud.JSONRFC3339ZNoT `json:"created_at"`
UpdatedAt gophercloud.JSONRFC3339ZNoT `json:"updated_at"`
}
err := json.Unmarshal(b, &s)
if err != nil {
return err
}
*r = Capsule(s.tmp)

r.CreatedAt = time.Time(s.CreatedAt)
r.UpdatedAt = time.Time(s.UpdatedAt)

return nil
}
1 change: 1 addition & 0 deletions openstack/container/v1/capsules/testing/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package testing
68 changes: 68 additions & 0 deletions openstack/container/v1/capsules/testing/fixtures.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package testing

import (
"fmt"
"net/http"
"testing"

th "github.com/gophercloud/gophercloud/testhelper"
fakeclient "github.com/gophercloud/gophercloud/testhelper/client"
)

type imageEntry struct {
ID string
JSON string
}

// HandleImageGetSuccessfully test setup
func HandleCapsuleGetSuccessfully(t *testing.T) {
th.Mux.HandleFunc("/capsules/cc654059-1a77-47a3-bfcf-715bde5aad9e", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", fakeclient.TokenID)

w.WriteHeader(http.StatusOK)
w.Header().Add("Content-Type", "application/json")
fmt.Fprintf(w, `{
"uuid": "cc654059-1a77-47a3-bfcf-715bde5aad9e",
"status": "Running",
"id": 1,
"user_id": "d33b18c384574fd2a3299447aac285f0",
"project_id": "6b8ffef2a0ac42ee87887b9cc98bdf68",
"cpu": 1,
"memory": "1024M",
"meta_name": "test",
"meta_labels": {"web": "app"},
"created_at": "2018-01-12 09:37:25+00:00",
"updated_at": "2018-01-12 09:37:25+01:00",
"links": [
{
"href": "http://10.10.10.10/v1/capsules/cc654059-1a77-47a3-bfcf-715bde5aad9e",
"rel": "self"
},
{
"href": "http://10.10.10.10/capsules/cc654059-1a77-47a3-bfcf-715bde5aad9e",
"rel": "bookmark"
}
],
"capsule_version": "beta",
"restart_policy": "always",
"containers_uuids": ["1739e28a-d391-4fd9-93a5-3ba3f29a4c9b", "d1469e8d-bcbc-43fc-b163-8b9b6a740930"],
"addresses": {
"b1295212-64e1-471d-aa01-25ff46f9818d": [
{
"version": 4,
"preserve_on_delete": false,
"addr": "172.24.4.11",
"port": "8439060f-381a-4386-a518-33d5a4058636",
"subnet_id": "4a2bcd64-93ad-4436-9f48-3a7f9b267e0a"
}
]
},
"volumes_info": {
"67618d54-dd55-4f7e-91b3-39ffb3ba7f5f": [
"4b725a92-2197-497b-b6b1-fb8caa4cb99b"
]
}
}`)
})
}
91 changes: 91 additions & 0 deletions openstack/container/v1/capsules/testing/requests_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package testing

import (
"testing"
"time"

"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack/container/v1/capsules"
th "github.com/gophercloud/gophercloud/testhelper"
fakeclient "github.com/gophercloud/gophercloud/testhelper/client"
)

func TestGetCapsule(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()

HandleCapsuleGetSuccessfully(t)

actualCapsule, err := capsules.Get(fakeclient.ServiceClient(), "cc654059-1a77-47a3-bfcf-715bde5aad9e").Extract()

th.AssertNoErr(t, err)

uuid := "cc654059-1a77-47a3-bfcf-715bde5aad9e"
status := "Running"
id := 1
userID := "d33b18c384574fd2a3299447aac285f0"
projectID := "6b8ffef2a0ac42ee87887b9cc98bdf68"
cpu := float64(1)
memory := "1024M"
metaName := "test"

createdAt, _ := time.Parse(gophercloud.RFC3339ZNoT, "2018-01-12 09:37:25+00:00")
updatedAt, _ := time.Parse(gophercloud.RFC3339ZNoT, "2018-01-12 09:37:25+01:00")
links := []interface{}{
map[string]interface{}{
"href": "http://10.10.10.10/v1/capsules/cc654059-1a77-47a3-bfcf-715bde5aad9e",
"rel": "self",
},
map[string]interface{}{
"href": "http://10.10.10.10/capsules/cc654059-1a77-47a3-bfcf-715bde5aad9e",
"rel": "bookmark",
},
}
capsuleVersion := "beta"
restartPolicy := "always"
metaLabels := map[string]string{
"web": "app",
}
containersUUIDs := []string{
"1739e28a-d391-4fd9-93a5-3ba3f29a4c9b",
"d1469e8d-bcbc-43fc-b163-8b9b6a740930",
}
addresses := map[string][]capsules.Address{
"b1295212-64e1-471d-aa01-25ff46f9818d": []capsules.Address{
{
PreserveOnDelete: false,
Addr: "172.24.4.11",
Port: "8439060f-381a-4386-a518-33d5a4058636",
Version: float64(4),
SubnetID: "4a2bcd64-93ad-4436-9f48-3a7f9b267e0a",
},
},
}
volumesInfo := map[string][]string{
"67618d54-dd55-4f7e-91b3-39ffb3ba7f5f": []string{
"4b725a92-2197-497b-b6b1-fb8caa4cb99b",
},
}

expectedCapsule := capsules.Capsule{
UUID: uuid,
ID: id,
UserID: userID,
ProjectID: projectID,
CPU: cpu,
Status: status,
Memory: memory,
MetaName: metaName,
CreatedAt: createdAt,
UpdatedAt: updatedAt,
Links: links,
CapsuleVersion: capsuleVersion,
RestartPolicy: restartPolicy,
MetaLabels: metaLabels,
ContainersUUIDs: containersUUIDs,
Addresses: addresses,
VolumesInfo: volumesInfo,
}

th.AssertDeepEquals(t, &expectedCapsule, actualCapsule)
}
7 changes: 7 additions & 0 deletions openstack/container/v1/capsules/urls.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package capsules

import "github.com/gophercloud/gophercloud"

func getURL(client *gophercloud.ServiceClient, id string) string {
return client.ServiceURL("capsules", id)
}
21 changes: 21 additions & 0 deletions results.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,27 @@ func (jt *JSONRFC3339NoZ) UnmarshalJSON(data []byte) error {
return nil
}

// RFC3339ZNoT is the time format used in Zun (Containers Service).
const RFC3339ZNoT = "2006-01-02 15:04:05-07:00"

type JSONRFC3339ZNoT time.Time

func (jt *JSONRFC3339ZNoT) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
if s == "" {
return nil
}
t, err := time.Parse(RFC3339ZNoT, s)
if err != nil {
return err
}
*jt = JSONRFC3339ZNoT(t)
return nil
}

/*
Link is an internal type to be used in packages of collection resources that are
paginated in a certain way.
Expand Down

0 comments on commit d240260

Please sign in to comment.