mirror of https://github.com/kubernetes/kops.git
Merge pull request #7652 from OpenSource-THG/master
Openstack block device mapping support
This commit is contained in:
commit
f671873629
|
@ -549,3 +549,28 @@ spec:
|
|||
minSize: 2
|
||||
role: Node
|
||||
```
|
||||
|
||||
## Booting from a volume in OpenStack
|
||||
|
||||
If you want to boot from a volume when you are running in openstack you can set annotations on the instance groups.
|
||||
|
||||
```yaml
|
||||
# Example for nodes
|
||||
apiVersion: kops.k8s.io/v1alpha2
|
||||
kind: InstanceGroup
|
||||
metadata:
|
||||
labels:
|
||||
kops.k8s.io/cluster: k8s.dev.local
|
||||
name: nodes
|
||||
annotations:
|
||||
openstack.kops.io/osVolumeBoot: enabled
|
||||
openstack.kops.io/osVolumeSize: "15" # In gigabytes
|
||||
spec:
|
||||
detailedInstanceMonitoring: true
|
||||
machineType: t2.medium
|
||||
maxSize: 2
|
||||
minSize: 2
|
||||
role: Node
|
||||
```
|
||||
|
||||
If `openstack.kops.io/osVolumeSize` is not set it will default to the minimum disk specified by the image.
|
||||
|
|
|
@ -64,6 +64,14 @@ func (b *ServerGroupModelBuilder) buildInstances(c *fi.ModelBuilderContext, sg *
|
|||
igMeta[openstack.INSTANCE_GROUP_GENERATION] = fmt.Sprintf("%d", ig.GetGeneration())
|
||||
igMeta[openstack.CLUSTER_GENERATION] = fmt.Sprintf("%d", b.Cluster.GetGeneration())
|
||||
|
||||
if e, ok := ig.ObjectMeta.Annotations[openstack.OS_ANNOTATION+openstack.BOOT_FROM_VOLUME]; ok {
|
||||
igMeta[openstack.BOOT_FROM_VOLUME] = e
|
||||
}
|
||||
|
||||
if v, ok := ig.ObjectMeta.Annotations[openstack.OS_ANNOTATION+openstack.BOOT_VOLUME_SIZE]; ok {
|
||||
igMeta[openstack.BOOT_VOLUME_SIZE] = v
|
||||
}
|
||||
|
||||
startupScript, err := b.BootstrapScript.ResourceNodeUp(ig, b.Cluster)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not create startup script for instance group %s: %v", ig.Name, err)
|
||||
|
|
|
@ -8,6 +8,7 @@ go_library(
|
|||
"cloud.go",
|
||||
"dns.go",
|
||||
"floatingip.go",
|
||||
"image.go",
|
||||
"instance.go",
|
||||
"keypair.go",
|
||||
"loadbalancer.go",
|
||||
|
@ -44,6 +45,7 @@ go_library(
|
|||
"//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/dns/v2/recordsets:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/dns/v2/zones:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/images:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/listeners:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/loadbalancers:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/monitors:go_default_library",
|
||||
|
|
|
@ -23,8 +23,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/kops/pkg/dns"
|
||||
|
||||
"github.com/gophercloud/gophercloud"
|
||||
os "github.com/gophercloud/gophercloud/openstack"
|
||||
cinder "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes"
|
||||
|
@ -36,6 +34,7 @@ import (
|
|||
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||
"github.com/gophercloud/gophercloud/openstack/dns/v2/recordsets"
|
||||
"github.com/gophercloud/gophercloud/openstack/dns/v2/zones"
|
||||
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
|
||||
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/listeners"
|
||||
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/loadbalancers"
|
||||
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/monitors"
|
||||
|
@ -54,6 +53,7 @@ import (
|
|||
"k8s.io/kops/dnsprovider/pkg/dnsprovider/providers/openstack/designate"
|
||||
"k8s.io/kops/pkg/apis/kops"
|
||||
"k8s.io/kops/pkg/cloudinstances"
|
||||
"k8s.io/kops/pkg/dns"
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/util/pkg/vfs"
|
||||
)
|
||||
|
@ -274,6 +274,8 @@ type OpenstackCloud interface {
|
|||
|
||||
GetFloatingIP(id string) (fip *floatingips.FloatingIP, err error)
|
||||
|
||||
GetImage(name string) (i *images.Image, err error)
|
||||
|
||||
AssociateFloatingIPToInstance(serverID string, opts floatingips.AssociateOpts) (err error)
|
||||
|
||||
ListServerFloatingIPs(id string) ([]*string, error)
|
||||
|
@ -292,6 +294,7 @@ type openstackCloud struct {
|
|||
novaClient *gophercloud.ServiceClient
|
||||
dnsClient *gophercloud.ServiceClient
|
||||
lbClient *gophercloud.ServiceClient
|
||||
glanceClient *gophercloud.ServiceClient
|
||||
floatingEnabled bool
|
||||
extNetworkName *string
|
||||
extSubnetName *string
|
||||
|
@ -368,6 +371,14 @@ func NewOpenstackCloud(tags map[string]string, spec *kops.ClusterSpec) (Openstac
|
|||
return nil, fmt.Errorf("error building nova client: %v", err)
|
||||
}
|
||||
|
||||
glanceClient, err := os.NewImageServiceV2(provider, gophercloud.EndpointOpts{
|
||||
Type: "image",
|
||||
Region: region,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error building glance client: %v", err)
|
||||
}
|
||||
|
||||
var dnsClient *gophercloud.ServiceClient
|
||||
if !dns.IsGossipHostname(tags[TagClusterName]) {
|
||||
//TODO: This should be replaced with the environment variable methods as done above
|
||||
|
@ -387,6 +398,7 @@ func NewOpenstackCloud(tags map[string]string, spec *kops.ClusterSpec) (Openstac
|
|||
neutronClient: neutronClient,
|
||||
novaClient: novaClient,
|
||||
dnsClient: dnsClient,
|
||||
glanceClient: glanceClient,
|
||||
tags: tags,
|
||||
region: region,
|
||||
useOctavia: false,
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
Copyright 2019 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 openstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
|
||||
)
|
||||
|
||||
func (c *openstackCloud) GetImage(name string) (*images.Image, error) {
|
||||
opts := images.ListOpts{Name: name}
|
||||
pager := images.List(c.glanceClient, opts)
|
||||
page, err := pager.AllPages()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list images: %v", err)
|
||||
}
|
||||
|
||||
i, err := images.ExtractImages(page)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to extract images: %v", err)
|
||||
}
|
||||
|
||||
switch len(i) {
|
||||
case 1:
|
||||
return &i[0], nil
|
||||
case 0:
|
||||
return nil, fmt.Errorf("no image found with name %v", name)
|
||||
default:
|
||||
return nil, fmt.Errorf("multiple images found with name %v", name)
|
||||
}
|
||||
}
|
|
@ -32,6 +32,9 @@ import (
|
|||
const (
|
||||
INSTANCE_GROUP_GENERATION = "ig_generation"
|
||||
CLUSTER_GENERATION = "cluster_generation"
|
||||
OS_ANNOTATION = "openstack.kops.io/"
|
||||
BOOT_FROM_VOLUME = "osVolumeBoot"
|
||||
BOOT_VOLUME_SIZE = "osVolumeSize"
|
||||
)
|
||||
|
||||
// floatingBackoff is the backoff strategy for listing openstack floatingips
|
||||
|
|
|
@ -45,6 +45,7 @@ go_library(
|
|||
"//util/pkg/vfs: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/bootfromvolume:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/schedulerhints:go_default_library",
|
||||
|
|
|
@ -18,7 +18,9 @@ package openstacktasks
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume"
|
||||
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs"
|
||||
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/schedulerhints"
|
||||
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||
|
@ -183,7 +185,13 @@ func (_ *Instance) RenderOpenstack(t *openstack.OpenstackAPITarget, a, e, change
|
|||
Group: *e.ServerGroup.ID,
|
||||
},
|
||||
}
|
||||
v, err := t.Cloud.CreateInstance(sgext)
|
||||
|
||||
opts, err := includeBootVolumeOptions(t, e, sgext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v, err := t.Cloud.CreateInstance(opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating instance: %v", err)
|
||||
}
|
||||
|
@ -198,3 +206,51 @@ func (_ *Instance) RenderOpenstack(t *openstack.OpenstackAPITarget, a, e, change
|
|||
klog.V(2).Infof("Openstack task Instance::RenderOpenstack did nothing")
|
||||
return nil
|
||||
}
|
||||
|
||||
func includeBootVolumeOptions(t *openstack.OpenstackAPITarget, e *Instance, opts servers.CreateOptsBuilder) (servers.CreateOptsBuilder, error) {
|
||||
if !bootFromVolume(e.Metadata) {
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
i, err := t.Cloud.GetImage(fi.StringValue(e.Image))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error getting image information: %v", err)
|
||||
}
|
||||
|
||||
bfv := bootfromvolume.CreateOptsExt{
|
||||
CreateOptsBuilder: opts,
|
||||
BlockDevice: []bootfromvolume.BlockDevice{{
|
||||
BootIndex: 0,
|
||||
DeleteOnTermination: true,
|
||||
DestinationType: "volume",
|
||||
SourceType: "image",
|
||||
UUID: i.ID,
|
||||
VolumeSize: i.MinDiskGigabytes,
|
||||
}},
|
||||
}
|
||||
|
||||
if s, ok := e.Metadata[openstack.BOOT_VOLUME_SIZE]; ok {
|
||||
i, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Invalid value for %v: %v", openstack.BOOT_VOLUME_SIZE, err)
|
||||
}
|
||||
|
||||
bfv.BlockDevice[0].VolumeSize = int(i)
|
||||
}
|
||||
|
||||
return bfv, nil
|
||||
}
|
||||
|
||||
func bootFromVolume(m map[string]string) bool {
|
||||
v, ok := m[openstack.BOOT_FROM_VOLUME]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
switch v {
|
||||
case "true", "enabled":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"pkg.go",
|
||||
"util.go",
|
||||
],
|
||||
importmap = "k8s.io/kops/vendor/github.com/gophercloud/gophercloud/internal",
|
||||
importpath = "github.com/gophercloud/gophercloud/internal",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1 @@
|
|||
package internal
|
|
@ -0,0 +1,34 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RemainingKeys will inspect a struct and compare it to a map. Any struct
|
||||
// field that does not have a JSON tag that matches a key in the map or
|
||||
// a matching lower-case field in the map will be returned as an extra.
|
||||
//
|
||||
// This is useful for determining the extra fields returned in response bodies
|
||||
// for resources that can contain an arbitrary or dynamic number of fields.
|
||||
func RemainingKeys(s interface{}, m map[string]interface{}) (extras map[string]interface{}) {
|
||||
extras = make(map[string]interface{})
|
||||
for k, v := range m {
|
||||
extras[k] = v
|
||||
}
|
||||
|
||||
valueOf := reflect.ValueOf(s)
|
||||
typeOf := reflect.TypeOf(s)
|
||||
for i := 0; i < valueOf.NumField(); i++ {
|
||||
field := typeOf.Field(i)
|
||||
|
||||
lowerField := strings.ToLower(field.Name)
|
||||
delete(extras, lowerField)
|
||||
|
||||
if tagValue := field.Tag.Get("json"); tagValue != "" && tagValue != "-" {
|
||||
delete(extras, tagValue)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
18
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume/BUILD.bazel
generated
vendored
Normal file
18
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume/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 = "k8s.io/kops/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume",
|
||||
importpath = "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/gophercloud/gophercloud:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers:go_default_library",
|
||||
],
|
||||
)
|
152
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume/doc.go
generated
vendored
Normal file
152
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
Package bootfromvolume extends a server create request with the ability to
|
||||
specify block device options. This can be used to boot a server from a block
|
||||
storage volume as well as specify multiple ephemeral disks upon creation.
|
||||
|
||||
It is recommended to refer to the Block Device Mapping documentation to see
|
||||
all possible ways to configure a server's block devices at creation time:
|
||||
|
||||
https://docs.openstack.org/nova/latest/user/block-device-mapping.html
|
||||
|
||||
Note that this package implements `block_device_mapping_v2`.
|
||||
|
||||
Example of Creating a Server From an Image
|
||||
|
||||
This example will boot a server from an image and use a standard ephemeral
|
||||
disk as the server's root disk. This is virtually no different than creating
|
||||
a server without using block device mappings.
|
||||
|
||||
blockDevices := []bootfromvolume.BlockDevice{
|
||||
bootfromvolume.BlockDevice{
|
||||
BootIndex: 0,
|
||||
DeleteOnTermination: true,
|
||||
DestinationType: bootfromvolume.DestinationLocal,
|
||||
SourceType: bootfromvolume.SourceImage,
|
||||
UUID: "image-uuid",
|
||||
},
|
||||
}
|
||||
|
||||
serverCreateOpts := servers.CreateOpts{
|
||||
Name: "server_name",
|
||||
FlavorRef: "flavor-uuid",
|
||||
ImageRef: "image-uuid",
|
||||
}
|
||||
|
||||
createOpts := bootfromvolume.CreateOptsExt{
|
||||
CreateOptsBuilder: serverCreateOpts,
|
||||
BlockDevice: blockDevices,
|
||||
}
|
||||
|
||||
server, err := bootfromvolume.Create(client, createOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example of Creating a Server From a New Volume
|
||||
|
||||
This example will create a block storage volume based on the given Image. The
|
||||
server will use this volume as its root disk.
|
||||
|
||||
blockDevices := []bootfromvolume.BlockDevice{
|
||||
bootfromvolume.BlockDevice{
|
||||
DeleteOnTermination: true,
|
||||
DestinationType: bootfromvolume.DestinationVolume,
|
||||
SourceType: bootfromvolume.SourceImage,
|
||||
UUID: "image-uuid",
|
||||
VolumeSize: 2,
|
||||
},
|
||||
}
|
||||
|
||||
serverCreateOpts := servers.CreateOpts{
|
||||
Name: "server_name",
|
||||
FlavorRef: "flavor-uuid",
|
||||
}
|
||||
|
||||
createOpts := bootfromvolume.CreateOptsExt{
|
||||
CreateOptsBuilder: serverCreateOpts,
|
||||
BlockDevice: blockDevices,
|
||||
}
|
||||
|
||||
server, err := bootfromvolume.Create(client, createOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example of Creating a Server From an Existing Volume
|
||||
|
||||
This example will create a server with an existing volume as its root disk.
|
||||
|
||||
blockDevices := []bootfromvolume.BlockDevice{
|
||||
bootfromvolume.BlockDevice{
|
||||
DeleteOnTermination: true,
|
||||
DestinationType: bootfromvolume.DestinationVolume,
|
||||
SourceType: bootfromvolume.SourceVolume,
|
||||
UUID: "volume-uuid",
|
||||
},
|
||||
}
|
||||
|
||||
serverCreateOpts := servers.CreateOpts{
|
||||
Name: "server_name",
|
||||
FlavorRef: "flavor-uuid",
|
||||
}
|
||||
|
||||
createOpts := bootfromvolume.CreateOptsExt{
|
||||
CreateOptsBuilder: serverCreateOpts,
|
||||
BlockDevice: blockDevices,
|
||||
}
|
||||
|
||||
server, err := bootfromvolume.Create(client, createOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example of Creating a Server with Multiple Ephemeral Disks
|
||||
|
||||
This example will create a server with multiple ephemeral disks. The first
|
||||
block device will be based off of an existing Image. Each additional
|
||||
ephemeral disks must have an index of -1.
|
||||
|
||||
blockDevices := []bootfromvolume.BlockDevice{
|
||||
bootfromvolume.BlockDevice{
|
||||
BootIndex: 0,
|
||||
DestinationType: bootfromvolume.DestinationLocal,
|
||||
DeleteOnTermination: true,
|
||||
SourceType: bootfromvolume.SourceImage,
|
||||
UUID: "image-uuid",
|
||||
VolumeSize: 5,
|
||||
},
|
||||
bootfromvolume.BlockDevice{
|
||||
BootIndex: -1,
|
||||
DestinationType: bootfromvolume.DestinationLocal,
|
||||
DeleteOnTermination: true,
|
||||
GuestFormat: "ext4",
|
||||
SourceType: bootfromvolume.SourceBlank,
|
||||
VolumeSize: 1,
|
||||
},
|
||||
bootfromvolume.BlockDevice{
|
||||
BootIndex: -1,
|
||||
DestinationType: bootfromvolume.DestinationLocal,
|
||||
DeleteOnTermination: true,
|
||||
GuestFormat: "ext4",
|
||||
SourceType: bootfromvolume.SourceBlank,
|
||||
VolumeSize: 1,
|
||||
},
|
||||
}
|
||||
|
||||
serverCreateOpts := servers.CreateOpts{
|
||||
Name: "server_name",
|
||||
FlavorRef: "flavor-uuid",
|
||||
ImageRef: "image-uuid",
|
||||
}
|
||||
|
||||
createOpts := bootfromvolume.CreateOptsExt{
|
||||
CreateOptsBuilder: serverCreateOpts,
|
||||
BlockDevice: blockDevices,
|
||||
}
|
||||
|
||||
server, err := bootfromvolume.Create(client, createOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
*/
|
||||
package bootfromvolume
|
128
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume/requests.go
generated
vendored
Normal file
128
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,128 @@
|
|||
package bootfromvolume
|
||||
|
||||
import (
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||
)
|
||||
|
||||
type (
|
||||
// DestinationType represents the type of medium being used as the
|
||||
// destination of the bootable device.
|
||||
DestinationType string
|
||||
|
||||
// SourceType represents the type of medium being used as the source of the
|
||||
// bootable device.
|
||||
SourceType string
|
||||
)
|
||||
|
||||
const (
|
||||
// DestinationLocal DestinationType is for using an ephemeral disk as the
|
||||
// destination.
|
||||
DestinationLocal DestinationType = "local"
|
||||
|
||||
// DestinationVolume DestinationType is for using a volume as the destination.
|
||||
DestinationVolume DestinationType = "volume"
|
||||
|
||||
// SourceBlank SourceType is for a "blank" or empty source.
|
||||
SourceBlank SourceType = "blank"
|
||||
|
||||
// SourceImage SourceType is for using images as the source of a block device.
|
||||
SourceImage SourceType = "image"
|
||||
|
||||
// SourceSnapshot SourceType is for using a volume snapshot as the source of
|
||||
// a block device.
|
||||
SourceSnapshot SourceType = "snapshot"
|
||||
|
||||
// SourceVolume SourceType is for using a volume as the source of block
|
||||
// device.
|
||||
SourceVolume SourceType = "volume"
|
||||
)
|
||||
|
||||
// BlockDevice is a structure with options for creating block devices in a
|
||||
// server. The block device may be created from an image, snapshot, new volume,
|
||||
// or existing volume. The destination may be a new volume, existing volume
|
||||
// which will be attached to the instance, ephemeral disk, or boot device.
|
||||
type BlockDevice struct {
|
||||
// SourceType must be one of: "volume", "snapshot", "image", or "blank".
|
||||
SourceType SourceType `json:"source_type" required:"true"`
|
||||
|
||||
// UUID is the unique identifier for the existing volume, snapshot, or
|
||||
// image (see above).
|
||||
UUID string `json:"uuid,omitempty"`
|
||||
|
||||
// BootIndex is the boot index. It defaults to 0.
|
||||
BootIndex int `json:"boot_index"`
|
||||
|
||||
// DeleteOnTermination specifies whether or not to delete the attached volume
|
||||
// when the server is deleted. Defaults to `false`.
|
||||
DeleteOnTermination bool `json:"delete_on_termination"`
|
||||
|
||||
// DestinationType is the type that gets created. Possible values are "volume"
|
||||
// and "local".
|
||||
DestinationType DestinationType `json:"destination_type,omitempty"`
|
||||
|
||||
// GuestFormat specifies the format of the block device.
|
||||
GuestFormat string `json:"guest_format,omitempty"`
|
||||
|
||||
// VolumeSize is the size of the volume to create (in gigabytes). This can be
|
||||
// omitted for existing volumes.
|
||||
VolumeSize int `json:"volume_size,omitempty"`
|
||||
|
||||
// DeviceType specifies the device type of the block devices.
|
||||
// Examples of this are disk, cdrom, floppy, lun, etc.
|
||||
DeviceType string `json:"device_type,omitempty"`
|
||||
|
||||
// DiskBus is the bus type of the block devices.
|
||||
// Examples of this are ide, usb, virtio, scsi, etc.
|
||||
DiskBus string `json:"disk_bus,omitempty"`
|
||||
}
|
||||
|
||||
// CreateOptsExt is a structure that extends the server `CreateOpts` structure
|
||||
// by allowing for a block device mapping.
|
||||
type CreateOptsExt struct {
|
||||
servers.CreateOptsBuilder
|
||||
BlockDevice []BlockDevice `json:"block_device_mapping_v2,omitempty"`
|
||||
}
|
||||
|
||||
// ToServerCreateMap adds the block device mapping option 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 len(opts.BlockDevice) == 0 {
|
||||
err := gophercloud.ErrMissingInput{}
|
||||
err.Argument = "bootfromvolume.CreateOptsExt.BlockDevice"
|
||||
return nil, err
|
||||
}
|
||||
|
||||
serverMap := base["server"].(map[string]interface{})
|
||||
|
||||
blockDevice := make([]map[string]interface{}, len(opts.BlockDevice))
|
||||
|
||||
for i, bd := range opts.BlockDevice {
|
||||
b, err := gophercloud.BuildRequestBody(bd, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockDevice[i] = b
|
||||
}
|
||||
serverMap["block_device_mapping_v2"] = blockDevice
|
||||
|
||||
return base, nil
|
||||
}
|
||||
|
||||
// Create requests the creation of a server from the given block device mapping.
|
||||
func Create(client *gophercloud.ServiceClient, opts servers.CreateOptsBuilder) (r servers.CreateResult) {
|
||||
b, err := opts.ToServerCreateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200, 202},
|
||||
})
|
||||
return
|
||||
}
|
12
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume/results.go
generated
vendored
Normal file
12
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume/results.go
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
package bootfromvolume
|
||||
|
||||
import (
|
||||
os "github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||
)
|
||||
|
||||
// CreateResult temporarily contains the response from a Create call.
|
||||
// It embeds the standard servers.CreateResults type and so can be used the
|
||||
// same way as a standard server request result.
|
||||
type CreateResult struct {
|
||||
os.CreateResult
|
||||
}
|
7
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume/urls.go
generated
vendored
Normal file
7
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
package bootfromvolume
|
||||
|
||||
import "github.com/gophercloud/gophercloud"
|
||||
|
||||
func createURL(c *gophercloud.ServiceClient) string {
|
||||
return c.ServiceURL("os-volumes_boot")
|
||||
}
|
21
vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/images/BUILD.bazel
generated
vendored
Normal file
21
vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/images/BUILD.bazel
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"requests.go",
|
||||
"results.go",
|
||||
"types.go",
|
||||
"urls.go",
|
||||
],
|
||||
importmap = "k8s.io/kops/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/images",
|
||||
importpath = "github.com/gophercloud/gophercloud/openstack/imageservice/v2/images",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/gophercloud/gophercloud:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/internal:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/openstack/utils:go_default_library",
|
||||
"//vendor/github.com/gophercloud/gophercloud/pagination:go_default_library",
|
||||
],
|
||||
)
|
60
vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/images/doc.go
generated
vendored
Normal file
60
vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/images/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
Package images enables management and retrieval of images from the OpenStack
|
||||
Image Service.
|
||||
|
||||
Example to List Images
|
||||
|
||||
images.ListOpts{
|
||||
Owner: "a7509e1ae65945fda83f3e52c6296017",
|
||||
}
|
||||
|
||||
allPages, err := images.List(imagesClient, 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)
|
||||
}
|
||||
|
||||
Example to Create an Image
|
||||
|
||||
createOpts := images.CreateOpts{
|
||||
Name: "image_name",
|
||||
Visibility: images.ImageVisibilityPrivate,
|
||||
}
|
||||
|
||||
image, err := images.Create(imageClient, createOpts)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example to Update an Image
|
||||
|
||||
imageID := "1bea47ed-f6a9-463b-b423-14b9cca9ad27"
|
||||
|
||||
updateOpts := images.UpdateOpts{
|
||||
images.ReplaceImageName{
|
||||
NewName: "new_name",
|
||||
},
|
||||
}
|
||||
|
||||
image, err := images.Update(imageClient, imageID, updateOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example to Delete an Image
|
||||
|
||||
imageID := "1bea47ed-f6a9-463b-b423-14b9cca9ad27"
|
||||
err := images.Delete(imageClient, imageID).ExtractErr()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
*/
|
||||
package images
|
366
vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/images/requests.go
generated
vendored
Normal file
366
vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/images/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,366 @@
|
|||
package images
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
// ListOptsBuilder allows extensions to add additional parameters to the
|
||||
// List request.
|
||||
type ListOptsBuilder interface {
|
||||
ToImageListQuery() (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.
|
||||
//
|
||||
// http://developer.openstack.org/api-ref-image-v2.html
|
||||
type ListOpts struct {
|
||||
// ID is the ID of the image.
|
||||
// Multiple IDs can be specified by constructing a string
|
||||
// such as "in:uuid1,uuid2,uuid3".
|
||||
ID string `q:"id"`
|
||||
|
||||
// Integer value for the limit of values to return.
|
||||
Limit int `q:"limit"`
|
||||
|
||||
// UUID of the server at which you want to set a marker.
|
||||
Marker string `q:"marker"`
|
||||
|
||||
// Name filters on the name of the image.
|
||||
// Multiple names can be specified by constructing a string
|
||||
// such as "in:name1,name2,name3".
|
||||
Name string `q:"name"`
|
||||
|
||||
// Visibility filters on the visibility of the image.
|
||||
Visibility ImageVisibility `q:"visibility"`
|
||||
|
||||
// MemberStatus filters on the member status of the image.
|
||||
MemberStatus ImageMemberStatus `q:"member_status"`
|
||||
|
||||
// Owner filters on the project ID of the image.
|
||||
Owner string `q:"owner"`
|
||||
|
||||
// Status filters on the status of the image.
|
||||
// Multiple statuses can be specified by constructing a string
|
||||
// such as "in:saving,queued".
|
||||
Status ImageStatus `q:"status"`
|
||||
|
||||
// SizeMin filters on the size_min image property.
|
||||
SizeMin int64 `q:"size_min"`
|
||||
|
||||
// SizeMax filters on the size_max image property.
|
||||
SizeMax int64 `q:"size_max"`
|
||||
|
||||
// Sort sorts the results using the new style of sorting. See the OpenStack
|
||||
// Image API reference for the exact syntax.
|
||||
//
|
||||
// Sort cannot be used with the classic sort options (sort_key and sort_dir).
|
||||
Sort string `q:"sort"`
|
||||
|
||||
// SortKey will sort the results based on a specified image property.
|
||||
SortKey string `q:"sort_key"`
|
||||
|
||||
// SortDir will sort the list results either ascending or decending.
|
||||
SortDir string `q:"sort_dir"`
|
||||
|
||||
// Tags filters on specific image tags.
|
||||
Tags []string `q:"tag"`
|
||||
|
||||
// CreatedAtQuery filters images based on their creation date.
|
||||
CreatedAtQuery *ImageDateQuery
|
||||
|
||||
// UpdatedAtQuery filters images based on their updated date.
|
||||
UpdatedAtQuery *ImageDateQuery
|
||||
|
||||
// ContainerFormat filters images based on the container_format.
|
||||
// Multiple container formats can be specified by constructing a
|
||||
// string such as "in:bare,ami".
|
||||
ContainerFormat string `q:"container_format"`
|
||||
|
||||
// DiskFormat filters images based on the disk_format.
|
||||
// Multiple disk formats can be specified by constructing a string
|
||||
// such as "in:qcow2,iso".
|
||||
DiskFormat string `q:"disk_format"`
|
||||
}
|
||||
|
||||
// ToImageListQuery formats a ListOpts into a query string.
|
||||
func (opts ListOpts) ToImageListQuery() (string, error) {
|
||||
q, err := gophercloud.BuildQueryString(opts)
|
||||
params := q.Query()
|
||||
|
||||
if opts.CreatedAtQuery != nil {
|
||||
createdAt := opts.CreatedAtQuery.Date.Format(time.RFC3339)
|
||||
if v := opts.CreatedAtQuery.Filter; v != "" {
|
||||
createdAt = fmt.Sprintf("%s:%s", v, createdAt)
|
||||
}
|
||||
|
||||
params.Add("created_at", createdAt)
|
||||
}
|
||||
|
||||
if opts.UpdatedAtQuery != nil {
|
||||
updatedAt := opts.UpdatedAtQuery.Date.Format(time.RFC3339)
|
||||
if v := opts.UpdatedAtQuery.Filter; v != "" {
|
||||
updatedAt = fmt.Sprintf("%s:%s", v, updatedAt)
|
||||
}
|
||||
|
||||
params.Add("updated_at", updatedAt)
|
||||
}
|
||||
|
||||
q = &url.URL{RawQuery: params.Encode()}
|
||||
|
||||
return q.String(), err
|
||||
}
|
||||
|
||||
// List implements image list request.
|
||||
func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
|
||||
url := listURL(c)
|
||||
if opts != nil {
|
||||
query, err := opts.ToImageListQuery()
|
||||
if err != nil {
|
||||
return pagination.Pager{Err: err}
|
||||
}
|
||||
url += query
|
||||
}
|
||||
return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
|
||||
imagePage := ImagePage{
|
||||
serviceURL: c.ServiceURL(),
|
||||
LinkedPageBase: pagination.LinkedPageBase{PageResult: r},
|
||||
}
|
||||
|
||||
return imagePage
|
||||
})
|
||||
}
|
||||
|
||||
// CreateOptsBuilder allows extensions to add parameters to the Create request.
|
||||
type CreateOptsBuilder interface {
|
||||
// Returns value that can be passed to json.Marshal
|
||||
ToImageCreateMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// CreateOpts represents options used to create an image.
|
||||
type CreateOpts struct {
|
||||
// Name is the name of the new image.
|
||||
Name string `json:"name" required:"true"`
|
||||
|
||||
// Id is the the image ID.
|
||||
ID string `json:"id,omitempty"`
|
||||
|
||||
// Visibility defines who can see/use the image.
|
||||
Visibility *ImageVisibility `json:"visibility,omitempty"`
|
||||
|
||||
// Tags is a set of image tags.
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
|
||||
// ContainerFormat is the format of the
|
||||
// container. Valid values are ami, ari, aki, bare, and ovf.
|
||||
ContainerFormat string `json:"container_format,omitempty"`
|
||||
|
||||
// DiskFormat is the format of the disk. If set,
|
||||
// valid values are ami, ari, aki, vhd, vmdk, raw, qcow2, vdi,
|
||||
// and iso.
|
||||
DiskFormat string `json:"disk_format,omitempty"`
|
||||
|
||||
// MinDisk is the amount of disk space in
|
||||
// GB that is required to boot the image.
|
||||
MinDisk int `json:"min_disk,omitempty"`
|
||||
|
||||
// MinRAM is the amount of RAM in MB that
|
||||
// is required to boot the image.
|
||||
MinRAM int `json:"min_ram,omitempty"`
|
||||
|
||||
// protected is whether the image is not deletable.
|
||||
Protected *bool `json:"protected,omitempty"`
|
||||
|
||||
// properties is a set of properties, if any, that
|
||||
// are associated with the image.
|
||||
Properties map[string]string `json:"-"`
|
||||
}
|
||||
|
||||
// ToImageCreateMap assembles a request body based on the contents of
|
||||
// a CreateOpts.
|
||||
func (opts CreateOpts) ToImageCreateMap() (map[string]interface{}, error) {
|
||||
b, err := gophercloud.BuildRequestBody(opts, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if opts.Properties != nil {
|
||||
for k, v := range opts.Properties {
|
||||
b[k] = v
|
||||
}
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Create implements create image request.
|
||||
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||
b, err := opts.ToImageCreateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return r
|
||||
}
|
||||
_, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{OkCodes: []int{201}})
|
||||
return
|
||||
}
|
||||
|
||||
// Delete implements image delete request.
|
||||
func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||
_, r.Err = client.Delete(deleteURL(client, id), nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Get implements image get request.
|
||||
func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||
_, r.Err = client.Get(getURL(client, id), &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Update implements image updated request.
|
||||
func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
|
||||
b, err := opts.ToImageUpdateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return r
|
||||
}
|
||||
_, r.Err = client.Patch(updateURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
MoreHeaders: map[string]string{"Content-Type": "application/openstack-images-v2.1-json-patch"},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateOptsBuilder allows extensions to add additional parameters to the
|
||||
// Update request.
|
||||
type UpdateOptsBuilder interface {
|
||||
// returns value implementing json.Marshaler which when marshaled matches
|
||||
// the patch schema:
|
||||
// http://specs.openstack.org/openstack/glance-specs/specs/api/v2/http-patch-image-api-v2.html
|
||||
ToImageUpdateMap() ([]interface{}, error)
|
||||
}
|
||||
|
||||
// UpdateOpts implements UpdateOpts
|
||||
type UpdateOpts []Patch
|
||||
|
||||
// ToImageUpdateMap assembles a request body based on the contents of
|
||||
// UpdateOpts.
|
||||
func (opts UpdateOpts) ToImageUpdateMap() ([]interface{}, error) {
|
||||
m := make([]interface{}, len(opts))
|
||||
for i, patch := range opts {
|
||||
patchJSON := patch.ToImagePatchMap()
|
||||
m[i] = patchJSON
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Patch represents a single update to an existing image. Multiple updates
|
||||
// to an image can be submitted at the same time.
|
||||
type Patch interface {
|
||||
ToImagePatchMap() map[string]interface{}
|
||||
}
|
||||
|
||||
// UpdateVisibility represents an updated visibility property request.
|
||||
type UpdateVisibility struct {
|
||||
Visibility ImageVisibility
|
||||
}
|
||||
|
||||
// ToImagePatchMap assembles a request body based on UpdateVisibility.
|
||||
func (r UpdateVisibility) ToImagePatchMap() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"op": "replace",
|
||||
"path": "/visibility",
|
||||
"value": r.Visibility,
|
||||
}
|
||||
}
|
||||
|
||||
// ReplaceImageName represents an updated image_name property request.
|
||||
type ReplaceImageName struct {
|
||||
NewName string
|
||||
}
|
||||
|
||||
// ToImagePatchMap assembles a request body based on ReplaceImageName.
|
||||
func (r ReplaceImageName) ToImagePatchMap() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"op": "replace",
|
||||
"path": "/name",
|
||||
"value": r.NewName,
|
||||
}
|
||||
}
|
||||
|
||||
// ReplaceImageChecksum represents an updated checksum property request.
|
||||
type ReplaceImageChecksum struct {
|
||||
Checksum string
|
||||
}
|
||||
|
||||
// ReplaceImageChecksum assembles a request body based on ReplaceImageChecksum.
|
||||
func (r ReplaceImageChecksum) ToImagePatchMap() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"op": "replace",
|
||||
"path": "/checksum",
|
||||
"value": r.Checksum,
|
||||
}
|
||||
}
|
||||
|
||||
// ReplaceImageTags represents an updated tags property request.
|
||||
type ReplaceImageTags struct {
|
||||
NewTags []string
|
||||
}
|
||||
|
||||
// ToImagePatchMap assembles a request body based on ReplaceImageTags.
|
||||
func (r ReplaceImageTags) ToImagePatchMap() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"op": "replace",
|
||||
"path": "/tags",
|
||||
"value": r.NewTags,
|
||||
}
|
||||
}
|
||||
|
||||
// ReplaceImageMinDisk represents an updated min_disk property request.
|
||||
type ReplaceImageMinDisk struct {
|
||||
NewMinDisk int
|
||||
}
|
||||
|
||||
// ToImagePatchMap assembles a request body based on ReplaceImageTags.
|
||||
func (r ReplaceImageMinDisk) ToImagePatchMap() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"op": "replace",
|
||||
"path": "/min_disk",
|
||||
"value": r.NewMinDisk,
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateOp represents a valid update operation.
|
||||
type UpdateOp string
|
||||
|
||||
const (
|
||||
AddOp UpdateOp = "add"
|
||||
ReplaceOp UpdateOp = "replace"
|
||||
RemoveOp UpdateOp = "remove"
|
||||
)
|
||||
|
||||
// UpdateImageProperty represents an update property request.
|
||||
type UpdateImageProperty struct {
|
||||
Op UpdateOp
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
// ToImagePatchMap assembles a request body based on UpdateImageProperty.
|
||||
func (r UpdateImageProperty) ToImagePatchMap() map[string]interface{} {
|
||||
updateMap := map[string]interface{}{
|
||||
"op": r.Op,
|
||||
"path": fmt.Sprintf("/%s", r.Name),
|
||||
}
|
||||
|
||||
if r.Value != "" {
|
||||
updateMap["value"] = r.Value
|
||||
}
|
||||
|
||||
return updateMap
|
||||
}
|
202
vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/images/results.go
generated
vendored
Normal file
202
vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/images/results.go
generated
vendored
Normal file
|
@ -0,0 +1,202 @@
|
|||
package images
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/internal"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
// Image represents an image found in the OpenStack Image service.
|
||||
type Image struct {
|
||||
// ID is the image UUID.
|
||||
ID string `json:"id"`
|
||||
|
||||
// Name is the human-readable display name for the image.
|
||||
Name string `json:"name"`
|
||||
|
||||
// Status is the image status. It can be "queued" or "active"
|
||||
// See imageservice/v2/images/type.go
|
||||
Status ImageStatus `json:"status"`
|
||||
|
||||
// Tags is a list of image tags. Tags are arbitrarily defined strings
|
||||
// attached to an image.
|
||||
Tags []string `json:"tags"`
|
||||
|
||||
// ContainerFormat is the format of the container.
|
||||
// Valid values are ami, ari, aki, bare, and ovf.
|
||||
ContainerFormat string `json:"container_format"`
|
||||
|
||||
// DiskFormat is the format of the disk.
|
||||
// If set, valid values are ami, ari, aki, vhd, vmdk, raw, qcow2, vdi,
|
||||
// and iso.
|
||||
DiskFormat string `json:"disk_format"`
|
||||
|
||||
// MinDiskGigabytes is the amount of disk space in GB that is required to
|
||||
// boot the image.
|
||||
MinDiskGigabytes int `json:"min_disk"`
|
||||
|
||||
// MinRAMMegabytes [optional] is the amount of RAM in MB that is required to
|
||||
// boot the image.
|
||||
MinRAMMegabytes int `json:"min_ram"`
|
||||
|
||||
// Owner is the tenant ID the image belongs to.
|
||||
Owner string `json:"owner"`
|
||||
|
||||
// Protected is whether the image is deletable or not.
|
||||
Protected bool `json:"protected"`
|
||||
|
||||
// Visibility defines who can see/use the image.
|
||||
Visibility ImageVisibility `json:"visibility"`
|
||||
|
||||
// Checksum is the checksum of the data that's associated with the image.
|
||||
Checksum string `json:"checksum"`
|
||||
|
||||
// SizeBytes is the size of the data that's associated with the image.
|
||||
SizeBytes int64 `json:"-"`
|
||||
|
||||
// Metadata is a set of metadata associated with the image.
|
||||
// Image metadata allow for meaningfully define the image properties
|
||||
// and tags.
|
||||
// See http://docs.openstack.org/developer/glance/metadefs-concepts.html.
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
|
||||
// Properties is a set of key-value pairs, if any, that are associated with
|
||||
// the image.
|
||||
Properties map[string]interface{}
|
||||
|
||||
// CreatedAt is the date when the image has been created.
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
|
||||
// UpdatedAt is the date when the last change has been made to the image or
|
||||
// it's properties.
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
// File is the trailing path after the glance endpoint that represent the
|
||||
// location of the image or the path to retrieve it.
|
||||
File string `json:"file"`
|
||||
|
||||
// Schema is the path to the JSON-schema that represent the image or image
|
||||
// entity.
|
||||
Schema string `json:"schema"`
|
||||
|
||||
// VirtualSize is the virtual size of the image
|
||||
VirtualSize int64 `json:"virtual_size"`
|
||||
}
|
||||
|
||||
func (r *Image) UnmarshalJSON(b []byte) error {
|
||||
type tmp Image
|
||||
var s struct {
|
||||
tmp
|
||||
SizeBytes interface{} `json:"size"`
|
||||
}
|
||||
err := json.Unmarshal(b, &s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*r = Image(s.tmp)
|
||||
|
||||
switch t := s.SizeBytes.(type) {
|
||||
case nil:
|
||||
r.SizeBytes = 0
|
||||
case float32:
|
||||
r.SizeBytes = int64(t)
|
||||
case float64:
|
||||
r.SizeBytes = int64(t)
|
||||
default:
|
||||
return fmt.Errorf("Unknown type for SizeBytes: %v (value: %v)", reflect.TypeOf(t), t)
|
||||
}
|
||||
|
||||
// Bundle all other fields into Properties
|
||||
var result interface{}
|
||||
err = json.Unmarshal(b, &result)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resultMap, ok := result.(map[string]interface{}); ok {
|
||||
delete(resultMap, "self")
|
||||
delete(resultMap, "size")
|
||||
r.Properties = internal.RemainingKeys(Image{}, resultMap)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type commonResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// Extract interprets any commonResult as an Image.
|
||||
func (r commonResult) Extract() (*Image, error) {
|
||||
var s *Image
|
||||
err := r.ExtractInto(&s)
|
||||
return s, err
|
||||
}
|
||||
|
||||
// CreateResult represents the result of a Create operation. Call its Extract
|
||||
// method to interpret it as an Image.
|
||||
type CreateResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// UpdateResult represents the result of an Update operation. Call its Extract
|
||||
// method to interpret it as an Image.
|
||||
type UpdateResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// GetResult represents the result of a Get operation. Call its Extract
|
||||
// method to interpret it as an Image.
|
||||
type GetResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// DeleteResult represents the result of a Delete operation. Call its
|
||||
// ExtractErr method to interpret it as an Image.
|
||||
type DeleteResult struct {
|
||||
gophercloud.ErrResult
|
||||
}
|
||||
|
||||
// ImagePage represents the results of a List request.
|
||||
type ImagePage struct {
|
||||
serviceURL string
|
||||
pagination.LinkedPageBase
|
||||
}
|
||||
|
||||
// IsEmpty returns true if an ImagePage contains no Images results.
|
||||
func (r ImagePage) IsEmpty() (bool, error) {
|
||||
images, err := ExtractImages(r)
|
||||
return len(images) == 0, err
|
||||
}
|
||||
|
||||
// NextPageURL uses the response's embedded link reference to navigate to
|
||||
// the next page of results.
|
||||
func (r ImagePage) NextPageURL() (string, error) {
|
||||
var s struct {
|
||||
Next string `json:"next"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if s.Next == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return nextPageURL(r.serviceURL, s.Next)
|
||||
}
|
||||
|
||||
// ExtractImages interprets the results of a single page from a List() call,
|
||||
// producing a slice of Image entities.
|
||||
func ExtractImages(r pagination.Page) ([]Image, error) {
|
||||
var s struct {
|
||||
Images []Image `json:"images"`
|
||||
}
|
||||
err := (r.(ImagePage)).ExtractInto(&s)
|
||||
return s.Images, err
|
||||
}
|
104
vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/images/types.go
generated
vendored
Normal file
104
vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/images/types.go
generated
vendored
Normal file
|
@ -0,0 +1,104 @@
|
|||
package images
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// ImageStatus image statuses
|
||||
// http://docs.openstack.org/developer/glance/statuses.html
|
||||
type ImageStatus string
|
||||
|
||||
const (
|
||||
// ImageStatusQueued is a status for an image which identifier has
|
||||
// been reserved for an image in the image registry.
|
||||
ImageStatusQueued ImageStatus = "queued"
|
||||
|
||||
// ImageStatusSaving denotes that an image’s raw data is currently being
|
||||
// uploaded to Glance
|
||||
ImageStatusSaving ImageStatus = "saving"
|
||||
|
||||
// ImageStatusActive denotes an image that is fully available in Glance.
|
||||
ImageStatusActive ImageStatus = "active"
|
||||
|
||||
// ImageStatusKilled denotes that an error occurred during the uploading
|
||||
// of an image’s data, and that the image is not readable.
|
||||
ImageStatusKilled ImageStatus = "killed"
|
||||
|
||||
// ImageStatusDeleted is used for an image that is no longer available to use.
|
||||
// The image information is retained in the image registry.
|
||||
ImageStatusDeleted ImageStatus = "deleted"
|
||||
|
||||
// ImageStatusPendingDelete is similar to Delete, but the image is not yet
|
||||
// deleted.
|
||||
ImageStatusPendingDelete ImageStatus = "pending_delete"
|
||||
|
||||
// ImageStatusDeactivated denotes that access to image data is not allowed to
|
||||
// any non-admin user.
|
||||
ImageStatusDeactivated ImageStatus = "deactivated"
|
||||
)
|
||||
|
||||
// ImageVisibility denotes an image that is fully available in Glance.
|
||||
// This occurs when the image data is uploaded, or the image size is explicitly
|
||||
// set to zero on creation.
|
||||
// According to design
|
||||
// https://wiki.openstack.org/wiki/Glance-v2-community-image-visibility-design
|
||||
type ImageVisibility string
|
||||
|
||||
const (
|
||||
// ImageVisibilityPublic all users
|
||||
ImageVisibilityPublic ImageVisibility = "public"
|
||||
|
||||
// ImageVisibilityPrivate users with tenantId == tenantId(owner)
|
||||
ImageVisibilityPrivate ImageVisibility = "private"
|
||||
|
||||
// ImageVisibilityShared images are visible to:
|
||||
// - users with tenantId == tenantId(owner)
|
||||
// - users with tenantId in the member-list of the image
|
||||
// - users with tenantId in the member-list with member_status == 'accepted'
|
||||
ImageVisibilityShared ImageVisibility = "shared"
|
||||
|
||||
// ImageVisibilityCommunity images:
|
||||
// - all users can see and boot it
|
||||
// - users with tenantId in the member-list of the image with
|
||||
// member_status == 'accepted' have this image in their default image-list.
|
||||
ImageVisibilityCommunity ImageVisibility = "community"
|
||||
)
|
||||
|
||||
// MemberStatus is a status for adding a new member (tenant) to an image
|
||||
// member list.
|
||||
type ImageMemberStatus string
|
||||
|
||||
const (
|
||||
// ImageMemberStatusAccepted is the status for an accepted image member.
|
||||
ImageMemberStatusAccepted ImageMemberStatus = "accepted"
|
||||
|
||||
// ImageMemberStatusPending shows that the member addition is pending
|
||||
ImageMemberStatusPending ImageMemberStatus = "pending"
|
||||
|
||||
// ImageMemberStatusAccepted is the status for a rejected image member
|
||||
ImageMemberStatusRejected ImageMemberStatus = "rejected"
|
||||
|
||||
// ImageMemberStatusAll
|
||||
ImageMemberStatusAll ImageMemberStatus = "all"
|
||||
)
|
||||
|
||||
// ImageDateFilter represents a valid filter to use for filtering
|
||||
// images by their date during a List.
|
||||
type ImageDateFilter string
|
||||
|
||||
const (
|
||||
FilterGT ImageDateFilter = "gt"
|
||||
FilterGTE ImageDateFilter = "gte"
|
||||
FilterLT ImageDateFilter = "lt"
|
||||
FilterLTE ImageDateFilter = "lte"
|
||||
FilterNEQ ImageDateFilter = "neq"
|
||||
FilterEQ ImageDateFilter = "eq"
|
||||
)
|
||||
|
||||
// ImageDateQuery represents a date field to be used for listing images.
|
||||
// If no filter is specified, the query will act as though FilterEQ was
|
||||
// set.
|
||||
type ImageDateQuery struct {
|
||||
Date time.Time
|
||||
Filter ImageDateFilter
|
||||
}
|
65
vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/images/urls.go
generated
vendored
Normal file
65
vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/images/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
package images
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/openstack/utils"
|
||||
)
|
||||
|
||||
// `listURL` is a pure function. `listURL(c)` is a URL for which a GET
|
||||
// request will respond with a list of images in the service `c`.
|
||||
func listURL(c *gophercloud.ServiceClient) string {
|
||||
return c.ServiceURL("images")
|
||||
}
|
||||
|
||||
func createURL(c *gophercloud.ServiceClient) string {
|
||||
return c.ServiceURL("images")
|
||||
}
|
||||
|
||||
// `imageURL(c,i)` is the URL for the image identified by ID `i` in
|
||||
// the service `c`.
|
||||
func imageURL(c *gophercloud.ServiceClient, imageID string) string {
|
||||
return c.ServiceURL("images", imageID)
|
||||
}
|
||||
|
||||
// `getURL(c,i)` is a URL for which a GET request will respond with
|
||||
// information about the image identified by ID `i` in the service
|
||||
// `c`.
|
||||
func getURL(c *gophercloud.ServiceClient, imageID string) string {
|
||||
return imageURL(c, imageID)
|
||||
}
|
||||
|
||||
func updateURL(c *gophercloud.ServiceClient, imageID string) string {
|
||||
return imageURL(c, imageID)
|
||||
}
|
||||
|
||||
func deleteURL(c *gophercloud.ServiceClient, imageID string) string {
|
||||
return imageURL(c, imageID)
|
||||
}
|
||||
|
||||
// builds next page full url based on current url
|
||||
func nextPageURL(serviceURL, requestedNext string) (string, error) {
|
||||
base, err := utils.BaseEndpoint(serviceURL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
requestedNextURL, err := url.Parse(requestedNext)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
base = gophercloud.NormalizeURL(base)
|
||||
nextPath := base + strings.TrimPrefix(requestedNextURL.Path, "/")
|
||||
|
||||
nextURL, err := url.Parse(nextPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
nextURL.RawQuery = requestedNextURL.RawQuery
|
||||
|
||||
return nextURL.String(), nil
|
||||
}
|
|
@ -252,9 +252,11 @@ github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips
|
|||
github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs
|
||||
github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups
|
||||
github.com/gophercloud/gophercloud/openstack/compute/v2/flavors
|
||||
github.com/gophercloud/gophercloud/openstack/imageservice/v2/images
|
||||
github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/listeners
|
||||
github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/pools
|
||||
github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external
|
||||
github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume
|
||||
github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/schedulerhints
|
||||
github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers
|
||||
github.com/gophercloud/gophercloud/openstack/objectstorage/v1/objects
|
||||
|
@ -262,6 +264,7 @@ github.com/gophercloud/gophercloud/openstack/identity/v2/tokens
|
|||
github.com/gophercloud/gophercloud/openstack/identity/v3/tokens
|
||||
github.com/gophercloud/gophercloud/openstack/utils
|
||||
github.com/gophercloud/gophercloud/openstack/compute/v2/images
|
||||
github.com/gophercloud/gophercloud/internal
|
||||
github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/l7policies
|
||||
github.com/gophercloud/gophercloud/openstack/objectstorage/v1/accounts
|
||||
github.com/gophercloud/gophercloud/openstack/identity/v2/tenants
|
||||
|
|
Loading…
Reference in New Issue