mirror of https://github.com/kubernetes/kops.git
add keypair role
This commit is contained in:
parent
02daea62ae
commit
ed8d03d402
|
|
@ -483,6 +483,10 @@
|
|||
".",
|
||||
"openstack",
|
||||
"openstack/blockstorage/v2/volumes",
|
||||
"openstack/compute/v2/extensions/keypairs",
|
||||
"openstack/compute/v2/flavors",
|
||||
"openstack/compute/v2/images",
|
||||
"openstack/compute/v2/servers",
|
||||
"openstack/identity/v2/tenants",
|
||||
"openstack/identity/v2/tokens",
|
||||
"openstack/identity/v3/tokens",
|
||||
|
|
@ -1706,6 +1710,6 @@
|
|||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "33c4809d9ffb5425549fab80b4edb6a9fa84726ca461e8caa314b12b27f61a8d"
|
||||
inputs-digest = "4708af635b2bbadafcb67be11520a8a6b34557b2f2ad2fec6f80b39a5ca646ad"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ go_library(
|
|||
"context.go",
|
||||
"convenience.go",
|
||||
"network.go",
|
||||
"sshkey.go",
|
||||
],
|
||||
importpath = "k8s.io/kops/pkg/model/openstackmodel",
|
||||
visibility = ["//visibility:public"],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package openstackmodel
|
||||
|
||||
import (
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/openstacktasks"
|
||||
)
|
||||
|
||||
// SSHKeyModelBuilder configures SSH objects
|
||||
type SSHKeyModelBuilder struct {
|
||||
*OpenstackModelContext
|
||||
Lifecycle *fi.Lifecycle
|
||||
}
|
||||
|
||||
var _ fi.ModelBuilder = &SSHKeyModelBuilder{}
|
||||
|
||||
func (b *SSHKeyModelBuilder) Build(c *fi.ModelBuilderContext) error {
|
||||
name, err := b.SSHKeyName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t := &openstacktasks.SSHKey{
|
||||
Name: s(name),
|
||||
Lifecycle: b.Lifecycle,
|
||||
PublicKey: fi.WrapResource(fi.NewStringResource(string(b.SSHPublicKeys[0]))),
|
||||
}
|
||||
c.AddTask(t)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -463,10 +463,21 @@ func (c *ApplyClusterCmd) Run() error {
|
|||
region = osCloud.Region()
|
||||
|
||||
l.AddTypes(map[string]interface{}{
|
||||
"sshKey": &openstacktasks.SSHKey{},
|
||||
// Networking
|
||||
"network": &openstacktasks.Network{},
|
||||
"router": &openstacktasks.Router{},
|
||||
})
|
||||
|
||||
if len(sshPublicKeys) == 0 {
|
||||
return fmt.Errorf("SSH public key must be specified when running with Openstack (create with `kops create secret --name %s sshpublickey admin -i ~/.ssh/id_rsa.pub`)", cluster.ObjectMeta.Name)
|
||||
}
|
||||
|
||||
modelContext.SSHPublicKeys = sshPublicKeys
|
||||
|
||||
if len(sshPublicKeys) != 1 {
|
||||
return fmt.Errorf("Exactly one 'admin' SSH public key can be specified when running with Openstack; please delete a key using `kops delete secret`")
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown CloudProvider %q", cluster.Spec.CloudProvider)
|
||||
|
|
@ -604,6 +615,7 @@ func (c *ApplyClusterCmd) Run() error {
|
|||
|
||||
l.Builders = append(l.Builders,
|
||||
&openstackmodel.NetworkModelBuilder{OpenstackModelContext: openstackModelContext, Lifecycle: &networkLifecycle},
|
||||
&openstackmodel.SSHKeyModelBuilder{OpenstackModelContext: openstackModelContext, Lifecycle: &securityLifecycle},
|
||||
)
|
||||
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ go_library(
|
|||
"//vendor/github.com/gophercloud/gophercloud:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules:go_default_library",
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"github.com/gophercloud/gophercloud"
|
||||
os "github.com/gophercloud/gophercloud/openstack"
|
||||
cinder "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes"
|
||||
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs"
|
||||
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers"
|
||||
sg "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups"
|
||||
sgr "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules"
|
||||
|
|
@ -42,6 +43,9 @@ const TagNameEtcdClusterPrefix = "k8s.io/etcd/"
|
|||
const TagNameRolePrefix = "k8s.io/role/"
|
||||
const TagClusterName = "KubernetesCluster"
|
||||
|
||||
// ErrNotFound is used to inform that the object is not found
|
||||
var ErrNotFound = "Resource not found"
|
||||
|
||||
// readBackoff is the backoff strategy for openstack read retries.
|
||||
var readBackoff = wait.Backoff{
|
||||
Duration: time.Second,
|
||||
|
|
@ -105,11 +109,18 @@ type OpenstackCloud interface {
|
|||
|
||||
//CreateSubnet will create a new Neutron subnet
|
||||
CreateSubnet(opt subnets.CreateOptsBuilder) (*subnets.Subnet, error)
|
||||
|
||||
// ListKeypair will return the Nova keypairs
|
||||
ListKeypair(name string) (*keypairs.KeyPair, error)
|
||||
|
||||
// CreateKeypair will create a new Nova Keypair
|
||||
CreateKeypair(opt keypairs.CreateOptsBuilder) (*keypairs.KeyPair, error)
|
||||
}
|
||||
|
||||
type openstackCloud struct {
|
||||
cinderClient *gophercloud.ServiceClient
|
||||
neutronClient *gophercloud.ServiceClient
|
||||
novaClient *gophercloud.ServiceClient
|
||||
tags map[string]string
|
||||
region string
|
||||
}
|
||||
|
|
@ -145,11 +156,22 @@ func NewOpenstackCloud(tags map[string]string) (OpenstackCloud, error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("error building neutron client: %v", err)
|
||||
}
|
||||
|
||||
endpointOpt, err = config.GetServiceConfig("Nova")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
novaClient, err := os.NewComputeV2(provider, endpointOpt)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error building nova client: %v", err)
|
||||
}
|
||||
|
||||
region := endpointOpt.Region
|
||||
|
||||
c := &openstackCloud{
|
||||
cinderClient: cinderClient,
|
||||
neutronClient: neutronClient,
|
||||
novaClient: novaClient,
|
||||
tags: tags,
|
||||
region: region,
|
||||
}
|
||||
|
|
@ -483,3 +505,45 @@ func (c *openstackCloud) CreateSubnet(opt subnets.CreateOptsBuilder) (*subnets.S
|
|||
return s, wait.ErrWaitTimeout
|
||||
}
|
||||
}
|
||||
|
||||
func (c *openstackCloud) ListKeypair(name string) (*keypairs.KeyPair, error) {
|
||||
var k *keypairs.KeyPair
|
||||
done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) {
|
||||
rs, err := keypairs.Get(c.novaClient, name).Extract()
|
||||
if err != nil {
|
||||
if err.Error() == ErrNotFound {
|
||||
return true, nil
|
||||
}
|
||||
return false, fmt.Errorf("error listing keypair: %v", err)
|
||||
}
|
||||
k = rs
|
||||
return true, nil
|
||||
})
|
||||
if err != nil {
|
||||
return k, err
|
||||
} else if done {
|
||||
return k, nil
|
||||
} else {
|
||||
return k, wait.ErrWaitTimeout
|
||||
}
|
||||
}
|
||||
|
||||
func (c *openstackCloud) CreateKeypair(opt keypairs.CreateOptsBuilder) (*keypairs.KeyPair, error) {
|
||||
var k *keypairs.KeyPair
|
||||
|
||||
done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) {
|
||||
v, err := keypairs.Create(c.novaClient, opt).Extract()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error creating keypair: %v", err)
|
||||
}
|
||||
k = v
|
||||
return true, nil
|
||||
})
|
||||
if err != nil {
|
||||
return k, err
|
||||
} else if done {
|
||||
return k, nil
|
||||
} else {
|
||||
return k, wait.ErrWaitTimeout
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ go_library(
|
|||
"securitygroup.go",
|
||||
"securitygroup_fitask.go",
|
||||
"securitygrouprule.go",
|
||||
"sshkey.go",
|
||||
"sshkey_fitask.go",
|
||||
"subnet.go",
|
||||
"subnet_fitask.go",
|
||||
"volume.go",
|
||||
|
|
@ -18,11 +20,13 @@ go_library(
|
|||
importpath = "k8s.io/kops/upup/pkg/fi/cloudup/openstacktasks",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/pki:go_default_library",
|
||||
"//upup/pkg/fi:go_default_library",
|
||||
"//upup/pkg/fi/cloudup/openstack:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules:go_default_library",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package openstacktasks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs"
|
||||
|
||||
"k8s.io/kops/pkg/pki"
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/openstack"
|
||||
)
|
||||
|
||||
//go:generate fitask -type=SSHKey
|
||||
type SSHKey struct {
|
||||
Name *string
|
||||
Lifecycle *fi.Lifecycle
|
||||
|
||||
PublicKey *fi.ResourceHolder
|
||||
|
||||
KeyFingerprint *string
|
||||
}
|
||||
|
||||
var _ fi.CompareWithID = &SSHKey{}
|
||||
|
||||
func (e *SSHKey) CompareWithID() *string {
|
||||
return e.Name
|
||||
}
|
||||
|
||||
func (e *SSHKey) Find(c *fi.Context) (*SSHKey, error) {
|
||||
cloud := c.Cloud.(openstack.OpenstackCloud)
|
||||
rs, err := cloud.ListKeypair(openstackKeyPairName(fi.StringValue(e.Name)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rs == nil {
|
||||
return nil, nil
|
||||
}
|
||||
actual := &SSHKey{
|
||||
Name: e.Name,
|
||||
KeyFingerprint: fi.String(rs.Fingerprint),
|
||||
}
|
||||
|
||||
// Avoid spurious changes
|
||||
if fi.StringValue(actual.KeyFingerprint) == fi.StringValue(e.KeyFingerprint) {
|
||||
glog.V(2).Infof("SSH key fingerprints match; assuming public keys match")
|
||||
actual.PublicKey = e.PublicKey
|
||||
} else {
|
||||
glog.V(2).Infof("Computed SSH key fingerprint mismatch: %q %q", fi.StringValue(e.KeyFingerprint), fi.StringValue(actual.KeyFingerprint))
|
||||
}
|
||||
actual.Lifecycle = e.Lifecycle
|
||||
return actual, nil
|
||||
}
|
||||
|
||||
func (e *SSHKey) Run(c *fi.Context) error {
|
||||
if e.KeyFingerprint == nil && e.PublicKey != nil {
|
||||
publicKey, err := e.PublicKey.AsString()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading SSH public key: %v", err)
|
||||
}
|
||||
|
||||
keyFingerprint, err := pki.ComputeAWSKeyFingerprint(publicKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error computing key fingerprint for SSH key: %v", err)
|
||||
}
|
||||
glog.V(2).Infof("Computed SSH key fingerprint as %q", keyFingerprint)
|
||||
e.KeyFingerprint = &keyFingerprint
|
||||
}
|
||||
return fi.DefaultDeltaRunMethod(e, c)
|
||||
}
|
||||
|
||||
func (s *SSHKey) CheckChanges(a, e, changes *SSHKey) error {
|
||||
if a != nil {
|
||||
if changes.Name != nil {
|
||||
return fi.CannotChangeField("Name")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func openstackKeyPairName(org string) string {
|
||||
name := strings.Replace(org, ".", "-", -1)
|
||||
name = strings.Replace(name, ":", "_", -1)
|
||||
return name
|
||||
}
|
||||
|
||||
func (_ *SSHKey) RenderOpenstack(t *openstack.OpenstackAPITarget, a, e, changes *SSHKey) error {
|
||||
if a == nil {
|
||||
glog.V(2).Infof("Creating Keypair with name:%q", fi.StringValue(e.Name))
|
||||
|
||||
opt := keypairs.CreateOpts{
|
||||
Name: openstackKeyPairName(fi.StringValue(e.Name)),
|
||||
}
|
||||
|
||||
if e.PublicKey != nil {
|
||||
d, err := e.PublicKey.AsString()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error rendering SSHKey PublicKey: %v", err)
|
||||
}
|
||||
opt.PublicKey = d
|
||||
}
|
||||
|
||||
v, err := t.Cloud.CreateKeypair(opt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating keypair: %v", err)
|
||||
}
|
||||
|
||||
e.KeyFingerprint = fi.String(v.Fingerprint)
|
||||
glog.V(2).Infof("Creating a new Openstack keypair, id=%s", v.Fingerprint)
|
||||
return nil
|
||||
}
|
||||
e.KeyFingerprint = a.KeyFingerprint
|
||||
glog.V(2).Infof("Using an existing Openstack keypair, id=%s", fi.StringValue(e.KeyFingerprint))
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by ""fitask" -type=SSHKey"; DO NOT EDIT
|
||||
|
||||
package openstacktasks
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
)
|
||||
|
||||
// SSHKey
|
||||
|
||||
// JSON marshalling boilerplate
|
||||
type realSSHKey SSHKey
|
||||
|
||||
// UnmarshalJSON implements conversion to JSON, supporitng an alternate specification of the object as a string
|
||||
func (o *SSHKey) UnmarshalJSON(data []byte) error {
|
||||
var jsonName string
|
||||
if err := json.Unmarshal(data, &jsonName); err == nil {
|
||||
o.Name = &jsonName
|
||||
return nil
|
||||
}
|
||||
|
||||
var r realSSHKey
|
||||
if err := json.Unmarshal(data, &r); err != nil {
|
||||
return err
|
||||
}
|
||||
*o = SSHKey(r)
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ fi.HasLifecycle = &SSHKey{}
|
||||
|
||||
// GetLifecycle returns the Lifecycle of the object, implementing fi.HasLifecycle
|
||||
func (o *SSHKey) GetLifecycle() *fi.Lifecycle {
|
||||
return o.Lifecycle
|
||||
}
|
||||
|
||||
// SetLifecycle sets the Lifecycle of the object, implementing fi.SetLifecycle
|
||||
func (o *SSHKey) SetLifecycle(lifecycle fi.Lifecycle) {
|
||||
o.Lifecycle = &lifecycle
|
||||
}
|
||||
|
||||
var _ fi.HasName = &SSHKey{}
|
||||
|
||||
// GetName returns the Name of the object, implementing fi.HasName
|
||||
func (o *SSHKey) GetName() *string {
|
||||
return o.Name
|
||||
}
|
||||
|
||||
// SetName sets the Name of the object, implementing fi.SetName
|
||||
func (o *SSHKey) SetName(name string) {
|
||||
o.Name = &name
|
||||
}
|
||||
|
||||
// String is the stringer function for the task, producing readable output using fi.TaskAsString
|
||||
func (o *SSHKey) String() string {
|
||||
return fi.TaskAsString(o)
|
||||
}
|
||||
19
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/BUILD.bazel
generated
vendored
Normal file
19
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/BUILD.bazel
generated
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"requests.go",
|
||||
"results.go",
|
||||
"urls.go",
|
||||
],
|
||||
importmap = "vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs",
|
||||
importpath = "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/gophercloud/gophercloud:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/pagination:go_default_library",
|
||||
],
|
||||
)
|
||||
71
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/doc.go
generated
vendored
Normal file
71
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
Package keypairs provides the ability to manage key pairs as well as create
|
||||
servers with a specified key pair.
|
||||
|
||||
Example to List Key Pairs
|
||||
|
||||
allPages, err := keypairs.List(computeClient).AllPages()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
allKeyPairs, err := keypairs.ExtractKeyPairs(allPages)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, kp := range allKeyPairs {
|
||||
fmt.Printf("%+v\n", kp)
|
||||
}
|
||||
|
||||
Example to Create a Key Pair
|
||||
|
||||
createOpts := keypairs.CreateOpts{
|
||||
Name: "keypair-name",
|
||||
}
|
||||
|
||||
keypair, err := keypairs.Create(computeClient, createOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%+v", keypair)
|
||||
|
||||
Example to Import a Key Pair
|
||||
|
||||
createOpts := keypairs.CreateOpts{
|
||||
Name: "keypair-name",
|
||||
PublicKey: "public-key",
|
||||
}
|
||||
|
||||
keypair, err := keypairs.Create(computeClient, createOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example to Delete a Key Pair
|
||||
|
||||
err := keypairs.Delete(computeClient, "keypair-name").ExtractErr()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example to Create a Server With a Key Pair
|
||||
|
||||
serverCreateOpts := servers.CreateOpts{
|
||||
Name: "server_name",
|
||||
ImageRef: "image-uuid",
|
||||
FlavorRef: "flavor-uuid",
|
||||
}
|
||||
|
||||
createOpts := keypairs.CreateOpts{
|
||||
CreateOptsBuilder: serverCreateOpts,
|
||||
KeyName: "keypair-name",
|
||||
}
|
||||
|
||||
server, err := servers.Create(computeClient, createOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
*/
|
||||
package keypairs
|
||||
86
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/requests.go
generated
vendored
Normal file
86
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/requests.go
generated
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
package keypairs
|
||||
|
||||
import (
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
// CreateOptsExt adds a KeyPair option to the base CreateOpts.
|
||||
type CreateOptsExt struct {
|
||||
servers.CreateOptsBuilder
|
||||
|
||||
// KeyName is the name of the key pair.
|
||||
KeyName string `json:"key_name,omitempty"`
|
||||
}
|
||||
|
||||
// ToServerCreateMap adds the key_name to the base server creation options.
|
||||
func (opts CreateOptsExt) ToServerCreateMap() (map[string]interface{}, error) {
|
||||
base, err := opts.CreateOptsBuilder.ToServerCreateMap()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if opts.KeyName == "" {
|
||||
return base, nil
|
||||
}
|
||||
|
||||
serverMap := base["server"].(map[string]interface{})
|
||||
serverMap["key_name"] = opts.KeyName
|
||||
|
||||
return base, nil
|
||||
}
|
||||
|
||||
// List returns a Pager that allows you to iterate over a collection of KeyPairs.
|
||||
func List(client *gophercloud.ServiceClient) pagination.Pager {
|
||||
return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
|
||||
return KeyPairPage{pagination.SinglePageBase(r)}
|
||||
})
|
||||
}
|
||||
|
||||
// CreateOptsBuilder allows extensions to add additional parameters to the
|
||||
// Create request.
|
||||
type CreateOptsBuilder interface {
|
||||
ToKeyPairCreateMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// CreateOpts specifies KeyPair creation or import parameters.
|
||||
type CreateOpts struct {
|
||||
// Name is a friendly name to refer to this KeyPair in other services.
|
||||
Name string `json:"name" required:"true"`
|
||||
|
||||
// PublicKey [optional] is a pregenerated OpenSSH-formatted public key.
|
||||
// If provided, this key will be imported and no new key will be created.
|
||||
PublicKey string `json:"public_key,omitempty"`
|
||||
}
|
||||
|
||||
// ToKeyPairCreateMap constructs a request body from CreateOpts.
|
||||
func (opts CreateOpts) ToKeyPairCreateMap() (map[string]interface{}, error) {
|
||||
return gophercloud.BuildRequestBody(opts, "keypair")
|
||||
}
|
||||
|
||||
// Create requests the creation of a new KeyPair on the server, or to import a
|
||||
// pre-existing keypair.
|
||||
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||
b, err := opts.ToKeyPairCreateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns public data about a previously uploaded KeyPair.
|
||||
func Get(client *gophercloud.ServiceClient, name string) (r GetResult) {
|
||||
_, r.Err = client.Get(getURL(client, name), &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete requests the deletion of a previous stored KeyPair from the server.
|
||||
func Delete(client *gophercloud.ServiceClient, name string) (r DeleteResult) {
|
||||
_, r.Err = client.Delete(deleteURL(client, name), nil)
|
||||
return
|
||||
}
|
||||
91
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/results.go
generated
vendored
Normal file
91
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/results.go
generated
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
package keypairs
|
||||
|
||||
import (
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
// KeyPair is an SSH key known to the OpenStack Cloud that is available to be
|
||||
// injected into servers.
|
||||
type KeyPair struct {
|
||||
// Name is used to refer to this keypair from other services within this
|
||||
// region.
|
||||
Name string `json:"name"`
|
||||
|
||||
// Fingerprint is a short sequence of bytes that can be used to authenticate
|
||||
// or validate a longer public key.
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
|
||||
// PublicKey is the public key from this pair, in OpenSSH format.
|
||||
// "ssh-rsa AAAAB3Nz..."
|
||||
PublicKey string `json:"public_key"`
|
||||
|
||||
// PrivateKey is the private key from this pair, in PEM format.
|
||||
// "-----BEGIN RSA PRIVATE KEY-----\nMIICXA..."
|
||||
// It is only present if this KeyPair was just returned from a Create call.
|
||||
PrivateKey string `json:"private_key"`
|
||||
|
||||
// UserID is the user who owns this KeyPair.
|
||||
UserID string `json:"user_id"`
|
||||
}
|
||||
|
||||
// KeyPairPage stores a single page of all KeyPair results from a List call.
|
||||
// Use the ExtractKeyPairs function to convert the results to a slice of
|
||||
// KeyPairs.
|
||||
type KeyPairPage struct {
|
||||
pagination.SinglePageBase
|
||||
}
|
||||
|
||||
// IsEmpty determines whether or not a KeyPairPage is empty.
|
||||
func (page KeyPairPage) IsEmpty() (bool, error) {
|
||||
ks, err := ExtractKeyPairs(page)
|
||||
return len(ks) == 0, err
|
||||
}
|
||||
|
||||
// ExtractKeyPairs interprets a page of results as a slice of KeyPairs.
|
||||
func ExtractKeyPairs(r pagination.Page) ([]KeyPair, error) {
|
||||
type pair struct {
|
||||
KeyPair KeyPair `json:"keypair"`
|
||||
}
|
||||
var s struct {
|
||||
KeyPairs []pair `json:"keypairs"`
|
||||
}
|
||||
err := (r.(KeyPairPage)).ExtractInto(&s)
|
||||
results := make([]KeyPair, len(s.KeyPairs))
|
||||
for i, pair := range s.KeyPairs {
|
||||
results[i] = pair.KeyPair
|
||||
}
|
||||
return results, err
|
||||
}
|
||||
|
||||
type keyPairResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// Extract is a method that attempts to interpret any KeyPair resource response
|
||||
// as a KeyPair struct.
|
||||
func (r keyPairResult) Extract() (*KeyPair, error) {
|
||||
var s struct {
|
||||
KeyPair *KeyPair `json:"keypair"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
return s.KeyPair, err
|
||||
}
|
||||
|
||||
// CreateResult is the response from a Create operation. Call its Extract method
|
||||
// to interpret it as a KeyPair.
|
||||
type CreateResult struct {
|
||||
keyPairResult
|
||||
}
|
||||
|
||||
// GetResult is the response from a Get operation. Call its Extract method to
|
||||
// interpret it as a KeyPair.
|
||||
type GetResult struct {
|
||||
keyPairResult
|
||||
}
|
||||
|
||||
// DeleteResult is the response from a Delete operation. Call its ExtractErr
|
||||
// method to determine if the call succeeded or failed.
|
||||
type DeleteResult struct {
|
||||
gophercloud.ErrResult
|
||||
}
|
||||
25
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/urls.go
generated
vendored
Normal file
25
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/urls.go
generated
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package keypairs
|
||||
|
||||
import "github.com/gophercloud/gophercloud"
|
||||
|
||||
const resourcePath = "os-keypairs"
|
||||
|
||||
func resourceURL(c *gophercloud.ServiceClient) string {
|
||||
return c.ServiceURL(resourcePath)
|
||||
}
|
||||
|
||||
func listURL(c *gophercloud.ServiceClient) string {
|
||||
return resourceURL(c)
|
||||
}
|
||||
|
||||
func createURL(c *gophercloud.ServiceClient) string {
|
||||
return resourceURL(c)
|
||||
}
|
||||
|
||||
func getURL(c *gophercloud.ServiceClient, name string) string {
|
||||
return c.ServiceURL(resourcePath, name)
|
||||
}
|
||||
|
||||
func deleteURL(c *gophercloud.ServiceClient, name string) string {
|
||||
return getURL(c, name)
|
||||
}
|
||||
18
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/BUILD.bazel
generated
vendored
Normal file
18
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/BUILD.bazel
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"requests.go",
|
||||
"results.go",
|
||||
"urls.go",
|
||||
],
|
||||
importmap = "vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors",
|
||||
importpath = "github.com/gophercloud/gophercloud/openstack/compute/v2/flavors",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/gophercloud/gophercloud:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/pagination:go_default_library",
|
||||
],
|
||||
)
|
||||
137
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/doc.go
generated
vendored
Normal file
137
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
Package flavors provides information and interaction with the flavor API
|
||||
in the OpenStack Compute service.
|
||||
|
||||
A flavor is an available hardware configuration for a server. Each flavor
|
||||
has a unique combination of disk space, memory capacity and priority for CPU
|
||||
time.
|
||||
|
||||
Example to List Flavors
|
||||
|
||||
listOpts := flavors.ListOpts{
|
||||
AccessType: flavors.PublicAccess,
|
||||
}
|
||||
|
||||
allPages, err := flavors.ListDetail(computeClient, listOpts).AllPages()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
allFlavors, err := flavors.ExtractFlavors(allPages)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, flavor := range allFlavors {
|
||||
fmt.Printf("%+v\n", flavor)
|
||||
}
|
||||
|
||||
Example to Create a Flavor
|
||||
|
||||
createOpts := flavors.CreateOpts{
|
||||
ID: "1",
|
||||
Name: "m1.tiny",
|
||||
Disk: gophercloud.IntToPointer(1),
|
||||
RAM: 512,
|
||||
VCPUs: 1,
|
||||
RxTxFactor: 1.0,
|
||||
}
|
||||
|
||||
flavor, err := flavors.Create(computeClient, createOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example to List Flavor Access
|
||||
|
||||
flavorID := "e91758d6-a54a-4778-ad72-0c73a1cb695b"
|
||||
|
||||
allPages, err := flavors.ListAccesses(computeClient, flavorID).AllPages()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
allAccesses, err := flavors.ExtractAccesses(allPages)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, access := range allAccesses {
|
||||
fmt.Printf("%+v", access)
|
||||
}
|
||||
|
||||
Example to Grant Access to a Flavor
|
||||
|
||||
flavorID := "e91758d6-a54a-4778-ad72-0c73a1cb695b"
|
||||
|
||||
accessOpts := flavors.AddAccessOpts{
|
||||
Tenant: "15153a0979884b59b0592248ef947921",
|
||||
}
|
||||
|
||||
accessList, err := flavors.AddAccess(computeClient, flavor.ID, accessOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example to Remove/Revoke Access to a Flavor
|
||||
|
||||
flavorID := "e91758d6-a54a-4778-ad72-0c73a1cb695b"
|
||||
|
||||
accessOpts := flavors.RemoveAccessOpts{
|
||||
Tenant: "15153a0979884b59b0592248ef947921",
|
||||
}
|
||||
|
||||
accessList, err := flavors.RemoveAccess(computeClient, flavor.ID, accessOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example to Create Extra Specs for a Flavor
|
||||
|
||||
flavorID := "e91758d6-a54a-4778-ad72-0c73a1cb695b"
|
||||
|
||||
createOpts := flavors.ExtraSpecsOpts{
|
||||
"hw:cpu_policy": "CPU-POLICY",
|
||||
"hw:cpu_thread_policy": "CPU-THREAD-POLICY",
|
||||
}
|
||||
createdExtraSpecs, err := flavors.CreateExtraSpecs(computeClient, flavorID, createOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%+v", createdExtraSpecs)
|
||||
|
||||
Example to Get Extra Specs for a Flavor
|
||||
|
||||
flavorID := "e91758d6-a54a-4778-ad72-0c73a1cb695b"
|
||||
|
||||
extraSpecs, err := flavors.ListExtraSpecs(computeClient, flavorID).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%+v", extraSpecs)
|
||||
|
||||
Example to Update Extra Specs for a Flavor
|
||||
|
||||
flavorID := "e91758d6-a54a-4778-ad72-0c73a1cb695b"
|
||||
|
||||
updateOpts := flavors.ExtraSpecsOpts{
|
||||
"hw:cpu_thread_policy": "CPU-THREAD-POLICY-UPDATED",
|
||||
}
|
||||
updatedExtraSpec, err := flavors.UpdateExtraSpec(computeClient, flavorID, updateOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%+v", updatedExtraSpec)
|
||||
|
||||
Example to Delete an Extra Spec for a Flavor
|
||||
|
||||
flavorID := "e91758d6-a54a-4778-ad72-0c73a1cb695b"
|
||||
err := flavors.DeleteExtraSpec(computeClient, flavorID, "hw:cpu_thread_policy").ExtractErr()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
*/
|
||||
package flavors
|
||||
347
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/requests.go
generated
vendored
Normal file
347
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/requests.go
generated
vendored
Normal file
|
|
@ -0,0 +1,347 @@
|
|||
package flavors
|
||||
|
||||
import (
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
// ListOptsBuilder allows extensions to add additional parameters to the
|
||||
// List request.
|
||||
type ListOptsBuilder interface {
|
||||
ToFlavorListQuery() (string, error)
|
||||
}
|
||||
|
||||
/*
|
||||
AccessType maps to OpenStack's Flavor.is_public field. Although the is_public
|
||||
field is boolean, the request options are ternary, which is why AccessType is
|
||||
a string. The following values are allowed:
|
||||
|
||||
The AccessType arguement is optional, and if it is not supplied, OpenStack
|
||||
returns the PublicAccess flavors.
|
||||
*/
|
||||
type AccessType string
|
||||
|
||||
const (
|
||||
// PublicAccess returns public flavors and private flavors associated with
|
||||
// that project.
|
||||
PublicAccess AccessType = "true"
|
||||
|
||||
// PrivateAccess (admin only) returns private flavors, across all projects.
|
||||
PrivateAccess AccessType = "false"
|
||||
|
||||
// AllAccess (admin only) returns public and private flavors across all
|
||||
// projects.
|
||||
AllAccess AccessType = "None"
|
||||
)
|
||||
|
||||
/*
|
||||
ListOpts filters the results returned by the List() function.
|
||||
For example, a flavor with a minDisk field of 10 will not be returned if you
|
||||
specify MinDisk set to 20.
|
||||
|
||||
Typically, software will use the last ID of the previous call to List to set
|
||||
the Marker for the current call.
|
||||
*/
|
||||
type ListOpts struct {
|
||||
// ChangesSince, if provided, instructs List to return only those things which
|
||||
// have changed since the timestamp provided.
|
||||
ChangesSince string `q:"changes-since"`
|
||||
|
||||
// MinDisk and MinRAM, if provided, elides flavors which do not meet your
|
||||
// criteria.
|
||||
MinDisk int `q:"minDisk"`
|
||||
MinRAM int `q:"minRam"`
|
||||
|
||||
// Marker and Limit control paging.
|
||||
// Marker instructs List where to start listing from.
|
||||
Marker string `q:"marker"`
|
||||
|
||||
// Limit instructs List to refrain from sending excessively large lists of
|
||||
// flavors.
|
||||
Limit int `q:"limit"`
|
||||
|
||||
// AccessType, if provided, instructs List which set of flavors to return.
|
||||
// If IsPublic not provided, flavors for the current project are returned.
|
||||
AccessType AccessType `q:"is_public"`
|
||||
}
|
||||
|
||||
// ToFlavorListQuery formats a ListOpts into a query string.
|
||||
func (opts ListOpts) ToFlavorListQuery() (string, error) {
|
||||
q, err := gophercloud.BuildQueryString(opts)
|
||||
return q.String(), err
|
||||
}
|
||||
|
||||
// ListDetail instructs OpenStack to provide a list of flavors.
|
||||
// You may provide criteria by which List curtails its results for easier
|
||||
// processing.
|
||||
func ListDetail(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
|
||||
url := listURL(client)
|
||||
if opts != nil {
|
||||
query, err := opts.ToFlavorListQuery()
|
||||
if err != nil {
|
||||
return pagination.Pager{Err: err}
|
||||
}
|
||||
url += query
|
||||
}
|
||||
return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
|
||||
return FlavorPage{pagination.LinkedPageBase{PageResult: r}}
|
||||
})
|
||||
}
|
||||
|
||||
type CreateOptsBuilder interface {
|
||||
ToFlavorCreateMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// CreateOpts specifies parameters used for creating a flavor.
|
||||
type CreateOpts struct {
|
||||
// Name is the name of the flavor.
|
||||
Name string `json:"name" required:"true"`
|
||||
|
||||
// RAM is the memory of the flavor, measured in MB.
|
||||
RAM int `json:"ram" required:"true"`
|
||||
|
||||
// VCPUs is the number of vcpus for the flavor.
|
||||
VCPUs int `json:"vcpus" required:"true"`
|
||||
|
||||
// Disk the amount of root disk space, measured in GB.
|
||||
Disk *int `json:"disk" required:"true"`
|
||||
|
||||
// ID is a unique ID for the flavor.
|
||||
ID string `json:"id,omitempty"`
|
||||
|
||||
// Swap is the amount of swap space for the flavor, measured in MB.
|
||||
Swap *int `json:"swap,omitempty"`
|
||||
|
||||
// RxTxFactor alters the network bandwidth of a flavor.
|
||||
RxTxFactor float64 `json:"rxtx_factor,omitempty"`
|
||||
|
||||
// IsPublic flags a flavor as being available to all projects or not.
|
||||
IsPublic *bool `json:"os-flavor-access:is_public,omitempty"`
|
||||
|
||||
// Ephemeral is the amount of ephemeral disk space, measured in GB.
|
||||
Ephemeral *int `json:"OS-FLV-EXT-DATA:ephemeral,omitempty"`
|
||||
}
|
||||
|
||||
// ToFlavorCreateMap constructs a request body from CreateOpts.
|
||||
func (opts CreateOpts) ToFlavorCreateMap() (map[string]interface{}, error) {
|
||||
return gophercloud.BuildRequestBody(opts, "flavor")
|
||||
}
|
||||
|
||||
// Create requests the creation of a new flavor.
|
||||
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||
b, err := opts.ToFlavorCreateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200, 201},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Get retrieves details of a single flavor. Use ExtractFlavor to convert its
|
||||
// result into a Flavor.
|
||||
func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||
_, r.Err = client.Get(getURL(client, id), &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes the specified flavor ID.
|
||||
func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||
_, r.Err = client.Delete(deleteURL(client, id), nil)
|
||||
return
|
||||
}
|
||||
|
||||
// ListAccesses retrieves the tenants which have access to a flavor.
|
||||
func ListAccesses(client *gophercloud.ServiceClient, id string) pagination.Pager {
|
||||
url := accessURL(client, id)
|
||||
|
||||
return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
|
||||
return AccessPage{pagination.SinglePageBase(r)}
|
||||
})
|
||||
}
|
||||
|
||||
// AddAccessOptsBuilder allows extensions to add additional parameters to the
|
||||
// AddAccess requests.
|
||||
type AddAccessOptsBuilder interface {
|
||||
ToFlavorAddAccessMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// AddAccessOpts represents options for adding access to a flavor.
|
||||
type AddAccessOpts struct {
|
||||
// Tenant is the project/tenant ID to grant access.
|
||||
Tenant string `json:"tenant"`
|
||||
}
|
||||
|
||||
// ToFlavorAddAccessMap constructs a request body from AddAccessOpts.
|
||||
func (opts AddAccessOpts) ToFlavorAddAccessMap() (map[string]interface{}, error) {
|
||||
return gophercloud.BuildRequestBody(opts, "addTenantAccess")
|
||||
}
|
||||
|
||||
// AddAccess grants a tenant/project access to a flavor.
|
||||
func AddAccess(client *gophercloud.ServiceClient, id string, opts AddAccessOptsBuilder) (r AddAccessResult) {
|
||||
b, err := opts.ToFlavorAddAccessMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = client.Post(accessActionURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// RemoveAccessOptsBuilder allows extensions to add additional parameters to the
|
||||
// RemoveAccess requests.
|
||||
type RemoveAccessOptsBuilder interface {
|
||||
ToFlavorRemoveAccessMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// RemoveAccessOpts represents options for removing access to a flavor.
|
||||
type RemoveAccessOpts struct {
|
||||
// Tenant is the project/tenant ID to grant access.
|
||||
Tenant string `json:"tenant"`
|
||||
}
|
||||
|
||||
// ToFlavorRemoveAccessMap constructs a request body from RemoveAccessOpts.
|
||||
func (opts RemoveAccessOpts) ToFlavorRemoveAccessMap() (map[string]interface{}, error) {
|
||||
return gophercloud.BuildRequestBody(opts, "removeTenantAccess")
|
||||
}
|
||||
|
||||
// RemoveAccess removes/revokes a tenant/project access to a flavor.
|
||||
func RemoveAccess(client *gophercloud.ServiceClient, id string, opts RemoveAccessOptsBuilder) (r RemoveAccessResult) {
|
||||
b, err := opts.ToFlavorRemoveAccessMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = client.Post(accessActionURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// ExtraSpecs requests all the extra-specs for the given flavor ID.
|
||||
func ListExtraSpecs(client *gophercloud.ServiceClient, flavorID string) (r ListExtraSpecsResult) {
|
||||
_, r.Err = client.Get(extraSpecsListURL(client, flavorID), &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
func GetExtraSpec(client *gophercloud.ServiceClient, flavorID string, key string) (r GetExtraSpecResult) {
|
||||
_, r.Err = client.Get(extraSpecsGetURL(client, flavorID, key), &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// CreateExtraSpecsOptsBuilder allows extensions to add additional parameters to the
|
||||
// CreateExtraSpecs requests.
|
||||
type CreateExtraSpecsOptsBuilder interface {
|
||||
ToExtraSpecsCreateMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// ExtraSpecsOpts is a map that contains key-value pairs.
|
||||
type ExtraSpecsOpts map[string]string
|
||||
|
||||
// ToExtraSpecsCreateMap assembles a body for a Create request based on the
|
||||
// contents of a ExtraSpecsOpts
|
||||
func (opts ExtraSpecsOpts) ToExtraSpecsCreateMap() (map[string]interface{}, error) {
|
||||
return map[string]interface{}{"extra_specs": opts}, nil
|
||||
}
|
||||
|
||||
// CreateExtraSpecs will create or update the extra-specs key-value pairs for the specified Flavor
|
||||
func CreateExtraSpecs(client *gophercloud.ServiceClient, flavorID string, opts CreateExtraSpecsOptsBuilder) (r CreateExtraSpecsResult) {
|
||||
b, err := opts.ToExtraSpecsCreateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = client.Post(extraSpecsCreateURL(client, flavorID), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateExtraSpecOptsBuilder allows extensions to add additional parameters to the
|
||||
// Update request.
|
||||
type UpdateExtraSpecOptsBuilder interface {
|
||||
ToExtraSpecUpdateMap() (map[string]string, string, error)
|
||||
}
|
||||
|
||||
// ToExtraSpecUpdateMap assembles a body for an Update request based on the
|
||||
// contents of a ExtraSpecOpts.
|
||||
func (opts ExtraSpecsOpts) ToExtraSpecUpdateMap() (map[string]string, string, error) {
|
||||
if len(opts) != 1 {
|
||||
err := gophercloud.ErrInvalidInput{}
|
||||
err.Argument = "flavors.ExtraSpecOpts"
|
||||
err.Info = "Must have 1 and only one key-value pair"
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
var key string
|
||||
for k := range opts {
|
||||
key = k
|
||||
}
|
||||
|
||||
return opts, key, nil
|
||||
}
|
||||
|
||||
// UpdateExtraSpec will updates the value of the specified flavor's extra spec for the key in opts.
|
||||
func UpdateExtraSpec(client *gophercloud.ServiceClient, flavorID string, opts UpdateExtraSpecOptsBuilder) (r UpdateExtraSpecResult) {
|
||||
b, key, err := opts.ToExtraSpecUpdateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = client.Put(extraSpecUpdateURL(client, flavorID, key), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteExtraSpec will delete the key-value pair with the given key for the given
|
||||
// flavor ID.
|
||||
func DeleteExtraSpec(client *gophercloud.ServiceClient, flavorID, key string) (r DeleteExtraSpecResult) {
|
||||
_, r.Err = client.Delete(extraSpecDeleteURL(client, flavorID, key), &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// IDFromName is a convienience function that returns a flavor's ID given its
|
||||
// name.
|
||||
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
|
||||
count := 0
|
||||
id := ""
|
||||
allPages, err := ListDetail(client, nil).AllPages()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
all, err := ExtractFlavors(allPages)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, f := range all {
|
||||
if f.Name == name {
|
||||
count++
|
||||
id = f.ID
|
||||
}
|
||||
}
|
||||
|
||||
switch count {
|
||||
case 0:
|
||||
err := &gophercloud.ErrResourceNotFound{}
|
||||
err.ResourceType = "flavor"
|
||||
err.Name = name
|
||||
return "", err
|
||||
case 1:
|
||||
return id, nil
|
||||
default:
|
||||
err := &gophercloud.ErrMultipleResourcesFound{}
|
||||
err.ResourceType = "flavor"
|
||||
err.Name = name
|
||||
err.Count = count
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
252
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/results.go
generated
vendored
Normal file
252
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/results.go
generated
vendored
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
package flavors
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
type commonResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// CreateResult is the response of a Get operations. Call its Extract method to
|
||||
// interpret it as a Flavor.
|
||||
type CreateResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// GetResult is the response of a Get operations. Call its Extract method to
|
||||
// interpret it as a Flavor.
|
||||
type GetResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// DeleteResult is the result from a Delete operation. Call its ExtractErr
|
||||
// method to determine if the call succeeded or failed.
|
||||
type DeleteResult struct {
|
||||
gophercloud.ErrResult
|
||||
}
|
||||
|
||||
// Extract provides access to the individual Flavor returned by the Get and
|
||||
// Create functions.
|
||||
func (r commonResult) Extract() (*Flavor, error) {
|
||||
var s struct {
|
||||
Flavor *Flavor `json:"flavor"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
return s.Flavor, err
|
||||
}
|
||||
|
||||
// Flavor represent (virtual) hardware configurations for server resources
|
||||
// in a region.
|
||||
type Flavor struct {
|
||||
// ID is the flavor's unique ID.
|
||||
ID string `json:"id"`
|
||||
|
||||
// Disk is the amount of root disk, measured in GB.
|
||||
Disk int `json:"disk"`
|
||||
|
||||
// RAM is the amount of memory, measured in MB.
|
||||
RAM int `json:"ram"`
|
||||
|
||||
// Name is the name of the flavor.
|
||||
Name string `json:"name"`
|
||||
|
||||
// RxTxFactor describes bandwidth alterations of the flavor.
|
||||
RxTxFactor float64 `json:"rxtx_factor"`
|
||||
|
||||
// Swap is the amount of swap space, measured in MB.
|
||||
Swap int `json:"swap"`
|
||||
|
||||
// VCPUs indicates how many (virtual) CPUs are available for this flavor.
|
||||
VCPUs int `json:"vcpus"`
|
||||
|
||||
// IsPublic indicates whether the flavor is public.
|
||||
IsPublic bool `json:"os-flavor-access:is_public"`
|
||||
|
||||
// Ephemeral is the amount of ephemeral disk space, measured in GB.
|
||||
Ephemeral int `json:"OS-FLV-EXT-DATA:ephemeral"`
|
||||
}
|
||||
|
||||
func (r *Flavor) UnmarshalJSON(b []byte) error {
|
||||
type tmp Flavor
|
||||
var s struct {
|
||||
tmp
|
||||
Swap interface{} `json:"swap"`
|
||||
}
|
||||
err := json.Unmarshal(b, &s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*r = Flavor(s.tmp)
|
||||
|
||||
switch t := s.Swap.(type) {
|
||||
case float64:
|
||||
r.Swap = int(t)
|
||||
case string:
|
||||
switch t {
|
||||
case "":
|
||||
r.Swap = 0
|
||||
default:
|
||||
swap, err := strconv.ParseFloat(t, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Swap = int(swap)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FlavorPage contains a single page of all flavors from a ListDetails call.
|
||||
type FlavorPage struct {
|
||||
pagination.LinkedPageBase
|
||||
}
|
||||
|
||||
// IsEmpty determines if a FlavorPage contains any results.
|
||||
func (page FlavorPage) IsEmpty() (bool, error) {
|
||||
flavors, err := ExtractFlavors(page)
|
||||
return len(flavors) == 0, err
|
||||
}
|
||||
|
||||
// NextPageURL uses the response's embedded link reference to navigate to the
|
||||
// next page of results.
|
||||
func (page FlavorPage) NextPageURL() (string, error) {
|
||||
var s struct {
|
||||
Links []gophercloud.Link `json:"flavors_links"`
|
||||
}
|
||||
err := page.ExtractInto(&s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return gophercloud.ExtractNextURL(s.Links)
|
||||
}
|
||||
|
||||
// ExtractFlavors provides access to the list of flavors in a page acquired
|
||||
// from the ListDetail operation.
|
||||
func ExtractFlavors(r pagination.Page) ([]Flavor, error) {
|
||||
var s struct {
|
||||
Flavors []Flavor `json:"flavors"`
|
||||
}
|
||||
err := (r.(FlavorPage)).ExtractInto(&s)
|
||||
return s.Flavors, err
|
||||
}
|
||||
|
||||
// AccessPage contains a single page of all FlavorAccess entries for a flavor.
|
||||
type AccessPage struct {
|
||||
pagination.SinglePageBase
|
||||
}
|
||||
|
||||
// IsEmpty indicates whether an AccessPage is empty.
|
||||
func (page AccessPage) IsEmpty() (bool, error) {
|
||||
v, err := ExtractAccesses(page)
|
||||
return len(v) == 0, err
|
||||
}
|
||||
|
||||
// ExtractAccesses interprets a page of results as a slice of FlavorAccess.
|
||||
func ExtractAccesses(r pagination.Page) ([]FlavorAccess, error) {
|
||||
var s struct {
|
||||
FlavorAccesses []FlavorAccess `json:"flavor_access"`
|
||||
}
|
||||
err := (r.(AccessPage)).ExtractInto(&s)
|
||||
return s.FlavorAccesses, err
|
||||
}
|
||||
|
||||
type accessResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// AddAccessResult is the response of an AddAccess operation. Call its
|
||||
// Extract method to interpret it as a slice of FlavorAccess.
|
||||
type AddAccessResult struct {
|
||||
accessResult
|
||||
}
|
||||
|
||||
// RemoveAccessResult is the response of a RemoveAccess operation. Call its
|
||||
// Extract method to interpret it as a slice of FlavorAccess.
|
||||
type RemoveAccessResult struct {
|
||||
accessResult
|
||||
}
|
||||
|
||||
// Extract provides access to the result of an access create or delete.
|
||||
// The result will be all accesses that the flavor has.
|
||||
func (r accessResult) Extract() ([]FlavorAccess, error) {
|
||||
var s struct {
|
||||
FlavorAccesses []FlavorAccess `json:"flavor_access"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
return s.FlavorAccesses, err
|
||||
}
|
||||
|
||||
// FlavorAccess represents an ACL of tenant access to a specific Flavor.
|
||||
type FlavorAccess struct {
|
||||
// FlavorID is the unique ID of the flavor.
|
||||
FlavorID string `json:"flavor_id"`
|
||||
|
||||
// TenantID is the unique ID of the tenant.
|
||||
TenantID string `json:"tenant_id"`
|
||||
}
|
||||
|
||||
// Extract interprets any extraSpecsResult as ExtraSpecs, if possible.
|
||||
func (r extraSpecsResult) Extract() (map[string]string, error) {
|
||||
var s struct {
|
||||
ExtraSpecs map[string]string `json:"extra_specs"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
return s.ExtraSpecs, err
|
||||
}
|
||||
|
||||
// extraSpecsResult contains the result of a call for (potentially) multiple
|
||||
// key-value pairs. Call its Extract method to interpret it as a
|
||||
// map[string]interface.
|
||||
type extraSpecsResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// ListExtraSpecsResult contains the result of a Get operation. Call its Extract
|
||||
// method to interpret it as a map[string]interface.
|
||||
type ListExtraSpecsResult struct {
|
||||
extraSpecsResult
|
||||
}
|
||||
|
||||
// CreateExtraSpecResult contains the result of a Create operation. Call its
|
||||
// Extract method to interpret it as a map[string]interface.
|
||||
type CreateExtraSpecsResult struct {
|
||||
extraSpecsResult
|
||||
}
|
||||
|
||||
// extraSpecResult contains the result of a call for individual a single
|
||||
// key-value pair.
|
||||
type extraSpecResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// GetExtraSpecResult contains the result of a Get operation. Call its Extract
|
||||
// method to interpret it as a map[string]interface.
|
||||
type GetExtraSpecResult struct {
|
||||
extraSpecResult
|
||||
}
|
||||
|
||||
// UpdateExtraSpecResult contains the result of an Update operation. Call its
|
||||
// Extract method to interpret it as a map[string]interface.
|
||||
type UpdateExtraSpecResult struct {
|
||||
extraSpecResult
|
||||
}
|
||||
|
||||
// DeleteExtraSpecResult contains the result of a Delete operation. Call its
|
||||
// ExtractErr method to determine if the call succeeded or failed.
|
||||
type DeleteExtraSpecResult struct {
|
||||
gophercloud.ErrResult
|
||||
}
|
||||
|
||||
// Extract interprets any extraSpecResult as an ExtraSpec, if possible.
|
||||
func (r extraSpecResult) Extract() (map[string]string, error) {
|
||||
var s map[string]string
|
||||
err := r.ExtractInto(&s)
|
||||
return s, err
|
||||
}
|
||||
49
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/urls.go
generated
vendored
Normal file
49
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/urls.go
generated
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
package flavors
|
||||
|
||||
import (
|
||||
"github.com/gophercloud/gophercloud"
|
||||
)
|
||||
|
||||
func getURL(client *gophercloud.ServiceClient, id string) string {
|
||||
return client.ServiceURL("flavors", id)
|
||||
}
|
||||
|
||||
func listURL(client *gophercloud.ServiceClient) string {
|
||||
return client.ServiceURL("flavors", "detail")
|
||||
}
|
||||
|
||||
func createURL(client *gophercloud.ServiceClient) string {
|
||||
return client.ServiceURL("flavors")
|
||||
}
|
||||
|
||||
func deleteURL(client *gophercloud.ServiceClient, id string) string {
|
||||
return client.ServiceURL("flavors", id)
|
||||
}
|
||||
|
||||
func accessURL(client *gophercloud.ServiceClient, id string) string {
|
||||
return client.ServiceURL("flavors", id, "os-flavor-access")
|
||||
}
|
||||
|
||||
func accessActionURL(client *gophercloud.ServiceClient, id string) string {
|
||||
return client.ServiceURL("flavors", id, "action")
|
||||
}
|
||||
|
||||
func extraSpecsListURL(client *gophercloud.ServiceClient, id string) string {
|
||||
return client.ServiceURL("flavors", id, "os-extra_specs")
|
||||
}
|
||||
|
||||
func extraSpecsGetURL(client *gophercloud.ServiceClient, id, key string) string {
|
||||
return client.ServiceURL("flavors", id, "os-extra_specs", key)
|
||||
}
|
||||
|
||||
func extraSpecsCreateURL(client *gophercloud.ServiceClient, id string) string {
|
||||
return client.ServiceURL("flavors", id, "os-extra_specs")
|
||||
}
|
||||
|
||||
func extraSpecUpdateURL(client *gophercloud.ServiceClient, id, key string) string {
|
||||
return client.ServiceURL("flavors", id, "os-extra_specs", key)
|
||||
}
|
||||
|
||||
func extraSpecDeleteURL(client *gophercloud.ServiceClient, id, key string) string {
|
||||
return client.ServiceURL("flavors", id, "os-extra_specs", key)
|
||||
}
|
||||
18
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/BUILD.bazel
generated
vendored
Normal file
18
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/BUILD.bazel
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"requests.go",
|
||||
"results.go",
|
||||
"urls.go",
|
||||
],
|
||||
importmap = "vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images",
|
||||
importpath = "github.com/gophercloud/gophercloud/openstack/compute/v2/images",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/gophercloud/gophercloud:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/pagination:go_default_library",
|
||||
],
|
||||
)
|
||||
32
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/doc.go
generated
vendored
Normal file
32
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
Package images provides information and interaction with the images through
|
||||
the OpenStack Compute service.
|
||||
|
||||
This API is deprecated and will be removed from a future version of the Nova
|
||||
API service.
|
||||
|
||||
An image is a collection of files used to create or rebuild a server.
|
||||
Operators provide a number of pre-built OS images by default. You may also
|
||||
create custom images from cloud servers you have launched.
|
||||
|
||||
Example to List Images
|
||||
|
||||
listOpts := images.ListOpts{
|
||||
Limit: 2,
|
||||
}
|
||||
|
||||
allPages, err := images.ListDetail(computeClient, listOpts).AllPages()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
allImages, err := images.ExtractImages(allPages)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, image := range allImages {
|
||||
fmt.Printf("%+v\n", image)
|
||||
}
|
||||
*/
|
||||
package images
|
||||
109
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/requests.go
generated
vendored
Normal file
109
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/requests.go
generated
vendored
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
package images
|
||||
|
||||
import (
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
// ListOptsBuilder allows extensions to add additional parameters to the
|
||||
// ListDetail request.
|
||||
type ListOptsBuilder interface {
|
||||
ToImageListQuery() (string, error)
|
||||
}
|
||||
|
||||
// ListOpts contain options filtering Images returned from a call to ListDetail.
|
||||
type ListOpts struct {
|
||||
// ChangesSince filters Images based on the last changed status (in date-time
|
||||
// format).
|
||||
ChangesSince string `q:"changes-since"`
|
||||
|
||||
// Limit limits the number of Images to return.
|
||||
Limit int `q:"limit"`
|
||||
|
||||
// Mark is an Image UUID at which to set a marker.
|
||||
Marker string `q:"marker"`
|
||||
|
||||
// Name is the name of the Image.
|
||||
Name string `q:"name"`
|
||||
|
||||
// Server is the name of the Server (in URL format).
|
||||
Server string `q:"server"`
|
||||
|
||||
// Status is the current status of the Image.
|
||||
Status string `q:"status"`
|
||||
|
||||
// Type is the type of image (e.g. BASE, SERVER, ALL).
|
||||
Type string `q:"type"`
|
||||
}
|
||||
|
||||
// ToImageListQuery formats a ListOpts into a query string.
|
||||
func (opts ListOpts) ToImageListQuery() (string, error) {
|
||||
q, err := gophercloud.BuildQueryString(opts)
|
||||
return q.String(), err
|
||||
}
|
||||
|
||||
// ListDetail enumerates the available images.
|
||||
func ListDetail(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
|
||||
url := listDetailURL(client)
|
||||
if opts != nil {
|
||||
query, err := opts.ToImageListQuery()
|
||||
if err != nil {
|
||||
return pagination.Pager{Err: err}
|
||||
}
|
||||
url += query
|
||||
}
|
||||
return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
|
||||
return ImagePage{pagination.LinkedPageBase{PageResult: r}}
|
||||
})
|
||||
}
|
||||
|
||||
// Get returns data about a specific image by its ID.
|
||||
func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||
_, r.Err = client.Get(getURL(client, id), &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes the specified image ID.
|
||||
func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||
_, r.Err = client.Delete(deleteURL(client, id), nil)
|
||||
return
|
||||
}
|
||||
|
||||
// IDFromName is a convienience function that returns an image's ID given its
|
||||
// name.
|
||||
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
|
||||
count := 0
|
||||
id := ""
|
||||
allPages, err := ListDetail(client, nil).AllPages()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
all, err := ExtractImages(allPages)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, f := range all {
|
||||
if f.Name == name {
|
||||
count++
|
||||
id = f.ID
|
||||
}
|
||||
}
|
||||
|
||||
switch count {
|
||||
case 0:
|
||||
err := &gophercloud.ErrResourceNotFound{}
|
||||
err.ResourceType = "image"
|
||||
err.Name = name
|
||||
return "", err
|
||||
case 1:
|
||||
return id, nil
|
||||
default:
|
||||
err := &gophercloud.ErrMultipleResourcesFound{}
|
||||
err.ResourceType = "image"
|
||||
err.Name = name
|
||||
err.Count = count
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
95
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/results.go
generated
vendored
Normal file
95
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/results.go
generated
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
package images
|
||||
|
||||
import (
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
// GetResult is the response from a Get operation. Call its Extract method to
|
||||
// interpret it as an Image.
|
||||
type GetResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// DeleteResult is the result from a Delete operation. Call its ExtractErr
|
||||
// method to determine if the call succeeded or failed.
|
||||
type DeleteResult struct {
|
||||
gophercloud.ErrResult
|
||||
}
|
||||
|
||||
// Extract interprets a GetResult as an Image.
|
||||
func (r GetResult) Extract() (*Image, error) {
|
||||
var s struct {
|
||||
Image *Image `json:"image"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
return s.Image, err
|
||||
}
|
||||
|
||||
// Image represents an Image returned by the Compute API.
|
||||
type Image struct {
|
||||
// ID is the unique ID of an image.
|
||||
ID string
|
||||
|
||||
// Created is the date when the image was created.
|
||||
Created string
|
||||
|
||||
// MinDisk is the minimum amount of disk a flavor must have to be able
|
||||
// to create a server based on the image, measured in GB.
|
||||
MinDisk int
|
||||
|
||||
// MinRAM is the minimum amount of RAM a flavor must have to be able
|
||||
// to create a server based on the image, measured in MB.
|
||||
MinRAM int
|
||||
|
||||
// Name provides a human-readable moniker for the OS image.
|
||||
Name string
|
||||
|
||||
// The Progress and Status fields indicate image-creation status.
|
||||
Progress int
|
||||
|
||||
// Status is the current status of the image.
|
||||
Status string
|
||||
|
||||
// Update is the date when the image was updated.
|
||||
Updated string
|
||||
|
||||
// Metadata provides free-form key/value pairs that further describe the
|
||||
// image.
|
||||
Metadata map[string]interface{}
|
||||
}
|
||||
|
||||
// ImagePage contains a single page of all Images returne from a ListDetail
|
||||
// operation. Use ExtractImages to convert it into a slice of usable structs.
|
||||
type ImagePage struct {
|
||||
pagination.LinkedPageBase
|
||||
}
|
||||
|
||||
// IsEmpty returns true if an ImagePage contains no Image results.
|
||||
func (page ImagePage) IsEmpty() (bool, error) {
|
||||
images, err := ExtractImages(page)
|
||||
return len(images) == 0, err
|
||||
}
|
||||
|
||||
// NextPageURL uses the response's embedded link reference to navigate to the
|
||||
// next page of results.
|
||||
func (page ImagePage) NextPageURL() (string, error) {
|
||||
var s struct {
|
||||
Links []gophercloud.Link `json:"images_links"`
|
||||
}
|
||||
err := page.ExtractInto(&s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return gophercloud.ExtractNextURL(s.Links)
|
||||
}
|
||||
|
||||
// ExtractImages converts a page of List results into a slice of usable Image
|
||||
// structs.
|
||||
func ExtractImages(r pagination.Page) ([]Image, error) {
|
||||
var s struct {
|
||||
Images []Image `json:"images"`
|
||||
}
|
||||
err := (r.(ImagePage)).ExtractInto(&s)
|
||||
return s.Images, err
|
||||
}
|
||||
15
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/urls.go
generated
vendored
Normal file
15
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/urls.go
generated
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
package images
|
||||
|
||||
import "github.com/gophercloud/gophercloud"
|
||||
|
||||
func listDetailURL(client *gophercloud.ServiceClient) string {
|
||||
return client.ServiceURL("images", "detail")
|
||||
}
|
||||
|
||||
func getURL(client *gophercloud.ServiceClient, id string) string {
|
||||
return client.ServiceURL("images", id)
|
||||
}
|
||||
|
||||
func deleteURL(client *gophercloud.ServiceClient, id string) string {
|
||||
return client.ServiceURL("images", id)
|
||||
}
|
||||
22
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/BUILD.bazel
generated
vendored
Normal file
22
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/BUILD.bazel
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"errors.go",
|
||||
"requests.go",
|
||||
"results.go",
|
||||
"urls.go",
|
||||
"util.go",
|
||||
],
|
||||
importmap = "vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers",
|
||||
importpath = "github.com/gophercloud/gophercloud/openstack/compute/v2/servers",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/gophercloud/gophercloud:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/pagination:go_default_library",
|
||||
],
|
||||
)
|
||||
115
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/doc.go
generated
vendored
Normal file
115
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
Package servers provides information and interaction with the server API
|
||||
resource in the OpenStack Compute service.
|
||||
|
||||
A server is a virtual machine instance in the compute system. In order for
|
||||
one to be provisioned, a valid flavor and image are required.
|
||||
|
||||
Example to List Servers
|
||||
|
||||
listOpts := servers.ListOpts{
|
||||
AllTenants: true,
|
||||
}
|
||||
|
||||
allPages, err := servers.List(computeClient, listOpts).AllPages()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
allServers, err := servers.ExtractServers(allPages)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, server := range allServers {
|
||||
fmt.Printf("%+v\n", server)
|
||||
}
|
||||
|
||||
Example to Create a Server
|
||||
|
||||
createOpts := servers.CreateOpts{
|
||||
Name: "server_name",
|
||||
ImageRef: "image-uuid",
|
||||
FlavorRef: "flavor-uuid",
|
||||
}
|
||||
|
||||
server, err := servers.Create(computeClient, createOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example to Delete a Server
|
||||
|
||||
serverID := "d9072956-1560-487c-97f2-18bdf65ec749"
|
||||
err := servers.Delete(computeClient, serverID).ExtractErr()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example to Force Delete a Server
|
||||
|
||||
serverID := "d9072956-1560-487c-97f2-18bdf65ec749"
|
||||
err := servers.ForceDelete(computeClient, serverID).ExtractErr()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example to Reboot a Server
|
||||
|
||||
rebootOpts := servers.RebootOpts{
|
||||
Type: servers.SoftReboot,
|
||||
}
|
||||
|
||||
serverID := "d9072956-1560-487c-97f2-18bdf65ec749"
|
||||
|
||||
err := servers.Reboot(computeClient, serverID, rebootOpts).ExtractErr()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example to Rebuild a Server
|
||||
|
||||
rebuildOpts := servers.RebuildOpts{
|
||||
Name: "new_name",
|
||||
ImageID: "image-uuid",
|
||||
}
|
||||
|
||||
serverID := "d9072956-1560-487c-97f2-18bdf65ec749"
|
||||
|
||||
server, err := servers.Rebuilt(computeClient, serverID, rebuildOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example to Resize a Server
|
||||
|
||||
resizeOpts := servers.ResizeOpts{
|
||||
FlavorRef: "flavor-uuid",
|
||||
}
|
||||
|
||||
serverID := "d9072956-1560-487c-97f2-18bdf65ec749"
|
||||
|
||||
err := servers.Resize(computeClient, serverID, resizeOpts).ExtractErr()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = servers.ConfirmResize(computeClient, serverID).ExtractErr()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example to Snapshot a Server
|
||||
|
||||
snapshotOpts := servers.CreateImageOpts{
|
||||
Name: "snapshot_name",
|
||||
}
|
||||
|
||||
serverID := "d9072956-1560-487c-97f2-18bdf65ec749"
|
||||
|
||||
image, err := servers.CreateImage(computeClient, serverID, snapshotOpts).ExtractImageID()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
*/
|
||||
package servers
|
||||
71
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/errors.go
generated
vendored
Normal file
71
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/errors.go
generated
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
package servers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gophercloud/gophercloud"
|
||||
)
|
||||
|
||||
// ErrNeitherImageIDNorImageNameProvided is the error when neither the image
|
||||
// ID nor the image name is provided for a server operation
|
||||
type ErrNeitherImageIDNorImageNameProvided struct{ gophercloud.ErrMissingInput }
|
||||
|
||||
func (e ErrNeitherImageIDNorImageNameProvided) Error() string {
|
||||
return "One and only one of the image ID and the image name must be provided."
|
||||
}
|
||||
|
||||
// ErrNeitherFlavorIDNorFlavorNameProvided is the error when neither the flavor
|
||||
// ID nor the flavor name is provided for a server operation
|
||||
type ErrNeitherFlavorIDNorFlavorNameProvided struct{ gophercloud.ErrMissingInput }
|
||||
|
||||
func (e ErrNeitherFlavorIDNorFlavorNameProvided) Error() string {
|
||||
return "One and only one of the flavor ID and the flavor name must be provided."
|
||||
}
|
||||
|
||||
type ErrNoClientProvidedForIDByName struct{ gophercloud.ErrMissingInput }
|
||||
|
||||
func (e ErrNoClientProvidedForIDByName) Error() string {
|
||||
return "A service client must be provided to find a resource ID by name."
|
||||
}
|
||||
|
||||
// ErrInvalidHowParameterProvided is the error when an unknown value is given
|
||||
// for the `how` argument
|
||||
type ErrInvalidHowParameterProvided struct{ gophercloud.ErrInvalidInput }
|
||||
|
||||
// ErrNoAdminPassProvided is the error when an administrative password isn't
|
||||
// provided for a server operation
|
||||
type ErrNoAdminPassProvided struct{ gophercloud.ErrMissingInput }
|
||||
|
||||
// ErrNoImageIDProvided is the error when an image ID isn't provided for a server
|
||||
// operation
|
||||
type ErrNoImageIDProvided struct{ gophercloud.ErrMissingInput }
|
||||
|
||||
// ErrNoIDProvided is the error when a server ID isn't provided for a server
|
||||
// operation
|
||||
type ErrNoIDProvided struct{ gophercloud.ErrMissingInput }
|
||||
|
||||
// ErrServer is a generic error type for servers HTTP operations.
|
||||
type ErrServer struct {
|
||||
gophercloud.ErrUnexpectedResponseCode
|
||||
ID string
|
||||
}
|
||||
|
||||
func (se ErrServer) Error() string {
|
||||
return fmt.Sprintf("Error while executing HTTP request for server [%s]", se.ID)
|
||||
}
|
||||
|
||||
// Error404 overrides the generic 404 error message.
|
||||
func (se ErrServer) Error404(e gophercloud.ErrUnexpectedResponseCode) error {
|
||||
se.ErrUnexpectedResponseCode = e
|
||||
return &ErrServerNotFound{se}
|
||||
}
|
||||
|
||||
// ErrServerNotFound is the error when a 404 is received during server HTTP
|
||||
// operations.
|
||||
type ErrServerNotFound struct {
|
||||
ErrServer
|
||||
}
|
||||
|
||||
func (e ErrServerNotFound) Error() string {
|
||||
return fmt.Sprintf("I couldn't find server [%s]", e.ID)
|
||||
}
|
||||
791
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/requests.go
generated
vendored
Normal file
791
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/requests.go
generated
vendored
Normal file
|
|
@ -0,0 +1,791 @@
|
|||
package servers
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/openstack/compute/v2/flavors"
|
||||
"github.com/gophercloud/gophercloud/openstack/compute/v2/images"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
// ListOptsBuilder allows extensions to add additional parameters to the
|
||||
// List request.
|
||||
type ListOptsBuilder interface {
|
||||
ToServerListQuery() (string, error)
|
||||
}
|
||||
|
||||
// ListOpts allows the filtering and sorting of paginated collections through
|
||||
// the API. Filtering is achieved by passing in struct field values that map to
|
||||
// the server attributes you want to see returned. Marker and Limit are used
|
||||
// for pagination.
|
||||
type ListOpts struct {
|
||||
// ChangesSince is a time/date stamp for when the server last changed status.
|
||||
ChangesSince string `q:"changes-since"`
|
||||
|
||||
// Image is the name of the image in URL format.
|
||||
Image string `q:"image"`
|
||||
|
||||
// Flavor is the name of the flavor in URL format.
|
||||
Flavor string `q:"flavor"`
|
||||
|
||||
// Name of the server as a string; can be queried with regular expressions.
|
||||
// Realize that ?name=bob returns both bob and bobb. If you need to match bob
|
||||
// only, you can use a regular expression matching the syntax of the
|
||||
// underlying database server implemented for Compute.
|
||||
Name string `q:"name"`
|
||||
|
||||
// Status is the value of the status of the server so that you can filter on
|
||||
// "ACTIVE" for example.
|
||||
Status string `q:"status"`
|
||||
|
||||
// Host is the name of the host as a string.
|
||||
Host string `q:"host"`
|
||||
|
||||
// Marker is a UUID of the server at which you want to set a marker.
|
||||
Marker string `q:"marker"`
|
||||
|
||||
// Limit is an integer value for the limit of values to return.
|
||||
Limit int `q:"limit"`
|
||||
|
||||
// AllTenants is a bool to show all tenants.
|
||||
AllTenants bool `q:"all_tenants"`
|
||||
|
||||
// TenantID lists servers for a particular tenant.
|
||||
// Setting "AllTenants = true" is required.
|
||||
TenantID string `q:"tenant_id"`
|
||||
}
|
||||
|
||||
// ToServerListQuery formats a ListOpts into a query string.
|
||||
func (opts ListOpts) ToServerListQuery() (string, error) {
|
||||
q, err := gophercloud.BuildQueryString(opts)
|
||||
return q.String(), err
|
||||
}
|
||||
|
||||
// List makes a request against the API to list servers accessible to you.
|
||||
func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
|
||||
url := listDetailURL(client)
|
||||
if opts != nil {
|
||||
query, err := opts.ToServerListQuery()
|
||||
if err != nil {
|
||||
return pagination.Pager{Err: err}
|
||||
}
|
||||
url += query
|
||||
}
|
||||
return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
|
||||
return ServerPage{pagination.LinkedPageBase{PageResult: r}}
|
||||
})
|
||||
}
|
||||
|
||||
// CreateOptsBuilder allows extensions to add additional parameters to the
|
||||
// Create request.
|
||||
type CreateOptsBuilder interface {
|
||||
ToServerCreateMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// Network is used within CreateOpts to control a new server's network
|
||||
// attachments.
|
||||
type Network struct {
|
||||
// UUID of a network to attach to the newly provisioned server.
|
||||
// Required unless Port is provided.
|
||||
UUID string
|
||||
|
||||
// Port of a neutron network to attach to the newly provisioned server.
|
||||
// Required unless UUID is provided.
|
||||
Port string
|
||||
|
||||
// FixedIP specifies a fixed IPv4 address to be used on this network.
|
||||
FixedIP string
|
||||
}
|
||||
|
||||
// Personality is an array of files that are injected into the server at launch.
|
||||
type Personality []*File
|
||||
|
||||
// File is used within CreateOpts and RebuildOpts to inject a file into the
|
||||
// server at launch.
|
||||
// File implements the json.Marshaler interface, so when a Create or Rebuild
|
||||
// operation is requested, json.Marshal will call File's MarshalJSON method.
|
||||
type File struct {
|
||||
// Path of the file.
|
||||
Path string
|
||||
|
||||
// Contents of the file. Maximum content size is 255 bytes.
|
||||
Contents []byte
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the escaped file, base64 encoding the contents.
|
||||
func (f *File) MarshalJSON() ([]byte, error) {
|
||||
file := struct {
|
||||
Path string `json:"path"`
|
||||
Contents string `json:"contents"`
|
||||
}{
|
||||
Path: f.Path,
|
||||
Contents: base64.StdEncoding.EncodeToString(f.Contents),
|
||||
}
|
||||
return json.Marshal(file)
|
||||
}
|
||||
|
||||
// CreateOpts specifies server creation parameters.
|
||||
type CreateOpts struct {
|
||||
// Name is the name to assign to the newly launched server.
|
||||
Name string `json:"name" required:"true"`
|
||||
|
||||
// ImageRef [optional; required if ImageName is not provided] is the ID or
|
||||
// full URL to the image that contains the server's OS and initial state.
|
||||
// Also optional if using the boot-from-volume extension.
|
||||
ImageRef string `json:"imageRef"`
|
||||
|
||||
// ImageName [optional; required if ImageRef is not provided] is the name of
|
||||
// the image that contains the server's OS and initial state.
|
||||
// Also optional if using the boot-from-volume extension.
|
||||
ImageName string `json:"-"`
|
||||
|
||||
// FlavorRef [optional; required if FlavorName is not provided] is the ID or
|
||||
// full URL to the flavor that describes the server's specs.
|
||||
FlavorRef string `json:"flavorRef"`
|
||||
|
||||
// FlavorName [optional; required if FlavorRef is not provided] is the name of
|
||||
// the flavor that describes the server's specs.
|
||||
FlavorName string `json:"-"`
|
||||
|
||||
// SecurityGroups lists the names of the security groups to which this server
|
||||
// should belong.
|
||||
SecurityGroups []string `json:"-"`
|
||||
|
||||
// UserData contains configuration information or scripts to use upon launch.
|
||||
// Create will base64-encode it for you, if it isn't already.
|
||||
UserData []byte `json:"-"`
|
||||
|
||||
// AvailabilityZone in which to launch the server.
|
||||
AvailabilityZone string `json:"availability_zone,omitempty"`
|
||||
|
||||
// Networks dictates how this server will be attached to available networks.
|
||||
// By default, the server will be attached to all isolated networks for the
|
||||
// tenant.
|
||||
Networks []Network `json:"-"`
|
||||
|
||||
// Metadata contains key-value pairs (up to 255 bytes each) to attach to the
|
||||
// server.
|
||||
Metadata map[string]string `json:"metadata,omitempty"`
|
||||
|
||||
// Personality includes files to inject into the server at launch.
|
||||
// Create will base64-encode file contents for you.
|
||||
Personality Personality `json:"personality,omitempty"`
|
||||
|
||||
// ConfigDrive enables metadata injection through a configuration drive.
|
||||
ConfigDrive *bool `json:"config_drive,omitempty"`
|
||||
|
||||
// AdminPass sets the root user password. If not set, a randomly-generated
|
||||
// password will be created and returned in the response.
|
||||
AdminPass string `json:"adminPass,omitempty"`
|
||||
|
||||
// AccessIPv4 specifies an IPv4 address for the instance.
|
||||
AccessIPv4 string `json:"accessIPv4,omitempty"`
|
||||
|
||||
// AccessIPv6 pecifies an IPv6 address for the instance.
|
||||
AccessIPv6 string `json:"accessIPv6,omitempty"`
|
||||
|
||||
// ServiceClient will allow calls to be made to retrieve an image or
|
||||
// flavor ID by name.
|
||||
ServiceClient *gophercloud.ServiceClient `json:"-"`
|
||||
}
|
||||
|
||||
// ToServerCreateMap assembles a request body based on the contents of a
|
||||
// CreateOpts.
|
||||
func (opts CreateOpts) ToServerCreateMap() (map[string]interface{}, error) {
|
||||
sc := opts.ServiceClient
|
||||
opts.ServiceClient = nil
|
||||
b, err := gophercloud.BuildRequestBody(opts, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if opts.UserData != nil {
|
||||
var userData string
|
||||
if _, err := base64.StdEncoding.DecodeString(string(opts.UserData)); err != nil {
|
||||
userData = base64.StdEncoding.EncodeToString(opts.UserData)
|
||||
} else {
|
||||
userData = string(opts.UserData)
|
||||
}
|
||||
b["user_data"] = &userData
|
||||
}
|
||||
|
||||
if len(opts.SecurityGroups) > 0 {
|
||||
securityGroups := make([]map[string]interface{}, len(opts.SecurityGroups))
|
||||
for i, groupName := range opts.SecurityGroups {
|
||||
securityGroups[i] = map[string]interface{}{"name": groupName}
|
||||
}
|
||||
b["security_groups"] = securityGroups
|
||||
}
|
||||
|
||||
if len(opts.Networks) > 0 {
|
||||
networks := make([]map[string]interface{}, len(opts.Networks))
|
||||
for i, net := range opts.Networks {
|
||||
networks[i] = make(map[string]interface{})
|
||||
if net.UUID != "" {
|
||||
networks[i]["uuid"] = net.UUID
|
||||
}
|
||||
if net.Port != "" {
|
||||
networks[i]["port"] = net.Port
|
||||
}
|
||||
if net.FixedIP != "" {
|
||||
networks[i]["fixed_ip"] = net.FixedIP
|
||||
}
|
||||
}
|
||||
b["networks"] = networks
|
||||
}
|
||||
|
||||
// If ImageRef isn't provided, check if ImageName was provided to ascertain
|
||||
// the image ID.
|
||||
if opts.ImageRef == "" {
|
||||
if opts.ImageName != "" {
|
||||
if sc == nil {
|
||||
err := ErrNoClientProvidedForIDByName{}
|
||||
err.Argument = "ServiceClient"
|
||||
return nil, err
|
||||
}
|
||||
imageID, err := images.IDFromName(sc, opts.ImageName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b["imageRef"] = imageID
|
||||
}
|
||||
}
|
||||
|
||||
// If FlavorRef isn't provided, use FlavorName to ascertain the flavor ID.
|
||||
if opts.FlavorRef == "" {
|
||||
if opts.FlavorName == "" {
|
||||
err := ErrNeitherFlavorIDNorFlavorNameProvided{}
|
||||
err.Argument = "FlavorRef/FlavorName"
|
||||
return nil, err
|
||||
}
|
||||
if sc == nil {
|
||||
err := ErrNoClientProvidedForIDByName{}
|
||||
err.Argument = "ServiceClient"
|
||||
return nil, err
|
||||
}
|
||||
flavorID, err := flavors.IDFromName(sc, opts.FlavorName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b["flavorRef"] = flavorID
|
||||
}
|
||||
|
||||
return map[string]interface{}{"server": b}, nil
|
||||
}
|
||||
|
||||
// Create requests a server to be provisioned to the user in the current tenant.
|
||||
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||
reqBody, err := opts.ToServerCreateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = client.Post(listURL(client), reqBody, &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete requests that a server previously provisioned be removed from your
|
||||
// account.
|
||||
func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||
_, r.Err = client.Delete(deleteURL(client, id), nil)
|
||||
return
|
||||
}
|
||||
|
||||
// ForceDelete forces the deletion of a server.
|
||||
func ForceDelete(client *gophercloud.ServiceClient, id string) (r ActionResult) {
|
||||
_, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"forceDelete": ""}, nil, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Get requests details on a single server, 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
|
||||
}
|
||||
|
||||
// UpdateOptsBuilder allows extensions to add additional attributes to the
|
||||
// Update request.
|
||||
type UpdateOptsBuilder interface {
|
||||
ToServerUpdateMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// UpdateOpts specifies the base attributes that may be updated on an existing
|
||||
// server.
|
||||
type UpdateOpts struct {
|
||||
// Name changes the displayed name of the server.
|
||||
// The server host name will *not* change.
|
||||
// Server names are not constrained to be unique, even within the same tenant.
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// AccessIPv4 provides a new IPv4 address for the instance.
|
||||
AccessIPv4 string `json:"accessIPv4,omitempty"`
|
||||
|
||||
// AccessIPv6 provides a new IPv6 address for the instance.
|
||||
AccessIPv6 string `json:"accessIPv6,omitempty"`
|
||||
}
|
||||
|
||||
// ToServerUpdateMap formats an UpdateOpts structure into a request body.
|
||||
func (opts UpdateOpts) ToServerUpdateMap() (map[string]interface{}, error) {
|
||||
return gophercloud.BuildRequestBody(opts, "server")
|
||||
}
|
||||
|
||||
// Update requests that various attributes of the indicated server be changed.
|
||||
func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
|
||||
b, err := opts.ToServerUpdateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = client.Put(updateURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// ChangeAdminPassword alters the administrator or root password for a specified
|
||||
// server.
|
||||
func ChangeAdminPassword(client *gophercloud.ServiceClient, id, newPassword string) (r ActionResult) {
|
||||
b := map[string]interface{}{
|
||||
"changePassword": map[string]string{
|
||||
"adminPass": newPassword,
|
||||
},
|
||||
}
|
||||
_, r.Err = client.Post(actionURL(client, id), b, nil, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// RebootMethod describes the mechanisms by which a server reboot can be requested.
|
||||
type RebootMethod string
|
||||
|
||||
// These constants determine how a server should be rebooted.
|
||||
// See the Reboot() function for further details.
|
||||
const (
|
||||
SoftReboot RebootMethod = "SOFT"
|
||||
HardReboot RebootMethod = "HARD"
|
||||
OSReboot = SoftReboot
|
||||
PowerCycle = HardReboot
|
||||
)
|
||||
|
||||
// RebootOptsBuilder allows extensions to add additional parameters to the
|
||||
// reboot request.
|
||||
type RebootOptsBuilder interface {
|
||||
ToServerRebootMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// RebootOpts provides options to the reboot request.
|
||||
type RebootOpts struct {
|
||||
// Type is the type of reboot to perform on the server.
|
||||
Type RebootMethod `json:"type" required:"true"`
|
||||
}
|
||||
|
||||
// ToServerRebootMap builds a body for the reboot request.
|
||||
func (opts *RebootOpts) ToServerRebootMap() (map[string]interface{}, error) {
|
||||
return gophercloud.BuildRequestBody(opts, "reboot")
|
||||
}
|
||||
|
||||
/*
|
||||
Reboot requests that a given server reboot.
|
||||
|
||||
Two methods exist for rebooting a server:
|
||||
|
||||
HardReboot (aka PowerCycle) starts the server instance by physically cutting
|
||||
power to the machine, or if a VM, terminating it at the hypervisor level.
|
||||
It's done. Caput. Full stop.
|
||||
Then, after a brief while, power is rtored or the VM instance restarted.
|
||||
|
||||
SoftReboot (aka OSReboot) simply tells the OS to restart under its own
|
||||
procedure.
|
||||
E.g., in Linux, asking it to enter runlevel 6, or executing
|
||||
"sudo shutdown -r now", or by asking Windows to rtart the machine.
|
||||
*/
|
||||
func Reboot(client *gophercloud.ServiceClient, id string, opts RebootOptsBuilder) (r ActionResult) {
|
||||
b, err := opts.ToServerRebootMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = client.Post(actionURL(client, id), b, nil, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// RebuildOptsBuilder allows extensions to provide additional parameters to the
|
||||
// rebuild request.
|
||||
type RebuildOptsBuilder interface {
|
||||
ToServerRebuildMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// RebuildOpts represents the configuration options used in a server rebuild
|
||||
// operation.
|
||||
type RebuildOpts struct {
|
||||
// AdminPass is the server's admin password
|
||||
AdminPass string `json:"adminPass,omitempty"`
|
||||
|
||||
// ImageID is the ID of the image you want your server to be provisioned on.
|
||||
ImageID string `json:"imageRef"`
|
||||
|
||||
// ImageName is readable name of an image.
|
||||
ImageName string `json:"-"`
|
||||
|
||||
// Name to set the server to
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// AccessIPv4 [optional] provides a new IPv4 address for the instance.
|
||||
AccessIPv4 string `json:"accessIPv4,omitempty"`
|
||||
|
||||
// AccessIPv6 [optional] provides a new IPv6 address for the instance.
|
||||
AccessIPv6 string `json:"accessIPv6,omitempty"`
|
||||
|
||||
// Metadata [optional] contains key-value pairs (up to 255 bytes each)
|
||||
// to attach to the server.
|
||||
Metadata map[string]string `json:"metadata,omitempty"`
|
||||
|
||||
// Personality [optional] includes files to inject into the server at launch.
|
||||
// Rebuild will base64-encode file contents for you.
|
||||
Personality Personality `json:"personality,omitempty"`
|
||||
|
||||
// ServiceClient will allow calls to be made to retrieve an image or
|
||||
// flavor ID by name.
|
||||
ServiceClient *gophercloud.ServiceClient `json:"-"`
|
||||
}
|
||||
|
||||
// ToServerRebuildMap formats a RebuildOpts struct into a map for use in JSON
|
||||
func (opts RebuildOpts) ToServerRebuildMap() (map[string]interface{}, error) {
|
||||
b, err := gophercloud.BuildRequestBody(opts, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If ImageRef isn't provided, check if ImageName was provided to ascertain
|
||||
// the image ID.
|
||||
if opts.ImageID == "" {
|
||||
if opts.ImageName != "" {
|
||||
if opts.ServiceClient == nil {
|
||||
err := ErrNoClientProvidedForIDByName{}
|
||||
err.Argument = "ServiceClient"
|
||||
return nil, err
|
||||
}
|
||||
imageID, err := images.IDFromName(opts.ServiceClient, opts.ImageName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b["imageRef"] = imageID
|
||||
}
|
||||
}
|
||||
|
||||
return map[string]interface{}{"rebuild": b}, nil
|
||||
}
|
||||
|
||||
// Rebuild will reprovision the server according to the configuration options
|
||||
// provided in the RebuildOpts struct.
|
||||
func Rebuild(client *gophercloud.ServiceClient, id string, opts RebuildOptsBuilder) (r RebuildResult) {
|
||||
b, err := opts.ToServerRebuildMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = client.Post(actionURL(client, id), b, &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// ResizeOptsBuilder allows extensions to add additional parameters to the
|
||||
// resize request.
|
||||
type ResizeOptsBuilder interface {
|
||||
ToServerResizeMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// ResizeOpts represents the configuration options used to control a Resize
|
||||
// operation.
|
||||
type ResizeOpts struct {
|
||||
// FlavorRef is the ID of the flavor you wish your server to become.
|
||||
FlavorRef string `json:"flavorRef" required:"true"`
|
||||
}
|
||||
|
||||
// ToServerResizeMap formats a ResizeOpts as a map that can be used as a JSON
|
||||
// request body for the Resize request.
|
||||
func (opts ResizeOpts) ToServerResizeMap() (map[string]interface{}, error) {
|
||||
return gophercloud.BuildRequestBody(opts, "resize")
|
||||
}
|
||||
|
||||
// Resize instructs the provider to change the flavor of the server.
|
||||
//
|
||||
// Note that this implies rebuilding it.
|
||||
//
|
||||
// Unfortunately, one cannot pass rebuild parameters to the resize function.
|
||||
// When the resize completes, the server will be in VERIFY_RESIZE state.
|
||||
// While in this state, you can explore the use of the new server's
|
||||
// configuration. If you like it, call ConfirmResize() to commit the resize
|
||||
// permanently. Otherwise, call RevertResize() to restore the old configuration.
|
||||
func Resize(client *gophercloud.ServiceClient, id string, opts ResizeOptsBuilder) (r ActionResult) {
|
||||
b, err := opts.ToServerResizeMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = client.Post(actionURL(client, id), b, nil, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// ConfirmResize confirms a previous resize operation on a server.
|
||||
// See Resize() for more details.
|
||||
func ConfirmResize(client *gophercloud.ServiceClient, id string) (r ActionResult) {
|
||||
_, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"confirmResize": nil}, nil, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{201, 202, 204},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// RevertResize cancels a previous resize operation on a server.
|
||||
// See Resize() for more details.
|
||||
func RevertResize(client *gophercloud.ServiceClient, id string) (r ActionResult) {
|
||||
_, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"revertResize": nil}, nil, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// RescueOptsBuilder is an interface that allows extensions to override the
|
||||
// default structure of a Rescue request.
|
||||
type RescueOptsBuilder interface {
|
||||
ToServerRescueMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// RescueOpts represents the configuration options used to control a Rescue
|
||||
// option.
|
||||
type RescueOpts struct {
|
||||
// AdminPass is the desired administrative password for the instance in
|
||||
// RESCUE mode. If it's left blank, the server will generate a password.
|
||||
AdminPass string `json:"adminPass,omitempty"`
|
||||
}
|
||||
|
||||
// ToServerRescueMap formats a RescueOpts as a map that can be used as a JSON
|
||||
// request body for the Rescue request.
|
||||
func (opts RescueOpts) ToServerRescueMap() (map[string]interface{}, error) {
|
||||
return gophercloud.BuildRequestBody(opts, "rescue")
|
||||
}
|
||||
|
||||
// Rescue instructs the provider to place the server into RESCUE mode.
|
||||
func Rescue(client *gophercloud.ServiceClient, id string, opts RescueOptsBuilder) (r RescueResult) {
|
||||
b, err := opts.ToServerRescueMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = client.Post(actionURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// ResetMetadataOptsBuilder allows extensions to add additional parameters to
|
||||
// the Reset request.
|
||||
type ResetMetadataOptsBuilder interface {
|
||||
ToMetadataResetMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// MetadataOpts is a map that contains key-value pairs.
|
||||
type MetadataOpts map[string]string
|
||||
|
||||
// ToMetadataResetMap assembles a body for a Reset request based on the contents
|
||||
// of a MetadataOpts.
|
||||
func (opts MetadataOpts) ToMetadataResetMap() (map[string]interface{}, error) {
|
||||
return map[string]interface{}{"metadata": opts}, nil
|
||||
}
|
||||
|
||||
// ToMetadataUpdateMap assembles a body for an Update request based on the
|
||||
// contents of a MetadataOpts.
|
||||
func (opts MetadataOpts) ToMetadataUpdateMap() (map[string]interface{}, error) {
|
||||
return map[string]interface{}{"metadata": opts}, nil
|
||||
}
|
||||
|
||||
// ResetMetadata will create multiple new key-value pairs for the given server
|
||||
// ID.
|
||||
// Note: Using this operation will erase any already-existing metadata and
|
||||
// create the new metadata provided. To keep any already-existing metadata,
|
||||
// use the UpdateMetadatas or UpdateMetadata function.
|
||||
func ResetMetadata(client *gophercloud.ServiceClient, id string, opts ResetMetadataOptsBuilder) (r ResetMetadataResult) {
|
||||
b, err := opts.ToMetadataResetMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = client.Put(metadataURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Metadata requests all the metadata for the given server ID.
|
||||
func Metadata(client *gophercloud.ServiceClient, id string) (r GetMetadataResult) {
|
||||
_, r.Err = client.Get(metadataURL(client, id), &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateMetadataOptsBuilder allows extensions to add additional parameters to
|
||||
// the Create request.
|
||||
type UpdateMetadataOptsBuilder interface {
|
||||
ToMetadataUpdateMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// UpdateMetadata updates (or creates) all the metadata specified by opts for
|
||||
// the given server ID. This operation does not affect already-existing metadata
|
||||
// that is not specified by opts.
|
||||
func UpdateMetadata(client *gophercloud.ServiceClient, id string, opts UpdateMetadataOptsBuilder) (r UpdateMetadataResult) {
|
||||
b, err := opts.ToMetadataUpdateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = client.Post(metadataURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// MetadatumOptsBuilder allows extensions to add additional parameters to the
|
||||
// Create request.
|
||||
type MetadatumOptsBuilder interface {
|
||||
ToMetadatumCreateMap() (map[string]interface{}, string, error)
|
||||
}
|
||||
|
||||
// MetadatumOpts is a map of length one that contains a key-value pair.
|
||||
type MetadatumOpts map[string]string
|
||||
|
||||
// ToMetadatumCreateMap assembles a body for a Create request based on the
|
||||
// contents of a MetadataumOpts.
|
||||
func (opts MetadatumOpts) ToMetadatumCreateMap() (map[string]interface{}, string, error) {
|
||||
if len(opts) != 1 {
|
||||
err := gophercloud.ErrInvalidInput{}
|
||||
err.Argument = "servers.MetadatumOpts"
|
||||
err.Info = "Must have 1 and only 1 key-value pair"
|
||||
return nil, "", err
|
||||
}
|
||||
metadatum := map[string]interface{}{"meta": opts}
|
||||
var key string
|
||||
for k := range metadatum["meta"].(MetadatumOpts) {
|
||||
key = k
|
||||
}
|
||||
return metadatum, key, nil
|
||||
}
|
||||
|
||||
// CreateMetadatum will create or update the key-value pair with the given key
|
||||
// for the given server ID.
|
||||
func CreateMetadatum(client *gophercloud.ServiceClient, id string, opts MetadatumOptsBuilder) (r CreateMetadatumResult) {
|
||||
b, key, err := opts.ToMetadatumCreateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = client.Put(metadatumURL(client, id, key), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Metadatum requests the key-value pair with the given key for the given
|
||||
// server ID.
|
||||
func Metadatum(client *gophercloud.ServiceClient, id, key string) (r GetMetadatumResult) {
|
||||
_, r.Err = client.Get(metadatumURL(client, id, key), &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteMetadatum will delete the key-value pair with the given key for the
|
||||
// given server ID.
|
||||
func DeleteMetadatum(client *gophercloud.ServiceClient, id, key string) (r DeleteMetadatumResult) {
|
||||
_, r.Err = client.Delete(metadatumURL(client, id, key), nil)
|
||||
return
|
||||
}
|
||||
|
||||
// ListAddresses makes a request against the API to list the servers IP
|
||||
// addresses.
|
||||
func ListAddresses(client *gophercloud.ServiceClient, id string) pagination.Pager {
|
||||
return pagination.NewPager(client, listAddressesURL(client, id), func(r pagination.PageResult) pagination.Page {
|
||||
return AddressPage{pagination.SinglePageBase(r)}
|
||||
})
|
||||
}
|
||||
|
||||
// ListAddressesByNetwork makes a request against the API to list the servers IP
|
||||
// addresses for the given network.
|
||||
func ListAddressesByNetwork(client *gophercloud.ServiceClient, id, network string) pagination.Pager {
|
||||
return pagination.NewPager(client, listAddressesByNetworkURL(client, id, network), func(r pagination.PageResult) pagination.Page {
|
||||
return NetworkAddressPage{pagination.SinglePageBase(r)}
|
||||
})
|
||||
}
|
||||
|
||||
// CreateImageOptsBuilder allows extensions to add additional parameters to the
|
||||
// CreateImage request.
|
||||
type CreateImageOptsBuilder interface {
|
||||
ToServerCreateImageMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// CreateImageOpts provides options to pass to the CreateImage request.
|
||||
type CreateImageOpts struct {
|
||||
// Name of the image/snapshot.
|
||||
Name string `json:"name" required:"true"`
|
||||
|
||||
// Metadata contains key-value pairs (up to 255 bytes each) to attach to
|
||||
// the created image.
|
||||
Metadata map[string]string `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
// ToServerCreateImageMap formats a CreateImageOpts structure into a request
|
||||
// body.
|
||||
func (opts CreateImageOpts) ToServerCreateImageMap() (map[string]interface{}, error) {
|
||||
return gophercloud.BuildRequestBody(opts, "createImage")
|
||||
}
|
||||
|
||||
// CreateImage makes a request against the nova API to schedule an image to be
|
||||
// created of the server
|
||||
func CreateImage(client *gophercloud.ServiceClient, id string, opts CreateImageOptsBuilder) (r CreateImageResult) {
|
||||
b, err := opts.ToServerCreateImageMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
resp, err := client.Post(actionURL(client, id), b, nil, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
r.Err = err
|
||||
r.Header = resp.Header
|
||||
return
|
||||
}
|
||||
|
||||
// IDFromName is a convienience function that returns a server's ID given its
|
||||
// name.
|
||||
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
|
||||
count := 0
|
||||
id := ""
|
||||
allPages, err := List(client, nil).AllPages()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
all, err := ExtractServers(allPages)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, f := range all {
|
||||
if f.Name == name {
|
||||
count++
|
||||
id = f.ID
|
||||
}
|
||||
}
|
||||
|
||||
switch count {
|
||||
case 0:
|
||||
return "", gophercloud.ErrResourceNotFound{Name: name, ResourceType: "server"}
|
||||
case 1:
|
||||
return id, nil
|
||||
default:
|
||||
return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "server"}
|
||||
}
|
||||
}
|
||||
|
||||
// GetPassword makes a request against the nova API to get the encrypted
|
||||
// administrative password.
|
||||
func GetPassword(client *gophercloud.ServiceClient, serverId string) (r GetPasswordResult) {
|
||||
_, r.Err = client.Get(passwordURL(client, serverId), &r.Body, nil)
|
||||
return
|
||||
}
|
||||
414
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/results.go
generated
vendored
Normal file
414
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/results.go
generated
vendored
Normal file
|
|
@ -0,0 +1,414 @@
|
|||
package servers
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
type serverResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// Extract interprets any serverResult as a Server, if possible.
|
||||
func (r serverResult) Extract() (*Server, error) {
|
||||
var s Server
|
||||
err := r.ExtractInto(&s)
|
||||
return &s, err
|
||||
}
|
||||
|
||||
func (r serverResult) ExtractInto(v interface{}) error {
|
||||
return r.Result.ExtractIntoStructPtr(v, "server")
|
||||
}
|
||||
|
||||
func ExtractServersInto(r pagination.Page, v interface{}) error {
|
||||
return r.(ServerPage).Result.ExtractIntoSlicePtr(v, "servers")
|
||||
}
|
||||
|
||||
// CreateResult is the response from a Create operation. Call its Extract
|
||||
// method to interpret it as a Server.
|
||||
type CreateResult struct {
|
||||
serverResult
|
||||
}
|
||||
|
||||
// GetResult is the response from a Get operation. Call its Extract
|
||||
// method to interpret it as a Server.
|
||||
type GetResult struct {
|
||||
serverResult
|
||||
}
|
||||
|
||||
// UpdateResult is the response from an Update operation. Call its Extract
|
||||
// method to interpret it as a Server.
|
||||
type UpdateResult struct {
|
||||
serverResult
|
||||
}
|
||||
|
||||
// DeleteResult is the response from a Delete operation. Call its ExtractErr
|
||||
// method to determine if the call succeeded or failed.
|
||||
type DeleteResult struct {
|
||||
gophercloud.ErrResult
|
||||
}
|
||||
|
||||
// RebuildResult is the response from a Rebuild operation. Call its Extract
|
||||
// method to interpret it as a Server.
|
||||
type RebuildResult struct {
|
||||
serverResult
|
||||
}
|
||||
|
||||
// ActionResult represents the result of server action operations, like reboot.
|
||||
// Call its ExtractErr method to determine if the action succeeded or failed.
|
||||
type ActionResult struct {
|
||||
gophercloud.ErrResult
|
||||
}
|
||||
|
||||
// RescueResult is the response from a Rescue operation. Call its ExtractErr
|
||||
// method to determine if the call succeeded or failed.
|
||||
type RescueResult struct {
|
||||
ActionResult
|
||||
}
|
||||
|
||||
// CreateImageResult is the response from a CreateImage operation. Call its
|
||||
// ExtractImageID method to retrieve the ID of the newly created image.
|
||||
type CreateImageResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// GetPasswordResult represent the result of a get os-server-password operation.
|
||||
// Call its ExtractPassword method to retrieve the password.
|
||||
type GetPasswordResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// ExtractPassword gets the encrypted password.
|
||||
// If privateKey != nil the password is decrypted with the private key.
|
||||
// If privateKey == nil the encrypted password is returned and can be decrypted
|
||||
// with:
|
||||
// echo '<pwd>' | base64 -D | openssl rsautl -decrypt -inkey <private_key>
|
||||
func (r GetPasswordResult) ExtractPassword(privateKey *rsa.PrivateKey) (string, error) {
|
||||
var s struct {
|
||||
Password string `json:"password"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
if err == nil && privateKey != nil && s.Password != "" {
|
||||
return decryptPassword(s.Password, privateKey)
|
||||
}
|
||||
return s.Password, err
|
||||
}
|
||||
|
||||
func decryptPassword(encryptedPassword string, privateKey *rsa.PrivateKey) (string, error) {
|
||||
b64EncryptedPassword := make([]byte, base64.StdEncoding.DecodedLen(len(encryptedPassword)))
|
||||
|
||||
n, err := base64.StdEncoding.Decode(b64EncryptedPassword, []byte(encryptedPassword))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Failed to base64 decode encrypted password: %s", err)
|
||||
}
|
||||
password, err := rsa.DecryptPKCS1v15(nil, privateKey, b64EncryptedPassword[0:n])
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Failed to decrypt password: %s", err)
|
||||
}
|
||||
|
||||
return string(password), nil
|
||||
}
|
||||
|
||||
// ExtractImageID gets the ID of the newly created server image from the header.
|
||||
func (r CreateImageResult) ExtractImageID() (string, error) {
|
||||
if r.Err != nil {
|
||||
return "", r.Err
|
||||
}
|
||||
// Get the image id from the header
|
||||
u, err := url.ParseRequestURI(r.Header.Get("Location"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imageID := path.Base(u.Path)
|
||||
if imageID == "." || imageID == "/" {
|
||||
return "", fmt.Errorf("Failed to parse the ID of newly created image: %s", u)
|
||||
}
|
||||
return imageID, nil
|
||||
}
|
||||
|
||||
// Extract interprets any RescueResult as an AdminPass, if possible.
|
||||
func (r RescueResult) Extract() (string, error) {
|
||||
var s struct {
|
||||
AdminPass string `json:"adminPass"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
return s.AdminPass, err
|
||||
}
|
||||
|
||||
// Server represents a server/instance in the OpenStack cloud.
|
||||
type Server struct {
|
||||
// ID uniquely identifies this server amongst all other servers,
|
||||
// including those not accessible to the current tenant.
|
||||
ID string `json:"id"`
|
||||
|
||||
// TenantID identifies the tenant owning this server resource.
|
||||
TenantID string `json:"tenant_id"`
|
||||
|
||||
// UserID uniquely identifies the user account owning the tenant.
|
||||
UserID string `json:"user_id"`
|
||||
|
||||
// Name contains the human-readable name for the server.
|
||||
Name string `json:"name"`
|
||||
|
||||
// Updated and Created contain ISO-8601 timestamps of when the state of the
|
||||
// server last changed, and when it was created.
|
||||
Updated time.Time `json:"updated"`
|
||||
Created time.Time `json:"created"`
|
||||
|
||||
// HostID is the host where the server is located in the cloud.
|
||||
HostID string `json:"hostid"`
|
||||
|
||||
// Status contains the current operational status of the server,
|
||||
// such as IN_PROGRESS or ACTIVE.
|
||||
Status string `json:"status"`
|
||||
|
||||
// Progress ranges from 0..100.
|
||||
// A request made against the server completes only once Progress reaches 100.
|
||||
Progress int `json:"progress"`
|
||||
|
||||
// AccessIPv4 and AccessIPv6 contain the IP addresses of the server,
|
||||
// suitable for remote access for administration.
|
||||
AccessIPv4 string `json:"accessIPv4"`
|
||||
AccessIPv6 string `json:"accessIPv6"`
|
||||
|
||||
// Image refers to a JSON object, which itself indicates the OS image used to
|
||||
// deploy the server.
|
||||
Image map[string]interface{} `json:"-"`
|
||||
|
||||
// Flavor refers to a JSON object, which itself indicates the hardware
|
||||
// configuration of the deployed server.
|
||||
Flavor map[string]interface{} `json:"flavor"`
|
||||
|
||||
// Addresses includes a list of all IP addresses assigned to the server,
|
||||
// keyed by pool.
|
||||
Addresses map[string]interface{} `json:"addresses"`
|
||||
|
||||
// Metadata includes a list of all user-specified key-value pairs attached
|
||||
// to the server.
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
|
||||
// Links includes HTTP references to the itself, useful for passing along to
|
||||
// other APIs that might want a server reference.
|
||||
Links []interface{} `json:"links"`
|
||||
|
||||
// KeyName indicates which public key was injected into the server on launch.
|
||||
KeyName string `json:"key_name"`
|
||||
|
||||
// AdminPass will generally be empty (""). However, it will contain the
|
||||
// administrative password chosen when provisioning a new server without a
|
||||
// set AdminPass setting in the first place.
|
||||
// Note that this is the ONLY time this field will be valid.
|
||||
AdminPass string `json:"adminPass"`
|
||||
|
||||
// SecurityGroups includes the security groups that this instance has applied
|
||||
// to it.
|
||||
SecurityGroups []map[string]interface{} `json:"security_groups"`
|
||||
|
||||
// Fault contains failure information about a server.
|
||||
Fault Fault `json:"fault"`
|
||||
}
|
||||
|
||||
type Fault struct {
|
||||
Code int `json:"code"`
|
||||
Created time.Time `json:"created"`
|
||||
Details string `json:"details"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (r *Server) UnmarshalJSON(b []byte) error {
|
||||
type tmp Server
|
||||
var s struct {
|
||||
tmp
|
||||
Image interface{} `json:"image"`
|
||||
}
|
||||
err := json.Unmarshal(b, &s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*r = Server(s.tmp)
|
||||
|
||||
switch t := s.Image.(type) {
|
||||
case map[string]interface{}:
|
||||
r.Image = t
|
||||
case string:
|
||||
switch t {
|
||||
case "":
|
||||
r.Image = nil
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// ServerPage abstracts the raw results of making a List() request against
|
||||
// the API. As OpenStack extensions may freely alter the response bodies of
|
||||
// structures returned to the client, you may only safely access the data
|
||||
// provided through the ExtractServers call.
|
||||
type ServerPage struct {
|
||||
pagination.LinkedPageBase
|
||||
}
|
||||
|
||||
// IsEmpty returns true if a page contains no Server results.
|
||||
func (r ServerPage) IsEmpty() (bool, error) {
|
||||
s, err := ExtractServers(r)
|
||||
return len(s) == 0, err
|
||||
}
|
||||
|
||||
// NextPageURL uses the response's embedded link reference to navigate to the
|
||||
// next page of results.
|
||||
func (r ServerPage) NextPageURL() (string, error) {
|
||||
var s struct {
|
||||
Links []gophercloud.Link `json:"servers_links"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return gophercloud.ExtractNextURL(s.Links)
|
||||
}
|
||||
|
||||
// ExtractServers interprets the results of a single page from a List() call,
|
||||
// producing a slice of Server entities.
|
||||
func ExtractServers(r pagination.Page) ([]Server, error) {
|
||||
var s []Server
|
||||
err := ExtractServersInto(r, &s)
|
||||
return s, err
|
||||
}
|
||||
|
||||
// MetadataResult contains the result of a call for (potentially) multiple
|
||||
// key-value pairs. Call its Extract method to interpret it as a
|
||||
// map[string]interface.
|
||||
type MetadataResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// GetMetadataResult contains the result of a Get operation. Call its Extract
|
||||
// method to interpret it as a map[string]interface.
|
||||
type GetMetadataResult struct {
|
||||
MetadataResult
|
||||
}
|
||||
|
||||
// ResetMetadataResult contains the result of a Reset operation. Call its
|
||||
// Extract method to interpret it as a map[string]interface.
|
||||
type ResetMetadataResult struct {
|
||||
MetadataResult
|
||||
}
|
||||
|
||||
// UpdateMetadataResult contains the result of an Update operation. Call its
|
||||
// Extract method to interpret it as a map[string]interface.
|
||||
type UpdateMetadataResult struct {
|
||||
MetadataResult
|
||||
}
|
||||
|
||||
// MetadatumResult contains the result of a call for individual a single
|
||||
// key-value pair.
|
||||
type MetadatumResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// GetMetadatumResult contains the result of a Get operation. Call its Extract
|
||||
// method to interpret it as a map[string]interface.
|
||||
type GetMetadatumResult struct {
|
||||
MetadatumResult
|
||||
}
|
||||
|
||||
// CreateMetadatumResult contains the result of a Create operation. Call its
|
||||
// Extract method to interpret it as a map[string]interface.
|
||||
type CreateMetadatumResult struct {
|
||||
MetadatumResult
|
||||
}
|
||||
|
||||
// DeleteMetadatumResult contains the result of a Delete operation. Call its
|
||||
// ExtractErr method to determine if the call succeeded or failed.
|
||||
type DeleteMetadatumResult struct {
|
||||
gophercloud.ErrResult
|
||||
}
|
||||
|
||||
// Extract interprets any MetadataResult as a Metadata, if possible.
|
||||
func (r MetadataResult) Extract() (map[string]string, error) {
|
||||
var s struct {
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
return s.Metadata, err
|
||||
}
|
||||
|
||||
// Extract interprets any MetadatumResult as a Metadatum, if possible.
|
||||
func (r MetadatumResult) Extract() (map[string]string, error) {
|
||||
var s struct {
|
||||
Metadatum map[string]string `json:"meta"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
return s.Metadatum, err
|
||||
}
|
||||
|
||||
// Address represents an IP address.
|
||||
type Address struct {
|
||||
Version int `json:"version"`
|
||||
Address string `json:"addr"`
|
||||
}
|
||||
|
||||
// AddressPage abstracts the raw results of making a ListAddresses() request
|
||||
// against the API. As OpenStack extensions may freely alter the response bodies
|
||||
// of structures returned to the client, you may only safely access the data
|
||||
// provided through the ExtractAddresses call.
|
||||
type AddressPage struct {
|
||||
pagination.SinglePageBase
|
||||
}
|
||||
|
||||
// IsEmpty returns true if an AddressPage contains no networks.
|
||||
func (r AddressPage) IsEmpty() (bool, error) {
|
||||
addresses, err := ExtractAddresses(r)
|
||||
return len(addresses) == 0, err
|
||||
}
|
||||
|
||||
// ExtractAddresses interprets the results of a single page from a
|
||||
// ListAddresses() call, producing a map of addresses.
|
||||
func ExtractAddresses(r pagination.Page) (map[string][]Address, error) {
|
||||
var s struct {
|
||||
Addresses map[string][]Address `json:"addresses"`
|
||||
}
|
||||
err := (r.(AddressPage)).ExtractInto(&s)
|
||||
return s.Addresses, err
|
||||
}
|
||||
|
||||
// NetworkAddressPage abstracts the raw results of making a
|
||||
// ListAddressesByNetwork() request against the API.
|
||||
// As OpenStack extensions may freely alter the response bodies of structures
|
||||
// returned to the client, you may only safely access the data provided through
|
||||
// the ExtractAddresses call.
|
||||
type NetworkAddressPage struct {
|
||||
pagination.SinglePageBase
|
||||
}
|
||||
|
||||
// IsEmpty returns true if a NetworkAddressPage contains no addresses.
|
||||
func (r NetworkAddressPage) IsEmpty() (bool, error) {
|
||||
addresses, err := ExtractNetworkAddresses(r)
|
||||
return len(addresses) == 0, err
|
||||
}
|
||||
|
||||
// ExtractNetworkAddresses interprets the results of a single page from a
|
||||
// ListAddressesByNetwork() call, producing a slice of addresses.
|
||||
func ExtractNetworkAddresses(r pagination.Page) ([]Address, error) {
|
||||
var s map[string][]Address
|
||||
err := (r.(NetworkAddressPage)).ExtractInto(&s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var key string
|
||||
for k := range s {
|
||||
key = k
|
||||
}
|
||||
|
||||
return s[key], err
|
||||
}
|
||||
51
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/urls.go
generated
vendored
Normal file
51
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/urls.go
generated
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
package servers
|
||||
|
||||
import "github.com/gophercloud/gophercloud"
|
||||
|
||||
func createURL(client *gophercloud.ServiceClient) string {
|
||||
return client.ServiceURL("servers")
|
||||
}
|
||||
|
||||
func listURL(client *gophercloud.ServiceClient) string {
|
||||
return createURL(client)
|
||||
}
|
||||
|
||||
func listDetailURL(client *gophercloud.ServiceClient) string {
|
||||
return client.ServiceURL("servers", "detail")
|
||||
}
|
||||
|
||||
func deleteURL(client *gophercloud.ServiceClient, id string) string {
|
||||
return client.ServiceURL("servers", id)
|
||||
}
|
||||
|
||||
func getURL(client *gophercloud.ServiceClient, id string) string {
|
||||
return deleteURL(client, id)
|
||||
}
|
||||
|
||||
func updateURL(client *gophercloud.ServiceClient, id string) string {
|
||||
return deleteURL(client, id)
|
||||
}
|
||||
|
||||
func actionURL(client *gophercloud.ServiceClient, id string) string {
|
||||
return client.ServiceURL("servers", id, "action")
|
||||
}
|
||||
|
||||
func metadatumURL(client *gophercloud.ServiceClient, id, key string) string {
|
||||
return client.ServiceURL("servers", id, "metadata", key)
|
||||
}
|
||||
|
||||
func metadataURL(client *gophercloud.ServiceClient, id string) string {
|
||||
return client.ServiceURL("servers", id, "metadata")
|
||||
}
|
||||
|
||||
func listAddressesURL(client *gophercloud.ServiceClient, id string) string {
|
||||
return client.ServiceURL("servers", id, "ips")
|
||||
}
|
||||
|
||||
func listAddressesByNetworkURL(client *gophercloud.ServiceClient, id, network string) string {
|
||||
return client.ServiceURL("servers", id, "ips", network)
|
||||
}
|
||||
|
||||
func passwordURL(client *gophercloud.ServiceClient, id string) string {
|
||||
return client.ServiceURL("servers", id, "os-server-password")
|
||||
}
|
||||
21
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/util.go
generated
vendored
Normal file
21
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/util.go
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package servers
|
||||
|
||||
import "github.com/gophercloud/gophercloud"
|
||||
|
||||
// WaitForStatus will continually poll a server until it successfully
|
||||
// transitions to a specified status. It will do this for at most the number
|
||||
// of seconds specified.
|
||||
func WaitForStatus(c *gophercloud.ServiceClient, id, status string, secs int) error {
|
||||
return gophercloud.WaitFor(secs, func() (bool, error) {
|
||||
current, err := Get(c, id).Extract()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if current.Status == status {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
})
|
||||
}
|
||||
Loading…
Reference in New Issue