Update photon controller go SDK in vendor code.

This commit is contained in:
Miao Luo
2017-03-14 15:48:02 -07:00
parent 442e920085
commit 1439ea2bba
34 changed files with 1536 additions and 393 deletions

View File

@@ -480,7 +480,7 @@ type Deployment struct {
ImageDatastores []string `json:"imageDatastores"`
SelfLink string `json:"selfLink"`
Migration *MigrationStatus `json:"migrationStatus,omitempty"`
ClusterConfigurations []ClusterConfiguration `json:"clusterConfigurations,omitempty"`
ServiceConfigurations []ServiceConfiguration `json:"serviceConfigurations,omitempty"`
LoadBalancerEnabled bool `json:"loadBalancerEnabled"`
LoadBalancerAddress string `json:"loadBalancerAddress"`
}
@@ -514,7 +514,6 @@ type AuthInfo struct {
Tenant string `json:"tenant,omitempty"`
Port int `json:"port,omitempty"`
SecurityGroups []string `json:"securityGroups,omitempty"`
Enabled bool `json:"enabled,omitempty"`
Username string `json:"username,omitempty"`
}
@@ -532,6 +531,8 @@ type NetworkConfigurationCreateSpec struct {
Password string `json:"networkManagerPassword,omitempty"`
NetworkZoneId string `json:"networkZoneId,omitempty"`
TopRouterId string `json:"networkTopRouterId,omitempty"`
EdgeIpPoolId string `json:"networkEdgeIpPoolId,omitempty"`
HostUplinkPnic string `json:"networkHostUplinkPnic,omitempty"`
IpRange string `json:"ipRange,omitempty"`
ExternalIpRange *IpRange `json:"externalIpRange,omitempty"`
DhcpServers []string `json:"dhcpServers,omitempty"`
@@ -545,21 +546,23 @@ type NetworkConfiguration struct {
Password string `json:"networkManagerPassword,omitempty"`
NetworkZoneId string `json:"networkZoneId,omitempty"`
TopRouterId string `json:"networkTopRouterId,omitempty"`
EdgeIpPoolId string `json:"networkEdgeIpPoolId,omitempty"`
HostUplinkPnic string `json:"networkHostUplinkPnic,omitempty"`
IpRange string `json:"ipRange,omitempty"`
FloatingIpRange *IpRange `json:"floatingIpRange,omitempty"`
SnatIp string `json:"snatIp,omitempty"`
DhcpServers []string `json:"dhcpServers,omitempty"`
}
// Creation spec for subnets.
type SubnetCreateSpec struct {
// Creation spec for networks.
type NetworkCreateSpec struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
PortGroups []string `json:"portGroups"`
}
// Represents a subnet
type Subnet struct {
type Network struct {
Kind string `json:"kind"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
@@ -572,8 +575,8 @@ type Subnet struct {
}
// Represents multiple subnets returned by the API
type Subnets struct {
Items []Subnet `json:"items"`
type Networks struct {
Items []Network `json:"items"`
}
// Create spec for virtual subnet
@@ -592,7 +595,7 @@ type VirtualSubnet struct {
Description string `json:"description,omitempty"`
State string `json:"state"`
RoutingType string `json:"routingType"`
IsDefault string `json:"isDefault"`
IsDefault bool `json:"isDefault"`
Cidr string `json:"cidr,omitempty"`
LowIpDynamic string `json:"lowIpDynamic,omitempty"`
HighIpDynamic string `json:"highIpDynamic,omitempty"`
@@ -607,33 +610,59 @@ type VirtualSubnets struct {
Items []VirtualSubnet `json:"items"`
}
// Creation spec for Cluster Configuration.
type ClusterConfigurationSpec struct {
// Represents a router
type Router struct {
ID string `json:"id"`
Kind string `json:"kind"`
Name string `json:"name"`
PrivateIpCidr string `json:"privateIpCidr"`
}
// Represents multiple routers returned by the API.
type Routers struct {
Items []Router `json:"items"`
}
type RouterCreateSpec struct {
Name string `json:"name"`
PrivateIpCidr string `json:"privateIpCidr"`
}
// Represents name that can be set for router
type RouterUpdateSpec struct {
RouterName string `json:"name"`
}
// Creation spec for Service Configuration.
type ServiceConfigurationSpec struct {
Type string `json:"type"`
ImageID string `json:"imageId"`
}
// Represnts a Cluster configuration.
type ClusterConfiguration struct {
// Represnts a Service configuration.
type ServiceConfiguration struct {
Kind string `json:"kind"`
Type string `json:"type"`
ImageID string `json:"imageId"`
}
// Creation spec for clusters.
type ClusterCreateSpec struct {
// Creation spec for services.
type ServiceCreateSpec struct {
Name string `json:"name"`
Type string `json:"type"`
VMFlavor string `json:"vmFlavor,omitempty"`
MasterVmFlavor string `json:"masterVmFlavor,omitempty"`
WorkerVmFlavor string `json:"workerVmFlavor,omitempty"`
DiskFlavor string `json:"diskFlavor,omitempty"`
NetworkID string `json:"vmNetworkId,omitempty"`
ImageID string `json:"imageId,omitempty"`
WorkerCount int `json:"workerCount"`
BatchSizeWorker int `json:"workerBatchExpansionSize,omitempty"`
ExtendedProperties map[string]string `json:"extendedProperties"`
}
// Represents a cluster
type Cluster struct {
// Represents a service
type Service struct {
Kind string `json:"kind"`
Name string `json:"name"`
State string `json:"state"`
@@ -646,16 +675,21 @@ type Cluster struct {
ExtendedProperties map[string]string `json:"extendedProperties"`
}
// Represents multiple clusters returned by the API
type Clusters struct {
Items []Cluster `json:"items"`
// Represents multiple services returned by the API
type Services struct {
Items []Service `json:"items"`
}
// Represents cluster size that can be resized for cluster
type ClusterResizeOperation struct {
// Represents service size that can be resized for service
type ServiceResizeOperation struct {
NewWorkerCount int `json:"newWorkerCount"`
}
// Represents service imageId that can be updated during change version
type ServiceChangeVersionOperation struct {
NewImageID string `json:"newImageId"`
}
// Represents a security group
type SecurityGroup struct {
Name string `json:"name"`
@@ -709,3 +743,60 @@ type Info struct {
GitCommitHash string `json:"gitCommitHash"`
NetworkType string `json:"networkType"`
}
// NSX configuration spec
type NsxConfigurationSpec struct {
NsxAddress string `json:"nsxAddress"`
NsxUsername string `json:"nsxUsername"`
NsxPassword string `json:"nsxPassword"`
DhcpServerAddresses map[string]string `json:"dhcpServerAddresses"`
PrivateIpRootCidr string `json:"privateIpRootCidr"`
FloatingIpRootRange IpRange `json:"floatingIpRootRange"`
T0RouterId string `json:"t0RouterId"`
EdgeClusterId string `json:"edgeClusterId"`
OverlayTransportZoneId string `json:"overlayTransportZoneId"`
TunnelIpPoolId string `json:"tunnelIpPoolId"`
HostUplinkPnic string `json:"hostUplinkPnic"`
HostUplinkVlanId int `json:"hostUplinkVlanId"`
}
// Represents a subnet
type Subnet struct {
ID string `json:"id"`
Kind string `json:"kind"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
PrivateIpCidr string `json:"privateIpCidr"`
ReservedIps map[string]string `json:"reservedIps"`
State string `json:"state"`
}
// Represents multiple subnets returned by the API.
type Subnets struct {
Items []Subnet `json:"items"`
}
// Creation spec for subnets.
type SubnetCreateSpec struct {
Name string `json:"name"`
Description string `json:"description"`
PrivateIpCidr string `json:"privateIpCidr"`
}
// Represents name that can be set for subnet
type SubnetUpdateSpec struct {
SubnetName string `json:"name"`
}
// Identity and Access Management (IAM)
// IAM Policy entry
type PolicyEntry struct {
Principal string `json:"principal"`
Roles []string `json:"roles"`
}
type PolicyDelta struct {
Principal string `json:"principal"`
Action string `json:"action"`
Role string `json:"role"`
}

View File

@@ -12,6 +12,7 @@ package photon
import (
"encoding/json"
"fmt"
"github.com/vmware/photon-controller-go-sdk/photon/lightwave"
)
@@ -20,11 +21,11 @@ type AuthAPI struct {
client *Client
}
const authUrl string = "/auth"
const authUrl string = rootUrl + "/auth"
// Gets authentication info.
func (api *AuthAPI) Get() (info *AuthInfo, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+authUrl, "")
res, err := api.client.restClient.Get(api.client.Endpoint+authUrl, nil)
if err != nil {
return
}
@@ -53,6 +54,22 @@ func (api *AuthAPI) GetTokensByPassword(username string, password string) (token
return api.toTokenOptions(tokenResponse), nil
}
// GetTokensFromWindowsLogInContext gets tokens based on Windows logged in context
// In case of running on platform other than Windows, it returns error
func (api *AuthAPI) GetTokensFromWindowsLogInContext() (tokenOptions *TokenOptions, err error) {
oidcClient, err := api.buildOIDCClient()
if err != nil {
return
}
tokenResponse, err := oidcClient.GetTokensFromWindowsLogInContext()
if err != nil {
return
}
return api.toTokenOptions(tokenResponse), nil
}
// Gets tokens from refresh token.
func (api *AuthAPI) GetTokensByRefreshToken(refreshtoken string) (tokenOptions *TokenOptions, err error) {
oidcClient, err := api.buildOIDCClient()
@@ -74,10 +91,6 @@ func (api *AuthAPI) getAuthEndpoint() (endpoint string, err error) {
return
}
if !authInfo.Enabled {
return "", SdkError{Message: "Authentication not enabled on this endpoint"}
}
if authInfo.Port == 0 {
authInfo.Port = 443
}
@@ -97,7 +110,7 @@ func (api *AuthAPI) buildOIDCClient() (client *lightwave.OIDCClient, err error)
api.client.restClient.logger), nil
}
const tokenScope string = "openid offline_access rs_esxcloud at_groups"
const tokenScope string = "openid offline_access rs_photon_platform at_groups"
func (api *AuthAPI) buildOIDCClientOptions(options *ClientOptions) *lightwave.OIDCClientOptions {
return &lightwave.OIDCClientOptions{

View File

@@ -19,7 +19,7 @@ type AvailabilityZonesAPI struct {
client *Client
}
var availabilityzoneUrl string = "/availabilityzones"
var availabilityzoneUrl string = rootUrl + "/availabilityzones"
// Creates availability zone.
func (api *AvailabilityZonesAPI) Create(availabilityzoneSpec *AvailabilityZoneCreateSpec) (task *Task, err error) {
@@ -31,7 +31,7 @@ func (api *AvailabilityZonesAPI) Create(availabilityzoneSpec *AvailabilityZoneCr
api.client.Endpoint+availabilityzoneUrl,
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -42,7 +42,7 @@ func (api *AvailabilityZonesAPI) Create(availabilityzoneSpec *AvailabilityZoneCr
// Gets availability zone with the specified ID.
func (api *AvailabilityZonesAPI) Get(id string) (availabilityzone *AvailabilityZone, err error) {
res, err := api.client.restClient.Get(api.getEntityUrl(id), api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Get(api.getEntityUrl(id), api.client.options.TokenOptions)
if err != nil {
return
}
@@ -59,7 +59,7 @@ func (api *AvailabilityZonesAPI) Get(id string) (availabilityzone *AvailabilityZ
// Returns all availability zones on an photon instance.
func (api *AvailabilityZonesAPI) GetAll() (result *AvailabilityZones, err error) {
uri := api.client.Endpoint + availabilityzoneUrl
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -71,7 +71,7 @@ func (api *AvailabilityZonesAPI) GetAll() (result *AvailabilityZones, err error)
// Deletes the availability zone with specified ID.
func (api *AvailabilityZonesAPI) Delete(id string) (task *Task, err error) {
res, err := api.client.restClient.Delete(api.client.Endpoint+availabilityzoneUrl+"/"+id, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Delete(api.client.Endpoint+availabilityzoneUrl+"/"+id, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -87,7 +87,7 @@ func (api *AvailabilityZonesAPI) GetTasks(id string, options *TaskGetOptions) (r
if options != nil {
uri += getQueryString(options)
}
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}

View File

@@ -36,12 +36,14 @@ type Client struct {
Hosts *HostsAPI
Deployments *DeploymentsAPI
ResourceTickets *ResourceTicketsAPI
Subnets *SubnetsAPI
Networks *NetworksAPI
VirtualSubnets *VirtualSubnetsAPI
Clusters *ClustersAPI
Services *ServicesAPI
Auth *AuthAPI
AvailabilityZones *AvailabilityZonesAPI
Info *InfoAPI
Routers *RoutersAPI
Subnets *SubnetsAPI
}
// Represents Tokens
@@ -53,6 +55,8 @@ type TokenOptions struct {
TokenType string `json:"token_type"`
}
type TokenCallback func(string)
// Options for Client
type ClientOptions struct {
// When using the Tasks.Wait APIs, defines the duration of how long
@@ -79,6 +83,11 @@ type ClientOptions struct {
// Tokens for user authentication. Default is empty.
TokenOptions *TokenOptions
// A function to be called if the access token was refreshed
// The client can save the new access token for future API
// calls so that it doesn't need to be refreshed again.
UpdateAccessTokenCallback TokenCallback
}
// Creates a new photon client with specified options. If options
@@ -110,6 +119,7 @@ func NewClient(endpoint string, options *ClientOptions, logger *log.Logger) (c *
defaultOptions.RootCAs = options.RootCAs
}
defaultOptions.IgnoreCertificate = options.IgnoreCertificate
defaultOptions.UpdateAccessTokenCallback = options.UpdateAccessTokenCallback
}
if logger == nil {
@@ -124,9 +134,17 @@ func NewClient(endpoint string, options *ClientOptions, logger *log.Logger) (c *
endpoint = strings.TrimRight(endpoint, "/")
tokenCallback := func(newToken string) {
c.options.TokenOptions.AccessToken = newToken
if c.options.UpdateAccessTokenCallback != nil {
c.options.UpdateAccessTokenCallback(newToken)
}
}
restClient := &restClient{
httpClient: &http.Client{Transport: tr},
logger: logger,
UpdateAccessTokenCallback: tokenCallback,
}
c = &Client{Endpoint: endpoint, restClient: restClient, logger: logger}
@@ -145,12 +163,18 @@ func NewClient(endpoint string, options *ClientOptions, logger *log.Logger) (c *
c.Hosts = &HostsAPI{c}
c.Deployments = &DeploymentsAPI{c}
c.ResourceTickets = &ResourceTicketsAPI{c}
c.Subnets = &SubnetsAPI{c}
c.Networks = &NetworksAPI{c}
c.VirtualSubnets = &VirtualSubnetsAPI{c}
c.Clusters = &ClustersAPI{c}
c.Services = &ServicesAPI{c}
c.Auth = &AuthAPI{c}
c.AvailabilityZones = &AvailabilityZonesAPI{c}
c.Info = &InfoAPI{c}
c.Routers = &RoutersAPI{c}
c.Subnets = &SubnetsAPI{c}
// Tell the restClient about the Auth API so it can request new
// acces tokens when they expire
restClient.Auth = c.Auth
return
}

View File

@@ -1,112 +0,0 @@
// Copyright (c) 2016 VMware, Inc. All Rights Reserved.
//
// This product is licensed to you under the Apache License, Version 2.0 (the "License").
// You may not use this product except in compliance with the License.
//
// This product may include a number of subcomponents with separate copyright notices and
// license terms. Your use of these subcomponents is subject to the terms and conditions
// of the subcomponent's license, as noted in the LICENSE file.
package photon
import (
"bytes"
"encoding/json"
)
// Contains functionality for clusters API.
type ClustersAPI struct {
client *Client
}
var clusterUrl string = "/clusters/"
const ExtendedPropertyDNS string = "dns"
const ExtendedPropertyGateway string = "gateway"
const ExtendedPropertyNetMask string = "netmask"
const ExtendedPropertyMasterIP string = "master_ip"
const ExtendedPropertyContainerNetwork string = "container_network"
const ExtendedPropertyZookeeperIP1 string = "zookeeper_ip1"
const ExtendedPropertyZookeeperIP2 string = "zookeeper_ip2"
const ExtendedPropertyZookeeperIP3 string = "zookeeper_ip3"
const ExtendedPropertyETCDIP1 string = "etcd_ip1"
const ExtendedPropertyETCDIP2 string = "etcd_ip2"
const ExtendedPropertyETCDIP3 string = "etcd_ip3"
const ExtendedPropertySSHKey string = "ssh_key"
const ExtendedPropertyRegistryCACert string = "registry_ca_cert"
const ExtendedPropertyAdminPassword string = "admin_password"
// Deletes a cluster with specified ID.
func (api *ClustersAPI) Delete(id string) (task *Task, err error) {
res, err := api.client.restClient.Delete(api.client.Endpoint+clusterUrl+id, api.client.options.TokenOptions.AccessToken)
if err != nil {
return
}
defer res.Body.Close()
task, err = getTask(getError(res))
return
}
// Gets a cluster with the specified ID.
func (api *ClustersAPI) Get(id string) (cluster *Cluster, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+clusterUrl+id, api.client.options.TokenOptions.AccessToken)
if err != nil {
return
}
defer res.Body.Close()
res, err = getError(res)
if err != nil {
return
}
var result Cluster
err = json.NewDecoder(res.Body).Decode(&result)
return &result, nil
}
// Gets vms for cluster with the specified ID.
func (api *ClustersAPI) GetVMs(id string) (result *VMs, err error) {
uri := api.client.Endpoint + clusterUrl + id + "/vms"
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
if err != nil {
return
}
result = &VMs{}
err = json.Unmarshal(res, result)
return
}
// Resize a cluster to specified count.
func (api *ClustersAPI) Resize(id string, resize *ClusterResizeOperation) (task *Task, err error) {
body, err := json.Marshal(resize)
if err != nil {
return
}
res, err := api.client.restClient.Post(
api.client.Endpoint+clusterUrl+id+"/resize",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
if err != nil {
return
}
defer res.Body.Close()
task, err = getTask(getError(res))
return
}
// Start a background process to recreate failed VMs in a cluster with the specified ID.
func (api *ClustersAPI) TriggerMaintenance(id string) (task *Task, err error) {
body := []byte{}
res, err := api.client.restClient.Post(
api.client.Endpoint+clusterUrl+id+"/trigger_maintenance",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
if err != nil {
return
}
defer res.Body.Close()
task, err = getTask(getError(res))
return
}

View File

@@ -19,7 +19,7 @@ type DeploymentsAPI struct {
client *Client
}
var deploymentUrl string = "/deployments"
var deploymentUrl string = rootUrl + "/deployments"
// Creates a deployment
func (api *DeploymentsAPI) Create(deploymentSpec *DeploymentCreateSpec) (task *Task, err error) {
@@ -30,8 +30,8 @@ func (api *DeploymentsAPI) Create(deploymentSpec *DeploymentCreateSpec) (task *T
res, err := api.client.restClient.Post(
api.client.Endpoint+deploymentUrl,
"application/json",
bytes.NewBuffer(body),
api.client.options.TokenOptions.AccessToken)
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -42,7 +42,7 @@ func (api *DeploymentsAPI) Create(deploymentSpec *DeploymentCreateSpec) (task *T
// Deletes a deployment with specified ID.
func (api *DeploymentsAPI) Delete(id string) (task *Task, err error) {
res, err := api.client.restClient.Delete(api.getEntityUrl(id), api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Delete(api.getEntityUrl(id), api.client.options.TokenOptions)
if err != nil {
return
}
@@ -61,8 +61,8 @@ func (api *DeploymentsAPI) Deploy(id string, config *DeploymentDeployOperation)
res, err := api.client.restClient.Post(
api.getEntityUrl(id)+"/deploy",
"application/json",
bytes.NewBuffer(body),
api.client.options.TokenOptions.AccessToken)
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -76,8 +76,8 @@ func (api *DeploymentsAPI) Destroy(id string) (task *Task, err error) {
res, err := api.client.restClient.Post(
api.getEntityUrl(id)+"/destroy",
"application/json",
bytes.NewBuffer([]byte("")),
api.client.options.TokenOptions.AccessToken)
bytes.NewReader([]byte("")),
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -88,7 +88,7 @@ func (api *DeploymentsAPI) Destroy(id string) (task *Task, err error) {
// Returns all deployments.
func (api *DeploymentsAPI) GetAll() (result *Deployments, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+deploymentUrl, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Get(api.client.Endpoint+deploymentUrl, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -104,7 +104,7 @@ func (api *DeploymentsAPI) GetAll() (result *Deployments, err error) {
// Gets a deployment with the specified ID.
func (api *DeploymentsAPI) Get(id string) (deployment *Deployment, err error) {
res, err := api.client.restClient.Get(api.getEntityUrl(id), api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Get(api.getEntityUrl(id), api.client.options.TokenOptions)
if err != nil {
return
}
@@ -121,7 +121,7 @@ func (api *DeploymentsAPI) Get(id string) (deployment *Deployment, err error) {
// Gets all hosts with the specified deployment ID.
func (api *DeploymentsAPI) GetHosts(id string) (result *Hosts, err error) {
uri := api.getEntityUrl(id) + "/hosts"
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -134,7 +134,7 @@ func (api *DeploymentsAPI) GetHosts(id string) (result *Hosts, err error) {
// Gets all the vms with the specified deployment ID.
func (api *DeploymentsAPI) GetVms(id string) (result *VMs, err error) {
uri := api.getEntityUrl(id) + "/vms"
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -153,8 +153,8 @@ func (api *DeploymentsAPI) InitializeDeploymentMigration(sourceAddress *Initiali
res, err := api.client.restClient.Post(
api.getEntityUrl(id)+"/initialize_migration",
"application/json",
bytes.NewBuffer(body),
api.client.options.TokenOptions.AccessToken)
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -172,8 +172,8 @@ func (api *DeploymentsAPI) FinalizeDeploymentMigration(sourceAddress *FinalizeMi
res, err := api.client.restClient.Post(
api.getEntityUrl(id)+"/finalize_migration",
"application/json",
bytes.NewBuffer(body),
api.client.options.TokenOptions.AccessToken)
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -196,8 +196,24 @@ func (api *DeploymentsAPI) SetImageDatastores(id string, imageDatastores *ImageD
res, err := api.client.restClient.Post(
api.getEntityUrl(id)+"/set_image_datastores",
"application/json",
bytes.NewBuffer(body),
api.client.options.TokenOptions.AccessToken)
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
task, err = getTask(getError(res))
return
}
// Synchronizes hosts configurations
func (api *DeploymentsAPI) SyncHostsConfig(id string) (task *Task, err error) {
res, err := api.client.restClient.Post(
api.getEntityUrl(id)+"/sync_hosts_config",
"application/json",
bytes.NewReader([]byte("")),
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -212,8 +228,8 @@ func (api *DeploymentsAPI) PauseSystem(id string) (task *Task, err error) {
res, err := api.client.restClient.Post(
api.getEntityUrl(id)+"/pause_system",
"application/json",
bytes.NewBuffer([]byte("")),
api.client.options.TokenOptions.AccessToken)
bytes.NewReader([]byte("")),
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -228,8 +244,8 @@ func (api *DeploymentsAPI) PauseBackgroundTasks(id string) (task *Task, err erro
res, err := api.client.restClient.Post(
api.getEntityUrl(id)+"/pause_background_tasks",
"application/json",
bytes.NewBuffer([]byte("")),
api.client.options.TokenOptions.AccessToken)
bytes.NewReader([]byte("")),
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -244,8 +260,8 @@ func (api *DeploymentsAPI) ResumeSystem(id string) (task *Task, err error) {
res, err := api.client.restClient.Post(
api.getEntityUrl(id)+"/resume_system",
"application/json",
bytes.NewBuffer([]byte("")),
api.client.options.TokenOptions.AccessToken)
bytes.NewReader([]byte("")),
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -255,17 +271,17 @@ func (api *DeploymentsAPI) ResumeSystem(id string) (task *Task, err error) {
return
}
// Enable cluster type with specified deployment ID.
func (api *DeploymentsAPI) EnableClusterType(id string, clusterConfigSpec *ClusterConfigurationSpec) (task *Task, err error) {
body, err := json.Marshal(clusterConfigSpec)
// Enable service type with specified deployment ID.
func (api *DeploymentsAPI) EnableServiceType(id string, serviceConfigSpec *ServiceConfigurationSpec) (task *Task, err error) {
body, err := json.Marshal(serviceConfigSpec)
if err != nil {
return
}
res, err := api.client.restClient.Post(
api.getEntityUrl(id)+"/enable_cluster_type",
api.getEntityUrl(id)+"/enable_service_type",
"application/json",
bytes.NewBuffer(body),
api.client.options.TokenOptions.AccessToken)
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -275,17 +291,38 @@ func (api *DeploymentsAPI) EnableClusterType(id string, clusterConfigSpec *Clust
return
}
// Disable cluster type with specified deployment ID.
func (api *DeploymentsAPI) DisableClusterType(id string, clusterConfigSpec *ClusterConfigurationSpec) (task *Task, err error) {
body, err := json.Marshal(clusterConfigSpec)
// Disable service type with specified deployment ID.
func (api *DeploymentsAPI) DisableServiceType(id string, serviceConfigSpec *ServiceConfigurationSpec) (task *Task, err error) {
body, err := json.Marshal(serviceConfigSpec)
if err != nil {
return
}
res, err := api.client.restClient.Post(
api.getEntityUrl(id)+"/disable_cluster_type",
api.getEntityUrl(id)+"/disable_service_type",
"application/json",
bytes.NewBuffer(body),
api.client.options.TokenOptions.AccessToken)
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
task, err = getTask(getError(res))
return
}
// Configure NSX.
func (api *DeploymentsAPI) ConfigureNsx(id string, nsxConfigSpec *NsxConfigurationSpec) (task *Task, err error) {
body, err := json.Marshal(nsxConfigSpec)
if err != nil {
return
}
res, err := api.client.restClient.Post(
api.getEntityUrl(id)+"/configure_nsx",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}

View File

@@ -18,11 +18,11 @@ type DisksAPI struct {
client *Client
}
var diskUrl string = "/disks/"
var diskUrl string = rootUrl + "/disks/"
// Gets a PersistentDisk for the disk with specified ID.
func (api *DisksAPI) Get(diskID string) (disk *PersistentDisk, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+diskUrl+diskID, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Get(api.client.Endpoint+diskUrl+diskID, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -38,7 +38,7 @@ func (api *DisksAPI) Get(diskID string) (disk *PersistentDisk, err error) {
// Deletes a disk with the specified ID.
func (api *DisksAPI) Delete(diskID string) (task *Task, err error) {
res, err := api.client.restClient.Delete(api.client.Endpoint+diskUrl+diskID, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Delete(api.client.Endpoint+diskUrl+diskID, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -54,7 +54,7 @@ func (api *DisksAPI) GetTasks(id string, options *TaskGetOptions) (result *TaskL
if options != nil {
uri += getQueryString(options)
}
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}

View File

@@ -25,7 +25,7 @@ type FlavorGetOptions struct {
Kind string `urlParam:"kind"`
}
var flavorUrl string = "/flavors"
var flavorUrl string = rootUrl + "/flavors"
// Creates a flavor.
func (api *FlavorsAPI) Create(spec *FlavorCreateSpec) (task *Task, err error) {
@@ -37,7 +37,7 @@ func (api *FlavorsAPI) Create(spec *FlavorCreateSpec) (task *Task, err error) {
api.client.Endpoint+flavorUrl,
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -48,7 +48,7 @@ func (api *FlavorsAPI) Create(spec *FlavorCreateSpec) (task *Task, err error) {
// Gets details of flavor with specified ID.
func (api *FlavorsAPI) Get(flavorID string) (flavor *Flavor, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+flavorUrl+"/"+flavorID, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Get(api.client.Endpoint+flavorUrl+"/"+flavorID, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -68,7 +68,7 @@ func (api *FlavorsAPI) GetAll(options *FlavorGetOptions) (flavors *FlavorList, e
if options != nil {
uri += getQueryString(options)
}
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -80,7 +80,7 @@ func (api *FlavorsAPI) GetAll(options *FlavorGetOptions) (flavors *FlavorList, e
// Deletes flavor with specified ID.
func (api *FlavorsAPI) Delete(flavorID string) (task *Task, err error) {
res, err := api.client.restClient.Delete(api.client.Endpoint+flavorUrl+"/"+flavorID, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Delete(api.client.Endpoint+flavorUrl+"/"+flavorID, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -97,7 +97,7 @@ func (api *FlavorsAPI) GetTasks(id string, options *TaskGetOptions) (result *Tas
uri += getQueryString(options)
}
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}

View File

@@ -19,7 +19,7 @@ type HostsAPI struct {
client *Client
}
var hostUrl string = "/hosts"
var hostUrl string = rootUrl + "/hosts"
// Creates a host.
func (api *HostsAPI) Create(hostSpec *HostCreateSpec, deploymentId string) (task *Task, err error) {
@@ -28,10 +28,10 @@ func (api *HostsAPI) Create(hostSpec *HostCreateSpec, deploymentId string) (task
return
}
res, err := api.client.restClient.Post(
api.client.Endpoint+deploymentUrl+"/"+deploymentId+hostUrl,
api.client.Endpoint+deploymentUrl+"/"+deploymentId+"/hosts",
"application/json",
bytes.NewBuffer(body),
api.client.options.TokenOptions.AccessToken)
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -42,7 +42,7 @@ func (api *HostsAPI) Create(hostSpec *HostCreateSpec, deploymentId string) (task
// Deletes a host with specified ID.
func (api *HostsAPI) Delete(id string) (task *Task, err error) {
res, err := api.client.restClient.Delete(api.client.Endpoint+hostUrl+"/"+id, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Delete(api.client.Endpoint+hostUrl+"/"+id, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -53,7 +53,7 @@ func (api *HostsAPI) Delete(id string) (task *Task, err error) {
// Returns all hosts
func (api *HostsAPI) GetAll() (result *Hosts, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+hostUrl, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Get(api.client.Endpoint+hostUrl, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -69,7 +69,7 @@ func (api *HostsAPI) GetAll() (result *Hosts, err error) {
// Gets a host with the specified ID.
func (api *HostsAPI) Get(id string) (host *Host, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+hostUrl+"/"+id, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Get(api.client.Endpoint+hostUrl+"/"+id, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -93,8 +93,8 @@ func (api *HostsAPI) SetAvailabilityZone(id string, availabilityZone *HostSetAva
res, err := api.client.restClient.Post(
api.client.Endpoint+hostUrl+"/"+id+"/set_availability_zone",
"application/json",
bytes.NewBuffer(body),
api.client.options.TokenOptions.AccessToken)
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
@@ -112,7 +112,7 @@ func (api *HostsAPI) GetTasks(id string, options *TaskGetOptions) (result *TaskL
if options != nil {
uri += getQueryString(options)
}
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -122,9 +122,9 @@ func (api *HostsAPI) GetTasks(id string, options *TaskGetOptions) (result *TaskL
return
}
// Gets all the vms with the specified deployment ID.
// Gets all the vms with the specified host ID.
func (api *HostsAPI) GetVMs(id string) (result *VMs, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+hostUrl+"/"+id+"/vms", api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Get(api.client.Endpoint+hostUrl+"/"+id+"/vms", api.client.options.TokenOptions)
if err != nil {
return
}
@@ -138,6 +138,22 @@ func (api *HostsAPI) GetVMs(id string) (result *VMs, err error) {
return
}
// provision the host with the specified id
func (api *HostsAPI) Provision(id string) (task *Task, err error) {
body := []byte{}
res, err := api.client.restClient.Post(
api.client.Endpoint+hostUrl+"/"+id+"/provision",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
task, err = getTask(getError(res))
return
}
// Suspend the host with the specified id
func (api *HostsAPI) Suspend(id string) (task *Task, err error) {
body := []byte{}
@@ -145,7 +161,7 @@ func (api *HostsAPI) Suspend(id string) (task *Task, err error) {
api.client.Endpoint+hostUrl+"/"+id+"/suspend",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -161,7 +177,7 @@ func (api *HostsAPI) Resume(id string) (task *Task, err error) {
api.client.Endpoint+hostUrl+"/"+id+"/resume",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -177,7 +193,7 @@ func (api *HostsAPI) EnterMaintenanceMode(id string) (task *Task, err error) {
api.client.Endpoint+hostUrl+"/"+id+"/enter_maintenance",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -193,7 +209,7 @@ func (api *HostsAPI) ExitMaintenanceMode(id string) (task *Task, err error) {
api.client.Endpoint+hostUrl+"/"+id+"/exit_maintenance",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}

View File

@@ -10,6 +10,7 @@
package photon
import (
"bytes"
"encoding/json"
"io"
)
@@ -24,13 +25,13 @@ type ImageGetOptions struct {
Name string `urlParam:"name"`
}
var imageUrl string = "/images"
var imageUrl string = rootUrl + "/images"
// Uploads a new image, reading from the specified image path.
// If options is nil, default options are used.
func (api *ImagesAPI) CreateFromFile(imagePath string, options *ImageCreateOptions) (task *Task, err error) {
params := imageCreateOptionsToMap(options)
res, err := api.client.restClient.MultipartUploadFile(api.client.Endpoint+imageUrl, imagePath, params, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.MultipartUploadFile(api.client.Endpoint+imageUrl, imagePath, params, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -43,9 +44,9 @@ func (api *ImagesAPI) CreateFromFile(imagePath string, options *ImageCreateOptio
// Name is a descriptive name of the image, it is used in the filename field of the Content-Disposition header,
// and does not need to be unique.
// If options is nil, default options are used.
func (api *ImagesAPI) Create(reader io.Reader, name string, options *ImageCreateOptions) (task *Task, err error) {
func (api *ImagesAPI) Create(reader io.ReadSeeker, name string, options *ImageCreateOptions) (task *Task, err error) {
params := imageCreateOptionsToMap(options)
res, err := api.client.restClient.MultipartUpload(api.client.Endpoint+imageUrl, reader, name, params, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.MultipartUpload(api.client.Endpoint+imageUrl, reader, name, params, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -60,7 +61,7 @@ func (api *ImagesAPI) GetAll(options *ImageGetOptions) (images *Images, err erro
if options != nil {
uri += getQueryString(options)
}
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -72,7 +73,7 @@ func (api *ImagesAPI) GetAll(options *ImageGetOptions) (images *Images, err erro
// Gets details of image with the specified ID.
func (api *ImagesAPI) Get(imageID string) (image *Image, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+imageUrl+"/"+imageID, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Get(api.client.Endpoint+imageUrl+"/"+imageID, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -88,7 +89,7 @@ func (api *ImagesAPI) Get(imageID string) (image *Image, err error) {
// Deletes image with the specified ID.
func (api *ImagesAPI) Delete(imageID string) (task *Task, err error) {
res, err := api.client.restClient.Delete(api.client.Endpoint+imageUrl+"/"+imageID, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Delete(api.client.Endpoint+imageUrl+"/"+imageID, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -105,7 +106,7 @@ func (api *ImagesAPI) GetTasks(id string, options *TaskGetOptions) (result *Task
uri += getQueryString(options)
}
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -115,6 +116,62 @@ func (api *ImagesAPI) GetTasks(id string, options *TaskGetOptions) (result *Task
return
}
// Gets IAM Policy of an image.
func (api *ImagesAPI) GetIam(imageID string) (policy *[]PolicyEntry, err error) {
res, err := api.client.restClient.Get(
api.client.Endpoint+imageUrl+"/"+imageID+"/iam",
api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
res, err = getError(res)
if err != nil {
return
}
var result []PolicyEntry
err = json.NewDecoder(res.Body).Decode(&result)
return &result, nil
}
// Sets IAM Policy on an image.
func (api *ImagesAPI) SetIam(imageID string, policy *[]PolicyEntry) (task *Task, err error) {
body, err := json.Marshal(policy)
if err != nil {
return
}
res, err := api.client.restClient.Post(
api.client.Endpoint+imageUrl+"/"+imageID+"/iam",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
task, err = getTask(getError(res))
return
}
// Modifies IAM Policy on an image.
func (api *ImagesAPI) ModifyIam(imageID string, policyDelta *PolicyDelta) (task *Task, err error) {
body, err := json.Marshal(policyDelta)
if err != nil {
return
}
res, err := api.client.restClient.Put(
api.client.Endpoint+imageUrl+"/"+imageID+"/iam",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
task, err = getTask(getError(res))
return
}
func imageCreateOptionsToMap(opts *ImageCreateOptions) map[string]string {
if opts == nil {
return nil

View File

@@ -17,11 +17,11 @@ type InfoAPI struct {
client *Client
}
var infoUrl = "/info"
var infoUrl = rootUrl + "/info"
// Get info
func (api *InfoAPI) Get() (info *Info, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+infoUrl, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Get(api.client.Endpoint+infoUrl, api.client.options.TokenOptions)
if err != nil {
return
}

View File

@@ -18,6 +18,7 @@ import (
"io/ioutil"
"log"
"net/http"
"net/url"
"strings"
)
@@ -168,6 +169,8 @@ type OIDCTokenResponse struct {
}
func (client *OIDCClient) GetTokenByPasswordGrant(username string, password string) (tokens *OIDCTokenResponse, err error) {
username = url.QueryEscape(username)
password = url.QueryEscape(password)
body := fmt.Sprintf(passwordGrantFormatString, username, password, client.Options.TokenScope)
return client.getToken(body)
}

View File

@@ -0,0 +1,131 @@
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
//
// This product is licensed to you under the Apache License, Version 2.0 (the "License").
// You may not use this product except in compliance with the License.
//
// This product may include a number of subcomponents with separate copyright notices and
// license terms. Your use of these subcomponents is subject to the terms and conditions
// of the subcomponent's license, as noted in the LICENSE file.
// +build windows
package lightwave
import (
"encoding/base64"
"fmt"
"github.com/vmware/photon-controller-go-sdk/SSPI"
"math/rand"
"net"
"net/url"
"strings"
"time"
)
const gssTicketGrantFormatString = "grant_type=urn:vmware:grant_type:gss_ticket&gss_ticket=%s&context_id=%s&scope=%s"
// GetTokensFromWindowsLogInContext gets tokens based on Windows logged in context
// Here is how it works:
// 1. Get the SPN (Service Principal Name) in the format host/FQDN of lightwave. This is needed for SSPI/Kerberos protocol
// 2. Call Windows API AcquireCredentialsHandle() using SSPI library. This will give the current users credential handle
// 3. Using this handle call Windows API AcquireCredentialsHandle(). This will give you byte[]
// 4. Encode this byte[] and send it to OIDC server over HTTP (using POST)
// 5. OIDC server can send either of the following
// - Access tokens. In this case return access tokens to client
// - Error in the format: invalid_grant: gss_continue_needed:'context id':'token from server'
// 6. In case you get error, parse it and get the token from server
// 7. Feed this token to step 3 and repeat steps till you get the access tokens from server
func (client *OIDCClient) GetTokensFromWindowsLogInContext() (tokens *OIDCTokenResponse, err error) {
spn, err := client.buildSPN()
if err != nil {
return nil, err
}
auth, _ := SSPI.GetAuth("", "", spn, "")
userContext, err := auth.InitialBytes()
if err != nil {
return nil, err
}
// In case of multiple req/res between client and server (as explained in above comment),
// server needs to maintain the mapping of context id -> token
// So we need to generate random string as a context id
// If we use same context id for all the requests, results can be erroneous
contextId := client.generateRandomString()
body := fmt.Sprintf(gssTicketGrantFormatString, url.QueryEscape(base64.StdEncoding.EncodeToString(userContext)), contextId, client.Options.TokenScope)
tokens, err = client.getToken(body)
for {
if err == nil {
break
}
// In case of error the response will be in format: invalid_grant: gss_continue_needed:'context id':'token from server'
gssToken := client.validateAndExtractGSSResponse(err, contextId)
if gssToken == "" {
return nil, err
}
data, err := base64.StdEncoding.DecodeString(gssToken)
if err != nil {
return nil, err
}
userContext, err := auth.NextBytes(data)
body := fmt.Sprintf(gssTicketGrantFormatString, url.QueryEscape(base64.StdEncoding.EncodeToString(userContext)), contextId, client.Options.TokenScope)
tokens, err = client.getToken(body)
}
return tokens, err
}
// Gets the SPN (Service Principal Name) in the format host/FQDN of lightwave
func (client *OIDCClient) buildSPN() (spn string, err error) {
u, err := url.Parse(client.Endpoint)
if err != nil {
return "", err
}
host, _, err := net.SplitHostPort(u.Host)
if err != nil {
return "", err
}
addr, err := net.LookupAddr(host)
if err != nil {
return "", err
}
var s = strings.TrimSuffix(addr[0], ".")
return "host/" + s, nil
}
// validateAndExtractGSSResponse parse the error from server and returns token from server
// In case of error from the server, response will be in format: invalid_grant: gss_continue_needed:'context id':'token from server'
// So, we check for the above format in error and then return the token from server
// If error is not in above format, we return empty string
func (client *OIDCClient) validateAndExtractGSSResponse(err error, contextId string) string {
parts := strings.Split(err.Error(), ":")
if !(len(parts) == 4 && strings.TrimSpace(parts[1]) == "gss_continue_needed" && parts[2] == contextId) {
return ""
} else {
return parts[3]
}
}
func (client *OIDCClient) generateRandomString() string {
const length = 10
const asciiA = 65
const asciiZ = 90
rand.Seed(time.Now().UTC().UnixNano())
bytes := make([]byte, length)
for i := 0; i < length; i++ {
bytes[i] = byte(randInt(asciiA, asciiZ))
}
return string(bytes)
}
func randInt(min int, max int) int {
return min + rand.Intn(max-min)
}

View File

@@ -0,0 +1,18 @@
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
//
// This product is licensed to you under the Apache License, Version 2.0 (the "License").
// You may not use this product except in compliance with the License.
//
// This product may include a number of subcomponents with separate copyright notices and
// license terms. Your use of these subcomponents is subject to the terms and conditions
// of the subcomponent's license, as noted in the LICENSE file.
// +build !windows
package lightwave
import "errors"
func (client *OIDCClient) GetTokensFromWindowsLogInContext() (tokens *OIDCTokenResponse, err error) {
return nil, errors.New("Not supported on this OS")
}

View File

@@ -15,28 +15,28 @@ import (
)
// Contains functionality for networks API.
type SubnetsAPI struct {
type NetworksAPI struct {
client *Client
}
// Options used for GetAll API
type SubnetGetOptions struct {
type NetworkGetOptions struct {
Name string `urlParam:"name"`
}
var subnetUrl string = "/subnets"
var networkUrl string = rootUrl + "/subnets"
// Creates a network.
func (api *SubnetsAPI) Create(networkSpec *SubnetCreateSpec) (task *Task, err error) {
func (api *NetworksAPI) Create(networkSpec *NetworkCreateSpec) (task *Task, err error) {
body, err := json.Marshal(networkSpec)
if err != nil {
return
}
res, err := api.client.restClient.Post(
api.client.Endpoint+subnetUrl,
api.client.Endpoint+networkUrl,
"application/json",
bytes.NewBuffer(body),
api.client.options.TokenOptions.AccessToken)
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -46,8 +46,8 @@ func (api *SubnetsAPI) Create(networkSpec *SubnetCreateSpec) (task *Task, err er
}
// Deletes a network with specified ID.
func (api *SubnetsAPI) Delete(id string) (task *Task, err error) {
res, err := api.client.restClient.Delete(api.client.Endpoint+subnetUrl+"/"+id, api.client.options.TokenOptions.AccessToken)
func (api *NetworksAPI) Delete(id string) (task *Task, err error) {
res, err := api.client.restClient.Delete(api.client.Endpoint+networkUrl+"/"+id, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -57,8 +57,8 @@ func (api *SubnetsAPI) Delete(id string) (task *Task, err error) {
}
// Gets a network with the specified ID.
func (api *SubnetsAPI) Get(id string) (network *Subnet, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+subnetUrl+"/"+id, api.client.options.TokenOptions.AccessToken)
func (api *NetworksAPI) Get(id string) (network *Network, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+networkUrl+"/"+id, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -67,31 +67,31 @@ func (api *SubnetsAPI) Get(id string) (network *Subnet, err error) {
if err != nil {
return
}
var result Subnet
var result Network
err = json.NewDecoder(res.Body).Decode(&result)
return &result, nil
}
// Returns all networks
func (api *SubnetsAPI) GetAll(options *SubnetGetOptions) (result *Subnets, err error) {
uri := api.client.Endpoint + subnetUrl
func (api *NetworksAPI) GetAll(options *NetworkGetOptions) (result *Networks, err error) {
uri := api.client.Endpoint + networkUrl
if options != nil {
uri += getQueryString(options)
}
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
result = &Subnets{}
result = &Networks{}
err = json.Unmarshal(res, result)
return
}
// Sets default network.
func (api *SubnetsAPI) SetDefault(id string) (task *Task, err error) {
func (api *NetworksAPI) SetDefault(id string) (task *Task, err error) {
res, err := api.client.restClient.Post(
api.client.Endpoint+subnetUrl+"/"+id+"/set_default",
api.client.Endpoint+networkUrl+"/"+id+"/set_default",
"application/json",
bytes.NewBuffer([]byte("")),
api.client.options.TokenOptions.AccessToken)
bytes.NewReader([]byte("")),
api.client.options.TokenOptions)
if err != nil {
return
}

View File

@@ -29,11 +29,11 @@ type VmGetOptions struct {
Name string `urlParam:"name"`
}
var projectUrl string = "/projects/"
var projectUrl string = rootUrl + "/projects/"
// Deletes the project with specified ID. Any VMs, disks, etc., owned by the project must be deleted first.
func (api *ProjectsAPI) Delete(projectID string) (task *Task, err error) {
res, err := api.client.restClient.Delete(api.client.Endpoint+projectUrl+projectID, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Delete(api.client.Endpoint+projectUrl+projectID, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -52,7 +52,7 @@ func (api *ProjectsAPI) CreateDisk(projectID string, spec *DiskCreateSpec) (task
api.client.Endpoint+projectUrl+projectID+"/disks",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -68,7 +68,7 @@ func (api *ProjectsAPI) GetDisks(projectID string, options *DiskGetOptions) (res
if options != nil {
uri += getQueryString(options)
}
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -88,7 +88,7 @@ func (api *ProjectsAPI) CreateVM(projectID string, spec *VmCreateSpec) (task *Ta
api.client.Endpoint+projectUrl+projectID+"/vms",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -104,7 +104,7 @@ func (api *ProjectsAPI) GetTasks(id string, options *TaskGetOptions) (result *Ta
if options != nil {
uri += getQueryString(options)
}
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -121,7 +121,7 @@ func (api *ProjectsAPI) GetVMs(projectID string, options *VmGetOptions) (result
if options != nil {
uri += getQueryString(options)
}
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -131,17 +131,17 @@ func (api *ProjectsAPI) GetVMs(projectID string, options *VmGetOptions) (result
return
}
// Creates a cluster on the specified project.
func (api *ProjectsAPI) CreateCluster(projectID string, spec *ClusterCreateSpec) (task *Task, err error) {
// Creates a service on the specified project.
func (api *ProjectsAPI) CreateService(projectID string, spec *ServiceCreateSpec) (task *Task, err error) {
body, err := json.Marshal(spec)
if err != nil {
return
}
res, err := api.client.restClient.Post(
api.client.Endpoint+projectUrl+projectID+"/clusters",
api.client.Endpoint+projectUrl+projectID+"/services",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -150,22 +150,22 @@ func (api *ProjectsAPI) CreateCluster(projectID string, spec *ClusterCreateSpec)
return
}
// Gets clusters for project with the specified ID
func (api *ProjectsAPI) GetClusters(projectID string) (result *Clusters, err error) {
uri := api.client.Endpoint + projectUrl + projectID + "/clusters"
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
// Gets services for project with the specified ID
func (api *ProjectsAPI) GetServices(projectID string) (result *Services, err error) {
uri := api.client.Endpoint + projectUrl + projectID + "/services"
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
result = &Clusters{}
result = &Services{}
err = json.Unmarshal(res, result)
return
}
// Gets the project with a specified ID.
func (api *ProjectsAPI) Get(id string) (project *ProjectCompact, err error) {
res, err := api.client.restClient.Get(api.getEntityUrl(id), api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Get(api.getEntityUrl(id), api.client.options.TokenOptions)
if err != nil {
return
}
@@ -187,3 +187,22 @@ func (api *ProjectsAPI) SetSecurityGroups(projectID string, securityGroups *Secu
func (api *ProjectsAPI) getEntityUrl(id string) string {
return api.client.Endpoint + projectUrl + id
}
// Creates a router on the specified project.
func (api *ProjectsAPI) CreateRouter(projectID string, spec *RouterCreateSpec) (task *Task, err error) {
body, err := json.Marshal(spec)
if err != nil {
return
}
res, err := api.client.restClient.Post(
api.client.Endpoint+projectUrl+projectID+"/routers",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
task, err = getTask(getError(res))
return
}

View File

@@ -18,7 +18,7 @@ type ResourceTicketsAPI struct {
client *Client
}
var resourceTicketUrl string = "/resource-tickets/"
var resourceTicketUrl string = rootUrl + "/resource-tickets/"
// Gets all tasks with the specified resource ticket ID, using options to filter the results.
// If options is nil, no filtering will occur.
@@ -27,7 +27,7 @@ func (api *ResourceTicketsAPI) GetTasks(id string, options *TaskGetOptions) (res
if options != nil {
uri += getQueryString(options)
}
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -40,7 +40,7 @@ func (api *ResourceTicketsAPI) GetTasks(id string, options *TaskGetOptions) (res
// Gets the resource ticket with a specified ID.
func (api *ResourceTicketsAPI) Get(id string) (resourceTicket *ResourceTicket, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+resourceTicketUrl+"/"+id,
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}

View File

@@ -10,10 +10,12 @@
package photon
import (
"bytes"
"crypto/rand"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
@@ -22,8 +24,10 @@ import (
)
type restClient struct {
httpClient *http.Client
logger *log.Logger
httpClient *http.Client
logger *log.Logger
Auth *AuthAPI
UpdateAccessTokenCallback TokenCallback
}
type request struct {
@@ -31,7 +35,7 @@ type request struct {
URL string
ContentType string
Body io.Reader
Token string
Tokens *TokenOptions
}
type page struct {
@@ -44,8 +48,13 @@ type documentList struct {
Items []interface{}
}
type bodyRewinder func() io.Reader
const appJson string = "application/json"
// Root URL specifies the API version.
const rootUrl string = "/v1"
// From https://golang.org/src/mime/multipart/writer.go
var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
@@ -65,15 +74,15 @@ func (client *restClient) AppendSlice(origSlice []interface{}, dataToAppend []in
return origSlice
}
func (client *restClient) Get(url string, token string) (res *http.Response, err error) {
req := request{"GET", url, "", nil, token}
res, err = client.Do(&req)
func (client *restClient) Get(url string, tokens *TokenOptions) (res *http.Response, err error) {
req := request{"GET", url, "", nil, tokens}
res, err = client.SendRequest(&req, nil)
return
}
func (client *restClient) GetList(endpoint string, url string, token string) (result []byte, err error) {
req := request{"GET", url, "", nil, token}
res, err := client.Do(&req)
func (client *restClient) GetList(endpoint string, url string, tokens *TokenOptions) (result []byte, err error) {
req := request{"GET", url, "", nil, tokens}
res, err := client.SendRequest(&req, nil)
if err != nil {
return
}
@@ -95,8 +104,8 @@ func (client *restClient) GetList(endpoint string, url string, token string) (re
documentList.Items = client.AppendSlice(documentList.Items, page.Items)
for page.NextPageLink != "" {
req = request{"GET", endpoint + page.NextPageLink, "", nil, token}
res, err = client.Do(&req)
req = request{"GET", endpoint + page.NextPageLink, "", nil, tokens}
res, err = client.SendRequest(&req, nil)
if err != nil {
return
}
@@ -124,23 +133,111 @@ func (client *restClient) GetList(endpoint string, url string, token string) (re
return
}
func (client *restClient) Post(url string, contentType string, body io.Reader, token string) (res *http.Response, err error) {
func (client *restClient) Post(url string, contentType string, body io.ReadSeeker, tokens *TokenOptions) (res *http.Response, err error) {
if contentType == "" {
contentType = appJson
}
req := request{"POST", url, contentType, body, token}
res, err = client.Do(&req)
req := request{"POST", url, contentType, body, tokens}
rewinder := func() io.Reader {
body.Seek(0, 0)
return body
}
res, err = client.SendRequest(&req, rewinder)
return
}
func (client *restClient) Delete(url string, token string) (res *http.Response, err error) {
req := request{"DELETE", url, "", nil, token}
res, err = client.Do(&req)
func (client *restClient) Patch(url string, contentType string, body io.ReadSeeker, tokens *TokenOptions) (res *http.Response, err error) {
if contentType == "" {
contentType = appJson
}
req := request{"PATCH", url, contentType, body, tokens}
rewinder := func() io.Reader {
body.Seek(0, 0)
return body
}
res, err = client.SendRequest(&req, rewinder)
return
}
func (client *restClient) Do(req *request) (res *http.Response, err error) {
func (client *restClient) Put(url string, contentType string, body io.ReadSeeker, tokens *TokenOptions) (res *http.Response, err error) {
if contentType == "" {
contentType = appJson
}
req := request{"PUT", url, contentType, body, tokens}
rewinder := func() io.Reader {
body.Seek(0, 0)
return body
}
res, err = client.SendRequest(&req, rewinder)
return
}
func (client *restClient) Delete(url string, tokens *TokenOptions) (res *http.Response, err error) {
req := request{"DELETE", url, "", nil, tokens}
res, err = client.SendRequest(&req, nil)
return
}
func (client *restClient) SendRequest(req *request, bodyRewinder bodyRewinder) (res *http.Response, err error) {
res, err = client.sendRequestHelper(req)
// In most cases, we'll return immediately
// If the operation succeeded, but we got a 401 response and if we're using
// authentication, then we'll look into the body to see if the token expired
if err != nil {
return res, err
}
if res.StatusCode != 401 {
// It's not a 401, so the token didn't expire
return res, err
}
if req.Tokens == nil || req.Tokens.AccessToken == "" {
// We don't have a token, so we can't renew the token, no need to proceed
return res, err
}
// We're going to look in the body to see if it failed because the token expired
// This means we need to read the body, but the functions that call us also
// expect to read the body. So we read the body, then create a new reader
// so they can read the body as normal.
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return res, err
}
res.Body = ioutil.NopCloser(bytes.NewReader(body))
// Now see if we had an expired token or not
var apiError ApiError
err = json.Unmarshal(body, &apiError)
if err != nil {
return res, err
}
if apiError.Code != "ExpiredAuthToken" {
return res, nil
}
// We were told that the access token expired, so try to renew it.
// Note that this looks recursive because GetTokensByRefreshToken() will
// call the /auth API, and therefore SendRequest(). However, it calls
// without a token, so we avoid having a loop
newTokens, err := client.Auth.GetTokensByRefreshToken(req.Tokens.RefreshToken)
if err != nil {
return res, err
}
req.Tokens.AccessToken = newTokens.AccessToken
if client.UpdateAccessTokenCallback != nil {
client.UpdateAccessTokenCallback(newTokens.AccessToken)
}
if req.Body != nil && bodyRewinder != nil {
req.Body = bodyRewinder()
}
res, err = client.sendRequestHelper(req)
return res, nil
}
func (client *restClient) sendRequestHelper(req *request) (res *http.Response, err error) {
r, err := http.NewRequest(req.Method, req.URL, req.Body)
if err != nil {
client.logger.Printf("An error occured creating request %s on %s. Error: %s", req.Method, req.URL, err)
@@ -149,8 +246,8 @@ func (client *restClient) Do(req *request) (res *http.Response, err error) {
if req.ContentType != "" {
r.Header.Add("Content-Type", req.ContentType)
}
if req.Token != "" {
r.Header.Add("Authorization", "Bearer "+req.Token)
if req.Tokens != nil && req.Tokens.AccessToken != "" {
r.Header.Add("Authorization", "Bearer "+req.Tokens.AccessToken)
}
res, err = client.httpClient.Do(r)
if err != nil {
@@ -162,21 +259,33 @@ func (client *restClient) Do(req *request) (res *http.Response, err error) {
return
}
func (client *restClient) MultipartUploadFile(url, filePath string, params map[string]string, token string) (res *http.Response, err error) {
func (client *restClient) MultipartUploadFile(url, filePath string, params map[string]string, tokens *TokenOptions) (res *http.Response, err error) {
file, err := os.Open(filePath)
if err != nil {
return
}
defer file.Close()
return client.MultipartUpload(url, file, filepath.Base(filePath), params, token)
return client.MultipartUpload(url, file, filepath.Base(filePath), params, tokens)
}
func (client *restClient) MultipartUpload(url string, reader io.Reader, filename string, params map[string]string, token string) (res *http.Response, err error) {
func (client *restClient) MultipartUpload(url string, reader io.ReadSeeker, filename string, params map[string]string, tokens *TokenOptions) (res *http.Response, err error) {
boundary := client.randomBoundary()
multiReader, contentType := client.createMultiReader(reader, filename, params, boundary)
rewinder := func() io.Reader {
reader.Seek(0, 0)
multiReader, _ := client.createMultiReader(reader, filename, params, boundary)
return multiReader
}
res, err = client.SendRequest(&request{"POST", url, contentType, multiReader, tokens}, rewinder)
return
}
func (client *restClient) createMultiReader(reader io.ReadSeeker, filename string, params map[string]string, boundary string) (io.Reader, string) {
// The mime/multipart package does not support streaming multipart data from disk,
// at least not without complicated, problematic goroutines that simultaneously read/write into a buffer.
// A much easier approach is to just construct the multipart request by hand, using io.MultiPart to
// concatenate the parts of the request together into a single io.Reader.
boundary := client.randomBoundary()
parts := []io.Reader{}
// Create a part for each key, val pair in params
@@ -195,9 +304,7 @@ func (client *restClient) MultipartUpload(url string, reader io.Reader, filename
contentType := fmt.Sprintf("multipart/form-data; boundary=%s", boundary)
res, err = client.Do(&request{"POST", url, contentType, io.MultiReader(parts...), token})
return
return io.MultiReader(parts...), contentType
}
// From https://golang.org/src/mime/multipart/writer.go

View File

@@ -0,0 +1,90 @@
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
//
// This product is licensed to you under the Apache License, Version 2.0 (the "License").
// You may not use this product except in compliance with the License.
//
// This product may include a number of subcomponents with separate copyright notices and
// license terms. Your use of these subcomponents is subject to the terms and conditions
// of the subcomponent's license, as noted in the LICENSE file.
package photon
import (
"bytes"
"encoding/json"
)
// Contains functionality for routers API.
type RoutersAPI struct {
client *Client
}
var routerUrl string = rootUrl + "/routers/"
// Gets a router with the specified ID.
func (api *RoutersAPI) Get(id string) (router *Router, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+routerUrl+id, api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
res, err = getError(res)
if err != nil {
return
}
var result Router
err = json.NewDecoder(res.Body).Decode(&result)
return &result, nil
}
// Updates router's attributes.
func (api *RoutersAPI) UpdateRouter(id string, routerSpec *RouterUpdateSpec) (task *Task, err error) {
body, err := json.Marshal(routerSpec)
if err != nil {
return
}
res, err := api.client.restClient.Put(
api.client.Endpoint+routerUrl+id,
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
task, err = getTask(getError(res))
return
}
// Deletes a router with specified ID.
func (api *RoutersAPI) Delete(routerID string) (task *Task, err error) {
res, err := api.client.restClient.Delete(api.client.Endpoint+routerUrl+routerID, api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
task, err = getTask(getError(res))
return
}
// Creates a subnet on the specified router.
func (api *RoutersAPI) CreateSubnet(routerID string, spec *SubnetCreateSpec) (task *Task, err error) {
body, err := json.Marshal(spec)
if err != nil {
return
}
res, err := api.client.restClient.Post(
api.client.Endpoint+routerUrl+routerID+"/subnets",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
task, err = getTask(getError(res))
return
}

View File

@@ -0,0 +1,139 @@
// Copyright (c) 2016 VMware, Inc. All Rights Reserved.
//
// This product is licensed to you under the Apache License, Version 2.0 (the "License").
// You may not use this product except in compliance with the License.
//
// This product may include a number of subcomponents with separate copyright notices and
// license terms. Your use of these subcomponents is subject to the terms and conditions
// of the subcomponent's license, as noted in the LICENSE file.
package photon
import (
"bytes"
"encoding/json"
)
// Contains functionality for services API.
type ServicesAPI struct {
client *Client
}
var serviceUrl = rootUrl + "/services/"
// Extended Properties
const (
ExtendedPropertyDNS = "dns"
ExtendedPropertyGateway = "gateway"
ExtendedPropertyNetMask = "netmask"
ExtendedPropertyLoadBalancerIP = "load_balancer_ip"
ExtendedPropertyNumberOfMasters = "number_of_masters"
ExtendedPropertyMasterIPs = "master_ips"
ExtendedPropertyMasterIP = "master_ip"
ExtendedPropertyMasterIP2 = "master_ip2"
ExtendedPropertyContainerNetwork = "container_network"
ExtendedPropertyZookeeperIP1 = "zookeeper_ip1"
ExtendedPropertyZookeeperIP2 = "zookeeper_ip2"
ExtendedPropertyZookeeperIP3 = "zookeeper_ip3"
ExtendedPropertyNumberOfETCDs = "number_of_etcds"
ExtendedPropertyETCDIP1 = "etcd_ip1"
ExtendedPropertyETCDIP2 = "etcd_ip2"
ExtendedPropertyETCDIP3 = "etcd_ip3"
ExtendedPropertySSHKey = "ssh_key"
ExtendedPropertyRegistryCACert = "registry_ca_cert"
ExtendedPropertyAdminPassword = "admin_password"
)
// Deletes a service with specified ID.
func (api *ServicesAPI) Delete(id string) (task *Task, err error) {
res, err := api.client.restClient.Delete(api.client.Endpoint+serviceUrl+id, api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
task, err = getTask(getError(res))
return
}
// Gets a service with the specified ID.
func (api *ServicesAPI) Get(id string) (service *Service, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+serviceUrl+id, api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
res, err = getError(res)
if err != nil {
return
}
var result Service
err = json.NewDecoder(res.Body).Decode(&result)
return &result, nil
}
// Gets vms for service with the specified ID.
func (api *ServicesAPI) GetVMs(id string) (result *VMs, err error) {
uri := api.client.Endpoint + serviceUrl + id + "/vms"
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
result = &VMs{}
err = json.Unmarshal(res, result)
return
}
// Resize a service to specified count.
func (api *ServicesAPI) Resize(id string, resize *ServiceResizeOperation) (task *Task, err error) {
body, err := json.Marshal(resize)
if err != nil {
return
}
res, err := api.client.restClient.Post(
api.client.Endpoint+serviceUrl+id+"/resize",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
task, err = getTask(getError(res))
return
}
// Start a background process to recreate failed VMs in a service with the specified ID.
func (api *ServicesAPI) TriggerMaintenance(id string) (task *Task, err error) {
body := []byte{}
res, err := api.client.restClient.Post(
api.client.Endpoint+serviceUrl+id+"/trigger_maintenance",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
task, err = getTask(getError(res))
return
}
// Change a service version to the specified image by destroying and recreating the VMs.
func (api *ServicesAPI) ChangeVersion(id string, changeVersion *ServiceChangeVersionOperation) (task *Task, err error) {
body, err := json.Marshal(changeVersion)
if err != nil {
return
}
res, err := api.client.restClient.Post(
api.client.Endpoint+serviceUrl+id+"/change_version",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
task, err = getTask(getError(res))
return
}

View File

@@ -18,11 +18,11 @@ type StatusAPI struct {
client *Client
}
var statusUrl string = "/status"
var statusUrl string = rootUrl + "/status"
// Returns the status of an photon endpoint.
func (api *StatusAPI) Get() (status *Status, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+statusUrl, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Get(api.client.Endpoint+statusUrl, api.client.options.TokenOptions)
if err != nil {
return
}

View File

@@ -0,0 +1,72 @@
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
//
// This product is licensed to you under the Apache License, Version 2.0 (the "License").
// You may not use this product except in compliance with the License.
//
// This product may include a number of subcomponents with separate copyright notices and
// license terms. Your use of these subcomponents is subject to the terms and conditions
// of the subcomponent's license, as noted in the LICENSE file.
package photon
import (
"bytes"
"encoding/json"
)
// Contains functionality for subnets API.
type SubnetsAPI struct {
client *Client
}
var subnetUrl string = "/temp-subnets/"
// Deletes a subnet with the specified ID.
func (api *SubnetsAPI) Delete(id string) (task *Task, err error) {
res, err := api.client.restClient.Delete(api.client.Endpoint+subnetUrl+id, api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
task, err = getTask(getError(res))
return
}
// Gets a subnet with the specified ID.
func (api *SubnetsAPI) Get(id string) (subnet *Subnet, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+subnetUrl+id, api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
res, err = getError(res)
if err != nil {
return
}
var result Subnet
err = json.NewDecoder(res.Body).Decode(&result)
return &result, nil
}
// Updates subnet's attributes.
func (api *SubnetsAPI) Update(id string, subnetSpec *SubnetUpdateSpec) (task *Task, err error) {
body, err := json.Marshal(subnetSpec)
if err != nil {
return
}
res, err := api.client.restClient.Put(
api.client.Endpoint+subnetUrl+id,
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
task, err = getTask(getError(res))
return
}

View File

@@ -19,11 +19,11 @@ type TasksAPI struct {
client *Client
}
var taskUrl string = "/tasks"
var taskUrl string = rootUrl + "/tasks"
// Gets a task by ID.
func (api *TasksAPI) Get(id string) (task *Task, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+taskUrl+"/"+id, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Get(api.client.Endpoint+taskUrl+"/"+id, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -39,7 +39,7 @@ func (api *TasksAPI) GetAll(options *TaskGetOptions) (result *TaskList, err erro
if options != nil {
uri += getQueryString(options)
}
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}

View File

@@ -12,6 +12,7 @@ package photon
import (
"bytes"
"encoding/json"
"fmt"
)
// Contains functionality for tenants API.
@@ -29,12 +30,12 @@ type ProjectGetOptions struct {
Name string `urlParam:"name"`
}
var tenantUrl string = "/tenants"
var tenantUrl string = rootUrl + "/tenants"
// Returns all tenants on an photon instance.
func (api *TenantsAPI) GetAll() (result *Tenants, err error) {
uri := api.client.Endpoint + tenantUrl
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -54,7 +55,7 @@ func (api *TenantsAPI) Create(tenantSpec *TenantCreateSpec) (task *Task, err err
api.client.Endpoint+tenantUrl,
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -65,7 +66,7 @@ func (api *TenantsAPI) Create(tenantSpec *TenantCreateSpec) (task *Task, err err
// Deletes the tenant with specified ID. Any projects, VMs, disks, etc., owned by the tenant must be deleted first.
func (api *TenantsAPI) Delete(id string) (task *Task, err error) {
res, err := api.client.restClient.Delete(api.client.Endpoint+tenantUrl+"/"+id, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Delete(api.client.Endpoint+tenantUrl+"/"+id, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -84,7 +85,7 @@ func (api *TenantsAPI) CreateResourceTicket(tenantId string, spec *ResourceTicke
api.client.Endpoint+tenantUrl+"/"+tenantId+"/resource-tickets",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -100,7 +101,7 @@ func (api *TenantsAPI) GetResourceTickets(tenantId string, options *ResourceTick
if options != nil {
uri += getQueryString(options)
}
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -120,7 +121,7 @@ func (api *TenantsAPI) CreateProject(tenantId string, spec *ProjectCreateSpec) (
api.client.Endpoint+tenantUrl+"/"+tenantId+"/projects",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -136,7 +137,7 @@ func (api *TenantsAPI) GetProjects(tenantId string, options *ProjectGetOptions)
if options != nil {
uri += getQueryString(options)
}
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -153,7 +154,7 @@ func (api *TenantsAPI) GetTasks(id string, options *TaskGetOptions) (result *Tas
if options != nil {
uri += getQueryString(options)
}
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -163,19 +164,42 @@ func (api *TenantsAPI) GetTasks(id string, options *TaskGetOptions) (result *Tas
return
}
// Gets a tenant with the specified ID.
func (api *TenantsAPI) Get(id string) (tenant *Tenant, err error) {
res, err := api.client.restClient.Get(api.getEntityUrl(id), api.client.options.TokenOptions.AccessToken)
// Gets a tenant with the specified ID or name
func (api *TenantsAPI) Get(identity string) (tenant *Tenant, err error) {
res, err := api.client.restClient.Get(api.getEntityUrl(identity), api.client.options.TokenOptions)
if err != nil {
return
}
defer res.Body.Close()
res, err = getError(res)
tenant = &Tenant{}
if res != nil {
err = json.NewDecoder(res.Body).Decode(tenant)
// ID corresponds to the tenant ID found, return tenant
if err == nil {
return
}
}
// Find by Name
uri := api.client.Endpoint + tenantUrl + "?name=" + identity
res2, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
tenant = &Tenant{}
err = json.NewDecoder(res.Body).Decode(tenant)
tenants := &Tenants{}
err = json.Unmarshal(res2, tenants)
if err != nil {
return
}
if len(tenants.Items) < 1 {
err = fmt.Errorf("Cannot find a tenant with id or name match %s", identity)
return
}
tenant = &(tenants.Items[0])
return
}

View File

@@ -100,7 +100,7 @@ func setSecurityGroups(client *Client, entityUrl string, securityGroups *Securit
url,
"application/json",
bytes.NewReader(body),
client.options.TokenOptions.AccessToken)
client.options.TokenOptions)
if err != nil {
return
}

View File

@@ -24,8 +24,8 @@ type VirtualSubnetGetOptions struct {
Name string `urlParam:"name"`
}
var subnetsUrl = "/subnets"
var projectsUrl = "/projects"
var subnetsUrl = rootUrl + "/subnets"
var projectsUrl = rootUrl + "/projects"
// Create a virtual network
func (api *VirtualSubnetsAPI) Create(projectId string,
@@ -39,8 +39,8 @@ func (api *VirtualSubnetsAPI) Create(projectId string,
res, err := api.client.restClient.Post(
api.client.Endpoint+projectsUrl+"/"+projectId+"/subnets",
"application/json",
bytes.NewBuffer(body),
api.client.options.TokenOptions.AccessToken)
bytes.NewReader(body),
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -54,7 +54,7 @@ func (api *VirtualSubnetsAPI) Create(projectId string,
// Delete a virtual network with the specified ID.
func (api *VirtualSubnetsAPI) Delete(id string) (task *Task, err error) {
res, err := api.client.restClient.Delete(api.client.Endpoint+subnetsUrl+"/"+id,
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -68,7 +68,7 @@ func (api *VirtualSubnetsAPI) Delete(id string) (task *Task, err error) {
// Get the virtual subnet with the specified id
func (api *VirtualSubnetsAPI) Get(id string) (subnet *VirtualSubnet, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+subnetsUrl+"/"+id,
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -94,7 +94,7 @@ func (api *VirtualSubnetsAPI) GetAll(projectId string,
uri += getQueryString(options)
}
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -109,8 +109,8 @@ func (api *VirtualSubnetsAPI) SetDefault(id string) (task *Task, err error) {
res, err := api.client.restClient.Post(
api.client.Endpoint+subnetsUrl+"/"+id+"/set_default",
"application/json",
bytes.NewBuffer([]byte("")),
api.client.options.TokenOptions.AccessToken)
bytes.NewReader([]byte("")),
api.client.options.TokenOptions)
if err != nil {
return
}

View File

@@ -20,10 +20,10 @@ type VmAPI struct {
client *Client
}
var vmUrl string = "/vms/"
var vmUrl string = rootUrl + "/vms/"
func (api *VmAPI) Get(id string) (vm *VM, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+vmUrl+id, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Get(api.client.Endpoint+vmUrl+id, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -38,7 +38,7 @@ func (api *VmAPI) Get(id string) (vm *VM, err error) {
}
func (api *VmAPI) Delete(id string) (task *Task, err error) {
res, err := api.client.restClient.Delete(api.client.Endpoint+vmUrl+id, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Delete(api.client.Endpoint+vmUrl+id, api.client.options.TokenOptions)
if err != nil {
return
@@ -57,7 +57,7 @@ func (api *VmAPI) AttachDisk(id string, op *VmDiskOperation) (task *Task, err er
api.client.Endpoint+vmUrl+id+"/attach_disk",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -75,7 +75,7 @@ func (api *VmAPI) DetachDisk(id string, op *VmDiskOperation) (task *Task, err er
api.client.Endpoint+vmUrl+id+"/detach_disk",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -84,9 +84,9 @@ func (api *VmAPI) DetachDisk(id string, op *VmDiskOperation) (task *Task, err er
return
}
func (api *VmAPI) AttachISO(id string, reader io.Reader, name string) (task *Task, err error) {
func (api *VmAPI) AttachISO(id string, reader io.ReadSeeker, name string) (task *Task, err error) {
res, err := api.client.restClient.MultipartUpload(
api.client.Endpoint+vmUrl+id+"/attach_iso", reader, name, nil, api.client.options.TokenOptions.AccessToken)
api.client.Endpoint+vmUrl+id+"/attach_iso", reader, name, nil, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -104,7 +104,7 @@ func (api *VmAPI) DetachISO(id string) (task *Task, err error) {
api.client.Endpoint+vmUrl+id+"/detach_iso",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -122,7 +122,7 @@ func (api *VmAPI) Start(id string) (task *Task, err error) {
api.client.Endpoint+vmUrl+id+"/start",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -140,7 +140,7 @@ func (api *VmAPI) Stop(id string) (task *Task, err error) {
api.client.Endpoint+vmUrl+id+"/stop",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -158,7 +158,7 @@ func (api *VmAPI) Restart(id string) (task *Task, err error) {
api.client.Endpoint+vmUrl+id+"/restart",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -176,7 +176,7 @@ func (api *VmAPI) Resume(id string) (task *Task, err error) {
api.client.Endpoint+vmUrl+id+"/resume",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -194,7 +194,7 @@ func (api *VmAPI) Suspend(id string) (task *Task, err error) {
api.client.Endpoint+vmUrl+id+"/suspend",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -212,7 +212,7 @@ func (api *VmAPI) SetMetadata(id string, metadata *VmMetadata) (task *Task, err
api.client.Endpoint+vmUrl+id+"/set_metadata",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -228,7 +228,7 @@ func (api *VmAPI) GetTasks(id string, options *TaskGetOptions) (result *TaskList
if options != nil {
uri += getQueryString(options)
}
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.GetList(api.client.Endpoint, uri, api.client.options.TokenOptions)
if err != nil {
return
}
@@ -239,7 +239,7 @@ func (api *VmAPI) GetTasks(id string, options *TaskGetOptions) (result *TaskList
}
func (api *VmAPI) GetNetworks(id string) (task *Task, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+vmUrl+id+"/subnets", api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Get(api.client.Endpoint+vmUrl+id+"/subnets", api.client.options.TokenOptions)
if err != nil {
return
}
@@ -258,7 +258,7 @@ func (api *VmAPI) AcquireFloatingIp(id string, spec *VmFloatingIpSpec) (task *Ta
api.client.Endpoint+vmUrl+id+"/acquire_floating_ip",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -271,7 +271,7 @@ func (api *VmAPI) ReleaseFloatingIp(id string) (task *Task, err error) {
res, err := api.client.restClient.Delete(
api.client.Endpoint+vmUrl+id+"/release_floating_ip",
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -281,7 +281,7 @@ func (api *VmAPI) ReleaseFloatingIp(id string) (task *Task, err error) {
}
func (api *VmAPI) GetMKSTicket(id string) (task *Task, err error) {
res, err := api.client.restClient.Get(api.client.Endpoint+vmUrl+id+"/mks_ticket", api.client.options.TokenOptions.AccessToken)
res, err := api.client.restClient.Get(api.client.Endpoint+vmUrl+id+"/mks_ticket", api.client.options.TokenOptions)
if err != nil {
return
}
@@ -299,7 +299,7 @@ func (api *VmAPI) SetTag(id string, tag *VmTag) (task *Task, err error) {
api.client.Endpoint+vmUrl+id+"/tags",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}
@@ -317,7 +317,7 @@ func (api *VmAPI) CreateImage(id string, options *ImageCreateSpec) (task *Task,
api.client.Endpoint+vmUrl+id+"/create_image",
"application/json",
bytes.NewReader(body),
api.client.options.TokenOptions.AccessToken)
api.client.options.TokenOptions)
if err != nil {
return
}