From ed4d6c534a992c6fb1d6d688c9e047a390061693 Mon Sep 17 00:00:00 2001 From: Stephen Benjamin Date: Tue, 21 May 2019 09:28:18 -0400 Subject: [PATCH] vendor: update terraform-provider-ironic to v0.1.2 This updates terraform-provider-ironic to the latest version, which supports terraform 0.12. We'll need this for the next rebase. This release of the ironic provider also enables inspection and cleaning explicitly on the masters, and it sets instance_uuid correctly in Ironic. Due to gophercloud being updated, terraform-provider-openstack is being pulled from master which has the changes needed to make it compatible with the latest gophercloud. When terraform-provider-openstack 1.19 is released, we can pin to that released version. --- data/data/baremetal/main.tf | 2 +- data/data/baremetal/masters/main.tf | 52 ++- data/data/baremetal/masters/variables.tf | 19 +- pkg/terraform/exec/plugins/Gopkg.lock | 23 +- pkg/terraform/exec/plugins/Gopkg.toml | 6 +- .../github.com/gophercloud/gophercloud/doc.go | 63 ++- .../openstack/baremetal/noauth/doc.go | 5 +- .../baremetal/v1/allocations/requests.go | 131 ++++++ .../baremetal/v1/allocations/results.go | 114 +++++ .../baremetal/v1/allocations/urls.go | 23 + .../openstack/baremetal/v1/nodes/doc.go | 79 +++- .../openstack/baremetal/v1/nodes/requests.go | 200 ++++++--- .../openstack/baremetal/v1/nodes/urls.go | 4 + .../openstack/baremetal/v1/ports/doc.go | 42 +- .../openstack/baremetal/v1/ports/requests.go | 7 +- .../v2/extensions/keypairs/requests.go | 2 +- .../containerinfra/v1/clusters/requests.go | 37 ++ .../containerinfra/v1/clusters/results.go | 5 + .../containerinfra/v1/clusters/urls.go | 4 + .../openstack/dns/v2/recordsets/requests.go | 17 +- .../v3/applicationcredentials/requests.go | 95 +++++ .../v3/applicationcredentials/results.go | 127 ++++++ .../v3/applicationcredentials/urls.go | 19 + .../networking/v2/extensions/dns/requests.go | 171 ++++++++ .../networking/v2/extensions/dns/results.go | 30 ++ .../networking/v2/extensions/mtu/requests.go | 87 ++++ .../networking/v2/extensions/mtu/results.go | 8 + .../v2/extensions/portsbinding/doc.go | 3 + .../v2/extensions/portsbinding/requests.go | 91 ++++ .../v2/extensions/portsbinding/results.go | 24 ++ .../v2/extensions/portsecurity/doc.go | 145 +++++++ .../v2/extensions/portsecurity/requests.go | 104 +++++ .../v2/extensions/portsecurity/results.go | 7 + .../openstack/networking/v2/networks/doc.go | 3 +- .../networking/v2/networks/requests.go | 2 +- .../openstack/networking/v2/subnets/doc.go | 6 +- .../networking/v2/subnets/requests.go | 4 +- .../objectstorage/v1/containers/doc.go | 3 + .../objectstorage/v1/containers/requests.go | 7 + .../sharedfilesystems/apiversions/doc.go | 3 + .../sharedfilesystems/apiversions/errors.go | 23 + .../sharedfilesystems/apiversions/requests.go | 19 + .../sharedfilesystems/apiversions/results.go | 73 ++++ .../sharedfilesystems/apiversions/urls.go | 20 + .../v2/availabilityzones/requests.go | 13 + .../v2/availabilityzones/results.go | 59 +++ .../v2/availabilityzones/urls.go | 7 + .../ironic/provider.go | 8 +- .../ironic/resource_ironic_allocation_v1.go | 170 ++++++++ .../ironic/resource_ironic_deployment.go | 117 +++++ .../ironic/resource_ironic_node_v1.go | 403 ++++++------------ .../ironic/workflow.go | 294 +++++++++++++ ...tack_blockstorage_availability_zones_v3.go | 73 ++++ ...source_openstack_identity_auth_scope_v3.go | 2 +- ...ce_openstack_networking_addressscope_v2.go | 101 +++++ ...urce_openstack_networking_floatingip_v2.go | 18 +- ..._source_openstack_networking_network_v2.go | 30 +- ...source_openstack_networking_port_ids_v2.go | 19 +- ...ata_source_openstack_networking_port_v2.go | 75 +++- ...ta_source_openstack_networking_trunk_v2.go | 185 ++++++++ ..._sharedfilesystem_availability_zones_v2.go | 62 +++ .../openstack/db_configuration_v1.go | 55 +++ .../openstack/db_database_v1.go | 58 +++ .../openstack/db_instance_v1.go | 99 +++++ .../openstack/db_user_v1.go | 81 ++++ .../openstack/fw_policy_v1.go | 12 +- .../identity_application_credential_v3.go | 21 + .../openstack/lb_v2_shared.go | 6 +- .../openstack/networking_floatingip_v2.go | 6 + .../openstack/networking_network_v2.go | 21 +- .../openstack/networking_port_v2.go | 146 +++++-- .../networking_router_interface_v2.go | 8 +- .../openstack/networking_router_route_v2.go | 25 ++ .../openstack/networking_secgroup_rule_v2.go | 102 +++++ .../openstack/networking_subnet_v2.go | 31 ++ .../openstack/networking_subnetpool_v2.go | 6 +- .../openstack/provider.go | 59 +-- ...source_openstack_blockstorage_volume_v1.go | 6 +- ...source_openstack_blockstorage_volume_v2.go | 6 +- ...source_openstack_blockstorage_volume_v3.go | 6 +- .../resource_openstack_compute_instance_v2.go | 2 +- ...rce_openstack_containerinfra_cluster_v1.go | 2 +- .../resource_openstack_db_configuration_v1.go | 94 ++-- .../resource_openstack_db_database_v1.go | 98 ++--- .../resource_openstack_db_instance_v1.go | 153 ++----- .../resource_openstack_db_user_v1.go | 121 ++---- .../resource_openstack_dns_recordset_v2.go | 3 +- ...tack_identity_application_credential_v3.go | 191 +++++++++ .../resource_openstack_lb_monitor_v1.go | 16 +- ...tack_networking_floatingip_associate_v2.go | 55 ++- ...urce_openstack_networking_floatingip_v2.go | 52 ++- ...esource_openstack_networking_network_v2.go | 121 ++++-- .../resource_openstack_networking_port_v2.go | 267 +++++++++--- ...ce_openstack_networking_router_route_v2.go | 184 ++++---- ...e_openstack_networking_secgroup_rule_v2.go | 195 +++------ ...source_openstack_networking_secgroup_v2.go | 6 +- ...resource_openstack_networking_subnet_v2.go | 145 ++++++- ...ce_openstack_objectstorage_container_v1.go | 4 +- ...nstack_sharedfilesystem_share_access_v2.go | 48 ++- ...source_openstack_vpnaas_ipsec_policy_v2.go | 6 +- .../openstack/types.go | 15 +- .../openstack/util.go | 75 +++- 102 files changed, 4816 insertions(+), 1336 deletions(-) create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/allocations/requests.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/allocations/results.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/allocations/urls.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/requests.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/results.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/urls.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/dns/requests.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/dns/results.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/mtu/requests.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/mtu/results.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsbinding/doc.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsbinding/requests.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsbinding/results.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/doc.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/requests.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/results.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/doc.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/errors.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/requests.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/results.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/urls.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/availabilityzones/requests.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/availabilityzones/results.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/availabilityzones/urls.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/resource_ironic_allocation_v1.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/resource_ironic_deployment.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/workflow.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_blockstorage_availability_zones_v3.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_addressscope_v2.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_trunk_v2.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_sharedfilesystem_availability_zones_v2.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/db_configuration_v1.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/db_database_v1.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/db_instance_v1.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/db_user_v1.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/identity_application_credential_v3.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_router_route_v2.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_secgroup_rule_v2.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_subnet_v2.go create mode 100644 pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_identity_application_credential_v3.go diff --git a/data/data/baremetal/main.tf b/data/data/baremetal/main.tf index 0761d9406..577481760 100644 --- a/data/data/baremetal/main.tf +++ b/data/data/baremetal/main.tf @@ -4,7 +4,7 @@ provider "libvirt" { provider "ironic" { url = "${var.ironic_uri}" - microversion = "1.50" + microversion = "1.52" } module "bootstrap" { diff --git a/data/data/baremetal/masters/main.tf b/data/data/baremetal/masters/main.tf index 7d369d79a..578e9ba02 100644 --- a/data/data/baremetal/masters/main.tf +++ b/data/data/baremetal/masters/main.tf @@ -1,31 +1,49 @@ -resource "ironic_node_v1" "openshift-master" { - count = "${length(keys(var.master_nodes))}" - name = "${lookup(var.master_nodes[format("openshift-master-%d", count.index)], "name")}" +resource "ironic_node_v1" "openshift-master-node" { + count = "${length(keys(var.master_nodes))}" + name = "${lookup(var.master_nodes[format("openshift-master-%d", count.index)], "name")}" + resource_class = "baremetal" - target_provision_state = "active" - user_data = "${var.ignition}" - - root_device = "${var.root_devices[format("openshift-master-%d", count.index)]}" - driver = "${lookup(var.master_nodes[format("openshift-master-%d", count.index)], "driver")}" - driver_info = "${var.driver_infos[format("openshift-master-%d", count.index)]}" + inspect = true + clean = true + available = true ports = [ { - address = "${lookup(var.master_nodes[format("openshift-master-%d", count.index)], "port_address")}" + address = "${lookup(var.master_nodes[format("openshift-master-%d", count.index)], "port_address")}" pxe_enabled = "true" }, ] - properties = "${var.properties[format("openshift-master-%d", count.index)]}" + properties = "${var.properties[format("openshift-master-%d", count.index)]}" + root_device = "${var.root_devices[format("openshift-master-%d", count.index)]}" + + driver = "${lookup(var.master_nodes[format("openshift-master-%d", count.index)], "driver")}" + driver_info = "${var.driver_infos[format("openshift-master-%d", count.index)]}" + + management_interface = "${lookup(var.master_nodes[format("openshift-master-%d", count.index)], "management_interface")}" + power_interface = "${lookup(var.master_nodes[format("openshift-master-%d", count.index)], "power_interface")}" + vendor_interface = "${lookup(var.master_nodes[format("openshift-master-%d", count.index)], "vendor_interface")}" +} + +resource "ironic_allocation_v1" "openshift-master-allocation" { + name = "master-${count.index}" + count = 3 + resource_class = "baremetal" + + candidate_nodes = [ + "${ironic_node_v1.openshift-master-node.*.id}", + ] +} + +resource "ironic_deployment" "openshift-master-deployment" { + count = 3 + node_uuid = "${element(ironic_allocation_v1.openshift-master-allocation.*.node_uuid, count.index)}" instance_info = { - image_source = "${var.image_source}" + image_source = "${var.image_source}" image_checksum = "${var.image_checksum}" - root_gb = "${var.root_gb}" + root_gb = "${var.root_gb}" } - management_interface = "${lookup(var.master_nodes[format("openshift-master-%d", count.index)], "management_interface")}" - power_interface = "${lookup(var.master_nodes[format("openshift-master-%d", count.index)], "power_interface")}" - vendor_interface = "${lookup(var.master_nodes[format("openshift-master-%d", count.index)], "vendor_interface")}" - + user_data = "${var.ignition}" } diff --git a/data/data/baremetal/masters/variables.tf b/data/data/baremetal/masters/variables.tf index 5f6659edc..82a5acb8e 100644 --- a/data/data/baremetal/masters/variables.tf +++ b/data/data/baremetal/masters/variables.tf @@ -1,45 +1,44 @@ variable "image_source" { description = "The URL of the OS disk image" - type = "string" + type = "string" } variable "image_checksum" { - type = "string" + type = "string" description = "The URL or checksum value of the image" } variable "root_gb" { - type = "string" + type = "string" description = "Size of the root disk" } variable "root_disk" { - type = "string" + type = "string" description = "Location of the root disk" } variable "ignition" { - type = "string" + type = "string" description = "The content of the master ignition file" } variable "master_nodes" { - type = "map" + type = "map" description = "Master bare metal node details" } variable "properties" { - type = "map" + type = "map" description = "Master bare metal properties" } variable "root_devices" { - type = "map" + type = "map" description = "Master root device configuration" } variable "driver_infos" { - type = "map" + type = "map" description = "Master driver info" } - diff --git a/pkg/terraform/exec/plugins/Gopkg.lock b/pkg/terraform/exec/plugins/Gopkg.lock index a0cebdada..124262808 100644 --- a/pkg/terraform/exec/plugins/Gopkg.lock +++ b/pkg/terraform/exec/plugins/Gopkg.lock @@ -415,13 +415,14 @@ version = "v1.1.1" [[projects]] - digest = "1:add9b9283890d79acb5b2e8b00e7a7596bb5fba7257215bec1e86d389b6b2a1a" + digest = "1:594c8c18e2da9a55a0743cf8f7f9255c26b89a78e50ce4bcf0a81b76d2853916" name = "github.com/gophercloud/gophercloud" packages = [ ".", "internal", "openstack", "openstack/baremetal/noauth", + "openstack/baremetal/v1/allocations", "openstack/baremetal/v1/nodes", "openstack/baremetal/v1/ports", "openstack/blockstorage/extensions/volumeactions", @@ -455,6 +456,7 @@ "openstack/dns/v2/zones", "openstack/identity/v2/tenants", "openstack/identity/v2/tokens", + "openstack/identity/v3/applicationcredentials", "openstack/identity/v3/endpoints", "openstack/identity/v3/groups", "openstack/identity/v3/projects", @@ -465,6 +467,7 @@ "openstack/imageservice/v2/imagedata", "openstack/imageservice/v2/images", "openstack/networking/v2/extensions/attributestags", + "openstack/networking/v2/extensions/dns", "openstack/networking/v2/extensions/external", "openstack/networking/v2/extensions/extradhcpopts", "openstack/networking/v2/extensions/fwaas/firewalls", @@ -483,6 +486,9 @@ "openstack/networking/v2/extensions/lbaas_v2/loadbalancers", "openstack/networking/v2/extensions/lbaas_v2/monitors", "openstack/networking/v2/extensions/lbaas_v2/pools", + "openstack/networking/v2/extensions/mtu", + "openstack/networking/v2/extensions/portsbinding", + "openstack/networking/v2/extensions/portsecurity", "openstack/networking/v2/extensions/provider", "openstack/networking/v2/extensions/security/groups", "openstack/networking/v2/extensions/security/rules", @@ -501,6 +507,8 @@ "openstack/objectstorage/v1/containers", "openstack/objectstorage/v1/objects", "openstack/objectstorage/v1/swauth", + "openstack/sharedfilesystems/apiversions", + "openstack/sharedfilesystems/v2/availabilityzones", "openstack/sharedfilesystems/v2/errors", "openstack/sharedfilesystems/v2/messages", "openstack/sharedfilesystems/v2/securityservices", @@ -511,7 +519,7 @@ "pagination", ] pruneopts = "NUT" - revision = "ff9851476e985a4f27ed846d6babd7b24b763da5" + revision = "7892efa714f10951c5483a28c7471d8051b12975" [[projects]] branch = "master" @@ -704,11 +712,12 @@ version = "v1.0.0" [[projects]] - digest = "1:1bf1fef73c9218824f6ea795bab09e0af6ace7527757eb5b4cd71becfa9a2fa6" + digest = "1:a134ebe9bd265156f476db135a9d65e8474a416b70a3849ad06bbebde984b4a0" name = "github.com/openshift-metalkube/terraform-provider-ironic" packages = ["ironic"] pruneopts = "NUT" - revision = "0538d0a8b33df2c112857649021c558d6375d2c8" + revision = "cce53c4cd7024e50b99cec489145f83d360752de" + version = "v0.1.2" [[projects]] digest = "1:6bc0652ea6e39e22ccd522458b8bdd8665bf23bdc5a20eec90056e4dc7e273ca" @@ -770,12 +779,12 @@ version = "v1.2.1" [[projects]] - digest = "1:e1c03b9be47df81a131b46c7c9879acecadf4590a5efe3f70c7e959183e94aec" + branch = "master" + digest = "1:f3ae869d0de02432e1d3f96e898624db97a9f3fcb5adcb18bf84e2a3cfe45e5f" name = "github.com/terraform-providers/terraform-provider-openstack" packages = ["openstack"] pruneopts = "NUT" - revision = "c3ed4eb64be2b0e31f560a3118e72deafd750e1b" - version = "v1.16.0" + revision = "b1406b8e4894faad993aff786f0bb50bfec8e281" [[projects]] digest = "1:31a7f8bae17ec284242aa6c319a5119619342ec8ecc7984214d04b4efb4860c4" diff --git a/pkg/terraform/exec/plugins/Gopkg.toml b/pkg/terraform/exec/plugins/Gopkg.toml index ac908e43b..2fc92085c 100644 --- a/pkg/terraform/exec/plugins/Gopkg.toml +++ b/pkg/terraform/exec/plugins/Gopkg.toml @@ -31,7 +31,7 @@ ignored = [ [[constraint]] name = "github.com/terraform-providers/terraform-provider-openstack" - version = "=1.16.0" + branch = "master" # FIXME: Update to 1.19 when it comes out [[override]] name = "github.com/coreos/ignition" @@ -39,7 +39,7 @@ ignored = [ [[override]] name = "github.com/gophercloud/gophercloud" - revision = "ff9851476e985a4f27ed846d6babd7b24b763da5" + revision = "7892efa714f10951c5483a28c7471d8051b12975" [[constraint]] name = "github.com/terraform-providers/terraform-provider-azurerm" @@ -63,4 +63,4 @@ ignored = [ [[constraint]] name = "github.com/openshift-metalkube/terraform-provider-ironic" - revision = "0538d0a8b33df2c112857649021c558d6375d2c8" + version = "v0.1.2" diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/doc.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/doc.go index 131cc8e30..953ca822a 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/doc.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/doc.go @@ -9,20 +9,37 @@ Provider structs represent the cloud providers that offer and manage a collection of services. You will generally want to create one Provider client per OpenStack cloud. + It is now recommended to use the `clientconfig` package found at + https://github.com/gophercloud/utils/tree/master/openstack/clientconfig + for all authentication purposes. + + The below documentation is still relevant. clientconfig simply implements + the below and presents it in an easier and more flexible way. + Use your OpenStack credentials to create a Provider client. The IdentityEndpoint is typically refered to as "auth_url" or "OS_AUTH_URL" in information provided by the cloud operator. Additionally, the cloud may refer to TenantID or TenantName as project_id and project_name. Credentials are specified like so: - opts := gophercloud.AuthOptions{ - IdentityEndpoint: "https://openstack.example.com:5000/v2.0", - Username: "{username}", - Password: "{password}", - TenantID: "{tenant_id}", - } + opts := gophercloud.AuthOptions{ + IdentityEndpoint: "https://openstack.example.com:5000/v2.0", + Username: "{username}", + Password: "{password}", + TenantID: "{tenant_id}", + } + + provider, err := openstack.AuthenticatedClient(opts) - provider, err := openstack.AuthenticatedClient(opts) +You can authenticate with a token by doing: + + opts := gophercloud.AuthOptions{ + IdentityEndpoint: "https://openstack.example.com:5000/v2.0", + TokenID: "{token_id}", + TenantID: "{tenant_id}", + } + + provider, err := openstack.AuthenticatedClient(opts) You may also use the openstack.AuthOptionsFromEnv() helper function. This function reads in standard environment variables frequently found in an @@ -39,16 +56,16 @@ operations for a particular OpenStack service. Examples of services include: Compute, Object Storage, Block Storage. In order to define one, you need to pass in the parent provider, like so: - opts := gophercloud.EndpointOpts{Region: "RegionOne"} + opts := gophercloud.EndpointOpts{Region: "RegionOne"} - client, err := openstack.NewComputeV2(provider, opts) + client, err := openstack.NewComputeV2(provider, opts) Resources Resource structs are the domain models that services make use of in order to work with and represent the state of API resources: - server, err := servers.Get(client, "{serverId}").Extract() + server, err := servers.Get(client, "{serverId}").Extract() Intermediate Result structs are returned for API operations, which allow generic access to the HTTP headers, response body, and any errors associated @@ -56,11 +73,11 @@ with the network transaction. To turn a result into a usable resource struct, you must call the Extract method which is chained to the response, or an Extract function from an applicable extension: - result := servers.Get(client, "{serverId}") + result := servers.Get(client, "{serverId}") - // Attempt to extract the disk configuration from the OS-DCF disk config - // extension: - config, err := diskconfig.ExtractGet(result) + // Attempt to extract the disk configuration from the OS-DCF disk config + // extension: + config, err := diskconfig.ExtractGet(result) All requests that enumerate a collection return a Pager struct that is used to iterate through the results one page at a time. Use the EachPage method on that @@ -68,17 +85,17 @@ Pager to handle each successive Page in a closure, then use the appropriate extraction method from that request's package to interpret that Page as a slice of results: - err := servers.List(client, nil).EachPage(func (page pagination.Page) (bool, error) { - s, err := servers.ExtractServers(page) - if err != nil { - return false, err - } + err := servers.List(client, nil).EachPage(func (page pagination.Page) (bool, error) { + s, err := servers.ExtractServers(page) + if err != nil { + return false, err + } - // Handle the []servers.Server slice. + // Handle the []servers.Server slice. - // Return "false" or an error to prematurely stop fetching new pages. - return true, nil - }) + // Return "false" or an error to prematurely stop fetching new pages. + return true, nil + }) If you want to obtain the entire collection of pages without doing any intermediary processing on each page, you can use the AllPages method: diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/noauth/doc.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/noauth/doc.go index 64106fc6b..9f83357b2 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/noauth/doc.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/noauth/doc.go @@ -1,9 +1,7 @@ -package noauth - /* Package noauth provides support for noauth bare metal endpoints. - Example of obtaining and using a client: +Example of obtaining and using a client: client, err := noauth.NewBareMetalNoAuth(noauth.EndpointOpts{ IronicEndpoint: "http://localhost:6385/v1/", @@ -16,3 +14,4 @@ Package noauth provides support for noauth bare metal endpoints. nodes.ListDetail(client, nodes.ListOpts{}) */ +package noauth diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/allocations/requests.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/allocations/requests.go new file mode 100644 index 000000000..7acb0021a --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/allocations/requests.go @@ -0,0 +1,131 @@ +package allocations + +import ( + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/pagination" +) + +// CreateOptsBuilder allows extensions to add additional parameters to the +// Create request. +type CreateOptsBuilder interface { + ToAllocationCreateMap() (map[string]interface{}, error) +} + +// CreateOpts specifies allocation creation parameters +type CreateOpts struct { + // The requested resource class for the allocation. + ResourceClass string `json:"resource_class" required:"true"` + + // The list of nodes (names or UUIDs) that should be considered for this allocation. If not provided, all available nodes will be considered. + CandidateNodes []string `json:"candidate_nodes,omitempty"` + + // The unique name of the Allocation. + Name string `json:"name,omitempty"` + + // The list of requested traits for the allocation. + Traits []string `json:"traits,omitempty"` + + // The UUID for the resource. + UUID string `json:"uuid,omitempty"` + + // A set of one or more arbitrary metadata key and value pairs. + Extra map[string]string `json:"extra,omitempty"` +} + +// ToAllocationCreateMap assembles a request body based on the contents of a CreateOpts. +func (opts CreateOpts) ToAllocationCreateMap() (map[string]interface{}, error) { + body, err := gophercloud.BuildRequestBody(opts, "") + if err != nil { + return nil, err + } + + return body, nil +} + +// Create requests a node to be created +func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { + reqBody, err := opts.ToAllocationCreateMap() + if err != nil { + r.Err = err + return + } + + _, r.Err = client.Post(createURL(client), reqBody, &r.Body, nil) + return +} + +type AllocationState string + +var ( + Allocating AllocationState = "allocating" + Active = "active" + Error = "error" +) + +// ListOptsBuilder allows extensions to add additional parameters to the List request. +type ListOptsBuilder interface { + ToAllocationListQuery() (string, error) +} + +// ListOpts allows the filtering and sorting of paginated collections through the API. +type ListOpts struct { + // Filter the list of allocations by the node UUID or name. + Node string `q:"node"` + + // Filter the list of returned nodes, and only return the ones with the specified resource class. + ResourceClass string `q:"resource_class"` + + // Filter the list of allocations by the allocation state, one of active, allocating or error. + State AllocationState `q:"state"` + + // One or more fields to be returned in the response. + Fields []string `q:"fields"` + + // Requests a page size of items. + Limit int `q:"limit"` + + // The ID of the last-seen item + Marker string `q:"marker"` + + // Sorts the response by the requested sort direction. + // Valid value is asc (ascending) or desc (descending). Default is asc. + SortDir string `q:"sort_dir"` + + // Sorts the response by the this attribute value. Default is id. + SortKey string `q:"sort_key"` +} + +// ToAllocationListQuery formats a ListOpts into a query string. +func (opts ListOpts) ToAllocationListQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts) + return q.String(), err +} + +// List makes a request against the API to list allocations accessible to you. +func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { + url := listURL(client) + if opts != nil { + query, err := opts.ToAllocationListQuery() + if err != nil { + return pagination.Pager{Err: err} + } + url += query + } + return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { + return AllocationPage{pagination.LinkedPageBase{PageResult: r}} + }) +} + +// Get requests the details of an allocation 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}, + }) + return +} + +// Delete requests the deletion of an allocation +func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) { + _, r.Err = client.Delete(deleteURL(client, id), nil) + return +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/allocations/results.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/allocations/results.go new file mode 100644 index 000000000..cbd211552 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/allocations/results.go @@ -0,0 +1,114 @@ +package allocations + +import ( + "time" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/pagination" +) + +type Allocation struct { + // The UUID for the resource. + UUID string `json:"uuid"` + + // A list of UUIDs of the nodes that are candidates for this allocation. + CandidateNodes []string `json:"candidate_nodes"` + + // The error message for the allocation if it is in the error state, null otherwise. + LastError string `json:"last_error"` + + // The unique name of the allocation. + Name string `json:"name"` + + // The UUID of the node assigned to the allocation. Will be null if a node is not yet assigned. + NodeUUID string `json:"node_uuid"` + + // The current state of the allocation. One of: allocation, active, error + State string `json:"state"` + + // The resource class requested for the allocation. + ResourceClass string `json:"resource_class"` + + // The list of the traits requested for the allocation. + Traits []string `json:"traits"` + + // A set of one or more arbitrary metadata key and value pairs. + Extra map[string]string `json:"extra"` + + // The UTC date and time when the resource was created, ISO 8601 format. + CreatedAt time.Time `json:"created_at"` + + // The UTC date and time when the resource was updated, ISO 8601 format. May be “null”. + UpdatedAt time.Time `json:"updated_at"` + + // A list of relative links. Includes the self and bookmark links. + Links []interface{} `json:"links"` +} + +type allocationResult struct { + gophercloud.Result +} + +func (r allocationResult) Extract() (*Allocation, error) { + var s Allocation + err := r.ExtractInto(&s) + return &s, err +} + +func (r allocationResult) ExtractInto(v interface{}) error { + return r.Result.ExtractIntoStructPtr(v, "") +} + +func ExtractAllocationsInto(r pagination.Page, v interface{}) error { + return r.(AllocationPage).Result.ExtractIntoSlicePtr(v, "allocations") +} + +// AllocationPage abstracts the raw results of making a List() request against +// the API. +type AllocationPage struct { + pagination.LinkedPageBase +} + +// IsEmpty returns true if a page contains no Allocation results. +func (r AllocationPage) IsEmpty() (bool, error) { + s, err := ExtractAllocations(r) + return len(s) == 0, err +} + +// NextPageURL uses the response's embedded link reference to navigate to the +// next page of results. +func (r AllocationPage) NextPageURL() (string, error) { + var s struct { + Links []gophercloud.Link `json:"allocations_links"` + } + err := r.ExtractInto(&s) + if err != nil { + return "", err + } + return gophercloud.ExtractNextURL(s.Links) +} + +// ExtractAllocations interprets the results of a single page from a List() call, +// producing a slice of Allocation entities. +func ExtractAllocations(r pagination.Page) ([]Allocation, error) { + var s []Allocation + err := ExtractAllocationsInto(r, &s) + return s, err +} + +// GetResult is the response from a Get operation. Call its Extract +// method to interpret it as a Allocation. +type GetResult struct { + allocationResult +} + +// CreateResult is the response from a Create operation. +type CreateResult struct { + allocationResult +} + +// 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 +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/allocations/urls.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/allocations/urls.go new file mode 100644 index 000000000..7163bbe33 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/allocations/urls.go @@ -0,0 +1,23 @@ +package allocations + +import "github.com/gophercloud/gophercloud" + +func createURL(client *gophercloud.ServiceClient) string { + return client.ServiceURL("allocations") +} + +func listURL(client *gophercloud.ServiceClient) string { + return createURL(client) +} + +func resourceURL(client *gophercloud.ServiceClient, id string) string { + return client.ServiceURL("allocations", id) +} + +func deleteURL(client *gophercloud.ServiceClient, id string) string { + return resourceURL(client, id) +} + +func getURL(client *gophercloud.ServiceClient, id string) string { + return resourceURL(client, id) +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes/doc.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes/doc.go index 40b9fe826..37f60b5f3 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes/doc.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes/doc.go @@ -1,10 +1,9 @@ -package nodes - /* Package nodes provides information and interaction with the nodes API resource in the OpenStack Bare Metal service. - // Example to List Nodes with Detail +Example to List Nodes with Detail + nodes.ListDetail(client, nodes.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) { nodeList, err := nodes.ExtractNodes(page) if err != nil { @@ -18,11 +17,14 @@ resource in the OpenStack Bare Metal service. return true, nil }) - // Example to List Nodes - nodes.List(client, nodes.ListOpts{ - ProvisionState: Deploying, - Fields: []string{"name"}, - }).EachPage(func(page pagination.Page) (bool, error) { +Example to List Nodes + + listOpts := nodes.ListOpts{ + ProvisionState: nodes.Deploying, + Fields: []string{"name"}, + } + + nodes.List(client, listOpts).EachPage(func(page pagination.Page) (bool, error) { nodeList, err := nodes.ExtractNodes(page) if err != nil { return false, err @@ -35,8 +37,9 @@ resource in the OpenStack Bare Metal service. return true, nil }) - // Example to Create Node - createNode, err := nodes.Create(client, nodes.CreateOpts{ +Example to Create Node + + createOpts := nodes.CreateOpts Driver: "ipmi", BootInterface: "pxe", Name: "coconuts", @@ -48,50 +51,80 @@ resource in the OpenStack Bare Metal service. "deploy_ramdisk": "http://172.22.0.1/images/tinyipa-stable-rocky.gz", "ipmi_password": "admin", }, - }).Extract() + } + + createNode, err := nodes.Create(client, createOpts).Extract() if err != nil { panic(err) } - // Example to Get Node +Example to Get Node + showNode, err := nodes.Get(client, "c9afd385-5d89-4ecb-9e1c-68194da6b474").Extract() if err != nil { panic(err) } - // Example to Update Node - updateNode, err := nodes.Update(client, "c9afd385-5d89-4ecb-9e1c-68194da6b474", nodes.UpdateOpts{ +Example to Update Node + + updateOpts := nodes.UpdateOpts{ nodes.UpdateOperation{ Op: ReplaceOp, Path: "/maintenance", Value: "true", }, - }).Extract() + } + + updateNode, err := nodes.Update(client, "c9afd385-5d89-4ecb-9e1c-68194da6b474", updateOpts).Extract() if err != nil { panic(err) } - // Example to Delete Node +Example to Delete Node + err = nodes.Delete(client, "c9afd385-5d89-4ecb-9e1c-68194da6b474").ExtractErr() if err != nil { panic(err) } - // Example to Validate Node +Example to Validate Node + validation, err := nodes.Validate(client, "a62b8495-52e2-407b-b3cb-62775d04c2b8").Extract() + if err != nil { + panic(err) + } + +Example to inject non-masking interrupts - // Example to inject non-masking interrupts err := nodes.InjectNMI(client, "a62b8495-52e2-407b-b3cb-62775d04c2b8").ExtractErr() + if err != nil { + panic(err) + } + +Example to get array of supported boot devices for a node - // Example to get array of supported boot devices for a node bootDevices, err := nodes.GetSupportedBootDevices(client, "a62b8495-52e2-407b-b3cb-62775d04c2b8").Extract() + if err != nil { + panic(err) + } + +Example to set boot device for a node - // Example to set boot device for a node - err := nodes.SetBootDevice(client, "a62b8495-52e2-407b-b3cb-62775d04c2b8", nodes.BootDeviceOpts{ + bootOpts := nodes.BootDeviceOpts{ BootDevice: "pxe", Persistent: false, - }) + } + + err := nodes.SetBootDevice(client, "a62b8495-52e2-407b-b3cb-62775d04c2b8", bootOpts).ExtractErr() + if err != nil { + panic(err) + } + +Example to get boot device for a node - // Example to get boot device for a node bootDevice, err := nodes.GetBootDevice(client, "a62b8495-52e2-407b-b3cb-62775d04c2b8").Extract() + if err != nil { + panic(err) + } */ +package nodes diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes/requests.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes/requests.go index 07fe2222b..4707f7b25 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes/requests.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes/requests.go @@ -19,30 +19,30 @@ type ProvisionState string const ( Enroll ProvisionState = "enroll" - Verifying = "verifying" - Manageable = "manageable" - Available = "available" - Active = "active" - DeployWait = "wait call-back" - Deploying = "deploying" - DeployFail = "deploy failed" - DeployDone = "deploy complete" - Deleting = "deleting" - Deleted = "deleted" - Cleaning = "cleaning" - CleanWait = "clean wait" - CleanFail = "clean failed" - Error = "error" - Rebuild = "rebuild" - Inpsecting = "inspecting" - InspectFail = "inspect failed" - InspectWait = "inspect wait" - Adopting = "adopting" - AdoptFail = "adopt failed" - Rescue = "rescue" - RescueFail = "rescue failed" - Rescuing = "rescuing" - UnrescueFail = "unrescue failed" + Verifying ProvisionState = "verifying" + Manageable ProvisionState = "manageable" + Available ProvisionState = "available" + Active ProvisionState = "active" + DeployWait ProvisionState = "wait call-back" + Deploying ProvisionState = "deploying" + DeployFail ProvisionState = "deploy failed" + DeployDone ProvisionState = "deploy complete" + Deleting ProvisionState = "deleting" + Deleted ProvisionState = "deleted" + Cleaning ProvisionState = "cleaning" + CleanWait ProvisionState = "clean wait" + CleanFail ProvisionState = "clean failed" + Error ProvisionState = "error" + Rebuild ProvisionState = "rebuild" + Inspecting ProvisionState = "inspecting" + InspectFail ProvisionState = "inspect failed" + InspectWait ProvisionState = "inspect wait" + Adopting ProvisionState = "adopting" + AdoptFail ProvisionState = "adopt failed" + Rescue ProvisionState = "rescue" + RescueFail ProvisionState = "rescue failed" + Rescuing ProvisionState = "rescuing" + UnrescueFail ProvisionState = "unrescue failed" ) // TargetProvisionState is used when setting the provision state for a node. @@ -50,15 +50,15 @@ type TargetProvisionState string const ( TargetActive TargetProvisionState = "active" - TargetDeleted = "deleted" - TargetManage = "manage" - TargetProvide = "provide" - TargetInspect = "inspect" - TargetAbort = "abort" - TargetClean = "clean" - TargetAdopt = "adopt" - TargetRescue = "rescue" - TargetUnrescue = "unrescue" + TargetDeleted TargetProvisionState = "deleted" + TargetManage TargetProvisionState = "manage" + TargetProvide TargetProvisionState = "provide" + TargetInspect TargetProvisionState = "inspect" + TargetAbort TargetProvisionState = "abort" + TargetClean TargetProvisionState = "clean" + TargetAdopt TargetProvisionState = "adopt" + TargetRescue TargetProvisionState = "rescue" + TargetUnrescue TargetProvisionState = "unrescue" ) // ListOpts allows the filtering and sorting of paginated collections through @@ -301,19 +301,10 @@ func Update(client *gophercloud.ServiceClient, id string, opts UpdateOpts) (r Up body[i] = result } - - resp, err := client.Request("PATCH", updateURL(client, id), &gophercloud.RequestOpts{ + _, r.Err = client.Patch(updateURL(client, id), body, &r.Body, &gophercloud.RequestOpts{ JSONBody: &body, OkCodes: []int{200}, }) - - if err != nil { - r.Err = err - } else { - r.Body = resp.Body - r.Header = resp.Header - } - return } @@ -408,11 +399,19 @@ type ProvisionStateOptsBuilder interface { ToProvisionStateMap() (map[string]interface{}, error) } +// Starting with Ironic API version 1.56, a configdrive may be a JSON object with structured data. +// Prior to this version, it must be a base64-encoded, gzipped ISO9660 image. +type ConfigDrive struct { + MetaData map[string]interface{} `json:"meta_data,omitempty"` + NetworkData map[string]interface{} `json:"network_data,omitempty"` + UserData interface{} `json:"user_data,omitempty"` +} + // ProvisionStateOpts for a request to change a node's provision state. A config drive should be base64-encoded // gzipped ISO9660 image. type ProvisionStateOpts struct { Target TargetProvisionState `json:"target" required:"true"` - ConfigDrive string `json:"configdrive,omitempty"` + ConfigDrive interface{} `json:"configdrive,omitempty"` CleanSteps []CleanStep `json:"clean_steps,omitempty"` RescuePassword string `json:"rescue_password,omitempty"` } @@ -447,10 +446,10 @@ type TargetPowerState string // TargetPowerState is used when changing the power state of a node. const ( PowerOn TargetPowerState = "power on" - PowerOff = "power off" - Rebooting = "rebooting" - SoftPowerOff = "soft power off" - SoftRebooting = "soft rebooting" + PowerOff TargetPowerState = "power off" + Rebooting TargetPowerState = "rebooting" + SoftPowerOff TargetPowerState = "soft power off" + SoftRebooting TargetPowerState = "soft rebooting" ) // PowerStateOptsBuilder allows extensions to add additional parameters to the ChangePowerState request. @@ -487,3 +486,108 @@ func ChangePowerState(client *gophercloud.ServiceClient, id string, opts PowerSt }) return } + +// This is the desired RAID configuration on the bare metal node. +type RAIDConfigOpts struct { + LogicalDisks []LogicalDisk `json:"logical_disks"` +} + +// RAIDConfigOptsBuilder allows extensions to modify a set RAID config request. +type RAIDConfigOptsBuilder interface { + ToRAIDConfigMap() (map[string]interface{}, error) +} + +// RAIDLevel type is used to specify the RAID level for a logical disk. +type RAIDLevel string + +const ( + RAID0 RAIDLevel = "0" + RAID1 RAIDLevel = "1" + RAID2 RAIDLevel = "2" + RAID5 RAIDLevel = "5" + RAID6 RAIDLevel = "6" + RAID10 RAIDLevel = "1+0" + RAID50 RAIDLevel = "5+0" + RAID60 RAIDLevel = "6+0" +) + +// DiskType is used to specify the disk type for a logical disk, e.g. hdd or ssd. +type DiskType string + +const ( + HDD DiskType = "hdd" + SSD DiskType = "ssd" +) + +// InterfaceType is used to specify the interface for a logical disk. +type InterfaceType string + +const ( + SATA DiskType = "sata" + SCSI DiskType = "scsi" + SAS DiskType = "sas" +) + +type LogicalDisk struct { + // Size (Integer) of the logical disk to be created in GiB. If unspecified, "MAX" will be used. + SizeGB *int `json:"size_gb"` + + // RAID level for the logical disk. + RAIDLevel RAIDLevel `json:"raid_level" required:"true"` + + // Name of the volume. Should be unique within the Node. If not specified, volume name will be auto-generated. + VolumeName string `json:"volume_name,omitempty"` + + // Set to true if this is the root volume. At most one logical disk can have this set to true. + IsRootVolume *bool `json:"is_root_volume,omitempty"` + + // Set to true if this logical disk can share physical disks with other logical disks. + SharePhysicalDisks *bool `json:"share_physical_disks,omitempty"` + + // If this is not specified, disk type will not be a criterion to find backing physical disks + DiskType DiskType `json:"disk_type,omitempty"` + + // If this is not specified, interface type will not be a criterion to find backing physical disks. + InterfaceType InterfaceType `json:"interface_type,omitempty"` + + // Integer, number of disks to use for the logical disk. Defaults to minimum number of disks required + // for the particular RAID level. + NumberOfPhysicalDisks int `json:"number_of_physical_disks,omitempty"` + + // The name of the controller as read by the RAID interface. + Controller string `json:"controller,omitempty"` + + // A list of physical disks to use as read by the RAID interface. + PhysicalDisks []string `json:"physical_disks,omitempty"` +} + +func (opts RAIDConfigOpts) ToRAIDConfigMap() (map[string]interface{}, error) { + body, err := gophercloud.BuildRequestBody(opts, "") + if err != nil { + return nil, err + } + + for _, v := range body["logical_disks"].([]interface{}) { + if logicalDisk, ok := v.(map[string]interface{}); ok { + if logicalDisk["size_gb"] == nil { + logicalDisk["size_gb"] = "MAX" + } + } + } + + return body, nil +} + +// Request to change a Node's RAID config. +func SetRAIDConfig(client *gophercloud.ServiceClient, id string, raidConfigOptsBuilder RAIDConfigOptsBuilder) (r ChangeStateResult) { + reqBody, err := raidConfigOptsBuilder.ToRAIDConfigMap() + if err != nil { + r.Err = err + return + } + + _, r.Err = client.Put(raidConfigURL(client, id), reqBody, nil, &gophercloud.RequestOpts{ + OkCodes: []int{204}, + }) + return +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes/urls.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes/urls.go index 8f9fe05e9..c7ef55036 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes/urls.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes/urls.go @@ -53,3 +53,7 @@ func powerStateURL(client *gophercloud.ServiceClient, id string) string { func provisionStateURL(client *gophercloud.ServiceClient, id string) string { return statesResourceURL(client, id, "provision") } + +func raidConfigURL(client *gophercloud.ServiceClient, id string) string { + return statesResourceURL(client, id, "raid") +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/ports/doc.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/ports/doc.go index 4e02409bb..eb0579bed 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/ports/doc.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/ports/doc.go @@ -1,5 +1,3 @@ -package ports - /* Package ports contains the functionality to Listing, Searching, Creating, Updating, and Deleting of bare metal Port resources @@ -7,8 +5,9 @@ package ports API reference: https://developer.openstack.org/api-ref/baremetal/#ports-ports - // Example to List Ports with Detail - ports.ListDetail(client, ports.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) { +Example to List Ports with Detail + + ports.ListDetail(client, nil).EachPage(func(page pagination.Page) (bool, error) { portList, err := ports.ExtractPorts(page) if err != nil { return false, err @@ -21,10 +20,13 @@ package ports return true, nil }) - // Example to List Ports - ports.List(client, ports.ListOpts{ +Example to List Ports + + listOpts := ports.ListOpts{ Limit: 10, - }).EachPage(func(page pagination.Page) (bool, error) { + } + + ports.List(client, listOpts).EachPage(func(page pagination.Page) (bool, error) { portList, err := ports.ExtractPorts(page) if err != nil { return false, err @@ -37,37 +39,47 @@ package ports return true, nil }) - // Example to Create a Port - createPort, err := ports.Create(client, ports.CreateOpts{ +Example to Create a Port + + createOpts := ports.CreateOpts{ NodeUUID: "e8920409-e07e-41bb-8cc1-72acb103e2dd", Address: "00:1B:63:84:45:E6", PhysicalNetwork: "my-network", - }).Extract() + } + + createPort, err := ports.Create(client, createOpts).Extract() if err != nil { panic(err) } - // Example to Get a Port +Example to Get a Port + showPort, err := ports.Get(client, "c9afd385-5d89-4ecb-9e1c-68194da6b474").Extract() if err != nil { panic(err) } - // Example to Update a Port - updatePort, err := ports.Update(client, "c9afd385-5d89-4ecb-9e1c-68194da6b474", ports.UpdateOpts{ +Example to Update a Port + + updateOpts := ports.UpdateOpts{ ports.UpdateOperation{ Op: ReplaceOp, Path: "/address", Value: "22:22:22:22:22:22", }, - }).Extract() + } + + updatePort, err := ports.Update(client, "c9afd385-5d89-4ecb-9e1c-68194da6b474", updateOpts).Extract() if err != nil { panic(err) } - // Example to Delete a Port +Example to Delete a Port + err = ports.Delete(client, "c9afd385-5d89-4ecb-9e1c-68194da6b474").ExtractErr() if err != nil { panic(err) + } */ +package ports diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/ports/requests.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/ports/requests.go index 89dc4b569..a5da3f834 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/ports/requests.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/baremetal/v1/ports/requests.go @@ -202,15 +202,10 @@ func Update(client *gophercloud.ServiceClient, id string, opts UpdateOpts) (r Up body[i] = patch.ToPortUpdateMap() } - resp, err := client.Request("PATCH", updateURL(client, id), &gophercloud.RequestOpts{ + _, r.Err = client.Patch(updateURL(client, id), body, &r.Body, &gophercloud.RequestOpts{ JSONBody: &body, OkCodes: []int{200}, }) - - r.Body = resp.Body - r.Header = resp.Header - r.Err = err - return } diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/requests.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/requests.go index 4e5e499e3..b72807770 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/requests.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/requests.go @@ -68,7 +68,7 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r Create return } _, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, + OkCodes: []int{200, 201}, }) return } diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/containerinfra/v1/clusters/requests.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/containerinfra/v1/clusters/requests.go index 66035adcb..5d5198018 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/containerinfra/v1/clusters/requests.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/containerinfra/v1/clusters/requests.go @@ -175,3 +175,40 @@ func Update(client *gophercloud.ServiceClient, id string, opts []UpdateOptsBuild } return } + +// ResizeOptsBuilder allows extensions to add additional parameters to the +// Resize request. +type ResizeOptsBuilder interface { + ToClusterResizeMap() (map[string]interface{}, error) +} + +// ResizeOpts params +type ResizeOpts struct { + NodeCount *int `json:"node_count" required:"true"` + NodesToRemove []string `json:"nodes_to_remove,omitempty"` + NodeGroup string `json:"nodegroup,omitempty"` +} + +// ToClusterResizeMap constructs a request body from ResizeOpts. +func (opts ResizeOpts) ToClusterResizeMap() (map[string]interface{}, error) { + return gophercloud.BuildRequestBody(opts, "") +} + +// Resize an existing cluster node count. +func Resize(client *gophercloud.ServiceClient, id string, opts ResizeOptsBuilder) (r ResizeResult) { + b, err := opts.ToClusterResizeMap() + if err != nil { + r.Err = err + return + } + + var result *http.Response + result, r.Err = client.Post(resizeURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200, 202}, + }) + + if r.Err == nil { + r.Header = result.Header + } + return +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/containerinfra/v1/clusters/results.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/containerinfra/v1/clusters/results.go index b386b9be2..b4a8734c2 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/containerinfra/v1/clusters/results.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/containerinfra/v1/clusters/results.go @@ -39,6 +39,11 @@ type UpdateResult struct { commonResult } +// ResizeResult is the response of a Resize operations. +type ResizeResult struct { + commonResult +} + func (r CreateResult) Extract() (string, error) { var s struct { UUID string diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/containerinfra/v1/clusters/urls.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/containerinfra/v1/clusters/urls.go index 6d132f74b..f0fcf1aef 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/containerinfra/v1/clusters/urls.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/containerinfra/v1/clusters/urls.go @@ -37,3 +37,7 @@ func listDetailURL(client *gophercloud.ServiceClient) string { func updateURL(client *gophercloud.ServiceClient, id string) string { return idURL(client, id) } + +func resizeURL(client *gophercloud.ServiceClient, id string) string { + return client.ServiceURL("clusters", id, "actions/resize") +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/dns/v2/recordsets/requests.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/dns/v2/recordsets/requests.go index 2bc457972..1d9a77bcf 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/dns/v2/recordsets/requests.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/dns/v2/recordsets/requests.go @@ -122,7 +122,7 @@ type UpdateOpts struct { Description *string `json:"description,omitempty"` // TTL is the time to live of the RecordSet. - TTL int `json:"ttl,omitempty"` + TTL *int `json:"ttl,omitempty"` // Records are the DNS records of the RecordSet. Records []string `json:"records,omitempty"` @@ -135,10 +135,17 @@ func (opts UpdateOpts) ToRecordSetUpdateMap() (map[string]interface{}, error) { return nil, err } - if opts.TTL > 0 { - b["ttl"] = opts.TTL - } else { - b["ttl"] = nil + // If opts.TTL was actually set, use 0 as a special value to send "null", + // even though the result from the API is 0. + // + // Otherwise, don't send the TTL field. + if opts.TTL != nil { + ttl := *(opts.TTL) + if ttl > 0 { + b["ttl"] = ttl + } else { + b["ttl"] = nil + } } return b, nil diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/requests.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/requests.go new file mode 100644 index 000000000..61111d2ef --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/requests.go @@ -0,0 +1,95 @@ +package applicationcredentials + +import ( + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/pagination" +) + +// ListOptsBuilder allows extensions to add additional parameters to +// the List request +type ListOptsBuilder interface { + ToApplicationCredentialListQuery() (string, error) +} + +// ListOpts provides options to filter the List results. +type ListOpts struct { + // Name filters the response by an application credential name + Name string `q:"name"` +} + +// ToApplicationCredentialListQuery formats a ListOpts into a query string. +func (opts ListOpts) ToApplicationCredentialListQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts) + return q.String(), err +} + +// List enumerates the ApplicationCredentials to which the current token has access. +func List(client *gophercloud.ServiceClient, userID string, opts ListOptsBuilder) pagination.Pager { + url := listURL(client, userID) + if opts != nil { + query, err := opts.ToApplicationCredentialListQuery() + if err != nil { + return pagination.Pager{Err: err} + } + url += query + } + return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { + return ApplicationCredentialPage{pagination.LinkedPageBase{PageResult: r}} + }) +} + +// Get retrieves details on a single user, by ID. +func Get(client *gophercloud.ServiceClient, userID string, id string) (r GetResult) { + _, r.Err = client.Get(getURL(client, userID, id), &r.Body, nil) + return +} + +// CreateOptsBuilder allows extensions to add additional parameters to +// the Create request. +type CreateOptsBuilder interface { + ToApplicationCredentialCreateMap() (map[string]interface{}, error) +} + +// CreateOpts provides options used to create an application credential. +type CreateOpts struct { + // The name of the application credential. + Name string `json:"name,omitempty" required:"true"` + // A description of the application credential’s purpose. + Description string `json:"description,omitempty"` + // A flag indicating whether the application credential may be used for creation or destruction of other application credentials or trusts. + // Defaults to false + Unrestricted bool `json:"unrestricted"` + // The secret for the application credential, either generated by the server or provided by the user. + // This is only ever shown once in the response to a create request. It is not stored nor ever shown again. + // If the secret is lost, a new application credential must be created. + Secret string `json:"secret,omitempty"` + // A list of one or more roles that this application credential has associated with its project. + // A token using this application credential will have these same roles. + Roles []Role `json:"roles,omitempty"` + // The expiration time of the application credential, if one was specified. + ExpiresAt string `json:"expires_at,omitempty"` +} + +// ToApplicationCredentialCreateMap formats a CreateOpts into a create request. +func (opts CreateOpts) ToApplicationCredentialCreateMap() (map[string]interface{}, error) { + return gophercloud.BuildRequestBody(opts, "application_credential") +} + +// Create creates a new ApplicationCredential. +func Create(client *gophercloud.ServiceClient, userID string, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToApplicationCredentialCreateMap() + if err != nil { + r.Err = err + return + } + _, r.Err = client.Post(createURL(client, userID), &b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{201}, + }) + return +} + +// Delete deletes an application credential. +func Delete(client *gophercloud.ServiceClient, userID string, id string) (r DeleteResult) { + _, r.Err = client.Delete(deleteURL(client, userID, id), nil) + return +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/results.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/results.go new file mode 100644 index 000000000..f68799763 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/results.go @@ -0,0 +1,127 @@ +package applicationcredentials + +import ( + "encoding/json" + "time" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/pagination" +) + +type Role struct { + // DomainID is the domain ID the role belongs to. + DomainID string `json:"domain_id,omitempty"` + // ID is the unique ID of the role. + ID string `json:"id,omitempty"` + // Name is the role name + Name string `json:"name,omitempty"` +} + +// ApplicationCredential represents the application credential object +type ApplicationCredential struct { + // The ID of the application credential. + ID string `json:"id"` + // The name of the application credential. + Name string `json:"name"` + // A description of the application credential’s purpose. + Description string `json:"description"` + // A flag indicating whether the application credential may be used for creation or destruction of other application credentials or trusts. + // Defaults to false + Unrestricted bool `json:"unrestricted"` + // The secret for the application credential, either generated by the server or provided by the user. + // This is only ever shown once in the response to a create request. It is not stored nor ever shown again. + // If the secret is lost, a new application credential must be created. + Secret string `json:"secret"` + // The ID of the project the application credential was created for and that authentication requests using this application credential will be scoped to. + ProjectID string `json:"project_id"` + // A list of one or more roles that this application credential has associated with its project. + // A token using this application credential will have these same roles. + Roles []Role `json:"roles"` + // The expiration time of the application credential, if one was specified. + ExpiresAt time.Time `json:"-"` + // Links contains referencing links to the application credential. + Links map[string]interface{} `json:"links"` +} + +func (r *ApplicationCredential) UnmarshalJSON(b []byte) error { + type tmp ApplicationCredential + var s struct { + tmp + ExpiresAt gophercloud.JSONRFC3339MilliNoZ `json:"expires_at"` + } + err := json.Unmarshal(b, &s) + if err != nil { + return err + } + *r = ApplicationCredential(s.tmp) + + r.ExpiresAt = time.Time(s.ExpiresAt) + + return nil +} + +type applicationCredentialResult struct { + gophercloud.Result +} + +// GetResult is the response from a Get operation. Call its Extract method +// to interpret it as an ApplicationCredential. +type GetResult struct { + applicationCredentialResult +} + +// CreateResult is the response from a Create operation. Call its Extract method +// to interpret it as an ApplicationCredential. +type CreateResult struct { + applicationCredentialResult +} + +// DeleteResult is the response from a Delete operation. Call its ExtractErr to +// determine if the request succeeded or failed. +type DeleteResult struct { + gophercloud.ErrResult +} + +// an ApplicationCredentialPage is a single page of an ApplicationCredential results. +type ApplicationCredentialPage struct { + pagination.LinkedPageBase +} + +// IsEmpty determines whether or not a an ApplicationCredentialPage contains any results. +func (r ApplicationCredentialPage) IsEmpty() (bool, error) { + applicationCredentials, err := ExtractApplicationCredentials(r) + return len(applicationCredentials) == 0, err +} + +// NextPageURL extracts the "next" link from the links section of the result. +func (r ApplicationCredentialPage) NextPageURL() (string, error) { + var s struct { + Links struct { + Next string `json:"next"` + Previous string `json:"previous"` + } `json:"links"` + } + err := r.ExtractInto(&s) + if err != nil { + return "", err + } + return s.Links.Next, err +} + +// Extractan ApplicationCredentials returns a slice of ApplicationCredentials contained in a single page of results. +func ExtractApplicationCredentials(r pagination.Page) ([]ApplicationCredential, error) { + var s struct { + ApplicationCredentials []ApplicationCredential `json:"application_credentials"` + } + err := (r.(ApplicationCredentialPage)).ExtractInto(&s) + return s.ApplicationCredentials, err +} + +// Extract interprets any application_credential results as an ApplicationCredential. +func (r applicationCredentialResult) Extract() (*ApplicationCredential, error) { + var s struct { + ApplicationCredential *ApplicationCredential `json:"application_credential"` + } + err := r.ExtractInto(&s) + return s.ApplicationCredential, err +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/urls.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/urls.go new file mode 100644 index 000000000..147620693 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials/urls.go @@ -0,0 +1,19 @@ +package applicationcredentials + +import "github.com/gophercloud/gophercloud" + +func listURL(client *gophercloud.ServiceClient, userID string) string { + return client.ServiceURL("users", userID, "application_credentials") +} + +func getURL(client *gophercloud.ServiceClient, userID string, id string) string { + return client.ServiceURL("users", userID, "application_credentials", id) +} + +func createURL(client *gophercloud.ServiceClient, userID string) string { + return client.ServiceURL("users", userID, "application_credentials") +} + +func deleteURL(client *gophercloud.ServiceClient, userID string, id string) string { + return client.ServiceURL("users", userID, "application_credentials", id) +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/dns/requests.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/dns/requests.go new file mode 100644 index 000000000..b7bd62d2c --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/dns/requests.go @@ -0,0 +1,171 @@ +package dns + +import ( + "net/url" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" + "github.com/gophercloud/gophercloud/openstack/networking/v2/networks" + "github.com/gophercloud/gophercloud/openstack/networking/v2/ports" +) + +// PortListOptsExt adds the DNS options to the base port ListOpts. +type PortListOptsExt struct { + ports.ListOptsBuilder + + DNSName string `q:"dns_name"` +} + +// ToPortListQuery adds the DNS options to the base port list options. +func (opts PortListOptsExt) ToPortListQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts.ListOptsBuilder) + if err != nil { + return "", err + } + + params := q.Query() + + if opts.DNSName != "" { + params.Add("dns_name", opts.DNSName) + } + + q = &url.URL{RawQuery: params.Encode()} + return q.String(), err +} + +// PortCreateOptsExt adds port DNS options to the base ports.CreateOpts. +type PortCreateOptsExt struct { + // CreateOptsBuilder is the interface options structs have to satisfy in order + // to be used in the main Create operation in this package. + ports.CreateOptsBuilder + + // Set DNS name to the port + DNSName string `json:"dns_name,omitempty"` +} + +// ToPortCreateMap casts a CreateOpts struct to a map. +func (opts PortCreateOptsExt) ToPortCreateMap() (map[string]interface{}, error) { + base, err := opts.CreateOptsBuilder.ToPortCreateMap() + if err != nil { + return nil, err + } + + port := base["port"].(map[string]interface{}) + + if opts.DNSName != "" { + port["dns_name"] = opts.DNSName + } + + return base, nil +} + +// PortUpdateOptsExt adds DNS options to the base ports.UpdateOpts +type PortUpdateOptsExt struct { + // UpdateOptsBuilder is the interface options structs have to satisfy in order + // to be used in the main Update operation in this package. + ports.UpdateOptsBuilder + + // Set DNS name to the port + DNSName *string `json:"dns_name,omitempty"` +} + +// ToPortUpdateMap casts an UpdateOpts struct to a map. +func (opts PortUpdateOptsExt) ToPortUpdateMap() (map[string]interface{}, error) { + base, err := opts.UpdateOptsBuilder.ToPortUpdateMap() + if err != nil { + return nil, err + } + + port := base["port"].(map[string]interface{}) + + if opts.DNSName != nil { + port["dns_name"] = *opts.DNSName + } + + return base, nil +} + +// FloatingIPCreateOptsExt adds floating IP DNS options to the base floatingips.CreateOpts. +type FloatingIPCreateOptsExt struct { + // CreateOptsBuilder is the interface options structs have to satisfy in order + // to be used in the main Create operation in this package. + floatingips.CreateOptsBuilder + + // Set DNS name to the floating IPs + DNSName string `json:"dns_name,omitempty"` + + // Set DNS domain to the floating IPs + DNSDomain string `json:"dns_domain,omitempty"` +} + +// ToFloatingIPCreateMap casts a CreateOpts struct to a map. +func (opts FloatingIPCreateOptsExt) ToFloatingIPCreateMap() (map[string]interface{}, error) { + base, err := opts.CreateOptsBuilder.ToFloatingIPCreateMap() + if err != nil { + return nil, err + } + + floatingip := base["floatingip"].(map[string]interface{}) + + if opts.DNSName != "" { + floatingip["dns_name"] = opts.DNSName + } + + if opts.DNSDomain != "" { + floatingip["dns_domain"] = opts.DNSDomain + } + + return base, nil +} + +// NetworkCreateOptsExt adds network DNS options to the base networks.CreateOpts. +type NetworkCreateOptsExt struct { + // CreateOptsBuilder is the interface options structs have to satisfy in order + // to be used in the main Create operation in this package. + networks.CreateOptsBuilder + + // Set DNS domain to the network + DNSDomain string `json:"dns_domain,omitempty"` +} + +// ToNetworkCreateMap casts a CreateOpts struct to a map. +func (opts NetworkCreateOptsExt) ToNetworkCreateMap() (map[string]interface{}, error) { + base, err := opts.CreateOptsBuilder.ToNetworkCreateMap() + if err != nil { + return nil, err + } + + network := base["network"].(map[string]interface{}) + + if opts.DNSDomain != "" { + network["dns_domain"] = opts.DNSDomain + } + + return base, nil +} + +// NetworkUpdateOptsExt adds network DNS options to the base networks.UpdateOpts +type NetworkUpdateOptsExt struct { + // UpdateOptsBuilder is the interface options structs have to satisfy in order + // to be used in the main Update operation in this package. + networks.UpdateOptsBuilder + + // Set DNS domain to the network + DNSDomain *string `json:"dns_domain,omitempty"` +} + +// ToNetworkUpdateMap casts an UpdateOpts struct to a map. +func (opts NetworkUpdateOptsExt) ToNetworkUpdateMap() (map[string]interface{}, error) { + base, err := opts.UpdateOptsBuilder.ToNetworkUpdateMap() + if err != nil { + return nil, err + } + + network := base["network"].(map[string]interface{}) + + if opts.DNSDomain != nil { + network["dns_domain"] = *opts.DNSDomain + } + + return base, nil +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/dns/results.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/dns/results.go new file mode 100644 index 000000000..ce5752fc5 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/dns/results.go @@ -0,0 +1,30 @@ +package dns + +// PortDNSExt represents a decorated form of a Port with the additional +// Port DNS information. +type PortDNSExt struct { + // The DNS name of the port. + DNSName string `json:"dns_name"` + + // The DNS assignment of the port. + DNSAssignment []map[string]string `json:"dns_assignment"` +} + +// FloatingIPDNSExt represents a decorated form of a Floating IP with the +// additional Floating IP DNS information. +type FloatingIPDNSExt struct { + // The DNS name of the floating IP, assigned to the external DNS + // service. + DNSName string `json:"dns_name"` + + // The DNS domain of the floating IP, assigned to the external DNS + // service. + DNSDomain string `json:"dns_domain"` +} + +// NetworkDNSExt represents a decorated form of a Network with the additional +// Network DNS information. +type NetworkDNSExt struct { + // The DNS domain of the network. + DNSDomain string `json:"dns_domain"` +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/mtu/requests.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/mtu/requests.go new file mode 100644 index 000000000..bffb7f5ef --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/mtu/requests.go @@ -0,0 +1,87 @@ +package mtu + +import ( + "fmt" + "net/url" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack/networking/v2/networks" +) + +// ListOptsExt adds an MTU option to the base ListOpts. +type ListOptsExt struct { + networks.ListOptsBuilder + + // The maximum transmission unit (MTU) value to address fragmentation. + // Minimum value is 68 for IPv4, and 1280 for IPv6. + MTU int `q:"mtu"` +} + +// ToNetworkListQuery adds the router:external option to the base network +// list options. +func (opts ListOptsExt) ToNetworkListQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts.ListOptsBuilder) + if err != nil { + return "", err + } + + params := q.Query() + if opts.MTU > 0 { + params.Add("mtu", fmt.Sprintf("%d", opts.MTU)) + } + + q = &url.URL{RawQuery: params.Encode()} + return q.String(), err +} + +// CreateOptsExt adds an MTU option to the base Network CreateOpts. +type CreateOptsExt struct { + networks.CreateOptsBuilder + + // The maximum transmission unit (MTU) value to address fragmentation. + // Minimum value is 68 for IPv4, and 1280 for IPv6. + MTU int `json:"mtu,omitempty"` +} + +// ToNetworkCreateMap adds an MTU to the base network creation options. +func (opts CreateOptsExt) ToNetworkCreateMap() (map[string]interface{}, error) { + base, err := opts.CreateOptsBuilder.ToNetworkCreateMap() + if err != nil { + return nil, err + } + + if opts.MTU == 0 { + return base, nil + } + + networkMap := base["network"].(map[string]interface{}) + networkMap["mtu"] = opts.MTU + + return base, nil +} + +// CreateOptsExt adds an MTU option to the base Network UpdateOpts. +type UpdateOptsExt struct { + networks.UpdateOptsBuilder + + // The maximum transmission unit (MTU) value to address fragmentation. + // Minimum value is 68 for IPv4, and 1280 for IPv6. + MTU int `json:"mtu,omitempty"` +} + +// ToNetworkUpdateMap adds an MTU to the base network uptade options. +func (opts UpdateOptsExt) ToNetworkUpdateMap() (map[string]interface{}, error) { + base, err := opts.UpdateOptsBuilder.ToNetworkUpdateMap() + if err != nil { + return nil, err + } + + if opts.MTU == 0 { + return base, nil + } + + networkMap := base["network"].(map[string]interface{}) + networkMap["mtu"] = opts.MTU + + return base, nil +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/mtu/results.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/mtu/results.go new file mode 100644 index 000000000..497c9c37a --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/mtu/results.go @@ -0,0 +1,8 @@ +package mtu + +// NetworkMTUExt represents an extended form of a Network with additional MTU field. +type NetworkMTUExt struct { + // The maximum transmission unit (MTU) value to address fragmentation. + // Minimum value is 68 for IPv4, and 1280 for IPv6. + MTU int `json:"mtu"` +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsbinding/doc.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsbinding/doc.go new file mode 100644 index 000000000..0d2ed5897 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsbinding/doc.go @@ -0,0 +1,3 @@ +// Package portsbinding provides information and interaction with the port +// binding extension for the OpenStack Networking service. +package portsbinding diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsbinding/requests.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsbinding/requests.go new file mode 100644 index 000000000..647b67ff1 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsbinding/requests.go @@ -0,0 +1,91 @@ +package portsbinding + +import ( + "github.com/gophercloud/gophercloud/openstack/networking/v2/ports" +) + +// CreateOptsExt adds port binding options to the base ports.CreateOpts. +type CreateOptsExt struct { + // CreateOptsBuilder is the interface options structs have to satisfy in order + // to be used in the main Create operation in this package. + ports.CreateOptsBuilder + + // The ID of the host where the port is allocated + HostID string `json:"binding:host_id,omitempty"` + + // The virtual network interface card (vNIC) type that is bound to the + // neutron port. + VNICType string `json:"binding:vnic_type,omitempty"` + + // A dictionary that enables the application running on the specified + // host to pass and receive virtual network interface (VIF) port-specific + // information to the plug-in. + Profile map[string]interface{} `json:"binding:profile,omitempty"` +} + +// ToPortCreateMap casts a CreateOpts struct to a map. +func (opts CreateOptsExt) ToPortCreateMap() (map[string]interface{}, error) { + base, err := opts.CreateOptsBuilder.ToPortCreateMap() + if err != nil { + return nil, err + } + + port := base["port"].(map[string]interface{}) + + if opts.HostID != "" { + port["binding:host_id"] = opts.HostID + } + + if opts.VNICType != "" { + port["binding:vnic_type"] = opts.VNICType + } + + if opts.Profile != nil { + port["binding:profile"] = opts.Profile + } + + return base, nil +} + +// UpdateOptsExt adds port binding options to the base ports.UpdateOpts +type UpdateOptsExt struct { + // UpdateOptsBuilder is the interface options structs have to satisfy in order + // to be used in the main Update operation in this package. + ports.UpdateOptsBuilder + + // The ID of the host where the port is allocated. + HostID *string `json:"binding:host_id,omitempty"` + + // The virtual network interface card (vNIC) type that is bound to the + // neutron port. + VNICType string `json:"binding:vnic_type,omitempty"` + + // A dictionary that enables the application running on the specified + // host to pass and receive virtual network interface (VIF) port-specific + // information to the plug-in. + Profile map[string]interface{} `json:"binding:profile,omitempty"` +} + +// ToPortUpdateMap casts an UpdateOpts struct to a map. +func (opts UpdateOptsExt) ToPortUpdateMap() (map[string]interface{}, error) { + base, err := opts.UpdateOptsBuilder.ToPortUpdateMap() + if err != nil { + return nil, err + } + + port := base["port"].(map[string]interface{}) + + if opts.HostID != nil { + port["binding:host_id"] = *opts.HostID + } + + if opts.VNICType != "" { + port["binding:vnic_type"] = opts.VNICType + } + + if opts.Profile != nil { + port["binding:profile"] = opts.Profile + } + + return base, nil +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsbinding/results.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsbinding/results.go new file mode 100644 index 000000000..4d8f856a0 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsbinding/results.go @@ -0,0 +1,24 @@ +package portsbinding + +// PortsBindingExt represents a decorated form of a Port with the additional +// port binding information. +type PortsBindingExt struct { + // The ID of the host where the port is allocated. + HostID string `json:"binding:host_id"` + + // A dictionary that enables the application to pass information about + // functions that the Networking API provides. + VIFDetails map[string]interface{} `json:"binding:vif_details"` + + // The VIF type for the port. + VIFType string `json:"binding:vif_type"` + + // The virtual network interface card (vNIC) type that is bound to the + // neutron port. + VNICType string `json:"binding:vnic_type"` + + // A dictionary that enables the application running on the specified + // host to pass and receive virtual network interface (VIF) port-specific + // information to the plug-in. + Profile map[string]interface{} `json:"binding:profile"` +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/doc.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/doc.go new file mode 100644 index 000000000..2b9a39168 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/doc.go @@ -0,0 +1,145 @@ +/* +Package portsecurity provides information and interaction with the port +security extension for the OpenStack Networking service. + +Example to List Networks with Port Security Information + + type NetworkWithPortSecurityExt struct { + networks.Network + portsecurity.PortSecurityExt + } + + var allNetworks []NetworkWithPortSecurityExt + + listOpts := networks.ListOpts{ + Name: "network_1", + } + + allPages, err := networks.List(networkClient, listOpts).AllPages() + if err != nil { + panic(err) + } + + err = networks.ExtractNetworksInto(allPages, &allNetworks) + if err != nil { + panic(err) + } + + for _, network := range allNetworks { + fmt.Println("%+v\n", network) + } + +Example to Create a Network without Port Security + + var networkWithPortSecurityExt struct { + networks.Network + portsecurity.PortSecurityExt + } + + networkCreateOpts := networks.CreateOpts{ + Name: "private", + } + + iFalse := false + createOpts := portsecurity.NetworkCreateOptsExt{ + CreateOptsBuilder: networkCreateOpts, + PortSecurityEnabled: &iFalse, + } + + err := networks.Create(networkClient, createOpts).ExtractInto(&networkWithPortSecurityExt) + if err != nil { + panic(err) + } + + fmt.Println("%+v\n", networkWithPortSecurityExt) + +Example to Disable Port Security on an Existing Network + + var networkWithPortSecurityExt struct { + networks.Network + portsecurity.PortSecurityExt + } + + iFalse := false + networkID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" + networkUpdateOpts := networks.UpdateOpts{} + updateOpts := portsecurity.NetworkUpdateOptsExt{ + UpdateOptsBuilder: networkUpdateOpts, + PortSecurityEnabled: &iFalse, + } + + err := networks.Update(networkClient, networkID, updateOpts).ExtractInto(&networkWithPortSecurityExt) + if err != nil { + panic(err) + } + + fmt.Println("%+v\n", networkWithPortSecurityExt) + +Example to Get a Port with Port Security Information + + var portWithPortSecurityExtensions struct { + ports.Port + portsecurity.PortSecurityExt + } + + portID := "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2" + + err := ports.Get(networkingClient, portID).ExtractInto(&portWithPortSecurityExtensions) + if err != nil { + panic(err) + } + + fmt.Println("%+v\n", portWithPortSecurityExtensions) + +Example to Create a Port Without Port Security + + var portWithPortSecurityExtensions struct { + ports.Port + portsecurity.PortSecurityExt + } + + iFalse := false + networkID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" + subnetID := "a87cc70a-3e15-4acf-8205-9b711a3531b7" + + portCreateOpts := ports.CreateOpts{ + NetworkID: networkID, + FixedIPs: []ports.IP{ports.IP{SubnetID: subnetID}}, + } + + createOpts := portsecurity.PortCreateOptsExt{ + CreateOptsBuilder: portCreateOpts, + PortSecurityEnabled: &iFalse, + } + + err := ports.Create(networkingClient, createOpts).ExtractInto(&portWithPortSecurityExtensions) + if err != nil { + panic(err) + } + + fmt.Println("%+v\n", portWithPortSecurityExtensions) + +Example to Disable Port Security on an Existing Port + + var portWithPortSecurityExtensions struct { + ports.Port + portsecurity.PortSecurityExt + } + + iFalse := false + portID := "65c0ee9f-d634-4522-8954-51021b570b0d" + + portUpdateOpts := ports.UpdateOpts{} + updateOpts := portsecurity.PortUpdateOptsExt{ + UpdateOptsBuilder: portUpdateOpts, + PortSecurityEnabled: &iFalse, + } + + err := ports.Update(networkingClient, portID, updateOpts).ExtractInto(&portWithPortSecurityExtensions) + if err != nil { + panic(err) + } + + fmt.Println("%+v\n", portWithPortSecurityExtensions) +*/ +package portsecurity diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/requests.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/requests.go new file mode 100644 index 000000000..c80f47cf6 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/requests.go @@ -0,0 +1,104 @@ +package portsecurity + +import ( + "github.com/gophercloud/gophercloud/openstack/networking/v2/networks" + "github.com/gophercloud/gophercloud/openstack/networking/v2/ports" +) + +// PortCreateOptsExt adds port security options to the base ports.CreateOpts. +type PortCreateOptsExt struct { + ports.CreateOptsBuilder + + // PortSecurityEnabled toggles port security on a port. + PortSecurityEnabled *bool `json:"port_security_enabled,omitempty"` +} + +// ToPortCreateMap casts a CreateOpts struct to a map. +func (opts PortCreateOptsExt) ToPortCreateMap() (map[string]interface{}, error) { + base, err := opts.CreateOptsBuilder.ToPortCreateMap() + if err != nil { + return nil, err + } + + port := base["port"].(map[string]interface{}) + + if opts.PortSecurityEnabled != nil { + port["port_security_enabled"] = &opts.PortSecurityEnabled + } + + return base, nil +} + +// PortUpdateOptsExt adds port security options to the base ports.UpdateOpts. +type PortUpdateOptsExt struct { + ports.UpdateOptsBuilder + + // PortSecurityEnabled toggles port security on a port. + PortSecurityEnabled *bool `json:"port_security_enabled,omitempty"` +} + +// ToPortUpdateMap casts a UpdateOpts struct to a map. +func (opts PortUpdateOptsExt) ToPortUpdateMap() (map[string]interface{}, error) { + base, err := opts.UpdateOptsBuilder.ToPortUpdateMap() + if err != nil { + return nil, err + } + + port := base["port"].(map[string]interface{}) + + if opts.PortSecurityEnabled != nil { + port["port_security_enabled"] = &opts.PortSecurityEnabled + } + + return base, nil +} + +// NetworkCreateOptsExt adds port security options to the base +// networks.CreateOpts. +type NetworkCreateOptsExt struct { + networks.CreateOptsBuilder + + // PortSecurityEnabled toggles port security on a port. + PortSecurityEnabled *bool `json:"port_security_enabled,omitempty"` +} + +// ToNetworkCreateMap casts a CreateOpts struct to a map. +func (opts NetworkCreateOptsExt) ToNetworkCreateMap() (map[string]interface{}, error) { + base, err := opts.CreateOptsBuilder.ToNetworkCreateMap() + if err != nil { + return nil, err + } + + network := base["network"].(map[string]interface{}) + + if opts.PortSecurityEnabled != nil { + network["port_security_enabled"] = &opts.PortSecurityEnabled + } + + return base, nil +} + +// NetworkUpdateOptsExt adds port security options to the base +// networks.UpdateOpts. +type NetworkUpdateOptsExt struct { + networks.UpdateOptsBuilder + + // PortSecurityEnabled toggles port security on a port. + PortSecurityEnabled *bool `json:"port_security_enabled,omitempty"` +} + +// ToNetworkUpdateMap casts a UpdateOpts struct to a map. +func (opts NetworkUpdateOptsExt) ToNetworkUpdateMap() (map[string]interface{}, error) { + base, err := opts.UpdateOptsBuilder.ToNetworkUpdateMap() + if err != nil { + return nil, err + } + + network := base["network"].(map[string]interface{}) + + if opts.PortSecurityEnabled != nil { + network["port_security_enabled"] = &opts.PortSecurityEnabled + } + + return base, nil +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/results.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/results.go new file mode 100644 index 000000000..7b3482a40 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity/results.go @@ -0,0 +1,7 @@ +package portsecurity + +type PortSecurityExt struct { + // PortSecurityEnabled specifies whether port security is enabled or + // disabled. + PortSecurityEnabled bool `json:"port_security_enabled"` +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/doc.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/doc.go index e768b71f8..9d1dd5a7e 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/doc.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/doc.go @@ -45,8 +45,9 @@ Example to Update a Network networkID := "484cda0e-106f-4f4b-bb3f-d413710bbe78" + name := "new_name" updateOpts := networks.UpdateOpts{ - Name: "new_name", + Name: &name, } network, err := networks.Update(networkClient, networkID, updateOpts).Extract() diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/requests.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/requests.go index d52d099a6..8006c4816 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/requests.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/requests.go @@ -112,7 +112,7 @@ type UpdateOptsBuilder interface { // UpdateOpts represents options used to update a network. type UpdateOpts struct { AdminStateUp *bool `json:"admin_state_up,omitempty"` - Name string `json:"name,omitempty"` + Name *string `json:"name,omitempty"` Description *string `json:"description,omitempty"` Shared *bool `json:"shared,omitempty"` } diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/doc.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/doc.go index d0ed8dff0..7d3a1b9b6 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/doc.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/doc.go @@ -97,10 +97,12 @@ Example to Create a Subnet With a Default Gateway Example to Update a Subnet subnetID := "db77d064-e34f-4d06-b060-f21e28a61c23" + dnsNameservers := []string{"8.8.8.8"} + name := "new_name" updateOpts := subnets.UpdateOpts{ - Name: "new_name", - DNSNameservers: []string{"8.8.8.8}, + Name: &name, + DNSNameservers: &dnsNameservers, } subnet, err := subnets.Update(networkClient, subnetID, updateOpts).Extract() diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/requests.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/requests.go index d2c4a29f7..3e56bf389 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/requests.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/requests.go @@ -173,7 +173,7 @@ type UpdateOptsBuilder interface { // UpdateOpts represents the attributes used when updating an existing subnet. type UpdateOpts struct { // Name is a human-readable name of the subnet. - Name string `json:"name,omitempty"` + Name *string `json:"name,omitempty"` // Description of the subnet. Description *string `json:"description,omitempty"` @@ -188,7 +188,7 @@ type UpdateOpts struct { GatewayIP *string `json:"gateway_ip,omitempty"` // DNSNameservers are the nameservers to be set via DHCP. - DNSNameservers []string `json:"dns_nameservers,omitempty"` + DNSNameservers *[]string `json:"dns_nameservers,omitempty"` // HostRoutes are any static host routes to be set via DHCP. HostRoutes *[]HostRoute `json:"host_routes,omitempty"` diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers/doc.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers/doc.go index 9e5f66419..ffc4f0529 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers/doc.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers/doc.go @@ -73,6 +73,9 @@ Example to Update a Container Metadata: map[string]string{ "bar": "baz", }, + RemoveMetadata: []string{ + "foo", + }, } container, err := containers.Update(objectStorageClient, containerName, updateOpts).Extract() diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers/requests.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers/requests.go index 89aa99683..ca99bb2a6 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers/requests.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers/requests.go @@ -130,6 +130,7 @@ type UpdateOptsBuilder interface { // deleting a container's metadata. type UpdateOpts struct { Metadata map[string]string + RemoveMetadata []string ContainerRead string `h:"X-Container-Read"` ContainerSyncTo string `h:"X-Container-Sync-To"` ContainerSyncKey string `h:"X-Container-Sync-Key"` @@ -148,9 +149,15 @@ func (opts UpdateOpts) ToContainerUpdateMap() (map[string]string, error) { if err != nil { return nil, err } + for k, v := range opts.Metadata { h["X-Container-Meta-"+k] = v } + + for _, k := range opts.RemoveMetadata { + h["X-Remove-Container-Meta-"+k] = "remove" + } + return h, nil } diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/doc.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/doc.go new file mode 100644 index 000000000..841a9c578 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/doc.go @@ -0,0 +1,3 @@ +// Package apiversions provides information and interaction with the different +// API versions for the Shared File System service, code-named Manila. +package apiversions diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/errors.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/errors.go new file mode 100644 index 000000000..8f0f7628d --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/errors.go @@ -0,0 +1,23 @@ +package apiversions + +import ( + "fmt" +) + +// ErrVersionNotFound is the error when the requested API version +// could not be found. +type ErrVersionNotFound struct{} + +func (e ErrVersionNotFound) Error() string { + return fmt.Sprintf("Unable to find requested API version") +} + +// ErrMultipleVersionsFound is the error when a request for an API +// version returns multiple results. +type ErrMultipleVersionsFound struct { + Count int +} + +func (e ErrMultipleVersionsFound) Error() string { + return fmt.Sprintf("Found %d API versions", e.Count) +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/requests.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/requests.go new file mode 100644 index 000000000..2e1f6639b --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/requests.go @@ -0,0 +1,19 @@ +package apiversions + +import ( + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/pagination" +) + +// List lists all the API versions available to end-users. +func List(c *gophercloud.ServiceClient) pagination.Pager { + return pagination.NewPager(c, listURL(c), func(r pagination.PageResult) pagination.Page { + return APIVersionPage{pagination.SinglePageBase(r)} + }) +} + +// Get will get a specific API version, specified by major ID. +func Get(client *gophercloud.ServiceClient, v string) (r GetResult) { + _, r.Err = client.Get(getURL(client, v), &r.Body, nil) + return +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/results.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/results.go new file mode 100644 index 000000000..60c1f1b3a --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/results.go @@ -0,0 +1,73 @@ +package apiversions + +import ( + "time" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/pagination" +) + +// APIVersion represents an API version for the Shared File System service. +type APIVersion struct { + // ID is the unique identifier of the API version. + ID string `json:"id"` + + // MinVersion is the minimum microversion supported. + MinVersion string `json:"min_version"` + + // Status is the API versions status. + Status string `json:"status"` + + // Updated is the date when the API was last updated. + Updated time.Time `json:"updated"` + + // Version is the maximum microversion supported. + Version string `json:"version"` +} + +// APIVersionPage is the page returned by a pager when traversing over a +// collection of API versions. +type APIVersionPage struct { + pagination.SinglePageBase +} + +// IsEmpty checks whether an APIVersionPage struct is empty. +func (r APIVersionPage) IsEmpty() (bool, error) { + is, err := ExtractAPIVersions(r) + return len(is) == 0, err +} + +// ExtractAPIVersions takes a collection page, extracts all of the elements, +// and returns them a slice of APIVersion structs. It is effectively a cast. +func ExtractAPIVersions(r pagination.Page) ([]APIVersion, error) { + var s struct { + Versions []APIVersion `json:"versions"` + } + err := (r.(APIVersionPage)).ExtractInto(&s) + return s.Versions, err +} + +// GetResult represents the result of a get operation. +type GetResult struct { + gophercloud.Result +} + +// Extract is a function that accepts a result and extracts an API version resource. +func (r GetResult) Extract() (*APIVersion, error) { + var s struct { + Versions []APIVersion `json:"versions"` + } + err := r.ExtractInto(&s) + if err != nil { + return nil, err + } + + switch len(s.Versions) { + case 0: + return nil, ErrVersionNotFound{} + case 1: + return &s.Versions[0], nil + default: + return nil, ErrMultipleVersionsFound{Count: len(s.Versions)} + } +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/urls.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/urls.go new file mode 100644 index 000000000..41aebdc5f --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions/urls.go @@ -0,0 +1,20 @@ +package apiversions + +import ( + "strings" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack/utils" +) + +func getURL(c *gophercloud.ServiceClient, version string) string { + baseEndpoint, _ := utils.BaseEndpoint(c.Endpoint) + endpoint := strings.TrimRight(baseEndpoint, "/") + "/" + strings.TrimRight(version, "/") + "/" + return endpoint +} + +func listURL(c *gophercloud.ServiceClient) string { + baseEndpoint, _ := utils.BaseEndpoint(c.Endpoint) + endpoint := strings.TrimRight(baseEndpoint, "/") + "/" + return endpoint +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/availabilityzones/requests.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/availabilityzones/requests.go new file mode 100644 index 000000000..df10b856e --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/availabilityzones/requests.go @@ -0,0 +1,13 @@ +package availabilityzones + +import ( + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/pagination" +) + +// List will return the existing availability zones. +func List(client *gophercloud.ServiceClient) pagination.Pager { + return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page { + return AvailabilityZonePage{pagination.SinglePageBase(r)} + }) +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/availabilityzones/results.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/availabilityzones/results.go new file mode 100644 index 000000000..83a76c1a8 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/availabilityzones/results.go @@ -0,0 +1,59 @@ +package availabilityzones + +import ( + "encoding/json" + "time" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/pagination" +) + +// AvailabilityZone contains all the information associated with an OpenStack +// AvailabilityZone. +type AvailabilityZone struct { + // The availability zone ID. + ID string `json:"id"` + // The name of the availability zone. + Name string `json:"name"` + // The date and time stamp when the availability zone was created. + CreatedAt time.Time `json:"-"` + // The date and time stamp when the availability zone was updated. + UpdatedAt time.Time `json:"-"` +} + +type commonResult struct { + gophercloud.Result +} + +// ListResult contains the response body and error from a List request. +type AvailabilityZonePage struct { + pagination.SinglePageBase +} + +// ExtractAvailabilityZones will get the AvailabilityZone objects out of the shareTypeAccessResult object. +func ExtractAvailabilityZones(r pagination.Page) ([]AvailabilityZone, error) { + var a struct { + AvailabilityZone []AvailabilityZone `json:"availability_zones"` + } + err := (r.(AvailabilityZonePage)).ExtractInto(&a) + return a.AvailabilityZone, err +} + +func (r *AvailabilityZone) UnmarshalJSON(b []byte) error { + type tmp AvailabilityZone + var s struct { + tmp + CreatedAt gophercloud.JSONRFC3339MilliNoZ `json:"created_at"` + UpdatedAt gophercloud.JSONRFC3339MilliNoZ `json:"updated_at"` + } + err := json.Unmarshal(b, &s) + if err != nil { + return err + } + *r = AvailabilityZone(s.tmp) + + r.CreatedAt = time.Time(s.CreatedAt) + r.UpdatedAt = time.Time(s.UpdatedAt) + + return nil +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/availabilityzones/urls.go b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/availabilityzones/urls.go new file mode 100644 index 000000000..fb4cdcf4e --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/availabilityzones/urls.go @@ -0,0 +1,7 @@ +package availabilityzones + +import "github.com/gophercloud/gophercloud" + +func listURL(c *gophercloud.ServiceClient) string { + return c.ServiceURL("os-availability-zone") +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/provider.go b/pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/provider.go index 6a3656a79..87f5917d4 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/provider.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/provider.go @@ -20,13 +20,15 @@ func Provider() terraform.ResourceProvider { "microversion": { Type: schema.TypeString, Required: true, - DefaultFunc: schema.EnvDefaultFunc("IRONIC_MICROVERSION", "1.50"), + DefaultFunc: schema.EnvDefaultFunc("IRONIC_MICROVERSION", "1.52"), Description: descriptions["microversion"], }, }, ResourcesMap: map[string]*schema.Resource{ - "ironic_node_v1": resourceNodeV1(), - "ironic_port_v1": resourcePortV1(), + "ironic_node_v1": resourceNodeV1(), + "ironic_port_v1": resourcePortV1(), + "ironic_allocation_v1": resourceAllocationV1(), + "ironic_deployment": resourceDeployment(), }, ConfigureFunc: configureProvider, } diff --git a/pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/resource_ironic_allocation_v1.go b/pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/resource_ironic_allocation_v1.go new file mode 100644 index 000000000..8a87ad32d --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/resource_ironic_allocation_v1.go @@ -0,0 +1,170 @@ +package ironic + +import ( + "fmt" + "log" + "time" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack/baremetal/v1/allocations" + "github.com/hashicorp/terraform/helper/schema" +) + +// Schema resource definition for an Ironic allocation. +func resourceAllocationV1() *schema.Resource { + return &schema.Resource{ + Create: resourceAllocationV1Create, + Read: resourceAllocationV1Read, + Delete: resourceAllocationV1Delete, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "resource_class": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "candidate_nodes": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + ForceNew: true, + }, + "traits": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + ForceNew: true, + }, + "extra": { + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + }, + "node_uuid": { + Type: schema.TypeString, + Computed: true, + }, + "state": { + Type: schema.TypeString, + Computed: true, + }, + "last_error": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +// Create an allocation, including driving Ironic's state machine +func resourceAllocationV1Create(d *schema.ResourceData, meta interface{}) error { + client := meta.(*gophercloud.ServiceClient) + + result, err := allocations.Create(client, allocationSchemaToCreateOpts(d)).Extract() + if err != nil { + return err + } + + d.SetId(result.UUID) + + // Wait for state to change from allocating + var state string + timeout := 1 * time.Minute + checkInterval := 2 * time.Second + + getState := func() string { + resourceAllocationV1Read(d, meta) + return d.Get("state").(string) + } + + for state = getState(); state == "allocating"; state = getState() { + log.Printf("[DEBUG] Requested allocation %s; current state is '%s'\n", d.Id(), state) + + time.Sleep(checkInterval) + checkInterval += 2 + timeout -= checkInterval + if timeout < 0 { + return fmt.Errorf("timed out waiting for allocation") + } + } + + if state == "error" { + err := d.Get("last_error").(string) + resourceAllocationV1Delete(d, meta) + d.SetId("") + return fmt.Errorf("error creating resource: %s", err) + } + + return nil +} + +// Read the allocation's data from Ironic +func resourceAllocationV1Read(d *schema.ResourceData, meta interface{}) error { + client := meta.(*gophercloud.ServiceClient) + + result, err := allocations.Get(client, d.Id()).Extract() + if err != nil { + return err + } + + d.Set("name", result.Name) + d.Set("resource_class", result.ResourceClass) + d.Set("candidate_nodes", result.CandidateNodes) + d.Set("traits", result.Traits) + d.Set("extra", result.Extra) + d.Set("node_uuid", result.NodeUUID) + d.Set("state", result.State) + d.Set("last_error", result.LastError) + + return nil +} + +// Delete an allocation from Ironic if it exists +func resourceAllocationV1Delete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*gophercloud.ServiceClient) + + _, err := allocations.Get(client, d.Id()).Extract() + if _, ok := err.(gophercloud.ErrDefault404); ok { + return nil + } + + return allocations.Delete(client, d.Id()).ExtractErr() +} + +func allocationSchemaToCreateOpts(d *schema.ResourceData) *allocations.CreateOpts { + candidateNodesRaw := d.Get("candidate_nodes").([]interface{}) + traitsRaw := d.Get("traits").([]interface{}) + extraRaw := d.Get("extra").(map[string]interface{}) + + candidateNodes := make([]string, len(candidateNodesRaw)) + for i := range candidateNodesRaw { + candidateNodes[i] = candidateNodesRaw[i].(string) + } + + traits := make([]string, len(traitsRaw)) + for i := range traitsRaw { + traits[i] = traitsRaw[i].(string) + } + + extra := make(map[string]string) + for k, v := range extraRaw { + extra[k] = v.(string) + } + + return &allocations.CreateOpts{ + Name: d.Get("name").(string), + ResourceClass: d.Get("resource_class").(string), + CandidateNodes: candidateNodes, + Traits: traits, + Extra: extra, + } +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/resource_ironic_deployment.go b/pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/resource_ironic_deployment.go new file mode 100644 index 000000000..26473ac12 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/resource_ironic_deployment.go @@ -0,0 +1,117 @@ +package ironic + +import ( + "fmt" + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes" + utils "github.com/gophercloud/utils/openstack/baremetal/v1/nodes" + "github.com/hashicorp/terraform/helper/schema" +) + +// Schema resource definition for an Ironic deployment. +func resourceDeployment() *schema.Resource { + return &schema.Resource{ + Create: resourceDeploymentCreate, + Read: resourceDeploymentRead, + Delete: resourceDeploymentDelete, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "node_uuid": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "instance_info": { + Type: schema.TypeMap, + Required: true, + ForceNew: true, + }, + "user_data": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "network_data": { + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + }, + "metadata": { + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + }, + "provision_state": { + Type: schema.TypeString, + Computed: true, + }, + "last_error": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +// Create an deployment, including driving Ironic's state machine +func resourceDeploymentCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*gophercloud.ServiceClient) + + // Reload the resource before returning + defer resourceDeploymentRead(d, meta) + + // Set instance info + instanceInfo := d.Get("instance_info").(map[string]interface{}) + if instanceInfo != nil { + _, err := nodes.Update(client, d.Get("node_uuid").(string), nodes.UpdateOpts{ + nodes.UpdateOperation{ + Op: nodes.AddOp, + Path: "/instance_info", + Value: instanceInfo, + }, + }).Extract() + if err != nil { + return fmt.Errorf("could not update instance info: %s", err) + } + } + + // Create config drive + configDrive := utils.ConfigDrive{ + UserData: utils.UserDataString(d.Get("user_data").(string)), + NetworkData: d.Get("network_data").(map[string]interface{}), + MetaData: d.Get("metadata").(map[string]interface{}), + } + + d.SetId(d.Get("node_uuid").(string)) + + // Deploy the node - drive Ironic state machine until node is 'active' + return ChangeProvisionStateToTarget(client, d.Id(), "active", &configDrive) +} + +// Read the deployment's data from Ironic +func resourceDeploymentRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*gophercloud.ServiceClient) + + // Ensure node exists first + id := d.Get("node_uuid").(string) + result, err := nodes.Get(client, id).Extract() + if err != nil { + return fmt.Errorf("could not find node %s: %s", id, err) + } + + d.Set("provision_state", result.ProvisionState) + d.Set("last_error", result.LastError) + + return nil +} + +// Delete an deployment from Ironic - this cleans the node and returns it's state to 'available' +func resourceDeploymentDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*gophercloud.ServiceClient) + return ChangeProvisionStateToTarget(client, d.Id(), "deleted", nil) +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/resource_ironic_node_v1.go b/pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/resource_ironic_node_v1.go index e0e3fa26a..68385b990 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/resource_ironic_node_v1.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/resource_ironic_node_v1.go @@ -2,13 +2,13 @@ package ironic import ( "fmt" + "log" + "time" + "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes" "github.com/gophercloud/gophercloud/openstack/baremetal/v1/ports" - utils "github.com/gophercloud/utils/openstack/baremetal/v1/nodes" "github.com/hashicorp/terraform/helper/schema" - "log" - "time" ) // Schema resource definition for an Ironic node. @@ -29,6 +29,10 @@ func resourceNodeV1() *schema.Resource { Optional: true, Default: "ipxe", }, + "clean": { + Type: schema.TypeBool, + Optional: true, + }, "conductor_group": { Type: schema.TypeString, Optional: true, @@ -80,8 +84,20 @@ func resourceNodeV1() *schema.Resource { Optional: true, Default: "inspector", }, - "instance_info": { - Type: schema.TypeMap, + "instance_uuid": { + Type: schema.TypeString, + Computed: true, + }, + "inspect": { + Type: schema.TypeBool, + Optional: true, + }, + "available": { + Type: schema.TypeBool, + Optional: true, + }, + "manage": { + Type: schema.TypeBool, Optional: true, }, "management_interface": { @@ -138,46 +154,27 @@ func resourceNodeV1() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "target_provision_state": { + "power_state": { Type: schema.TypeString, - Optional: true, - - // This did not change if the current provision state matches the target - DiffSuppressFunc: targetStateMatchesReality, + Computed: true, }, - // FIXME: Suppress config drive on updates - "user_data": { + "target_power_state": { Type: schema.TypeString, Optional: true, + + // If power_state is same as target_power_state, we have no changes to apply + DiffSuppressFunc: func(_, old, new string, d *schema.ResourceData) bool { + return new == d.Get("power_state").(string) + }, }, - "network_data": { - Type: schema.TypeMap, - Optional: true, - }, - "metadata": { - Type: schema.TypeMap, + "power_state_timeout": { + Type: schema.TypeInt, Optional: true, }, }, } } -// Match up Ironic verbs and nouns for target_provision_state -func targetStateMatchesReality(_, old, new string, d *schema.ResourceData) bool { - log.Printf("[DEBUG] Current state is '%s', target is '%s'\n", d.Get("provision_state").(string), new) - - switch new { - case "manage": - return d.Get("provision_state").(string) == "manageable" - case "provide": - return d.Get("provision_state").(string) == "available" - case "active": - return d.Get("provision_state").(string) == "active" - } - - return false -} - // Create a node, including driving Ironic's state machine func resourceNodeV1Create(d *schema.ResourceData, meta interface{}) error { client := meta.(*gophercloud.ServiceClient) @@ -194,20 +191,7 @@ func resourceNodeV1Create(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Node created with ID %s\n", d.Id()) d.SetId(result.UUID) - // Some fields can only be set in an update after create - updateOpts := postCreateUpdateOpts(d) - if len(updateOpts) > 0 { - log.Printf("[DEBUG] Node updates required, issuing updates: %+v\n", updateOpts) - _, err = nodes.Update(client, d.Id(), updateOpts).Extract() - if err != nil { - resourceNodeV1Read(d, meta) - return err - } - } - - // FIXME - This is ugly, but terraform doesn't handle nested resources well :-( We need the port created - // in the middle of the process, after we create the node but before we start deploying it. Maybe - // there's a better solution. + // Create ports as part of the node object - you may also use the native port resource portSet := d.Get("ports").(*schema.Set) if portSet != nil { portList := portSet.List() @@ -224,7 +208,7 @@ func resourceNodeV1Create(d *schema.ResourceData, meta interface{}) error { } } - // FIXME all values other than address and pxe + // FIXME: All values other than address and pxe portCreateOpts := ports.CreateOpts{ NodeUUID: d.Id(), Address: port["address"].(string), @@ -238,34 +222,43 @@ func resourceNodeV1Create(d *schema.ResourceData, meta interface{}) error { } } - // target_provision_state is special, we need to drive ironic through it's state machine - // to reach the desired state, which could take multiple long-running steps. - if target := d.Get("target_provision_state").(string); target != "" { - if err := changeProvisionStateToTarget(d, client); err != nil { - return err + // Make node manageable + if d.Get("manage").(bool) || d.Get("clean").(bool) || d.Get("inspect").(bool) { + if err := ChangeProvisionStateToTarget(client, d.Id(), "manage", nil); err != nil { + return fmt.Errorf("could not manage: %s", err) } } - return resourceNodeV1Read(d, meta) -} + // Clean node + if d.Get("clean").(bool) { + if err := ChangeProvisionStateToTarget(client, d.Id(), "clean", nil); err != nil { + return fmt.Errorf("could not clean: %s", err) + } + } -// All the options that need to be updated on the node, post-create. Not everything -// can be created through the POST to /v1/nodes. TODO: The rest of the fields other -// than instance_info. -func postCreateUpdateOpts(d *schema.ResourceData) nodes.UpdateOpts { - opts := nodes.UpdateOpts{} - - instanceInfo := d.Get("instance_info").(map[string]interface{}) - if instanceInfo != nil { - opts = append(opts, nodes.UpdateOperation{ - Op: nodes.AddOp, - Path: "/instance_info", - Value: instanceInfo, - }, - ) + // Inspect node + if d.Get("inspect").(bool) { + if err := ChangeProvisionStateToTarget(client, d.Id(), "inspect", nil); err != nil { + return fmt.Errorf("could not inspect: %s", err) + } + } + + // Make node available + if d.Get("available").(bool) { + if err := ChangeProvisionStateToTarget(client, d.Id(), "provide", nil); err != nil { + return fmt.Errorf("could not make node available: %s", err) + } } - return opts + // Change power state, if required + if targetPowerState := d.Get("target_power_state").(string); targetPowerState != "" { + err := changePowerState(client, d, nodes.TargetPowerState(targetPowerState)) + if err != nil { + return fmt.Errorf("could not change power state: %s", err) + } + } + + return resourceNodeV1Read(d, meta) } // Read the node's data from Ironic @@ -288,11 +281,13 @@ func resourceNodeV1Read(d *schema.ResourceData, meta interface{}) error { d.Set("driver_info", node.DriverInfo) d.Set("extra", node.Extra) d.Set("inspect_interface", node.InspectInterface) + d.Set("instance_uuid", node.InstanceUUID) d.Set("management_interface", node.ManagementInterface) d.Set("name", node.Name) d.Set("network_interface", node.NetworkInterface) d.Set("owner", node.Owner) d.Set("power_interface", node.PowerInterface) + d.Set("power_state", node.PowerState) d.Set("root_device", node.Properties["root_device"]) delete(node.Properties, "root_device") d.Set("properties", node.Properties) @@ -302,7 +297,6 @@ func resourceNodeV1Read(d *schema.ResourceData, meta interface{}) error { d.Set("storage_interface", node.StorageInterface) d.Set("vendor_interface", node.VendorInterface) d.Set("provision_state", node.ProvisionState) - d.Set("target_provision_state", node.TargetProvisionState) return nil } @@ -348,13 +342,43 @@ func resourceNodeV1Update(d *schema.ResourceData, meta interface{}) error { } } - // Update provision state if required - this could take a while - if d.HasChange("target_provision_state") { - if err := changeProvisionStateToTarget(d, client); err != nil { + // Make node manageable + if (d.HasChange("manage") && d.Get("manage").(bool)) || + (d.HasChange("clean") && d.Get("clean").(bool)) || + (d.HasChange("inspect") && d.Get("inspect").(bool)) { + if err := ChangeProvisionStateToTarget(client, d.Id(), "manage", nil); err != nil { + return fmt.Errorf("could not manage: %s", err) + } + } + + // Update power state if required + if targetPowerState := d.Get("target_power_state").(string); d.HasChange("target_power_state") && targetPowerState != "" { + if err := changePowerState(client, d, nodes.TargetPowerState(targetPowerState)); err != nil { return err } } + // Clean node + if d.HasChange("clean") && d.Get("clean").(bool) { + if err := ChangeProvisionStateToTarget(client, d.Id(), "clean", nil); err != nil { + return fmt.Errorf("could not clean: %s", err) + } + } + + // Inspect node + if d.HasChange("inspect") && d.Get("inspect").(bool) { + if err := ChangeProvisionStateToTarget(client, d.Id(), "inspect", nil); err != nil { + return fmt.Errorf("could not inspect: %s", err) + } + } + + // Make node available + if d.HasChange("available") && d.Get("available").(bool) { + if err := ChangeProvisionStateToTarget(client, d.Id(), "provide", nil); err != nil { + return fmt.Errorf("could not make node available: %s", err) + } + } + if d.HasChange("properties") || d.HasChange("root_device") { properties := propertiesMerge(d, "root_device") opts := nodes.UpdateOpts{ @@ -377,8 +401,11 @@ func resourceNodeV1Update(d *schema.ResourceData, meta interface{}) error { // Delete a node from Ironic func resourceNodeV1Delete(d *schema.ResourceData, meta interface{}) error { client := meta.(*gophercloud.ServiceClient) - d.Set("target_provision_state", "deleted") - return changeProvisionStateToTarget(d, client) + if err := ChangeProvisionStateToTarget(client, d.Id(), "deleted", nil); err != nil { + return err + } + + return nodes.Delete(client, d.Id()).ExtractErr() } func propertiesMerge(d *schema.ResourceData, key string) map[string]interface{} { @@ -414,218 +441,42 @@ func schemaToCreateOpts(d *schema.ResourceData) *nodes.CreateOpts { } } -// provisionStateWorkflow is used to track state through the process of updating's it's provision state -type provisionStateWorkflow struct { - client *gophercloud.ServiceClient - d *schema.ResourceData - target string - wait time.Duration -} - -// Drive Ironic's state machine through the process to reach our desired end state. This requires multiple -// possibly long-running steps. If required, we'll build a config drive ISO for deployment. -// TODO: Handle clean steps and rescue password -func changeProvisionStateToTarget(d *schema.ResourceData, client *gophercloud.ServiceClient) error { - defer resourceNodeV1Read(d, client) // Always refresh resource state before returning - - target := d.Get("target_provision_state").(string) - - // Run the provisionStateWorkflow - this could take a while - wf := provisionStateWorkflow{ - target: target, - client: client, - wait: 5 * time.Second, // FIXME - Make configurable - d: d, - } - - err := wf.run() - return err -} - -// Keep driving the state machine forward -func (workflow *provisionStateWorkflow) run() error { - log.Printf("[INFO] Beginning provisioning workflow, will try to change node to state '%s'", workflow.target) - - for { - done, err := workflow.next() - if done || err != nil { - return err - } - - time.Sleep(workflow.wait) - } - - return nil -} - -func (workflow *provisionStateWorkflow) next() (done bool, err error) { - // Refresh the node on each run - if err := resourceNodeV1Read(workflow.d, workflow.client); err != nil { - return true, err - } - - log.Printf("[DEBUG] Node current state is '%s'", workflow.d.Get("provision_state").(string)) - - switch target := nodes.TargetProvisionState(workflow.target); target { - case nodes.TargetManage: - return workflow.toManageable() - case nodes.TargetProvide: - return workflow.toAvailable() - case nodes.TargetActive: - return workflow.toActive() - case nodes.TargetDeleted: - return workflow.toDeleted() - default: - return true, fmt.Errorf("unknown target state '%s'", target) +// Call Ironic's API and change the power state of the node +func changePowerState(client *gophercloud.ServiceClient, d *schema.ResourceData, target nodes.TargetPowerState) error { + opts := nodes.PowerStateOpts{ + Target: target, } -} -// Change a node to "manageable" stable -func (workflow *provisionStateWorkflow) toManageable() (done bool, err error) { - switch state := workflow.d.Get("provision_state").(string); state { - case "manageable": - // We're done! - return true, err - case "enroll", - "adopt failed", - "clean failed", - "inspect failed", - "available": - return workflow.changeProvisionState(nodes.TargetManage) - case "verifying": - // Not done, no error - Ironic is working - return false, nil - - default: - // TODO: If node is not in a position to go back to manageable, should we delete it (ForceNew) and create it again? - return true, fmt.Errorf("cannot go from state '%s' to state 'manageable'", state) + timeout := d.Get("power_state_timeout").(int) + if timeout != 0 { + opts.Timeout = timeout + } else { + timeout = 300 // used below for how long to wait for Ironic to finish } - return false, nil -} - -// Change a node to "available" state -func (workflow *provisionStateWorkflow) toAvailable() (done bool, err error) { - switch state := workflow.d.Get("provision_state").(string); state { - case "available": - // We're done! - return true, nil - case "cleaning", - "clean wait": - // Not done, no error - Ironic is working - log.Printf("[DEBUG] Node %s is '%s', waiting for Ironic to finish.", workflow.d.Id(), state) - return false, nil - case "manageable": - // From manageable, we can go to provide - log.Printf("[DEBUG] Node %s is '%s', going to change to 'available'", workflow.d.Id(), state) - return workflow.changeProvisionState(nodes.TargetProvide) - default: - // Otherwise we have to get into manageable state first - log.Printf("[DEBUG] Node %s is '%s', going to change to 'manageable'.", workflow.d.Id(), state) - _, err := workflow.toManageable() - if err != nil { - return true, err - } - return false, nil + if err := nodes.ChangePowerState(client, d.Id(), opts).ExtractErr(); err != nil { + return err } - return false, nil -} + // Wait for target_power_state to be empty, i.e. Ironic thinks it's finished + checkInterval := 5 -// Change a node to "active" state -func (workflow *provisionStateWorkflow) toActive() (bool, error) { - - switch state := workflow.d.Get("provision_state"); state { - case "active": - // We're done! - log.Printf("[DEBUG] Node %s is 'active', we are done.", workflow.d.Id()) - return true, nil - case "deploying", - "wait call-back": - // Not done, no error - Ironic is working - log.Printf("[DEBUG] Node %s is '%s', waiting for Ironic to finish.", workflow.d.Id(), state) - return false, nil - case "available": - // From available, we can go to active - log.Printf("[DEBUG] Node %s is 'available', going to change to 'active'.", workflow.d.Id()) - workflow.wait = 30 * time.Second // Deployment takes a while - return workflow.changeProvisionState(nodes.TargetActive) - default: - // Otherwise we have to get into available state first - log.Printf("[DEBUG] Node %s is '%s', going to change to 'available'.", workflow.d.Id(), state) - _, err := workflow.toAvailable() + for { + node, err := nodes.Get(client, d.Id()).Extract() if err != nil { - return true, err - } - return false, nil - } -} - -// Change a node to be "deleted," and remove the object from Ironic -func (workflow *provisionStateWorkflow) toDeleted() (bool, error) { - switch state := workflow.d.Get("provision_state"); state { - case "available", - "enroll": - // We're done deleting the node, we can now remove the object - err := nodes.Delete(workflow.client, workflow.d.Id()).ExtractErr() - return true, err - case "cleaning", - "deleting": - // Not done, no error - Ironic is working - log.Printf("[DEBUG] Node %s is '%s', waiting for Ironic to finish.", workflow.d.Id(), state) - return false, nil - case "active", - "wait call-back", - "deploy failed", - "error": - log.Printf("[DEBUG] Node %s is '%s', going to change to 'deleted'.", workflow.d.Id(), state) - return workflow.changeProvisionState(nodes.TargetDeleted) - default: - return true, fmt.Errorf("cannot delete node in state '%s'", state) - } - - return false, nil -} - -// Builds the ProvisionStateOpts to send to Ironic -- including config drive. -func (workflow *provisionStateWorkflow) buildProvisionStateOpts(target nodes.TargetProvisionState) (*nodes.ProvisionStateOpts, error) { - opts := nodes.ProvisionStateOpts{ - Target: target, - } - - // If we're deploying, then build a config drive to send to Ironic - if target == "active" { - configDrive := utils.ConfigDrive{} - - if userData := utils.UserDataString(workflow.d.Get("user_data").(string)); userData != "" { - configDrive.UserData = userData - } - - if metaData := workflow.d.Get("meta_data"); metaData != nil { - configDrive.MetaData = metaData.(map[string]interface{}) + return err } - if networkData := workflow.d.Get("network_data"); networkData != nil { - configDrive.NetworkData = networkData.(map[string]interface{}) + if node.TargetPowerState == "" { + break } - configDriveData, err := configDrive.ToConfigDrive() - if err != nil { - return nil, err + time.Sleep(time.Duration(checkInterval) * time.Second) + timeout -= checkInterval + if timeout <= 0 { + return fmt.Errorf("timed out waiting for power state change") } - opts.ConfigDrive = configDriveData } - return &opts, nil -} - -// Call Ironic's API and issue the change provision state request. -func (workflow *provisionStateWorkflow) changeProvisionState(target nodes.TargetProvisionState) (done bool, err error) { - opts, err := workflow.buildProvisionStateOpts(target) - if err != nil { - log.Printf("[ERROR] Unable to construct provisioning state options: %s", err.Error()) - return true, err - } - - return false, nodes.ChangeProvisionState(workflow.client, workflow.d.Id(), *opts).ExtractErr() + return nil } diff --git a/pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/workflow.go b/pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/workflow.go new file mode 100644 index 000000000..7dd26fee2 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/openshift-metalkube/terraform-provider-ironic/ironic/workflow.go @@ -0,0 +1,294 @@ +package ironic + +import ( + "fmt" + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes" + utils "github.com/gophercloud/utils/openstack/baremetal/v1/nodes" + "log" + "time" +) + +// provisionStateWorkflow is used to track state through the process of updating's it's provision state +type provisionStateWorkflow struct { + client *gophercloud.ServiceClient + node nodes.Node + uuid string + target nodes.TargetProvisionState + wait time.Duration + + configDrive *utils.ConfigDrive +} + +// ChangeProvisionStateToTarget drives Ironic's state machine through the process to reach our desired end state. This requires multiple +// possibly long-running steps. If required, we'll build a config drive ISO for deployment. +func ChangeProvisionStateToTarget(client *gophercloud.ServiceClient, uuid string, target nodes.TargetProvisionState, configDrive *utils.ConfigDrive) error { + + // Run the provisionStateWorkflow - this could take a while + wf := provisionStateWorkflow{ + target: target, + client: client, + wait: 5 * time.Second, + uuid: uuid, + configDrive: configDrive, + } + + err := wf.run() + return err +} + +// Keep driving the state machine forward +func (workflow *provisionStateWorkflow) run() error { + log.Printf("[INFO] Beginning provisioning workflow, will try to change node to state '%s'", workflow.target) + + for { + done, err := workflow.next() + if done || err != nil { + return err + } + + time.Sleep(workflow.wait) + } + + return nil +} + +// Do the next thing to get us to our target state +func (workflow *provisionStateWorkflow) next() (done bool, err error) { + // Refresh the node on each run + if err := workflow.reloadNode(); err != nil { + return true, err + } + + log.Printf("[DEBUG] Node current state is '%s'", workflow.node.ProvisionState) + + switch target := nodes.TargetProvisionState(workflow.target); target { + case nodes.TargetManage: + return workflow.toManageable() + case nodes.TargetProvide: + return workflow.toAvailable() + case nodes.TargetActive: + return workflow.toActive() + case nodes.TargetDeleted: + return workflow.toDeleted() + case nodes.TargetClean: + return workflow.toClean() + case nodes.TargetInspect: + return workflow.toInspect() + default: + return true, fmt.Errorf("unknown target state '%s'", target) + } +} + +// Change a node to "manageable" stable +func (workflow *provisionStateWorkflow) toManageable() (done bool, err error) { + switch state := workflow.node.ProvisionState; state { + case "manageable": + // We're done! + return true, err + case "enroll", + "adopt failed", + "clean failed", + "inspect failed", + "available": + return workflow.changeProvisionState(nodes.TargetManage) + case "verifying": + // Not done, no error - Ironic is working + return false, nil + + default: + return true, fmt.Errorf("cannot go from state '%s' to state 'manageable'", state) + } + + return false, nil +} + +// Clean a node +func (workflow *provisionStateWorkflow) toClean() (done bool, err error) { + // Node must be manageable first + workflow.reloadNode() + if workflow.node.ProvisionState != string(nodes.Manageable) { + if err := ChangeProvisionStateToTarget(workflow.client, workflow.uuid, nodes.TargetManage, nil); err != nil { + return true, err + } + } + + // Set target to clean + workflow.changeProvisionState(nodes.TargetClean) + + for { + workflow.reloadNode() + state := workflow.node.ProvisionState + + switch state { + case "manageable": + return true, nil + case "cleaning", + "clean wait": + // Not done, no error - Ironic is working + continue + default: + return true, fmt.Errorf("could not clean node, node is currently '%s', last error was '%s'", state, workflow.node.LastError) + } + } + + return true, nil +} + +// Inspect a node +func (workflow *provisionStateWorkflow) toInspect() (done bool, err error) { + // Node must be manageable first + workflow.reloadNode() + if workflow.node.ProvisionState != string(nodes.Manageable) { + if err := ChangeProvisionStateToTarget(workflow.client, workflow.uuid, nodes.TargetManage, nil); err != nil { + return true, err + } + } + + // Set target to inspect + workflow.changeProvisionState(nodes.TargetInspect) + + for { + workflow.reloadNode() + state := workflow.node.ProvisionState + + switch state { + case "manageable": + return true, nil + case "inspecting", + "inspect wait": + // Not done, no error - Ironic is working + continue + default: + return true, fmt.Errorf("could not inspect node, node is currently '%s', last error was '%s'", state, workflow.node.LastError) + } + } + + return true, nil +} + +// Change a node to "available" state +func (workflow *provisionStateWorkflow) toAvailable() (done bool, err error) { + switch state := workflow.node.ProvisionState; state { + case "available": + // We're done! + return true, nil + case "cleaning", + "clean wait": + // Not done, no error - Ironic is working + log.Printf("[DEBUG] Node %s is '%s', waiting for Ironic to finish.", workflow.uuid, state) + return false, nil + case "manageable": + // From manageable, we can go to provide + log.Printf("[DEBUG] Node %s is '%s', going to change to 'available'", workflow.uuid, state) + return workflow.changeProvisionState(nodes.TargetProvide) + default: + // Otherwise we have to get into manageable state first + log.Printf("[DEBUG] Node %s is '%s', going to change to 'manageable'.", workflow.uuid, state) + _, err := workflow.toManageable() + if err != nil { + return true, err + } + return false, nil + } + + return false, nil +} + +// Change a node to "active" state +func (workflow *provisionStateWorkflow) toActive() (bool, error) { + + switch state := workflow.node.ProvisionState; state { + case "active": + // We're done! + log.Printf("[DEBUG] Node %s is 'active', we are done.", workflow.uuid) + return true, nil + case "deploying", + "wait call-back": + // Not done, no error - Ironic is working + log.Printf("[DEBUG] Node %s is '%s', waiting for Ironic to finish.", workflow.uuid, state) + return false, nil + case "available": + // From available, we can go to active + log.Printf("[DEBUG] Node %s is 'available', going to change to 'active'.", workflow.uuid) + workflow.wait = 30 * time.Second // Deployment takes a while + return workflow.changeProvisionState(nodes.TargetActive) + default: + // Otherwise we have to get into available state first + log.Printf("[DEBUG] Node %s is '%s', going to change to 'available'.", workflow.uuid, state) + _, err := workflow.toAvailable() + if err != nil { + return true, err + } + return false, nil + } +} + +// Change a node to be "deleted," and remove the object from Ironic +func (workflow *provisionStateWorkflow) toDeleted() (bool, error) { + switch state := workflow.node.ProvisionState; state { + case "manageable", + "available", + "enroll": + // We're done deleting the node + return true, nil + case "cleaning", + "deleting": + // Not done, no error - Ironic is working + log.Printf("[DEBUG] Node %s is '%s', waiting for Ironic to finish.", workflow.uuid, state) + return false, nil + case "active", + "wait call-back", + "deploy failed", + "error": + log.Printf("[DEBUG] Node %s is '%s', going to change to 'deleted'.", workflow.uuid, state) + return workflow.changeProvisionState(nodes.TargetDeleted) + case "inspect failed", + "clean failed": + // We have to get into manageable state first + log.Printf("[DEBUG] Node %s is '%s', going to change to 'manageable'.", workflow.uuid, state) + _, err := workflow.toManageable() + if err != nil { + return true, err + } + return false, nil + default: + return true, fmt.Errorf("cannot delete node in state '%s'", state) + } + + return false, nil +} + +// Builds the ProvisionStateOpts to send to Ironic -- including config drive. +func (workflow *provisionStateWorkflow) buildProvisionStateOpts(target nodes.TargetProvisionState) (*nodes.ProvisionStateOpts, error) { + opts := nodes.ProvisionStateOpts{ + Target: target, + } + + // If we're deploying, then build a config drive to send to Ironic + if target == "active" { + configDriveData, err := workflow.configDrive.ToConfigDrive() + if err != nil { + return nil, err + } + opts.ConfigDrive = configDriveData + } + + return &opts, nil +} + +// Call Ironic's API and issue the change provision state request. +func (workflow *provisionStateWorkflow) changeProvisionState(target nodes.TargetProvisionState) (done bool, err error) { + opts, err := workflow.buildProvisionStateOpts(target) + if err != nil { + log.Printf("[ERROR] Unable to construct provisioning state options: %s", err.Error()) + return true, err + } + + return false, nodes.ChangeProvisionState(workflow.client, workflow.uuid, *opts).ExtractErr() +} + +// Call Ironic's API and reload the node's current state +func (workflow *provisionStateWorkflow) reloadNode() error { + return nodes.Get(workflow.client, workflow.uuid).ExtractInto(&workflow.node) +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_blockstorage_availability_zones_v3.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_blockstorage_availability_zones_v3.go new file mode 100644 index 000000000..b57829ddc --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_blockstorage_availability_zones_v3.go @@ -0,0 +1,73 @@ +package openstack + +import ( + "fmt" + "sort" + + "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/availabilityzones" + "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" +) + +func dataSourceBlockStorageAvailabilityZonesV3() *schema.Resource { + return &schema.Resource{ + Read: dataSourceBlockStorageAvailabilityZonesV3Read, + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + + "state": { + Type: schema.TypeString, + Default: "available", + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"available", "unavailable"}, true), + }, + + "names": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceBlockStorageAvailabilityZonesV3Read(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + client, err := config.blockStorageV3Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating OpenStack block storage client: %s", err) + } + + allPages, err := availabilityzones.List(client).AllPages() + if err != nil { + return fmt.Errorf("Error retrieving openstack_blockstorage_availability_zones_v3: %s", err) + } + zoneInfo, err := availabilityzones.ExtractAvailabilityZones(allPages) + if err != nil { + return fmt.Errorf("Error extracting openstack_blockstorage_availability_zones_v3 from response: %s", err) + } + + stateBool := d.Get("state").(string) == "available" + var zones []string + for _, z := range zoneInfo { + if z.ZoneState.Available == stateBool { + zones = append(zones, z.ZoneName) + } + } + + // sort.Strings sorts in place, returns nothing + sort.Strings(zones) + + d.SetId(hashcode.Strings(zones)) + d.Set("names", zones) + d.Set("region", GetRegion(d, config)) + + return nil +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_identity_auth_scope_v3.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_identity_auth_scope_v3.go index d062f734b..230ecd211 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_identity_auth_scope_v3.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_identity_auth_scope_v3.go @@ -105,7 +105,7 @@ func dataSourceIdentityAuthScopeV3Read(d *schema.ResourceData, meta interface{}) } d.Set("user_name", user.Name) - d.Set("user_id", user.Name) + d.Set("user_id", user.ID) d.Set("user_domain_name", user.Domain.Name) d.Set("user_domain_id", user.Domain.ID) diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_addressscope_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_addressscope_v2.go new file mode 100644 index 000000000..a56d9920b --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_addressscope_v2.go @@ -0,0 +1,101 @@ +package openstack + +import ( + "fmt" + "log" + + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/addressscopes" + + "github.com/hashicorp/terraform/helper/schema" +) + +func dataSourceNetworkingAddressScopeV2() *schema.Resource { + return &schema.Resource{ + Read: dataSourceNetworkingAddressScopeV2Read, + + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + }, + + "name": { + Type: schema.TypeString, + Optional: true, + }, + + "ip_version": { + Type: schema.TypeInt, + Optional: true, + }, + + "shared": { + Type: schema.TypeBool, + Optional: true, + }, + + "project_id": { + Type: schema.TypeString, + Optional: true, + }, + }, + } +} + +func dataSourceNetworkingAddressScopeV2Read(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + listOpts := addressscopes.ListOpts{} + + if v, ok := d.GetOk("name"); ok { + listOpts.Name = v.(string) + } + + if v, ok := d.GetOk("ip_version"); ok { + listOpts.IPVersion = v.(int) + } + + if v, ok := d.GetOkExists("shared"); ok { + shared := v.(bool) + listOpts.Shared = &shared + } + + if v, ok := d.GetOk("project_id"); ok { + listOpts.ProjectID = v.(string) + } + + pages, err := addressscopes.List(networkingClient, listOpts).AllPages() + if err != nil { + return fmt.Errorf("Unable to list openstack_networking_addressscope_v2: %s", err) + } + + allAddressScopes, err := addressscopes.ExtractAddressScopes(pages) + if err != nil { + return fmt.Errorf("Unable to retrieve openstack_networking_addressscope_v2: %s", err) + } + + if len(allAddressScopes) < 1 { + return fmt.Errorf("No openstack_networking_addressscope_v2 found") + } + + if len(allAddressScopes) > 1 { + return fmt.Errorf("More than one openstack_networking_addressscope_v2 found") + } + + a := allAddressScopes[0] + + log.Printf("[DEBUG] Retrieved openstack_networking_addressscope_v2 %s: %+v", a.ID, a) + d.SetId(a.ID) + + d.Set("region", GetRegion(d, config)) + d.Set("name", a.Name) + d.Set("ip_version", a.IPVersion) + d.Set("shared", a.Shared) + d.Set("project_id", a.ProjectID) + + return nil +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_floatingip_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_floatingip_v2.go index 144e91584..b0379f224 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_floatingip_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_floatingip_v2.go @@ -61,6 +61,16 @@ func dataSourceNetworkingFloatingIPV2() *schema.Resource { Elem: &schema.Schema{Type: schema.TypeString}, }, + "dns_name": { + Type: schema.TypeString, + Computed: true, + }, + + "dns_domain": { + Type: schema.TypeString, + Computed: true, + }, + "all_tags": { Type: schema.TypeSet, Computed: true, @@ -117,7 +127,9 @@ func dataSourceNetworkingFloatingIPV2Read(d *schema.ResourceData, meta interface return fmt.Errorf("Unable to list openstack_networking_floatingips_v2: %s", err) } - allFloatingIPs, err := floatingips.ExtractFloatingIPs(pages) + var allFloatingIPs []floatingIPExtended + + err = floatingips.ExtractFloatingIPsInto(pages, &allFloatingIPs) if err != nil { return fmt.Errorf("Unable to retrieve openstack_networking_floatingips_v2: %s", err) } @@ -136,13 +148,15 @@ func dataSourceNetworkingFloatingIPV2Read(d *schema.ResourceData, meta interface d.SetId(fip.ID) d.Set("description", fip.Description) - d.Set("address", fip.FloatingIP) + d.Set("address", fip.FloatingIP.FloatingIP) d.Set("pool", fip.FloatingNetworkID) d.Set("port_id", fip.PortID) d.Set("fixed_ip", fip.FixedIP) d.Set("tenant_id", fip.TenantID) d.Set("status", fip.Status) d.Set("all_tags", fip.Tags) + d.Set("dns_name", fip.DNSName) + d.Set("dns_domain", fip.DNSDomain) d.Set("region", GetRegion(d, config)) return nil diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_network_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_network_v2.go index 50b626785..8c3c27970 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_network_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_network_v2.go @@ -10,6 +10,7 @@ import ( "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external" + mtuext "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/mtu" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/vlantransparent" "github.com/gophercloud/gophercloud/openstack/networking/v2/networks" "github.com/gophercloud/gophercloud/openstack/networking/v2/subnets" @@ -90,6 +91,16 @@ func dataSourceNetworkingNetworkV2() *schema.Resource { Elem: &schema.Schema{Type: schema.TypeString}, }, + "mtu": { + Type: schema.TypeInt, + Optional: true, + }, + + "dns_domain": { + Type: schema.TypeString, + Computed: true, + }, + "all_tags": { Type: schema.TypeSet, Computed: true, @@ -140,6 +151,14 @@ func dataSourceNetworkingNetworkV2Read(d *schema.ResourceData, meta interface{}) } } + // Add the MTU attribute if specified. + if v, ok := d.GetOkExists("mtu"); ok { + listOpts = mtuext.ListOptsExt{ + ListOptsBuilder: listOpts, + MTU: v.(int), + } + } + tags := networkV2AttributesTags(d) if len(tags) > 0 { listOpts = networks.ListOpts{Tags: strings.Join(tags, ",")} @@ -162,18 +181,13 @@ func dataSourceNetworkingNetworkV2Read(d *schema.ResourceData, meta interface{}) "Please change your search criteria and try again.") } - type networkWithExternalExt struct { - networks.Network - external.NetworkExternalExt - vlantransparent.TransparentExt - } - var allNetworks []networkWithExternalExt + var allNetworks []networkExtended err = networks.ExtractNetworksInto(pages, &allNetworks) if err != nil { return fmt.Errorf("Unable to retrieve openstack_networking_networks_v2: %s", err) } - var refinedNetworks []networkWithExternalExt + var refinedNetworks []networkExtended if cidr := d.Get("matching_subnet_cidr").(string); cidr != "" { for _, n := range allNetworks { for _, s := range n.Subnets { @@ -220,6 +234,8 @@ func dataSourceNetworkingNetworkV2Read(d *schema.ResourceData, meta interface{}) d.Set("tenant_id", network.TenantID) d.Set("transparent_vlan", network.VLANTransparent) d.Set("all_tags", network.Tags) + d.Set("mtu", network.MTU) + d.Set("dns_domain", network.DNSDomain) d.Set("region", GetRegion(d, config)) return nil diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_port_ids_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_port_ids_v2.go index f84c24e94..ef32bb45a 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_port_ids_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_port_ids_v2.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/dns" "github.com/gophercloud/gophercloud/openstack/networking/v2/ports" ) @@ -105,6 +106,12 @@ func dataSourceNetworkingPortIDsV2() *schema.Resource { Elem: &schema.Schema{Type: schema.TypeString}, }, + "dns_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "sort_key": { Type: schema.TypeString, Optional: true, @@ -137,6 +144,7 @@ func dataSourceNetworkingPortIDsV2Read(d *schema.ResourceData, meta interface{}) } listOpts := ports.ListOpts{} + var listOptsBuilder ports.ListOptsBuilder if v, ok := d.GetOk("sort_key"); ok { listOpts.SortKey = v.(string) @@ -192,7 +200,16 @@ func dataSourceNetworkingPortIDsV2Read(d *schema.ResourceData, meta interface{}) listOpts.Tags = strings.Join(tags, ",") } - allPages, err := ports.List(networkingClient, listOpts).AllPages() + listOptsBuilder = listOpts + + if v, ok := d.GetOk("dns_name"); ok { + listOptsBuilder = dns.PortListOptsExt{ + ListOptsBuilder: listOptsBuilder, + DNSName: v.(string), + } + } + + allPages, err := ports.List(networkingClient, listOptsBuilder).AllPages() if err != nil { return fmt.Errorf("Unable to list openstack_networking_port_ids_v2: %s", err) } diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_port_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_port_v2.go index 87e571376..d8cb10b9c 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_port_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_port_v2.go @@ -6,17 +6,13 @@ import ( "strings" "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/structure" "github.com/hashicorp/terraform/helper/validation" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/extradhcpopts" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/dns" "github.com/gophercloud/gophercloud/openstack/networking/v2/ports" ) -type extraPort struct { - ports.Port - extradhcpopts.ExtraDHCPOptsExt -} - func dataSourceNetworkingPortV2() *schema.Resource { return &schema.Resource{ Read: dataSourceNetworkingPortV2Read, @@ -140,7 +136,7 @@ func dataSourceNetworkingPortV2() *schema.Resource { }, "extra_dhcp_option": { - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -159,6 +155,50 @@ func dataSourceNetworkingPortV2() *schema.Resource { }, }, }, + + "binding": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "host_id": { + Type: schema.TypeString, + Computed: true, + }, + "profile": { + Type: schema.TypeString, + Computed: true, + StateFunc: func(v interface{}) string { + json, _ := structure.NormalizeJsonString(v) + return json + }, + }, + "vif_details": { + Type: schema.TypeMap, + Computed: true, + }, + "vif_type": { + Type: schema.TypeString, + Computed: true, + }, + "vnic_type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "dns_name": { + Type: schema.TypeString, + Optional: true, + }, + + "dns_assignment": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeMap}, + }, }, } } @@ -171,6 +211,7 @@ func dataSourceNetworkingPortV2Read(d *schema.ResourceData, meta interface{}) er } listOpts := ports.ListOpts{} + var listOptsBuilder ports.ListOptsBuilder if v, ok := d.GetOk("port_id"); ok { listOpts.ID = v.(string) @@ -222,12 +263,21 @@ func dataSourceNetworkingPortV2Read(d *schema.ResourceData, meta interface{}) er listOpts.Tags = strings.Join(tags, ",") } - allPages, err := ports.List(networkingClient, listOpts).AllPages() + listOptsBuilder = listOpts + + if v, ok := d.GetOk("dns_name"); ok { + listOptsBuilder = dns.PortListOptsExt{ + ListOptsBuilder: listOptsBuilder, + DNSName: v.(string), + } + } + + allPages, err := ports.List(networkingClient, listOptsBuilder).AllPages() if err != nil { return fmt.Errorf("Unable to list openstack_networking_ports_v2: %s", err) } - var allPorts []extraPort + var allPorts []portExtended err = ports.ExtractPortsInto(allPages, &allPorts) if err != nil { @@ -238,7 +288,7 @@ func dataSourceNetworkingPortV2Read(d *schema.ResourceData, meta interface{}) er return fmt.Errorf("No openstack_networking_port_v2 found") } - var portsList []extraPort + var portsList []portExtended // Filter returned Fixed IPs by a "fixed_ip". if v, ok := d.GetOk("fixed_ip"); ok { @@ -259,7 +309,7 @@ func dataSourceNetworkingPortV2Read(d *schema.ResourceData, meta interface{}) er securityGroups := expandToStringSlice(d.Get("security_group_ids").(*schema.Set).List()) if len(securityGroups) > 0 { - var sgPorts []extraPort + var sgPorts []portExtended for _, p := range portsList { for _, sg := range p.SecurityGroups { if strSliceContains(securityGroups, sg) { @@ -299,6 +349,9 @@ func dataSourceNetworkingPortV2Read(d *schema.ResourceData, meta interface{}) er d.Set("all_fixed_ips", expandNetworkingPortFixedIPToStringSlice(port.FixedIPs)) d.Set("allowed_address_pairs", flattenNetworkingPortAllowedAddressPairsV2(port.MACAddress, port.AllowedAddressPairs)) d.Set("extra_dhcp_option", flattenNetworkingPortDHCPOptsV2(port.ExtraDHCPOptsExt)) + d.Set("binding", flattenNetworkingPortBindingV2(port)) + d.Set("dns_name", port.DNSName) + d.Set("dns_assignment", port.DNSAssignment) return nil } diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_trunk_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_trunk_v2.go new file mode 100644 index 000000000..8b3a613a7 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_networking_trunk_v2.go @@ -0,0 +1,185 @@ +package openstack + +import ( + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform/helper/schema" + + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/trunks" +) + +func dataSourceNetworkingTrunkV2() *schema.Resource { + return &schema.Resource{ + Read: dataSourceNetworkingTrunkV2Read, + + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "name": { + Type: schema.TypeString, + Optional: true, + }, + + "description": { + Type: schema.TypeString, + Optional: true, + }, + + "trunk_id": { + Type: schema.TypeString, + Optional: true, + }, + + "port_id": { + Type: schema.TypeString, + Optional: true, + }, + + "admin_state_up": { + Type: schema.TypeBool, + Optional: true, + }, + + "status": { + Type: schema.TypeString, + Optional: true, + }, + + "project_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "sub_port": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "port_id": { + Type: schema.TypeString, + Computed: true, + }, + "segmentation_type": { + Type: schema.TypeString, + Computed: true, + }, + "segmentation_id": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + + "tags": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "all_tags": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func dataSourceNetworkingTrunkV2Read(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + listOpts := trunks.ListOpts{} + + if v, ok := d.GetOk("name"); ok { + listOpts.Name = v.(string) + } + + if v, ok := d.GetOk("description"); ok { + listOpts.Description = v.(string) + } + + if v, ok := d.GetOk("trunk_id"); ok { + listOpts.ID = v.(string) + } + + if v, ok := d.GetOk("port_id"); ok { + listOpts.PortID = v.(string) + } + + if v, ok := d.GetOkExists("admin_state_up"); ok { + asu := v.(bool) + listOpts.AdminStateUp = &asu + } + + if v, ok := d.GetOk("project_id"); ok { + listOpts.ProjectID = v.(string) + } + + if v, ok := d.GetOk("status"); ok { + listOpts.Status = v.(string) + } + + tags := networkV2AttributesTags(d) + if len(tags) > 0 { + listOpts.Tags = strings.Join(tags, ",") + } + + pages, err := trunks.List(networkingClient, listOpts).AllPages() + if err != nil { + return fmt.Errorf("Unable to retrieve trunks: %s", err) + } + + allTrunks, err := trunks.ExtractTrunks(pages) + if err != nil { + return fmt.Errorf("Unable to extract trunks: %s", err) + } + + if len(allTrunks) < 1 { + return fmt.Errorf("Your query returned no results. " + + "Please change your search criteria and try again.") + } + + if len(allTrunks) > 1 { + return fmt.Errorf("Your query returned more than one result." + + " Please try a more specific search criteria") + } + + trunk := allTrunks[0] + + log.Printf("[DEBUG] Retrieved Trunk %s: %+v", trunk.ID, trunk) + d.SetId(trunk.ID) + + d.Set("region", GetRegion(d, config)) + d.Set("name", trunk.Name) + d.Set("description", trunk.Description) + d.Set("port_id", trunk.PortID) + d.Set("admin_state_up", trunk.AdminStateUp) + d.Set("status", trunk.Status) + d.Set("project_id", trunk.ProjectID) + d.Set("all_tags", trunk.Tags) + + subports := make([]map[string]interface{}, len(trunk.Subports)) + for i, trunkSubport := range trunk.Subports { + subports[i] = make(map[string]interface{}) + subports[i]["port_id"] = trunkSubport.PortID + subports[i]["segmentation_type"] = trunkSubport.SegmentationType + subports[i]["segmentation_id"] = trunkSubport.SegmentationID + } + if err = d.Set("sub_port", subports); err != nil { + return fmt.Errorf("Unable to set sub_port for trunk %s: %s", d.Id(), err) + } + + return nil +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_sharedfilesystem_availability_zones_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_sharedfilesystem_availability_zones_v2.go new file mode 100644 index 000000000..5789be8e5 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/data_source_openstack_sharedfilesystem_availability_zones_v2.go @@ -0,0 +1,62 @@ +package openstack + +import ( + "fmt" + "sort" + + "github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/availabilityzones" + "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/schema" +) + +func dataSourceSharedFilesystemAvailabilityZonesV2() *schema.Resource { + return &schema.Resource{ + Read: dataSourceSharedFilesystemAvailabilityZonesV2Read, + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + + "names": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceSharedFilesystemAvailabilityZonesV2Read(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + client, err := config.sharedfilesystemV2Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating OpenStack sharedfilesystem client: %s", err) + } + + allPages, err := availabilityzones.List(client).AllPages() + if err != nil { + return fmt.Errorf("Error retrieving openstack_sharedfilesystem_availability_zones_v2: %s", err) + } + zoneInfo, err := availabilityzones.ExtractAvailabilityZones(allPages) + if err != nil { + return fmt.Errorf("Error extracting openstack_sharedfilesystem_availability_zones_v2 from response: %s", err) + } + + var zones []string + for _, z := range zoneInfo { + zones = append(zones, z.Name) + } + + // sort.Strings sorts in place, returns nothing + sort.Strings(zones) + + d.SetId(hashcode.Strings(zones)) + d.Set("names", zones) + d.Set("region", GetRegion(d, config)) + + return nil +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/db_configuration_v1.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/db_configuration_v1.go new file mode 100644 index 000000000..715d14b6e --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/db_configuration_v1.go @@ -0,0 +1,55 @@ +package openstack + +import ( + "strconv" + + "github.com/hashicorp/terraform/helper/resource" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack/db/v1/configurations" +) + +func expandDatabaseConfigurationV1Datastore(rawDatastore []interface{}) configurations.DatastoreOpts { + v := rawDatastore[0].(map[string]interface{}) + datastore := configurations.DatastoreOpts{ + Version: v["version"].(string), + Type: v["type"].(string), + } + + return datastore +} + +func expandDatabaseConfigurationV1Values(rawValues []interface{}) map[string]interface{} { + values := make(map[string]interface{}) + + for _, rawValue := range rawValues { + v := rawValue.(map[string]interface{}) + name := v["name"].(string) + value := v["value"].(interface{}) + + // check if value can be converted into int + if valueInt, err := strconv.Atoi(value.(string)); err == nil { + value = valueInt + } + + values[name] = value + } + + return values +} + +// databaseConfigurationV1StateRefreshFunc returns a resource.StateRefreshFunc that is used to watch +// an cloud database instance. +func databaseConfigurationV1StateRefreshFunc(client *gophercloud.ServiceClient, cgroupID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + i, err := configurations.Get(client, cgroupID).Extract() + if err != nil { + if _, ok := err.(gophercloud.ErrDefault404); ok { + return i, "DELETED", nil + } + return nil, "", err + } + + return i, "ACTIVE", nil + } +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/db_database_v1.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/db_database_v1.go new file mode 100644 index 000000000..c5a3fcd6b --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/db_database_v1.go @@ -0,0 +1,58 @@ +package openstack + +import ( + "fmt" + + "github.com/hashicorp/terraform/helper/resource" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack/db/v1/databases" +) + +// databaseDatabaseV1StateRefreshFunc returns a resource.StateRefreshFunc +// that is used to watch a database. +func databaseDatabaseV1StateRefreshFunc(client *gophercloud.ServiceClient, instanceID string, dbName string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + pages, err := databases.List(client, instanceID).AllPages() + if err != nil { + return nil, "", fmt.Errorf("Unable to retrieve OpenStack databases: %s", err) + } + + allDatabases, err := databases.ExtractDBs(pages) + if err != nil { + return nil, "", fmt.Errorf("Unable to extract OpenStack databases: %s", err) + } + + for _, v := range allDatabases { + if v.Name == dbName { + return v, "ACTIVE", nil + } + } + + return nil, "BUILD", nil + } +} + +func databaseDatabaseV1Exists(client *gophercloud.ServiceClient, instanceID string, dbName string) (bool, error) { + var exists bool + var err error + + pages, err := databases.List(client, instanceID).AllPages() + if err != nil { + return exists, err + } + + allDatabases, err := databases.ExtractDBs(pages) + if err != nil { + return exists, err + } + + for _, v := range allDatabases { + if v.Name == dbName { + exists = true + return exists, err + } + } + + return false, nil +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/db_instance_v1.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/db_instance_v1.go new file mode 100644 index 000000000..01a251a23 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/db_instance_v1.go @@ -0,0 +1,99 @@ +package openstack + +import ( + "fmt" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack/db/v1/databases" + "github.com/gophercloud/gophercloud/openstack/db/v1/instances" + "github.com/gophercloud/gophercloud/openstack/db/v1/users" +) + +func expandDatabaseInstanceV1Datastore(rawDatastore []interface{}) instances.DatastoreOpts { + v := rawDatastore[0].(map[string]interface{}) + datastore := instances.DatastoreOpts{ + Version: v["version"].(string), + Type: v["type"].(string), + } + + return datastore +} + +func expandDatabaseInstanceV1Networks(rawNetworks []interface{}) []instances.NetworkOpts { + var networks []instances.NetworkOpts + for _, v := range rawNetworks { + network := v.(map[string]interface{}) + networks = append(networks, instances.NetworkOpts{ + UUID: network["uuid"].(string), + Port: network["port"].(string), + V4FixedIP: network["fixed_ip_v4"].(string), + V6FixedIP: network["fixed_ip_v6"].(string), + }) + } + + return networks +} + +func expandDatabaseInstanceV1Databases(rawDatabases []interface{}) databases.BatchCreateOpts { + var dbs databases.BatchCreateOpts + for _, v := range rawDatabases { + db := v.(map[string]interface{}) + dbs = append(dbs, databases.CreateOpts{ + Name: db["name"].(string), + CharSet: db["charset"].(string), + Collate: db["collate"].(string), + }) + } + + return dbs +} + +func expandDatabaseInstanceV1Users(rawUsers []interface{}) users.BatchCreateOpts { + var userList users.BatchCreateOpts + for _, v := range rawUsers { + user := v.(map[string]interface{}) + userList = append(userList, users.CreateOpts{ + Name: user["name"].(string), + Password: user["password"].(string), + Databases: expandInstanceV1UserDatabases(user["databases"].(*schema.Set).List()), + Host: user["host"].(string), + }) + } + + return userList +} + +// databaseInstanceV1StateRefreshFunc returns a resource.StateRefreshFunc +// that is used to watch a database instance. +func databaseInstanceV1StateRefreshFunc(client *gophercloud.ServiceClient, instanceID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + i, err := instances.Get(client, instanceID).Extract() + if err != nil { + if _, ok := err.(gophercloud.ErrDefault404); ok { + return i, "DELETED", nil + } + return nil, "", err + } + + if i.Status == "error" { + return i, i.Status, fmt.Errorf("There was an error creating the database instance.") + } + + return i, i.Status, nil + } +} + +func expandInstanceV1UserDatabases(v []interface{}) databases.BatchCreateOpts { + var dbs databases.BatchCreateOpts + + for _, db := range v { + dbs = append(dbs, databases.CreateOpts{ + Name: db.(string), + }) + } + + return dbs +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/db_user_v1.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/db_user_v1.go new file mode 100644 index 000000000..49705d6ee --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/db_user_v1.go @@ -0,0 +1,81 @@ +package openstack + +import ( + "fmt" + + "github.com/hashicorp/terraform/helper/resource" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack/db/v1/databases" + "github.com/gophercloud/gophercloud/openstack/db/v1/users" +) + +func expandDatabaseUserV1Databases(rawDatabases []interface{}) databases.BatchCreateOpts { + var dbs databases.BatchCreateOpts + + for _, db := range rawDatabases { + dbs = append(dbs, databases.CreateOpts{ + Name: db.(string), + }) + } + + return dbs +} + +func flattenDatabaseUserV1Databases(dbs []databases.Database) []string { + var databases []string + for _, db := range dbs { + databases = append(databases, db.Name) + } + + return databases +} + +// databaseUserV1StateRefreshFunc returns a resource.StateRefreshFunc that is used to watch db user. +func databaseUserV1StateRefreshFunc(client *gophercloud.ServiceClient, instanceID string, userName string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + pages, err := users.List(client, instanceID).AllPages() + if err != nil { + return nil, "", fmt.Errorf("Unable to retrieve OpenStack database users: %s", err) + } + + allUsers, err := users.ExtractUsers(pages) + if err != nil { + return nil, "", fmt.Errorf("Unable to extract OpenStack database users: %s", err) + } + + for _, v := range allUsers { + if v.Name == userName { + return v, "ACTIVE", nil + } + } + + return nil, "BUILD", nil + } +} + +// databaseUserV1Exists is used to check whether user exists on particular database instance +func databaseUserV1Exists(client *gophercloud.ServiceClient, instanceID string, userName string) (bool, users.User, error) { + var exists bool + var err error + var userObj users.User + + pages, err := users.List(client, instanceID).AllPages() + if err != nil { + return exists, userObj, err + } + + allUsers, err := users.ExtractUsers(pages) + if err != nil { + return exists, userObj, err + } + + for _, v := range allUsers { + if v.Name == userName { + exists = true + return exists, v, nil + } + } + + return false, userObj, err +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/fw_policy_v1.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/fw_policy_v1.go index 4781ba773..4211110ba 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/fw_policy_v1.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/fw_policy_v1.go @@ -26,13 +26,11 @@ func fwPolicyV1DeleteFunc(networkingClient *gophercloud.ServiceClient, id string return "", "DELETED", nil } - if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok { - if errCode.Actual == 409 { - // This error usually means that the policy is attached - // to a firewall. At this point, the firewall is probably - // being delete. So, we retry a few times. - return nil, "ACTIVE", nil - } + if _, ok := err.(gophercloud.ErrDefault409); ok { + // This error usually means that the policy is attached + // to a firewall. At this point, the firewall is probably + // being delete. So, we retry a few times. + return nil, "ACTIVE", nil } return nil, "ACTIVE", err diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/identity_application_credential_v3.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/identity_application_credential_v3.go new file mode 100644 index 000000000..54b632d92 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/identity_application_credential_v3.go @@ -0,0 +1,21 @@ +package openstack + +import ( + "github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials" +) + +func flattenIdentityApplicationCredentialRolesV3(roles []applicationcredentials.Role) []string { + var res []string + for _, role := range roles { + res = append(res, role.Name) + } + return res +} + +func expandIdentityApplicationCredentialRolesV3(roles []interface{}) []applicationcredentials.Role { + var res []applicationcredentials.Role + for _, role := range roles { + res = append(res, applicationcredentials.Role{Name: role.(string)}) + } + return res +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/lb_v2_shared.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/lb_v2_shared.go index d41e90e1c..71dca200e 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/lb_v2_shared.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/lb_v2_shared.go @@ -327,7 +327,11 @@ func resourceLBV2LoadBalancerStatusRefreshFuncNeutron(lbClient *gophercloud.Serv return nil, "", fmt.Errorf("Unable to get statuses from the Load Balancer %s statuses tree: %s", lbID, err) } - if !strSliceContains(lbSkipLBStatuses, statuses.Loadbalancer.ProvisioningStatus) { + // Don't fail, when statuses returns "null" + if statuses == nil || statuses.Loadbalancer == nil { + statuses = new(loadbalancers.StatusTree) + statuses.Loadbalancer = new(loadbalancers.LoadBalancer) + } else if !strSliceContains(lbSkipLBStatuses, statuses.Loadbalancer.ProvisioningStatus) { return statuses.Loadbalancer, statuses.Loadbalancer.ProvisioningStatus, nil } diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_floatingip_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_floatingip_v2.go index 6b51ef9fc..ebdb6a9ff 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_floatingip_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_floatingip_v2.go @@ -4,10 +4,16 @@ import ( "fmt" "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/dns" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" "github.com/hashicorp/terraform/helper/resource" ) +type floatingIPExtended struct { + floatingips.FloatingIP + dns.FloatingIPDNSExt +} + // networkingFloatingIPV2ID retrieves floating IP ID by the provided IP address. func networkingFloatingIPV2ID(client *gophercloud.ServiceClient, floatingIP string) (string, error) { listOpts := floatingips.ListOpts{ diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_network_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_network_v2.go index d7f001757..3d4e0563f 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_network_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_network_v2.go @@ -4,7 +4,12 @@ import ( "fmt" "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/dns" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/mtu" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/provider" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/vlantransparent" "github.com/gophercloud/gophercloud/openstack/networking/v2/networks" "github.com/gophercloud/gophercloud/pagination" @@ -12,6 +17,16 @@ import ( "github.com/hashicorp/terraform/helper/schema" ) +type networkExtended struct { + networks.Network + external.NetworkExternalExt + vlantransparent.TransparentExt + provider.NetworkProviderExt + portsecurity.PortSecurityExt + mtu.NetworkMTUExt + dns.NetworkDNSExt +} + // networkingNetworkV2ID retrieves network ID by the provided name. func networkingNetworkV2ID(d *schema.ResourceData, meta interface{}, networkName string) (string, error) { config := meta.(*Config) @@ -81,10 +96,8 @@ func resourceNetworkingNetworkV2StateRefreshFunc(client *gophercloud.ServiceClie if _, ok := err.(gophercloud.ErrDefault404); ok { return n, "DELETED", nil } - if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok { - if errCode.Actual == 409 { - return n, "ACTIVE", nil - } + if _, ok := err.(gophercloud.ErrDefault409); ok { + return n, "ACTIVE", nil } return n, "", err diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_port_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_port_v2.go index 96b35203c..04e03bb84 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_port_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_port_v2.go @@ -2,16 +2,29 @@ package openstack import ( "bytes" + "encoding/json" "fmt" + "log" "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/dns" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/extradhcpopts" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsbinding" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity" "github.com/gophercloud/gophercloud/openstack/networking/v2/ports" "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" ) +type portExtended struct { + ports.Port + extradhcpopts.ExtraDHCPOptsExt + portsecurity.PortSecurityExt + portsbinding.PortsBindingExt + dns.PortDNSExt +} + func resourceNetworkingPortV2StateRefreshFunc(client *gophercloud.ServiceClient, portID string) resource.StateRefreshFunc { return func() (interface{}, string, error) { n, err := ports.Get(client, portID).Extract() @@ -28,60 +41,62 @@ func resourceNetworkingPortV2StateRefreshFunc(client *gophercloud.ServiceClient, } func expandNetworkingPortDHCPOptsV2Create(dhcpOpts *schema.Set) []extradhcpopts.CreateExtraDHCPOpt { - rawDHCPOpts := dhcpOpts.List() + var extraDHCPOpts []extradhcpopts.CreateExtraDHCPOpt - extraDHCPOpts := make([]extradhcpopts.CreateExtraDHCPOpt, len(rawDHCPOpts)) - for i, raw := range rawDHCPOpts { - rawMap := raw.(map[string]interface{}) + if dhcpOpts != nil { + for _, raw := range dhcpOpts.List() { + rawMap := raw.(map[string]interface{}) - ipVersion := rawMap["ip_version"].(int) - optName := rawMap["name"].(string) - optValue := rawMap["value"].(string) + ipVersion := rawMap["ip_version"].(int) + optName := rawMap["name"].(string) + optValue := rawMap["value"].(string) - extraDHCPOpts[i] = extradhcpopts.CreateExtraDHCPOpt{ - OptName: optName, - OptValue: optValue, - IPVersion: gophercloud.IPVersion(ipVersion), + extraDHCPOpts = append(extraDHCPOpts, extradhcpopts.CreateExtraDHCPOpt{ + OptName: optName, + OptValue: optValue, + IPVersion: gophercloud.IPVersion(ipVersion), + }) } } return extraDHCPOpts } -func expandNetworkingPortDHCPOptsV2Update(dhcpOpts *schema.Set) []extradhcpopts.UpdateExtraDHCPOpt { - rawDHCPOpts := dhcpOpts.List() - - extraDHCPOpts := make([]extradhcpopts.UpdateExtraDHCPOpt, len(rawDHCPOpts)) - for i, raw := range rawDHCPOpts { - rawMap := raw.(map[string]interface{}) - - ipVersion := rawMap["ip_version"].(int) - optName := rawMap["name"].(string) - optValue := rawMap["value"].(string) - - extraDHCPOpts[i] = extradhcpopts.UpdateExtraDHCPOpt{ - OptName: optName, - OptValue: &optValue, - IPVersion: gophercloud.IPVersion(ipVersion), +func expandNetworkingPortDHCPOptsV2Update(oldDHCPopts, newDHCPopts *schema.Set) []extradhcpopts.UpdateExtraDHCPOpt { + var extraDHCPOpts []extradhcpopts.UpdateExtraDHCPOpt + var newOptNames []string + + if newDHCPopts != nil { + for _, raw := range newDHCPopts.List() { + rawMap := raw.(map[string]interface{}) + + ipVersion := rawMap["ip_version"].(int) + optName := rawMap["name"].(string) + optValue := rawMap["value"].(string) + // DHCP option name is the primary key, we will check this key below + newOptNames = append(newOptNames, optName) + + extraDHCPOpts = append(extraDHCPOpts, extradhcpopts.UpdateExtraDHCPOpt{ + OptName: optName, + OptValue: &optValue, + IPVersion: gophercloud.IPVersion(ipVersion), + }) } } - return extraDHCPOpts -} - -func expandNetworkingPortDHCPOptsV2Delete(dhcpOpts *schema.Set) []extradhcpopts.UpdateExtraDHCPOpt { - if dhcpOpts == nil { - return []extradhcpopts.UpdateExtraDHCPOpt{} - } + if oldDHCPopts != nil { + for _, raw := range oldDHCPopts.List() { + rawMap := raw.(map[string]interface{}) - rawDHCPOpts := dhcpOpts.List() + optName := rawMap["name"].(string) - extraDHCPOpts := make([]extradhcpopts.UpdateExtraDHCPOpt, len(rawDHCPOpts)) - for i, raw := range rawDHCPOpts { - rawMap := raw.(map[string]interface{}) - extraDHCPOpts[i] = extradhcpopts.UpdateExtraDHCPOpt{ - OptName: rawMap["name"].(string), - OptValue: nil, + // if we already add a new option with the same name, it means that we update it, no need to delete + if !strSliceContains(newOptNames, optName) { + extraDHCPOpts = append(extraDHCPOpts, extradhcpopts.UpdateExtraDHCPOpt{ + OptName: optName, + OptValue: nil, + }) + } } } @@ -178,3 +193,54 @@ func expandNetworkingPortFixedIPToStringSlice(fixedIPs []ports.IP) []string { return s } + +func flattenNetworkingPortBindingV2(port portExtended) interface{} { + var portBinding []map[string]interface{} + var profile interface{} + + // "TypeMap" with "ValidateFunc", "DiffSuppressFunc" and "StateFunc" combination + // is not supported by Terraform. Therefore a regular JSON string is used for the + // port resource. + tmp, err := json.Marshal(port.Profile) + if err != nil { + log.Printf("[DEBUG] flattenNetworkingPortBindingV2: Cannot marshal port.Profile: %s", err) + } + profile = string(tmp) + + vifDetails := make(map[string]string) + for k, v := range port.VIFDetails { + // don't marshal, if it is a regular string + if s, ok := v.(string); ok { + vifDetails[k] = s + continue + } + + p, err := json.Marshal(v) + if err != nil { + log.Printf("[DEBUG] flattenNetworkingPortBindingV2: Cannot marshal %s key value: %s", k, err) + } + vifDetails[k] = string(p) + } + + portBinding = append(portBinding, map[string]interface{}{ + "profile": profile, + "vif_type": port.VIFType, + "vif_details": vifDetails, + "vnic_type": port.VNICType, + "host_id": port.HostID, + }) + + return portBinding +} + +func suppressDiffPortBindingProfileV2(k, old, new string, d *schema.ResourceData) bool { + if old == "{}" && new == "" { + return true + } + + if old == "" && new == "{}" { + return true + } + + return false +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_router_interface_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_router_interface_v2.go index b6d45e825..dd642b207 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_router_interface_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_router_interface_v2.go @@ -52,11 +52,9 @@ func resourceNetworkingRouterInterfaceV2DeleteRefreshFunc(networkingClient *goph log.Printf("[DEBUG] Successfully deleted openstack_networking_router_interface_v2 %s", routerInterfaceID) return r, "DELETED", nil } - if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok { - if errCode.Actual == 409 { - log.Printf("[DEBUG] openstack_networking_router_interface_v2 %s is still in use", routerInterfaceID) - return r, "ACTIVE", nil - } + if _, ok := err.(gophercloud.ErrDefault409); ok { + log.Printf("[DEBUG] openstack_networking_router_interface_v2 %s is still in use", routerInterfaceID) + return r, "ACTIVE", nil } return r, "ACTIVE", err diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_router_route_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_router_route_v2.go new file mode 100644 index 000000000..f44575c92 --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_router_route_v2.go @@ -0,0 +1,25 @@ +package openstack + +import ( + "fmt" + "strings" +) + +func resourceNetworkingRouterRouteV2BuildID(routerID, dstCIDR, nextHop string) string { + return fmt.Sprintf("%s-route-%s-%s", routerID, dstCIDR, nextHop) +} + +func resourceNetworkingRouterRouteV2ParseID(routeID string) (string, string, string, error) { + routeIDAllParts := strings.Split(routeID, "-route-") + if len(routeIDAllParts) != 2 { + return "", "", "", fmt.Errorf("invalid ID format: %s", routeID) + } + + routeIDLastPart := routeIDAllParts[1] + routeIDLastParts := strings.Split(routeIDLastPart, "-") + if len(routeIDLastParts) != 2 { + return "", "", "", fmt.Errorf("invalid last part format for %s: %s", routeID, routeIDLastPart) + } + + return routeIDAllParts[0], routeIDLastParts[0], routeIDLastParts[1], nil +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_secgroup_rule_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_secgroup_rule_v2.go new file mode 100644 index 000000000..bf8e1568a --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_secgroup_rule_v2.go @@ -0,0 +1,102 @@ +package openstack + +import ( + "fmt" + "strconv" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules" + "github.com/hashicorp/terraform/helper/resource" +) + +func resourceNetworkingSecGroupRuleV2StateRefreshFunc(client *gophercloud.ServiceClient, sgRuleID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + sgRule, err := rules.Get(client, sgRuleID).Extract() + if err != nil { + if _, ok := err.(gophercloud.ErrDefault404); ok { + return sgRule, "DELETED", nil + } + + return sgRule, "", err + } + + return sgRule, "ACTIVE", nil + } +} + +func resourceNetworkingSecGroupRuleV2Direction(direction string) (rules.RuleDirection, error) { + switch direction { + case string(rules.DirIngress): + return rules.DirIngress, nil + case string(rules.DirEgress): + return rules.DirEgress, nil + } + + return "", fmt.Errorf("unknown direction for openstack_networking_secgroup_rule_v2: %s", direction) +} + +func resourceNetworkingSecGroupRuleV2EtherType(etherType string) (rules.RuleEtherType, error) { + switch etherType { + case string(rules.EtherType4): + return rules.EtherType4, nil + case string(rules.EtherType6): + return rules.EtherType6, nil + } + + return "", fmt.Errorf("unknown ether type for openstack_networking_secgroup_rule_v2: %s", etherType) +} + +func resourceNetworkingSecGroupRuleV2Protocol(protocol string) (rules.RuleProtocol, error) { + switch protocol { + case string(rules.ProtocolAH): + return rules.ProtocolAH, nil + case string(rules.ProtocolDCCP): + return rules.ProtocolDCCP, nil + case string(rules.ProtocolEGP): + return rules.ProtocolEGP, nil + case string(rules.ProtocolESP): + return rules.ProtocolESP, nil + case string(rules.ProtocolGRE): + return rules.ProtocolGRE, nil + case string(rules.ProtocolICMP): + return rules.ProtocolICMP, nil + case string(rules.ProtocolIGMP): + return rules.ProtocolIGMP, nil + case string(rules.ProtocolIPv6Encap): + return rules.ProtocolIPv6Encap, nil + case string(rules.ProtocolIPv6Frag): + return rules.ProtocolIPv6Frag, nil + case string(rules.ProtocolIPv6ICMP): + return rules.ProtocolIPv6ICMP, nil + case string(rules.ProtocolIPv6NoNxt): + return rules.ProtocolIPv6NoNxt, nil + case string(rules.ProtocolIPv6Opts): + return rules.ProtocolIPv6Opts, nil + case string(rules.ProtocolIPv6Route): + return rules.ProtocolIPv6Route, nil + case string(rules.ProtocolOSPF): + return rules.ProtocolOSPF, nil + case string(rules.ProtocolPGM): + return rules.ProtocolPGM, nil + case string(rules.ProtocolRSVP): + return rules.ProtocolRSVP, nil + case string(rules.ProtocolSCTP): + return rules.ProtocolSCTP, nil + case string(rules.ProtocolTCP): + return rules.ProtocolTCP, nil + case string(rules.ProtocolUDP): + return rules.ProtocolUDP, nil + case string(rules.ProtocolUDPLite): + return rules.ProtocolUDPLite, nil + case string(rules.ProtocolVRRP): + return rules.ProtocolVRRP, nil + } + + // If the protocol wasn't matched above, see if it's an integer. + _, err := strconv.Atoi(protocol) + if err == nil { + return rules.RuleProtocol(protocol), nil + } + + return "", fmt.Errorf("unknown protocol for openstack_networking_secgroup_rule_v2: %s", protocol) +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_subnet_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_subnet_v2.go new file mode 100644 index 000000000..6ed59b9fa --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_subnet_v2.go @@ -0,0 +1,31 @@ +package openstack + +func networkingSubnetV2AllocationPoolsMatch(oldPools, newPools []interface{}) bool { + if len(oldPools) != len(newPools) { + return false + } + + for _, newPool := range newPools { + var found bool + + newPoolPool := newPool.(map[string]interface{}) + newStart := newPoolPool["start"].(string) + newEnd := newPoolPool["end"].(string) + + for _, oldPool := range oldPools { + oldPoolPool := oldPool.(map[string]interface{}) + oldStart := oldPoolPool["start"].(string) + oldEnd := oldPoolPool["end"].(string) + + if oldStart == newStart && oldEnd == newEnd { + found = true + } + } + + if !found { + return false + } + } + + return true +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_subnetpool_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_subnetpool_v2.go index a9682e295..399954e25 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_subnetpool_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/networking_subnetpool_v2.go @@ -13,10 +13,8 @@ func networkingSubnetpoolV2StateRefreshFunc(client *gophercloud.ServiceClient, i if _, ok := err.(gophercloud.ErrDefault404); ok { return subnetpool, "DELETED", nil } - if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok { - if errCode.Actual == 409 { - return subnetpool, "ACTIVE", nil - } + if _, ok := err.(gophercloud.ErrDefault409); ok { + return subnetpool, "ACTIVE", nil } return nil, "", err diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/provider.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/provider.go index 6c559ade2..f36c1b3fc 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/provider.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/provider.go @@ -219,33 +219,37 @@ func Provider() terraform.ResourceProvider { }, DataSourcesMap: map[string]*schema.Resource{ - "openstack_blockstorage_snapshot_v2": dataSourceBlockStorageSnapshotV2(), - "openstack_blockstorage_snapshot_v3": dataSourceBlockStorageSnapshotV3(), - "openstack_compute_availability_zones_v2": dataSourceComputeAvailabilityZonesV2(), - "openstack_compute_flavor_v2": dataSourceComputeFlavorV2(), - "openstack_compute_keypair_v2": dataSourceComputeKeypairV2(), - "openstack_containerinfra_clustertemplate_v1": dataSourceContainerInfraClusterTemplateV1(), - "openstack_containerinfra_cluster_v1": dataSourceContainerInfraCluster(), - "openstack_dns_zone_v2": dataSourceDNSZoneV2(), - "openstack_fw_policy_v1": dataSourceFWPolicyV1(), - "openstack_identity_role_v3": dataSourceIdentityRoleV3(), - "openstack_identity_project_v3": dataSourceIdentityProjectV3(), - "openstack_identity_user_v3": dataSourceIdentityUserV3(), - "openstack_identity_auth_scope_v3": dataSourceIdentityAuthScopeV3(), - "openstack_identity_endpoint_v3": dataSourceIdentityEndpointV3(), - "openstack_identity_group_v3": dataSourceIdentityGroupV3(), - "openstack_images_image_v2": dataSourceImagesImageV2(), - "openstack_networking_network_v2": dataSourceNetworkingNetworkV2(), - "openstack_networking_subnet_v2": dataSourceNetworkingSubnetV2(), - "openstack_networking_secgroup_v2": dataSourceNetworkingSecGroupV2(), - "openstack_networking_subnetpool_v2": dataSourceNetworkingSubnetPoolV2(), - "openstack_networking_floatingip_v2": dataSourceNetworkingFloatingIPV2(), - "openstack_networking_router_v2": dataSourceNetworkingRouterV2(), - "openstack_networking_port_v2": dataSourceNetworkingPortV2(), - "openstack_networking_port_ids_v2": dataSourceNetworkingPortIDsV2(), - "openstack_sharedfilesystem_sharenetwork_v2": dataSourceSharedFilesystemShareNetworkV2(), - "openstack_sharedfilesystem_share_v2": dataSourceSharedFilesystemShareV2(), - "openstack_sharedfilesystem_snapshot_v2": dataSourceSharedFilesystemSnapshotV2(), + "openstack_blockstorage_availability_zones_v3": dataSourceBlockStorageAvailabilityZonesV3(), + "openstack_blockstorage_snapshot_v2": dataSourceBlockStorageSnapshotV2(), + "openstack_blockstorage_snapshot_v3": dataSourceBlockStorageSnapshotV3(), + "openstack_compute_availability_zones_v2": dataSourceComputeAvailabilityZonesV2(), + "openstack_compute_flavor_v2": dataSourceComputeFlavorV2(), + "openstack_compute_keypair_v2": dataSourceComputeKeypairV2(), + "openstack_containerinfra_clustertemplate_v1": dataSourceContainerInfraClusterTemplateV1(), + "openstack_containerinfra_cluster_v1": dataSourceContainerInfraCluster(), + "openstack_dns_zone_v2": dataSourceDNSZoneV2(), + "openstack_fw_policy_v1": dataSourceFWPolicyV1(), + "openstack_identity_role_v3": dataSourceIdentityRoleV3(), + "openstack_identity_project_v3": dataSourceIdentityProjectV3(), + "openstack_identity_user_v3": dataSourceIdentityUserV3(), + "openstack_identity_auth_scope_v3": dataSourceIdentityAuthScopeV3(), + "openstack_identity_endpoint_v3": dataSourceIdentityEndpointV3(), + "openstack_identity_group_v3": dataSourceIdentityGroupV3(), + "openstack_images_image_v2": dataSourceImagesImageV2(), + "openstack_networking_addressscope_v2": dataSourceNetworkingAddressScopeV2(), + "openstack_networking_network_v2": dataSourceNetworkingNetworkV2(), + "openstack_networking_subnet_v2": dataSourceNetworkingSubnetV2(), + "openstack_networking_secgroup_v2": dataSourceNetworkingSecGroupV2(), + "openstack_networking_subnetpool_v2": dataSourceNetworkingSubnetPoolV2(), + "openstack_networking_floatingip_v2": dataSourceNetworkingFloatingIPV2(), + "openstack_networking_router_v2": dataSourceNetworkingRouterV2(), + "openstack_networking_port_v2": dataSourceNetworkingPortV2(), + "openstack_networking_port_ids_v2": dataSourceNetworkingPortIDsV2(), + "openstack_networking_trunk_v2": dataSourceNetworkingTrunkV2(), + "openstack_sharedfilesystem_availability_zones_v2": dataSourceSharedFilesystemAvailabilityZonesV2(), + "openstack_sharedfilesystem_sharenetwork_v2": dataSourceSharedFilesystemShareNetworkV2(), + "openstack_sharedfilesystem_share_v2": dataSourceSharedFilesystemShareV2(), + "openstack_sharedfilesystem_snapshot_v2": dataSourceSharedFilesystemSnapshotV2(), }, ResourcesMap: map[string]*schema.Resource{ @@ -279,6 +283,7 @@ func Provider() terraform.ResourceProvider { "openstack_identity_role_v3": resourceIdentityRoleV3(), "openstack_identity_role_assignment_v3": resourceIdentityRoleAssignmentV3(), "openstack_identity_user_v3": resourceIdentityUserV3(), + "openstack_identity_application_credential_v3": resourceIdentityApplicationCredentialV3(), "openstack_images_image_v2": resourceImagesImageV2(), "openstack_lb_member_v1": resourceLBMemberV1(), "openstack_lb_monitor_v1": resourceLBMonitorV1(), diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_blockstorage_volume_v1.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_blockstorage_volume_v1.go index e82e0f549..7c8e74c5b 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_blockstorage_volume_v1.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_blockstorage_volume_v1.go @@ -262,10 +262,8 @@ func resourceBlockStorageVolumeV1Delete(d *schema.ResourceData, meta interface{} // A 409 is also acceptable because there's another // concurrent action happening. - if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok { - if errCode.Actual == 409 { - continue - } + if _, ok := err.(gophercloud.ErrDefault409); ok { + continue } return fmt.Errorf( diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_blockstorage_volume_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_blockstorage_volume_v2.go index 97a8b565b..d7b64913f 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_blockstorage_volume_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_blockstorage_volume_v2.go @@ -275,10 +275,8 @@ func resourceBlockStorageVolumeV2Delete(d *schema.ResourceData, meta interface{} // A 409 is also acceptable because there's another // concurrent action happening. - if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok { - if errCode.Actual == 409 { - continue - } + if _, ok := err.(gophercloud.ErrDefault409); ok { + continue } return fmt.Errorf( diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_blockstorage_volume_v3.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_blockstorage_volume_v3.go index ee74c36a8..35a895475 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_blockstorage_volume_v3.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_blockstorage_volume_v3.go @@ -330,10 +330,8 @@ func resourceBlockStorageVolumeV3Delete(d *schema.ResourceData, meta interface{} // A 409 is also acceptable because there's another // concurrent action happening. - if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok { - if errCode.Actual == 409 { - continue - } + if _, ok := err.(gophercloud.ErrDefault409); ok { + continue } return fmt.Errorf( diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_compute_instance_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_compute_instance_v2.go index a0e0c0bec..9fc8b914e 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_compute_instance_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_compute_instance_v2.go @@ -897,7 +897,7 @@ func resourceComputeInstanceV2Delete(d *schema.ResourceData, meta interface{}) e Pending: []string{"ACTIVE"}, Target: []string{"SHUTOFF"}, Refresh: ServerV2StateRefreshFunc(computeClient, d.Id()), - Timeout: 3 * time.Minute, + Timeout: d.Timeout(schema.TimeoutDelete), Delay: 10 * time.Second, MinTimeout: 3 * time.Second, } diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_containerinfra_cluster_v1.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_containerinfra_cluster_v1.go index bf1ddfff7..e3def9d41 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_containerinfra_cluster_v1.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_containerinfra_cluster_v1.go @@ -198,7 +198,7 @@ func resourceContainerInfraClusterV1Create(d *schema.ResourceData, meta interfac return fmt.Errorf("Unable to determine openstack_containerinfra_cluster_v1 flavor") } - masterFlavor, err := containerInfraClusterV1Flavor(d) + masterFlavor, err := containerInfraClusterV1MasterFlavor(d) if err != nil { return fmt.Errorf("Unable to determine openstack_containerinfra_cluster_v1 master_flavor") } diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_db_configuration_v1.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_db_configuration_v1.go index 70f4834d8..7fc966651 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_db_configuration_v1.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_db_configuration_v1.go @@ -3,10 +3,8 @@ package openstack import ( "fmt" "log" - "strconv" "time" - "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack/db/v1/configurations" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" @@ -25,21 +23,24 @@ func resourceDatabaseConfigurationV1() *schema.Resource { Schema: map[string]*schema.Schema{ "region": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - DefaultFunc: schema.EnvDefaultFunc("OS_REGION_NAME", ""), + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, }, + "name": { Type: schema.TypeString, Required: true, ForceNew: true, }, + "description": { Type: schema.TypeString, Required: true, ForceNew: true, }, + "datastore": { Type: schema.TypeList, Required: true, @@ -60,6 +61,7 @@ func resourceDatabaseConfigurationV1() *schema.Resource { }, MaxItems: 1, }, + "configuration": { Type: schema.TypeList, Optional: true, @@ -87,17 +89,7 @@ func resourceDatabaseConfigurationV1Create(d *schema.ResourceData, meta interfac config := meta.(*Config) databaseV1Client, err := config.databaseV1Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error creating cloud database client: %s", err) - } - - var datastore configurations.DatastoreOpts - if p, ok := d.GetOk("datastore"); ok { - pV := (p.([]interface{}))[0].(map[string]interface{}) - - datastore = configurations.DatastoreOpts{ - Version: pV["version"].(string), - Type: pV["type"].(string), - } + return fmt.Errorf("Error creating OpenStack database client: %s", err) } createOpts := &configurations.CreateOpts{ @@ -105,41 +97,29 @@ func resourceDatabaseConfigurationV1Create(d *schema.ResourceData, meta interfac Description: d.Get("description").(string), } + var datastore configurations.DatastoreOpts + if v, ok := d.GetOk("datastore"); ok { + datastore = expandDatabaseConfigurationV1Datastore(v.([]interface{})) + } createOpts.Datastore = &datastore values := make(map[string]interface{}) - if p, ok := d.GetOk("configuration"); ok { - - listSlice, _ := p.([]interface{}) - for _, d := range listSlice { - if z, ok := d.(map[string]interface{}); ok { - name := z["name"].(string) - value := z["value"].(interface{}) - - // check if value can be converted into int - if valueInt, err := strconv.Atoi(value.(string)); err == nil { - value = valueInt - } - - values[name] = value - } - } + if v, ok := d.GetOk("configuration"); ok { + values = expandDatabaseConfigurationV1Values(v.([]interface{})) } - createOpts.Values = values - log.Printf("[DEBUG] Create Options: %#v", createOpts) + log.Printf("[DEBUG] openstack_db_configuration_v1 create options: %#v", createOpts) cgroup, err := configurations.Create(databaseV1Client, createOpts).Extract() if err != nil { - return fmt.Errorf("Error creating cloud database configuration: %s", err) + return fmt.Errorf("Error creating openstack_db_configuration_v1: %s", err) } - log.Printf("[INFO] configuration ID: %s", cgroup.ID) stateConf := &resource.StateChangeConf{ Pending: []string{"BUILD"}, Target: []string{"ACTIVE"}, - Refresh: DatabaseConfigurationV1StateRefreshFunc(databaseV1Client, cgroup.ID), + Refresh: databaseConfigurationV1StateRefreshFunc(databaseV1Client, cgroup.ID), Timeout: d.Timeout(schema.TimeoutCreate), Delay: 10 * time.Second, MinTimeout: 3 * time.Second, @@ -147,9 +127,7 @@ func resourceDatabaseConfigurationV1Create(d *schema.ResourceData, meta interfac _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf( - "Error waiting for configuration (%s) to become ready: %s", - cgroup.ID, err) + return fmt.Errorf("Error waiting for openstack_db_configuration_v1 %s to become ready: %s", cgroup.ID, err) } // Store the ID now @@ -162,15 +140,15 @@ func resourceDatabaseConfigurationV1Read(d *schema.ResourceData, meta interface{ config := meta.(*Config) databaseV1Client, err := config.databaseV1Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error creating OpenStack cloud database client: %s", err) + return fmt.Errorf("Error creating OpenStack database client: %s", err) } cgroup, err := configurations.Get(databaseV1Client, d.Id()).Extract() if err != nil { - return CheckDeleted(d, err, "configuration") + return CheckDeleted(d, err, "Error retrieving openstack_db_configuration_v1") } - log.Printf("[DEBUG] Retrieved configuration %s: %+v", d.Id(), cgroup) + log.Printf("[DEBUG] Retrieved openstack_db_configuration_v1 %s: %#v", d.Id(), cgroup) d.Set("name", cgroup.Name) d.Set("description", cgroup.Description) @@ -183,19 +161,18 @@ func resourceDatabaseConfigurationV1Delete(d *schema.ResourceData, meta interfac config := meta.(*Config) databaseV1Client, err := config.databaseV1Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error creating RS cloud instance client: %s", err) + return fmt.Errorf("Error creating OpenStack database client: %s", err) } - log.Printf("[DEBUG] Deleting cloud database configuration %s", d.Id()) err = configurations.Delete(databaseV1Client, d.Id()).ExtractErr() if err != nil { - return fmt.Errorf("Error deleting cloud configuration: %s", err) + return fmt.Errorf("Error deleting openstack_db_configuration_v1 %s: %s", d.Id(), err) } stateConf := &resource.StateChangeConf{ Pending: []string{"ACTIVE", "SHUTOFF"}, Target: []string{"DELETED"}, - Refresh: DatabaseConfigurationV1StateRefreshFunc(databaseV1Client, d.Id()), + Refresh: databaseConfigurationV1StateRefreshFunc(databaseV1Client, d.Id()), Timeout: d.Timeout(schema.TimeoutDelete), Delay: 10 * time.Second, MinTimeout: 3 * time.Second, @@ -203,27 +180,8 @@ func resourceDatabaseConfigurationV1Delete(d *schema.ResourceData, meta interfac _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf( - "Error waiting for configuration (%s) to delete: %s", - d.Id(), err) + return fmt.Errorf("Error waiting for openstack_db_configuration_v1 %s to delete: %s", d.Id(), err) } - d.SetId("") return nil } - -// DatabaseConfigurationV1StateRefreshFunc returns a resource.StateRefreshFunc that is used to watch -// an cloud database instance. -func DatabaseConfigurationV1StateRefreshFunc(client *gophercloud.ServiceClient, cgroupID string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - i, err := configurations.Get(client, cgroupID).Extract() - if err != nil { - if _, ok := err.(gophercloud.ErrDefault404); ok { - return i, "DELETED", nil - } - return nil, "", err - } - - return i, "ACTIVE", nil - } -} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_db_database_v1.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_db_database_v1.go index dc95ce93e..849dad170 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_db_database_v1.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_db_database_v1.go @@ -2,11 +2,9 @@ package openstack import ( "fmt" - "log" "strings" "time" - "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack/db/v1/databases" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" @@ -28,16 +26,18 @@ func resourceDatabaseDatabaseV1() *schema.Resource { Schema: map[string]*schema.Schema{ "region": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - DefaultFunc: schema.EnvDefaultFunc("OS_REGION_NAME", ""), + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, }, + "name": { Type: schema.TypeString, Required: true, ForceNew: true, }, + "instance_id": { Type: schema.TypeString, Required: true, @@ -51,7 +51,7 @@ func resourceDatabaseDatabaseV1Create(d *schema.ResourceData, meta interface{}) config := meta.(*Config) databaseV1Client, err := config.databaseV1Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error creating cloud database client: %s", err) + return fmt.Errorf("Error creating OpenStack database client: %s", err) } dbName := d.Get("name").(string) @@ -62,24 +62,24 @@ func resourceDatabaseDatabaseV1Create(d *schema.ResourceData, meta interface{}) Name: dbName, }) - exists, err := DatabaseDatabaseV1State(databaseV1Client, instanceID, dbName) + exists, err := databaseDatabaseV1Exists(databaseV1Client, instanceID, dbName) if err != nil { - return fmt.Errorf("Error checking database status: %s", err) + return fmt.Errorf("Error checking openstack_db_database_v1 %s status on %s: %s", dbName, instanceID, err) } if exists { - return fmt.Errorf("Database %s exists on instance %s", dbName, instanceID) + return fmt.Errorf("openstack_db_database_v1 %s already exists on instance %s", dbName, instanceID) } err = databases.Create(databaseV1Client, instanceID, dbs).ExtractErr() if err != nil { - return err + return fmt.Errorf("Error creating openstack_db_database_v1 %s on %s: %s", dbName, instanceID, err) } stateConf := &resource.StateChangeConf{ Pending: []string{"BUILD"}, Target: []string{"ACTIVE"}, - Refresh: DatabaseDatabaseV1StateRefreshFunc(databaseV1Client, instanceID, dbName), + Refresh: databaseDatabaseV1StateRefreshFunc(databaseV1Client, instanceID, dbName), Timeout: d.Timeout(schema.TimeoutCreate), Delay: 10 * time.Second, MinTimeout: 3 * time.Second, @@ -87,8 +87,7 @@ func resourceDatabaseDatabaseV1Create(d *schema.ResourceData, meta interface{}) _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf( - "Error waiting for database to become ready: %s", err) + return fmt.Errorf("Error waiting for openstack_db_database_v1 %s on %s to become ready: %s", dbName, instanceID, err) } // Store the ID now @@ -101,30 +100,29 @@ func resourceDatabaseDatabaseV1Read(d *schema.ResourceData, meta interface{}) er config := meta.(*Config) databaseV1Client, err := config.databaseV1Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error creating database client: %s", err) + return fmt.Errorf("Error creating OpenStack database client: %s", err) } dbID := strings.SplitN(d.Id(), "/", 2) if len(dbID) != 2 { - return fmt.Errorf("Invalid openstack_db_database_v1 ID format") + return fmt.Errorf("Invalid openstack_db_database_v1 ID: %s", d.Id()) } instanceID := dbID[0] dbName := dbID[1] - exists, err := DatabaseDatabaseV1State(databaseV1Client, instanceID, dbName) + exists, err := databaseDatabaseV1Exists(databaseV1Client, instanceID, dbName) if err != nil { - return fmt.Errorf("Error checking database status: %s", err) + return fmt.Errorf("Error checking if openstack_db_database_v1 %s exists: %s", d.Id(), err) } if !exists { - return fmt.Errorf("database %s was not found", err) + d.SetId("") + return nil } - log.Printf("[DEBUG] Retrieved database %s", dbName) - - d.Set("name", dbName) d.Set("instance_id", instanceID) + d.Set("name", dbName) return nil } @@ -133,7 +131,7 @@ func resourceDatabaseDatabaseV1Delete(d *schema.ResourceData, meta interface{}) config := meta.(*Config) databaseV1Client, err := config.databaseV1Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error creating cloud database client: %s", err) + return fmt.Errorf("Error creating OpenStack database client: %s", err) } dbID := strings.SplitN(d.Id(), "/", 2) @@ -144,9 +142,9 @@ func resourceDatabaseDatabaseV1Delete(d *schema.ResourceData, meta interface{}) instanceID := dbID[0] dbName := dbID[1] - exists, err := DatabaseDatabaseV1State(databaseV1Client, instanceID, dbName) + exists, err := databaseDatabaseV1Exists(databaseV1Client, instanceID, dbName) if err != nil { - return fmt.Errorf("Error checking database status: %s", err) + return fmt.Errorf("Error checking if openstack_db_database_v1 %s exists: %s", d.Id(), err) } if !exists { @@ -155,56 +153,8 @@ func resourceDatabaseDatabaseV1Delete(d *schema.ResourceData, meta interface{}) err = databases.Delete(databaseV1Client, instanceID, dbName).ExtractErr() if err != nil { - return fmt.Errorf("Error deleting database %s: %s", dbName, err) + return fmt.Errorf("Error deleting openstack_db_database_v1 %s: %s", dbName, err) } return nil } - -// DatabaseDatabaseV1StateRefreshFunc returns a resource.StateRefreshFunc -// that is used to watch a database. -func DatabaseDatabaseV1StateRefreshFunc(client *gophercloud.ServiceClient, instanceID string, dbName string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - pages, err := databases.List(client, instanceID).AllPages() - if err != nil { - return nil, "", fmt.Errorf("Unable to retrieve databases: %s", err) - } - - allDatabases, err := databases.ExtractDBs(pages) - if err != nil { - return nil, "", fmt.Errorf("Unable to extract databases: %s", err) - } - - for _, v := range allDatabases { - if v.Name == dbName { - return v, "ACTIVE", nil - } - } - - return nil, "BUILD", nil - } -} - -func DatabaseDatabaseV1State(client *gophercloud.ServiceClient, instanceID string, dbName string) (exists bool, err error) { - exists = false - err = nil - - pages, err := databases.List(client, instanceID).AllPages() - if err != nil { - return - } - - allDatabases, err := databases.ExtractDBs(pages) - if err != nil { - return - } - - for _, v := range allDatabases { - if v.Name == dbName { - exists = true - return - } - } - - return false, err -} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_db_instance_v1.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_db_instance_v1.go index f72e26597..a246b4d0f 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_db_instance_v1.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_db_instance_v1.go @@ -5,7 +5,6 @@ import ( "log" "time" - "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack/db/v1/databases" "github.com/gophercloud/gophercloud/openstack/db/v1/instances" "github.com/gophercloud/gophercloud/openstack/db/v1/users" @@ -27,16 +26,17 @@ func resourceDatabaseInstanceV1() *schema.Resource { Schema: map[string]*schema.Schema{ "region": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - DefaultFunc: schema.EnvDefaultFunc("OS_REGION_NAME", ""), + Type: schema.TypeString, + Optional: true, + Computed: true, }, + "name": { Type: schema.TypeString, Required: true, ForceNew: true, }, + "flavor_id": { Type: schema.TypeString, Optional: true, @@ -44,11 +44,13 @@ func resourceDatabaseInstanceV1() *schema.Resource { Computed: true, DefaultFunc: schema.EnvDefaultFunc("OS_FLAVOR_ID", nil), }, + "size": { Type: schema.TypeInt, Required: true, ForceNew: true, }, + "datastore": { Type: schema.TypeList, Required: true, @@ -69,6 +71,7 @@ func resourceDatabaseInstanceV1() *schema.Resource { }, }, }, + "network": { Type: schema.TypeList, Optional: true, @@ -98,6 +101,7 @@ func resourceDatabaseInstanceV1() *schema.Resource { }, }, }, + "database": { Type: schema.TypeList, Optional: true, @@ -122,6 +126,7 @@ func resourceDatabaseInstanceV1() *schema.Resource { }, }, }, + "user": { Type: schema.TypeList, Optional: true, @@ -153,6 +158,7 @@ func resourceDatabaseInstanceV1() *schema.Resource { }, }, }, + "configuration_id": { Type: schema.TypeString, Optional: true, @@ -167,7 +173,7 @@ func resourceDatabaseInstanceV1Create(d *schema.ResourceData, meta interface{}) config := meta.(*Config) databaseV1Client, err := config.databaseV1Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error creating database client: %s", err) + return fmt.Errorf("Error creating OpenStack database client: %s", err) } createOpts := &instances.CreateOpts{ @@ -176,90 +182,48 @@ func resourceDatabaseInstanceV1Create(d *schema.ResourceData, meta interface{}) Size: d.Get("size").(int), } + // datastore var datastore instances.DatastoreOpts if v, ok := d.GetOk("datastore"); ok { - if v, ok := v.([]interface{}); ok && len(v) > 0 { - ds := v[0].(map[string]interface{}) - datastore = instances.DatastoreOpts{ - Version: ds["version"].(string), - Type: ds["type"].(string), - } - createOpts.Datastore = &datastore - } + datastore = expandDatabaseInstanceV1Datastore(v.([]interface{})) } + createOpts.Datastore = &datastore // networks var networks []instances.NetworkOpts - if v, ok := d.GetOk("network"); ok { - if networkList, ok := v.([]interface{}); ok { - for _, v := range networkList { - network := v.(map[string]interface{}) - networks = append(networks, instances.NetworkOpts{ - UUID: network["uuid"].(string), - Port: network["port"].(string), - V4FixedIP: network["fixed_ip_v4"].(string), - V6FixedIP: network["fixed_ip_v6"].(string), - }) - } - } + networks = expandDatabaseInstanceV1Networks(v.([]interface{})) } - createOpts.Networks = networks // databases var dbs databases.BatchCreateOpts - if v, ok := d.GetOk("database"); ok { - if databaseList, ok := v.([]interface{}); ok { - for _, v := range databaseList { - db := v.(map[string]interface{}) - dbs = append(dbs, databases.CreateOpts{ - Name: db["name"].(string), - CharSet: db["charset"].(string), - Collate: db["collate"].(string), - }) - } - } + dbs = expandDatabaseInstanceV1Databases(v.([]interface{})) } - createOpts.Databases = dbs // users - var UserList users.BatchCreateOpts - + var userList users.BatchCreateOpts if v, ok := d.GetOk("user"); ok { - if userList, ok := v.([]interface{}); ok { - for _, v := range userList { - user := v.(map[string]interface{}) - UserList = append(UserList, users.CreateOpts{ - Name: user["name"].(string), - Password: user["password"].(string), - Databases: resourceDBv1GetDatabases(user["databases"]), - Host: user["host"].(string), - }) - } - } + userList = expandDatabaseInstanceV1Users(v.([]interface{})) } + createOpts.Users = userList - createOpts.Users = UserList + log.Printf("[DEBUG] openstack_db_instance_v1 create options: %#v", createOpts) - log.Printf("[DEBUG] Create Options: %#v", createOpts) instance, err := instances.Create(databaseV1Client, createOpts).Extract() if err != nil { - return fmt.Errorf("Error creating database instance: %s", err) + return fmt.Errorf("Error creating openstack_db_instance_v1: %s", err) } - log.Printf("[INFO] database instance ID: %s", instance.ID) // Wait for the instance to become available. - log.Printf( - "[DEBUG] Waiting for database instance (%s) to become available", - instance.ID) + log.Printf("[DEBUG] Waiting for openstack_db_instance_v1 %s to become available", instance.ID) stateConf := &resource.StateChangeConf{ Pending: []string{"BUILD"}, Target: []string{"ACTIVE"}, - Refresh: DatabaseInstanceV1StateRefreshFunc(databaseV1Client, instance.ID), + Refresh: databaseInstanceV1StateRefreshFunc(databaseV1Client, instance.ID), Timeout: d.Timeout(schema.TimeoutCreate), Delay: 10 * time.Second, MinTimeout: 3 * time.Second, @@ -267,17 +231,16 @@ func resourceDatabaseInstanceV1Create(d *schema.ResourceData, meta interface{}) _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf( - "Error waiting for database instance (%s) to become ready: %s", - instance.ID, err) + return fmt.Errorf("Error waiting for openstack_db_instance_v1 %s to become ready: %s", instance.ID, err) } if configuration, ok := d.GetOk("configuration_id"); ok { + log.Printf("[DEBUG] Attaching configuration %s to openstack_db_instance_v1 %s", configuration, instance.ID) err := instances.AttachConfigurationGroup(databaseV1Client, instance.ID, configuration.(string)).ExtractErr() if err != nil { - return err + return fmt.Errorf("error attaching configuration group %s to openstack_db_instance_v1 %s: %s", + configuration, instance.ID, err) } - log.Printf("Attaching configuration %v to the instance %v", configuration, instance.ID) } // Store the ID now @@ -290,15 +253,15 @@ func resourceDatabaseInstanceV1Read(d *schema.ResourceData, meta interface{}) er config := meta.(*Config) databaseV1Client, err := config.databaseV1Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error creating database client: %s", err) + return fmt.Errorf("Error creating OpenStack database client: %s", err) } instance, err := instances.Get(databaseV1Client, d.Id()).Extract() if err != nil { - return CheckDeleted(d, err, "instance") + return CheckDeleted(d, err, "Error retrieving openstack_db_instance_v1") } - log.Printf("[DEBUG] Retrieved database instance %s: %+v", d.Id(), instance) + log.Printf("[DEBUG] Retrieved openstack_db_instance_v1 %s: %#v", d.Id(), instance) d.Set("name", instance.Name) d.Set("flavor_id", instance.Flavor) @@ -312,7 +275,7 @@ func resourceDatabaseInstanceUpdate(d *schema.ResourceData, meta interface{}) er config := meta.(*Config) databaseV1Client, err := config.databaseV1Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error creating database client: %s", err) + return fmt.Errorf("Error creating OpenStack database client: %s", err) } if d.HasChange("configuration_id") { @@ -322,14 +285,14 @@ func resourceDatabaseInstanceUpdate(d *schema.ResourceData, meta interface{}) er if err != nil { return err } - log.Printf("Detaching configuration %v from the instance %v", old, d.Id()) + log.Printf("Detaching configuration %s from openstack_db_instance_v1 %s", old, d.Id()) if new != "" { err := instances.AttachConfigurationGroup(databaseV1Client, d.Id(), new.(string)).ExtractErr() if err != nil { return err } - log.Printf("Attaching configuration %v to the instance %v", new, d.Id()) + log.Printf("Attaching configuration %s to openstack_db_instance_v1 %s", new, d.Id()) } } @@ -340,22 +303,18 @@ func resourceDatabaseInstanceV1Delete(d *schema.ResourceData, meta interface{}) config := meta.(*Config) databaseV1Client, err := config.databaseV1Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error creating database client: %s", err) + return fmt.Errorf("Error creating OpenStack database client: %s", err) } - log.Printf("[DEBUG] Deleting database instance %s", d.Id()) err = instances.Delete(databaseV1Client, d.Id()).ExtractErr() if err != nil { - return fmt.Errorf("Error deleting database instance: %s", err) + return CheckDeleted(d, err, "Error deleting openstack_db_instance_v1") } - // Wait for the database to delete before moving on. - log.Printf("[DEBUG] Waiting for database instance (%s) to delete", d.Id()) - stateConf := &resource.StateChangeConf{ Pending: []string{"ACTIVE", "SHUTDOWN"}, Target: []string{"DELETED"}, - Refresh: DatabaseInstanceV1StateRefreshFunc(databaseV1Client, d.Id()), + Refresh: databaseInstanceV1StateRefreshFunc(databaseV1Client, d.Id()), Timeout: d.Timeout(schema.TimeoutDelete), Delay: 10 * time.Second, MinTimeout: 3 * time.Second, @@ -363,44 +322,8 @@ func resourceDatabaseInstanceV1Delete(d *schema.ResourceData, meta interface{}) _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf( - "Error waiting for database instance (%s) to delete: %s", - d.Id(), err) + return fmt.Errorf("Error waiting for openstack_db_instance_v1 %s to delete: %s", d.Id(), err) } return nil } - -// DatabaseInstanceV1StateRefreshFunc returns a resource.StateRefreshFunc -// that is used to watch a database instance. -func DatabaseInstanceV1StateRefreshFunc(client *gophercloud.ServiceClient, instanceID string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - i, err := instances.Get(client, instanceID).Extract() - if err != nil { - if _, ok := err.(gophercloud.ErrDefault404); ok { - return i, "DELETED", nil - } - return nil, "", err - } - - if i.Status == "error" { - return i, i.Status, fmt.Errorf("There was an error creating the database instance.") - } - - return i, i.Status, nil - } -} - -func resourceDBv1GetDatabases(v interface{}) databases.BatchCreateOpts { - var dbs databases.BatchCreateOpts - - if v, ok := v.(*schema.Set); ok { - for _, db := range v.List() { - dbs = append(dbs, databases.CreateOpts{ - Name: db.(string), - }) - } - } - - return dbs -} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_db_user_v1.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_db_user_v1.go index 4936c11cb..f667c57de 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_db_user_v1.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_db_user_v1.go @@ -2,12 +2,9 @@ package openstack import ( "fmt" - "log" "strings" "time" - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack/db/v1/databases" "github.com/gophercloud/gophercloud/openstack/db/v1/users" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" @@ -26,32 +23,37 @@ func resourceDatabaseUserV1() *schema.Resource { Schema: map[string]*schema.Schema{ "region": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - DefaultFunc: schema.EnvDefaultFunc("OS_REGION_NAME", ""), + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, }, + "name": { Type: schema.TypeString, Required: true, ForceNew: true, }, + "instance_id": { Type: schema.TypeString, Required: true, ForceNew: true, }, + "password": { Type: schema.TypeString, Required: true, ForceNew: true, Sensitive: true, }, + "host": { Type: schema.TypeString, Optional: true, ForceNew: true, }, + "databases": { Type: schema.TypeSet, Optional: true, @@ -67,34 +69,30 @@ func resourceDatabaseUserV1Create(d *schema.ResourceData, meta interface{}) erro config := meta.(*Config) databaseV1Client, err := config.databaseV1Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error creating cloud database client: %s", err) + return fmt.Errorf("Error creating OpenStack database client: %s", err) } userName := d.Get("name").(string) rawDatabases := d.Get("databases").(*schema.Set).List() instanceID := d.Get("instance_id").(string) - var dbs databases.BatchCreateOpts - for _, db := range rawDatabases { - dbs = append(dbs, databases.CreateOpts{ - Name: db.(string), - }) - } - var usersList users.BatchCreateOpts usersList = append(usersList, users.CreateOpts{ Name: userName, Password: d.Get("password").(string), Host: d.Get("host").(string), - Databases: dbs, + Databases: expandDatabaseUserV1Databases(rawDatabases), }) - users.Create(databaseV1Client, instanceID, usersList) + err = users.Create(databaseV1Client, instanceID, usersList).ExtractErr() + if err != nil { + return fmt.Errorf("Error creating openstack_db_user_v1: %s", err) + } stateConf := &resource.StateChangeConf{ Pending: []string{"BUILD"}, Target: []string{"ACTIVE"}, - Refresh: DatabaseUserV1StateRefreshFunc(databaseV1Client, instanceID, userName), + Refresh: databaseUserV1StateRefreshFunc(databaseV1Client, instanceID, userName), Timeout: d.Timeout(schema.TimeoutCreate), Delay: 10 * time.Second, MinTimeout: 3 * time.Second, @@ -102,8 +100,7 @@ func resourceDatabaseUserV1Create(d *schema.ResourceData, meta interface{}) erro _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf( - "Error waiting for user (%s) to be created", err) + return fmt.Errorf("Error waiting for openstack_db_user_v1 %s to be created: %s", userName, err) } // Store the ID now @@ -116,35 +113,30 @@ func resourceDatabaseUserV1Read(d *schema.ResourceData, meta interface{}) error config := meta.(*Config) databaseV1Client, err := config.databaseV1Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error creating cloud database client: %s", err) + return fmt.Errorf("Error creating OpenStack database client: %s", err) } userID := strings.SplitN(d.Id(), "/", 2) if len(userID) != 2 { - return fmt.Errorf("Invalid openstack_db_user_v1 ID format") + return fmt.Errorf("Invalid openstack_db_user_v1 ID: %s", d.Id()) } instanceID := userID[0] userName := userID[1] - exists, userObj, err := DatabaseUserV1State(databaseV1Client, instanceID, userName) + exists, userObj, err := databaseUserV1Exists(databaseV1Client, instanceID, userName) if err != nil { - return fmt.Errorf("Error checking user status: %s", err) + return fmt.Errorf("Error checking if openstack_db_user_v1 %s exists: %s", d.Id(), err) } if !exists { - return fmt.Errorf("User %s was not found: %s", userName, err) + d.SetId("") + return nil } - log.Printf("[DEBUG] Retrieved user %s", userName) - d.Set("name", userName) - var databases []string - for _, dbName := range userObj.Databases { - databases = append(databases, dbName.Name) - } - + databases := flattenDatabaseUserV1Databases(userObj.Databases) if err := d.Set("databases", databases); err != nil { return fmt.Errorf("Unable to set databases: %s", err) } @@ -156,81 +148,30 @@ func resourceDatabaseUserV1Delete(d *schema.ResourceData, meta interface{}) erro config := meta.(*Config) databaseV1Client, err := config.databaseV1Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error creating cloud database client: %s", err) + return fmt.Errorf("Error creating OpenStack database client: %s", err) } userID := strings.SplitN(d.Id(), "/", 2) if len(userID) != 2 { - return fmt.Errorf("Invalid openstack_db_user_v1 ID format") + return fmt.Errorf("Invalid openstack_db_user_v1 ID: %s", d.Id()) } instanceID := userID[0] userName := userID[1] - exists, _, err := DatabaseUserV1State(databaseV1Client, instanceID, userName) + exists, _, err := databaseUserV1Exists(databaseV1Client, instanceID, userName) if err != nil { - return fmt.Errorf("Error checking user status: %s", err) + return fmt.Errorf("Error checking if openstack_db_user_v1 %s exists: %s", d.Id(), err) } if !exists { - log.Printf("User %s was not found on instance %s", userName, instanceID) return nil } - log.Printf("[DEBUG] Retrieved user %s", userName) - - users.Delete(databaseV1Client, instanceID, userName) - - d.SetId("") - return nil -} - -// DatabaseUserV1StateRefreshFunc returns a resource.StateRefreshFunc that is used to watch db user. -func DatabaseUserV1StateRefreshFunc(client *gophercloud.ServiceClient, instanceID string, userName string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - - pages, err := users.List(client, instanceID).AllPages() - if err != nil { - return nil, "", fmt.Errorf("Unable to retrieve users, pages: %s", err) - } - - allUsers, err := users.ExtractUsers(pages) - if err != nil { - return nil, "", fmt.Errorf("Unable to retrieve users, extract: %s", err) - } - - for _, v := range allUsers { - if v.Name == userName { - return v, "ACTIVE", nil - } - } - - return nil, "BUILD", nil - } -} - -// DatabaseUserV1State is used to check whether user exists on particular database instance -func DatabaseUserV1State(client *gophercloud.ServiceClient, instanceID string, userName string) (exists bool, userObj users.User, err error) { - exists = false - err = nil - - pages, err := users.List(client, instanceID).AllPages() + err = users.Delete(databaseV1Client, instanceID, userName).ExtractErr() if err != nil { - return + return fmt.Errorf("Error deleting openstack_db_user_v1 %s: %s", d.Id(), err) } - allUsers, err := users.ExtractUsers(pages) - if err != nil { - return - } - - for _, v := range allUsers { - if v.Name == userName { - exists = true - userObj = v - return - } - } - - return false, userObj, err + return nil } diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_dns_recordset_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_dns_recordset_v2.go index a283f777f..fd8ea7813 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_dns_recordset_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_dns_recordset_v2.go @@ -177,7 +177,8 @@ func resourceDNSRecordSetV2Update(d *schema.ResourceData, meta interface{}) erro var updateOpts recordsets.UpdateOpts if d.HasChange("ttl") { - updateOpts.TTL = d.Get("ttl").(int) + ttl := d.Get("ttl").(int) + updateOpts.TTL = &ttl } if d.HasChange("records") { diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_identity_application_credential_v3.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_identity_application_credential_v3.go new file mode 100644 index 000000000..1b5e5e3fa --- /dev/null +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_identity_application_credential_v3.go @@ -0,0 +1,191 @@ +package openstack + +import ( + "fmt" + "log" + "time" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack/identity/v3/applicationcredentials" + "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" +) + +func resourceIdentityApplicationCredentialV3() *schema.Resource { + return &schema.Resource{ + Create: resourceIdentityApplicationCredentialV3Create, + Read: resourceIdentityApplicationCredentialV3Read, + Delete: resourceIdentityApplicationCredentialV3Delete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "unrestricted": { + Type: schema.TypeBool, + Optional: true, + Default: false, + ForceNew: true, + }, + + "secret": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Sensitive: true, + ForceNew: true, + }, + + "project_id": { + Type: schema.TypeString, + Computed: true, + ForceNew: true, + }, + + "roles": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "expires_at": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.ValidateRFC3339TimeString, + }, + }, + } +} + +func resourceIdentityApplicationCredentialV3Create(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + identityClient, err := config.identityV3Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating OpenStack identity client: %s", err) + } + + token := tokens.Get(identityClient, config.OsClient.TokenID) + if token.Err != nil { + return token.Err + } + + user, err := token.ExtractUser() + if err != nil { + return err + } + + createOpts := applicationcredentials.CreateOpts{ + Name: d.Get("name").(string), + Description: d.Get("description").(string), + Unrestricted: d.Get("unrestricted").(bool), + Roles: expandIdentityApplicationCredentialRolesV3(d.Get("roles").(*schema.Set).List()), + ExpiresAt: d.Get("expires_at").(string), + } + + log.Printf("[DEBUG] openstack_identity_application_credential_v3 create options: %#v", createOpts) + + createOpts.Secret = d.Get("secret").(string) + + applicationCredential, err := applicationcredentials.Create(identityClient, user.ID, createOpts).Extract() + if err != nil { + if v, ok := err.(gophercloud.ErrDefault404); ok { + return fmt.Errorf("Error creating openstack_identity_application_credential_v3: %s", v.ErrUnexpectedResponseCode.Body) + } + return fmt.Errorf("Error creating openstack_identity_application_credential_v3: %s", err) + } + + d.SetId(applicationCredential.ID) + + // Secret is returned only once + d.Set("secret", applicationCredential.Secret) + + return resourceIdentityApplicationCredentialV3Read(d, meta) +} + +func resourceIdentityApplicationCredentialV3Read(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + identityClient, err := config.identityV3Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating OpenStack identity client: %s", err) + } + + token := tokens.Get(identityClient, config.OsClient.TokenID) + if token.Err != nil { + return token.Err + } + + user, err := token.ExtractUser() + if err != nil { + return err + } + + applicationCredential, err := applicationcredentials.Get(identityClient, user.ID, d.Id()).Extract() + if err != nil { + return CheckDeleted(d, err, "Error retrieving openstack_identity_application_credential_v3") + } + + log.Printf("[DEBUG] Retrieved openstack_identity_application_credential_v3 %s: %#v", d.Id(), applicationCredential) + + d.Set("name", applicationCredential.Name) + d.Set("description", applicationCredential.Description) + d.Set("unrestricted", applicationCredential.Unrestricted) + d.Set("roles", flattenIdentityApplicationCredentialRolesV3(applicationCredential.Roles)) + d.Set("project_id", applicationCredential.ProjectID) + d.Set("region", GetRegion(d, config)) + + if applicationCredential.ExpiresAt == (time.Time{}) { + d.Set("expires_at", "") + } else { + d.Set("expires_at", applicationCredential.ExpiresAt.UTC().Format(time.RFC3339)) + } + + return nil +} + +func resourceIdentityApplicationCredentialV3Delete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + identityClient, err := config.identityV3Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating OpenStack identity client: %s", err) + } + + token := tokens.Get(identityClient, config.OsClient.TokenID) + if token.Err != nil { + return token.Err + } + + user, err := token.ExtractUser() + if err != nil { + return err + } + + err = applicationcredentials.Delete(identityClient, user.ID, d.Id()).ExtractErr() + if err != nil { + return CheckDeleted(d, err, "Error deleting openstack_identity_application_credential_v3") + } + + return nil +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_lb_monitor_v1.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_lb_monitor_v1.go index 8fe6f00ab..6fdfc9582 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_lb_monitor_v1.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_lb_monitor_v1.go @@ -275,11 +275,9 @@ func waitForLBMonitorDelete(networkingClient *gophercloud.ServiceClient, monitor return m, "DELETED", nil } - if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok { - if errCode.Actual == 409 { - log.Printf("[DEBUG] OpenStack LB Monitor (%s) is waiting for Pool to delete.", monitorId) - return m, "PENDING", nil - } + if _, ok := err.(gophercloud.ErrDefault409); ok { + log.Printf("[DEBUG] OpenStack LB Monitor (%s) is waiting for Pool to delete.", monitorId) + return m, "PENDING", nil } return m, "ACTIVE", err @@ -293,11 +291,9 @@ func waitForLBMonitorDelete(networkingClient *gophercloud.ServiceClient, monitor return m, "DELETED", nil } - if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok { - if errCode.Actual == 409 { - log.Printf("[DEBUG] OpenStack LB Monitor (%s) is waiting for Pool to delete.", monitorId) - return m, "PENDING", nil - } + if _, ok := err.(gophercloud.ErrDefault409); ok { + log.Printf("[DEBUG] OpenStack LB Monitor (%s) is waiting for Pool to delete.", monitorId) + return m, "PENDING", nil } return m, "ACTIVE", err diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_floatingip_associate_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_floatingip_associate_v2.go index f77bcdf07..aabd88ca1 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_floatingip_associate_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_floatingip_associate_v2.go @@ -13,6 +13,7 @@ func resourceNetworkingFloatingIPAssociateV2() *schema.Resource { return &schema.Resource{ Create: resourceNetworkingFloatingIPAssociateV2Create, Read: resourceNetworkingFloatingIPAssociateV2Read, + Update: resourceNetworkingFloatingIPAssociateV2Update, Delete: resourceNetworkingFloatingIPAssociateV2Delete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, @@ -35,7 +36,12 @@ func resourceNetworkingFloatingIPAssociateV2() *schema.Resource { "port_id": { Type: schema.TypeString, Required: true, - ForceNew: true, + }, + + "fixed_ip": { + Type: schema.TypeString, + Optional: true, + Computed: true, }, }, } @@ -50,27 +56,26 @@ func resourceNetworkingFloatingIPAssociateV2Create(d *schema.ResourceData, meta floatingIP := d.Get("floating_ip").(string) portID := d.Get("port_id").(string) + fixedIP := d.Get("fixed_ip").(string) fipID, err := networkingFloatingIPV2ID(networkingClient, floatingIP) if err != nil { - return fmt.Errorf("Unable to get ID of openstack_networking_floatingip_v2: %s", err) + return fmt.Errorf("Unable to get ID of openstack_networking_floatingip_associate_v2 floating_ip %s: %s", floatingIP, err) } updateOpts := floatingips.UpdateOpts{ - PortID: &portID, + PortID: &portID, + FixedIP: fixedIP, } log.Printf("[DEBUG] openstack_networking_floatingip_associate_v2 create options: %#v", updateOpts) _, err = floatingips.Update(networkingClient, fipID, updateOpts).Extract() if err != nil { - return fmt.Errorf("Error associating openstack_networking_floatingip_v2 %s to openstack_networking_port_v2 %s: %s", - fipID, portID, err) + return fmt.Errorf("Error associating openstack_networking_floatingip_associate_v2 floating_ip %s with port %s: %s", fipID, portID, err) } d.SetId(fipID) - log.Printf("[DEBUG] Created association between openstack_networking_floatingip_v2 %s and openstack_networking_port_v2 %s", - fipID, portID) return resourceNetworkingFloatingIPAssociateV2Read(d, meta) } @@ -83,18 +88,45 @@ func resourceNetworkingFloatingIPAssociateV2Read(d *schema.ResourceData, meta in fip, err := floatingips.Get(networkingClient, d.Id()).Extract() if err != nil { - return CheckDeleted(d, err, "Error getting openstack_networking_floatingip_v2") + return CheckDeleted(d, err, "Error getting openstack_networking_floatingip_associate_v2") } - log.Printf("[DEBUG] Retrieved openstack_networking_floatingip_v2 %s: %#v", d.Id(), fip) + log.Printf("[DEBUG] Retrieved openstack_networking_floatingip_associate_v2 %s: %#v", d.Id(), fip) d.Set("floating_ip", fip.FloatingIP) d.Set("port_id", fip.PortID) + d.Set("fixed_ip", fip.FixedIP) d.Set("region", GetRegion(d, config)) return nil } +func resourceNetworkingFloatingIPAssociateV2Update(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating OpenStack network client: %s", err) + } + + var updateOpts floatingips.UpdateOpts + + // port_id must always exists + portID := d.Get("port_id").(string) + updateOpts.PortID = &portID + + if d.HasChange("fixed_ip") { + updateOpts.FixedIP = d.Get("fixed_ip").(string) + } + + log.Printf("[DEBUG] openstack_networking_floatingip_associate_v2 %s update options: %#v", d.Id(), updateOpts) + _, err = floatingips.Update(networkingClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating openstack_networking_floatingip_associate_v2 %s: %s", d.Id(), err) + } + + return resourceNetworkingFloatingIPAssociateV2Read(d, meta) +} + func resourceNetworkingFloatingIPAssociateV2Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := config.networkingV2Client(GetRegion(d, config)) @@ -107,11 +139,10 @@ func resourceNetworkingFloatingIPAssociateV2Delete(d *schema.ResourceData, meta PortID: new(string), } - log.Printf("[DEBUG] openstack_networking_floatingip_v2 disassociating options: %#v", updateOpts) + log.Printf("[DEBUG] openstack_networking_floatingip_associate_v2 disassociating options: %#v", updateOpts) _, err = floatingips.Update(networkingClient, d.Id(), updateOpts).Extract() if err != nil { - return fmt.Errorf("Error disassociating openstack_networking_floatingip_v2 %s from openstack_networking_port_v2 %s: %s", - d.Id(), portID, err) + return fmt.Errorf("Error disassociating openstack_networking_floatingip_associate_v2 floating_ip %s with port %s: %s", d.Id(), portID, err) } return nil diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_floatingip_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_floatingip_v2.go index 930d716ae..6638d8ec6 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_floatingip_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_floatingip_v2.go @@ -3,12 +3,15 @@ package openstack import ( "fmt" "log" + "regexp" "time" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/attributestags" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/dns" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" ) @@ -95,6 +98,19 @@ func resourceNetworkingFloatingIPV2() *schema.Resource { Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + + "dns_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "dns_domain": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringMatch(regexp.MustCompile(`^$|\.$`), "fully-qualified (unambiguous) DNS domain names must have a dot at the end"), + }, }, } } @@ -127,8 +143,23 @@ func resourceNetworkFloatingIPV2Create(d *schema.ResourceData, meta interface{}) MapValueSpecs(d), } - log.Printf("[DEBUG] openstack_networking_floatingip_v2 create options: %#v", createOpts) - fip, err := floatingips.Create(networkingClient, createOpts).Extract() + var finalCreateOpts floatingips.CreateOptsBuilder + finalCreateOpts = createOpts + + dnsName := d.Get("dns_name").(string) + dnsDomain := d.Get("dns_domain").(string) + if dnsName != "" || dnsDomain != "" { + finalCreateOpts = dns.FloatingIPCreateOptsExt{ + CreateOptsBuilder: finalCreateOpts, + DNSName: dnsName, + DNSDomain: dnsDomain, + } + } + + var fip floatingIPExtended + + log.Printf("[DEBUG] openstack_networking_floatingip_v2 create options: %#v", finalCreateOpts) + err = floatingips.Create(networkingClient, finalCreateOpts).ExtractInto(&fip) if err != nil { return fmt.Errorf("Error creating openstack_networking_floatingip_v2: %s", err) } @@ -171,7 +202,9 @@ func resourceNetworkFloatingIPV2Read(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("Error creating OpenStack network client: %s", err) } - fip, err := floatingips.Get(networkingClient, d.Id()).Extract() + var fip floatingIPExtended + + err = floatingips.Get(networkingClient, d.Id()).ExtractInto(&fip) if err != nil { return CheckDeleted(d, err, "Error getting openstack_networking_floatingip_v2") } @@ -179,10 +212,12 @@ func resourceNetworkFloatingIPV2Read(d *schema.ResourceData, meta interface{}) e log.Printf("[DEBUG] Retrieved openstack_networking_floatingip_v2 %s: %#v", d.Id(), fip) d.Set("description", fip.Description) - d.Set("address", fip.FloatingIP) + d.Set("address", fip.FloatingIP.FloatingIP) d.Set("port_id", fip.PortID) d.Set("fixed_ip", fip.FixedIP) d.Set("tenant_id", fip.TenantID) + d.Set("dns_name", fip.DNSName) + d.Set("dns_domain", fip.DNSDomain) d.Set("region", GetRegion(d, config)) networkV2ReadAttributesTags(d, fip.Tags) @@ -212,12 +247,19 @@ func resourceNetworkFloatingIPV2Update(d *schema.ResourceData, meta interface{}) updateOpts.Description = &description } - if d.HasChange("port_id") { + // fixed_ip_address cannot be specified without a port_id + if d.HasChange("port_id") || d.HasChange("fixed_ip") { hasChange = true portID := d.Get("port_id").(string) updateOpts.PortID = &portID } + if d.HasChange("fixed_ip") { + hasChange = true + fixedIP := d.Get("fixed_ip").(string) + updateOpts.FixedIP = fixedIP + } + if hasChange { log.Printf("[DEBUG] openstack_networking_floatingip_v2 %s update options: %#v", d.Id(), updateOpts) _, err = floatingips.Update(networkingClient, d.Id(), updateOpts).Extract() diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_network_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_network_v2.go index 4280fa4ff..495001632 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_network_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_network_v2.go @@ -3,13 +3,18 @@ package openstack import ( "fmt" "log" + "regexp" "time" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/attributestags" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/dns" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external" + mtuext "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/mtu" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/provider" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/vlantransparent" "github.com/gophercloud/gophercloud/openstack/networking/v2/networks" @@ -135,6 +140,24 @@ func resourceNetworkingNetworkV2() *schema.Resource { ForceNew: true, Computed: true, }, + + "port_security_enabled": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + + "mtu": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + + "dns_domain": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringMatch(regexp.MustCompile(`^$|\.$`), "fully-qualified (unambiguous) DNS domain names must have a dot at the end"), + }, }, } } @@ -168,15 +191,12 @@ func resourceNetworkingNetworkV2Create(d *schema.ResourceData, meta interface{}) createOpts.Shared = &shared } - segments := expandNetworkingNetworkSegmentsV2(d.Get("segments").(*schema.Set)) - isExternal := d.Get("external").(bool) - isVLANTransparent := d.Get("transparent_vlan").(bool) - // Declare a finalCreateOpts interface. var finalCreateOpts networks.CreateOptsBuilder finalCreateOpts = createOpts // Add networking segments if specified. + segments := expandNetworkingNetworkSegmentsV2(d.Get("segments").(*schema.Set)) if len(segments) > 0 { finalCreateOpts = provider.CreateOptsExt{ CreateOptsBuilder: finalCreateOpts, @@ -185,6 +205,7 @@ func resourceNetworkingNetworkV2Create(d *schema.ResourceData, meta interface{}) } // Add the external attribute if specified. + isExternal := d.Get("external").(bool) if isExternal { finalCreateOpts = external.CreateOptsExt{ CreateOptsBuilder: finalCreateOpts, @@ -193,6 +214,7 @@ func resourceNetworkingNetworkV2Create(d *schema.ResourceData, meta interface{}) } // Add the transparent VLAN attribute if specified. + isVLANTransparent := d.Get("transparent_vlan").(bool) if isVLANTransparent { finalCreateOpts = vlantransparent.CreateOptsExt{ CreateOptsBuilder: finalCreateOpts, @@ -200,6 +222,32 @@ func resourceNetworkingNetworkV2Create(d *schema.ResourceData, meta interface{}) } } + // Add the port security attribute if specified. + if v, ok := d.GetOkExists("port_security_enabled"); ok { + portSecurityEnabled := v.(bool) + finalCreateOpts = portsecurity.NetworkCreateOptsExt{ + CreateOptsBuilder: finalCreateOpts, + PortSecurityEnabled: &portSecurityEnabled, + } + } + + mtu := d.Get("mtu").(int) + // Add the MTU attribute if specified. + if mtu > 0 { + finalCreateOpts = mtuext.CreateOptsExt{ + CreateOptsBuilder: finalCreateOpts, + MTU: mtu, + } + } + + // Add the DNS Domain attribute if specified. + if dnsDomain := d.Get("dns_domain").(string); dnsDomain != "" { + finalCreateOpts = dns.NetworkCreateOptsExt{ + CreateOptsBuilder: finalCreateOpts, + DNSDomain: dnsDomain, + } + } + log.Printf("[DEBUG] openstack_networking_network_v2 create options: %#v", finalCreateOpts) n, err := networks.Create(networkingClient, finalCreateOpts).Extract() if err != nil { @@ -245,30 +293,30 @@ func resourceNetworkingNetworkV2Read(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("Error creating OpenStack networking client: %s", err) } - var n struct { - networks.Network - external.NetworkExternalExt - vlantransparent.TransparentExt - } - err = networks.Get(networkingClient, d.Id()).ExtractInto(&n) + var network networkExtended + + err = networks.Get(networkingClient, d.Id()).ExtractInto(&network) if err != nil { return CheckDeleted(d, err, "Error getting openstack_networking_network_v2") } - log.Printf("[DEBUG] Retrieved openstack_networking_network_v2 %s: %#v", d.Id(), n) - - d.Set("name", n.Name) - d.Set("description", n.Description) - d.Set("admin_state_up", n.AdminStateUp) - d.Set("shared", n.Shared) - d.Set("external", n.External) - d.Set("tenant_id", n.TenantID) + log.Printf("[DEBUG] Retrieved openstack_networking_network_v2 %s: %#v", d.Id(), network) + + d.Set("name", network.Name) + d.Set("description", network.Description) + d.Set("admin_state_up", network.AdminStateUp) + d.Set("shared", network.Shared) + d.Set("external", network.External) + d.Set("tenant_id", network.TenantID) + d.Set("transparent_vlan", network.VLANTransparent) + d.Set("port_security_enabled", network.PortSecurityEnabled) + d.Set("mtu", network.MTU) + d.Set("dns_domain", network.DNSDomain) d.Set("region", GetRegion(d, config)) - d.Set("transparent_vlan", n.VLANTransparent) - networkV2ReadAttributesTags(d, n.Tags) + networkV2ReadAttributesTags(d, network.Tags) - if err := d.Set("availability_zone_hints", n.AvailabilityZoneHints); err != nil { + if err := d.Set("availability_zone_hints", network.AvailabilityZoneHints); err != nil { log.Printf("[DEBUG] Unable to set openstack_networking_network_v2 %s availability_zone_hints: %s", d.Id(), err) } @@ -290,7 +338,8 @@ func resourceNetworkingNetworkV2Update(d *schema.ResourceData, meta interface{}) // Populate basic updateOpts. if d.HasChange("name") { - updateOpts.Name = d.Get("name").(string) + name := d.Get("name").(string) + updateOpts.Name = &name } if d.HasChange("description") { description := d.Get("description").(string) @@ -320,15 +369,39 @@ func resourceNetworkingNetworkV2Update(d *schema.ResourceData, meta interface{}) finalUpdateOpts = updateOpts // Populate extensions options. - isExternal := false if d.HasChange("external") { - isExternal = d.Get("external").(bool) + isExternal := d.Get("external").(bool) finalUpdateOpts = external.UpdateOptsExt{ UpdateOptsBuilder: finalUpdateOpts, External: &isExternal, } } + // Populate port security options. + if d.HasChange("port_security_enabled") { + portSecurityEnabled := d.Get("port_security_enabled").(bool) + finalUpdateOpts = portsecurity.NetworkUpdateOptsExt{ + UpdateOptsBuilder: finalUpdateOpts, + PortSecurityEnabled: &portSecurityEnabled, + } + } + + if d.HasChange("mtu") { + mtu := d.Get("mtu").(int) + finalUpdateOpts = mtuext.UpdateOptsExt{ + UpdateOptsBuilder: finalUpdateOpts, + MTU: mtu, + } + } + + if d.HasChange("dns_domain") { + dnsDomain := d.Get("dns_domain").(string) + finalUpdateOpts = dns.NetworkUpdateOptsExt{ + UpdateOptsBuilder: finalUpdateOpts, + DNSDomain: &dnsDomain, + } + } + log.Printf("[DEBUG] openstack_networking_network_v2 %s update options: %#v", d.Id(), finalUpdateOpts) _, err = networks.Update(networkingClient, d.Id(), finalUpdateOpts).Extract() if err != nil { diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_port_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_port_v2.go index 48edab481..c219d7416 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_port_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_port_v2.go @@ -1,15 +1,21 @@ package openstack import ( + "encoding/json" "fmt" "log" "time" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/attributestags" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/dns" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/extradhcpopts" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsbinding" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/portsecurity" "github.com/gophercloud/gophercloud/openstack/networking/v2/ports" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/structure" + "github.com/hashicorp/terraform/helper/validation" ) func resourceNetworkingPortV2() *schema.Resource { @@ -199,6 +205,65 @@ func resourceNetworkingPortV2() *schema.Resource { Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + + "port_security_enabled": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + + "binding": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "host_id": { + Type: schema.TypeString, + Optional: true, + }, + "profile": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.ValidateJsonString, + DiffSuppressFunc: suppressDiffPortBindingProfileV2, + StateFunc: func(v interface{}) string { + json, _ := structure.NormalizeJsonString(v) + return json + }, + }, + "vif_details": { + Type: schema.TypeMap, + Computed: true, + }, + "vif_type": { + Type: schema.TypeString, + Computed: true, + }, + "vnic_type": { + Type: schema.TypeString, + Optional: true, + Default: "normal", + ValidateFunc: validation.StringInSlice([]string{ + "direct", "direct-physical", "macvtap", "normal", "baremetal", "virtio-forwarder", + }, true), + }, + }, + }, + }, + + "dns_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "dns_assignment": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeMap}, + }, }, } } @@ -263,24 +328,61 @@ func resourceNetworkingPortV2Create(d *schema.ResourceData, meta interface{}) er } } - log.Printf("[DEBUG] openstack_networking_port_v2 create options: %#v", finalCreateOpts) + // Add the port security attribute if specified. + if v, ok := d.GetOkExists("port_security_enabled"); ok { + portSecurityEnabled := v.(bool) + finalCreateOpts = portsecurity.PortCreateOptsExt{ + CreateOptsBuilder: finalCreateOpts, + PortSecurityEnabled: &portSecurityEnabled, + } + } + + // Add the port binding parameters if specified. + if v, ok := d.GetOkExists("binding"); ok { + for _, raw := range v.([]interface{}) { + binding := raw.(map[string]interface{}) + profile := map[string]interface{}{} + + // Convert raw string into the map + rawProfile := binding["profile"].(string) + if len(rawProfile) > 0 { + err := json.Unmarshal([]byte(rawProfile), &profile) + if err != nil { + return fmt.Errorf("Failed to unmarshal the JSON: %s", err) + } + } - // Create a Neutron port and set extra DHCP options if they're specified. - var p struct { - ports.Port - extradhcpopts.ExtraDHCPOptsExt + finalCreateOpts = portsbinding.CreateOptsExt{ + CreateOptsBuilder: finalCreateOpts, + HostID: binding["host_id"].(string), + Profile: profile, + VNICType: binding["vnic_type"].(string), + } + } + } + + if dnsName := d.Get("dns_name").(string); dnsName != "" { + finalCreateOpts = dns.PortCreateOptsExt{ + CreateOptsBuilder: finalCreateOpts, + DNSName: dnsName, + } } - err = ports.Create(networkingClient, finalCreateOpts).ExtractInto(&p) + log.Printf("[DEBUG] openstack_networking_port_v2 create options: %#v", finalCreateOpts) + + // Create a Neutron port and set extra options if they're specified. + var port portExtended + + err = ports.Create(networkingClient, finalCreateOpts).ExtractInto(&port) if err != nil { return fmt.Errorf("Error creating openstack_networking_port_v2: %s", err) } - log.Printf("[DEBUG] Waiting for openstack_networking_port_v2 %s to become available.", p.ID) + log.Printf("[DEBUG] Waiting for openstack_networking_port_v2 %s to become available.", port.ID) stateConf := &resource.StateChangeConf{ Target: []string{"ACTIVE", "DOWN"}, - Refresh: resourceNetworkingPortV2StateRefreshFunc(networkingClient, p.ID), + Refresh: resourceNetworkingPortV2StateRefreshFunc(networkingClient, port.ID), Timeout: d.Timeout(schema.TimeoutCreate), Delay: 5 * time.Second, MinTimeout: 3 * time.Second, @@ -288,22 +390,22 @@ func resourceNetworkingPortV2Create(d *schema.ResourceData, meta interface{}) er _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf("Error waiting for openstack_networking_port_v2 %s to become available: %s", p.ID, err) + return fmt.Errorf("Error waiting for openstack_networking_port_v2 %s to become available: %s", port.ID, err) } - d.SetId(p.ID) + d.SetId(port.ID) tags := networkV2AttributesTags(d) if len(tags) > 0 { tagOpts := attributestags.ReplaceAllOpts{Tags: tags} - tags, err := attributestags.ReplaceAll(networkingClient, "ports", p.ID, tagOpts).Extract() + tags, err := attributestags.ReplaceAll(networkingClient, "ports", port.ID, tagOpts).Extract() if err != nil { - return fmt.Errorf("Error setting tags on openstack_networking_port_v2 %s: %s", p.ID, err) + return fmt.Errorf("Error setting tags on openstack_networking_port_v2 %s: %s", port.ID, err) } - log.Printf("[DEBUG] Set tags %s on openstack_networking_port_v2 %s", tags, p.ID) + log.Printf("[DEBUG] Set tags %s on openstack_networking_port_v2 %s", tags, port.ID) } - log.Printf("[DEBUG] Created openstack_networking_port_v2 %s: %#v", p.ID, p) + log.Printf("[DEBUG] Created openstack_networking_port_v2 %s: %#v", port.ID, port) return resourceNetworkingPortV2Read(d, meta) } @@ -314,40 +416,41 @@ func resourceNetworkingPortV2Read(d *schema.ResourceData, meta interface{}) erro return fmt.Errorf("Error creating OpenStack networking client: %s", err) } - var p struct { - ports.Port - extradhcpopts.ExtraDHCPOptsExt - } - err = ports.Get(networkingClient, d.Id()).ExtractInto(&p) + var port portExtended + err = ports.Get(networkingClient, d.Id()).ExtractInto(&port) if err != nil { return CheckDeleted(d, err, "Error getting openstack_networking_port_v2") } - log.Printf("[DEBUG] Retrieved openstack_networking_port_v2 %s: %#v", d.Id(), p) + log.Printf("[DEBUG] Retrieved openstack_networking_port_v2 %s: %#v", d.Id(), port) - d.Set("name", p.Name) - d.Set("description", p.Description) - d.Set("admin_state_up", p.AdminStateUp) - d.Set("network_id", p.NetworkID) - d.Set("mac_address", p.MACAddress) - d.Set("tenant_id", p.TenantID) - d.Set("device_owner", p.DeviceOwner) - d.Set("device_id", p.DeviceID) + d.Set("name", port.Name) + d.Set("description", port.Description) + d.Set("admin_state_up", port.AdminStateUp) + d.Set("network_id", port.NetworkID) + d.Set("mac_address", port.MACAddress) + d.Set("tenant_id", port.TenantID) + d.Set("device_owner", port.DeviceOwner) + d.Set("device_id", port.DeviceID) - networkV2ReadAttributesTags(d, p.Tags) + networkV2ReadAttributesTags(d, port.Tags) // Set a slice of all returned Fixed IPs. // This will be in the order returned by the API, // which is usually alpha-numeric. - d.Set("all_fixed_ips", expandNetworkingPortFixedIPToStringSlice(p.FixedIPs)) + d.Set("all_fixed_ips", expandNetworkingPortFixedIPToStringSlice(port.FixedIPs)) // Set all security groups. // This can be different from what the user specified since // the port can have the "default" group automatically applied. - d.Set("all_security_group_ids", p.SecurityGroups) + d.Set("all_security_group_ids", port.SecurityGroups) - d.Set("allowed_address_pairs", flattenNetworkingPortAllowedAddressPairsV2(p.MACAddress, p.AllowedAddressPairs)) - d.Set("extra_dhcp_option", flattenNetworkingPortDHCPOptsV2(p.ExtraDHCPOptsExt)) + d.Set("allowed_address_pairs", flattenNetworkingPortAllowedAddressPairsV2(port.MACAddress, port.AllowedAddressPairs)) + d.Set("extra_dhcp_option", flattenNetworkingPortDHCPOptsV2(port.ExtraDHCPOptsExt)) + d.Set("port_security_enabled", port.PortSecurityEnabled) + d.Set("binding", flattenNetworkingPortBindingV2(port)) + d.Set("dns_name", port.DNSName) + d.Set("dns_assignment", port.DNSAssignment) d.Set("region", GetRegion(d, config)) @@ -430,51 +533,91 @@ func resourceNetworkingPortV2Update(d *schema.ResourceData, meta interface{}) er } } - // At this point, perform the update for all "standard" port changes. - if hasChange { - log.Printf("[DEBUG] openstack_networking_port_v2 %s update options: %#v", d.Id(), updateOpts) - _, err = ports.Update(networkingClient, d.Id(), updateOpts).Extract() - if err != nil { - return fmt.Errorf("Error updating OpenStack Neutron Port: %s", err) + var finalUpdateOpts ports.UpdateOptsBuilder + finalUpdateOpts = updateOpts + + if d.HasChange("port_security_enabled") { + hasChange = true + portSecurityEnabled := d.Get("port_security_enabled").(bool) + finalUpdateOpts = portsecurity.PortUpdateOptsExt{ + UpdateOptsBuilder: finalUpdateOpts, + PortSecurityEnabled: &portSecurityEnabled, } } // Next, perform any dhcp option changes. if d.HasChange("extra_dhcp_option") { + hasChange = true + o, n := d.GetChange("extra_dhcp_option") oldDHCPOpts := o.(*schema.Set) newDHCPOpts := n.(*schema.Set) - // Delete all old DHCP options, regardless of if they still exist. - // If they do still exist, they will be re-added below. - if oldDHCPOpts.Len() != 0 { - deleteExtraDHCPOpts := expandNetworkingPortDHCPOptsV2Delete(oldDHCPOpts) - dhcpUpdateOpts := extradhcpopts.UpdateOptsExt{ - UpdateOptsBuilder: &ports.UpdateOpts{}, - ExtraDHCPOpts: deleteExtraDHCPOpts, - } + deleteDHCPOpts := oldDHCPOpts.Difference(newDHCPOpts) + addDHCPOpts := newDHCPOpts.Difference(oldDHCPOpts) - log.Printf("[DEBUG] Deleting old DHCP opts for openstack_networking_port_v2 %s", d.Id()) - _, err = ports.Update(networkingClient, d.Id(), dhcpUpdateOpts).Extract() - if err != nil { - return fmt.Errorf("Error updating OpenStack Neutron Port: %s", err) - } + updateExtraDHCPOpts := expandNetworkingPortDHCPOptsV2Update(deleteDHCPOpts, addDHCPOpts) + finalUpdateOpts = extradhcpopts.UpdateOptsExt{ + UpdateOptsBuilder: finalUpdateOpts, + ExtraDHCPOpts: updateExtraDHCPOpts, } + } - // Add any new DHCP options and re-add previously set DHCP options. - if newDHCPOpts.Len() != 0 { - updateExtraDHCPOpts := expandNetworkingPortDHCPOptsV2Update(newDHCPOpts) - dhcpUpdateOpts := extradhcpopts.UpdateOptsExt{ - UpdateOptsBuilder: &ports.UpdateOpts{}, - ExtraDHCPOpts: updateExtraDHCPOpts, + // Next, perform port binding option changes. + if d.HasChange("binding") { + hasChange = true + + profile := map[string]interface{}{} + + // default options, when unsetting the port bindings + newOpts := portsbinding.UpdateOptsExt{ + UpdateOptsBuilder: finalUpdateOpts, + HostID: new(string), + Profile: profile, + VNICType: "normal", + } + + for _, raw := range d.Get("binding").([]interface{}) { + binding := raw.(map[string]interface{}) + + // Convert raw string into the map + rawProfile := binding["profile"].(string) + if len(rawProfile) > 0 { + err := json.Unmarshal([]byte(rawProfile), &profile) + if err != nil { + return fmt.Errorf("Failed to unmarshal the JSON: %s", err) + } } - log.Printf("[DEBUG] Updating openstack_networking_port_v2 %s with options: %#v", d.Id(), dhcpUpdateOpts) - _, err = ports.Update(networkingClient, d.Id(), dhcpUpdateOpts).Extract() - if err != nil { - return fmt.Errorf("Error updating openstack_networking_port_v2 %s: %s", d.Id(), err) + hostID := binding["host_id"].(string) + newOpts = portsbinding.UpdateOptsExt{ + UpdateOptsBuilder: finalUpdateOpts, + HostID: &hostID, + Profile: profile, + VNICType: binding["vnic_type"].(string), } } + + finalUpdateOpts = newOpts + } + + if d.HasChange("dns_name") { + hasChange = true + + dnsName := d.Get("dns_name").(string) + finalUpdateOpts = dns.PortUpdateOptsExt{ + UpdateOptsBuilder: finalUpdateOpts, + DNSName: &dnsName, + } + } + + // At this point, perform the update for all "standard" port changes. + if hasChange { + log.Printf("[DEBUG] openstack_networking_port_v2 %s update options: %#v", d.Id(), finalUpdateOpts) + _, err = ports.Update(networkingClient, d.Id(), finalUpdateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating OpenStack Neutron Port: %s", err) + } } // Next, perform any required updates to the tags. diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_router_route_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_router_route_v2.go index 1556c852f..1c7d66b2d 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_router_route_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_router_route_v2.go @@ -3,11 +3,9 @@ package openstack import ( "fmt" "log" - "strings" "github.com/hashicorp/terraform/helper/schema" - "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers" ) @@ -27,16 +25,19 @@ func resourceNetworkingRouterRouteV2() *schema.Resource { Computed: true, ForceNew: true, }, + "router_id": { Type: schema.TypeString, Required: true, ForceNew: true, }, + "destination_cidr": { Type: schema.TypeString, Required: true, ForceNew: true, }, + "next_hop": { Type: schema.TypeString, Required: true, @@ -47,117 +48,86 @@ func resourceNetworkingRouterRouteV2() *schema.Resource { } func resourceNetworkingRouterRouteV2Create(d *schema.ResourceData, meta interface{}) error { - - routerId := d.Get("router_id").(string) - osMutexKV.Lock(routerId) - defer osMutexKV.Unlock(routerId) - - var destCidr string = d.Get("destination_cidr").(string) - var nextHop string = d.Get("next_hop").(string) - config := meta.(*Config) networkingClient, err := config.networkingV2Client(GetRegion(d, config)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } - n, err := routers.Get(networkingClient, routerId).Extract() - if err != nil { - if _, ok := err.(gophercloud.ErrDefault404); ok { - d.SetId("") - return nil - } + routerID := d.Get("router_id").(string) + osMutexKV.Lock(routerID) + defer osMutexKV.Unlock(routerID) - return fmt.Errorf("Error retrieving OpenStack Neutron Router: %s", err) + r, err := routers.Get(networkingClient, routerID).Extract() + if err != nil { + return CheckDeleted(d, err, "Error getting openstack_networking_router_v2") } - var updateOpts routers.UpdateOpts - var routeExists bool = false + log.Printf("[DEBUG] Retrieved openstack_networking_router_v2 %s: %#v", routerID, r) - var rts []routers.Route = n.Routes - for _, r := range rts { + routes := r.Routes + dstCIDR := d.Get("destination_cidr").(string) + nextHop := d.Get("next_hop").(string) + exists := false - if r.DestinationCIDR == destCidr && r.NextHop == nextHop { - routeExists = true + for _, route := range routes { + if route.DestinationCIDR == dstCIDR && route.NextHop == nextHop { + exists = true break } } - if !routeExists { - - if destCidr != "" && nextHop != "" { - r := routers.Route{DestinationCIDR: destCidr, NextHop: nextHop} - log.Printf( - "[INFO] Adding route %s", r) - rts = append(rts, r) - } - - updateOpts.Routes = rts - - log.Printf("[DEBUG] Updating Router %s with options: %+v", routerId, updateOpts) - - _, err = routers.Update(networkingClient, routerId, updateOpts).Extract() - if err != nil { - return fmt.Errorf("Error updating OpenStack Neutron Router: %s", err) - } - d.SetId(fmt.Sprintf("%s-route-%s-%s", routerId, destCidr, nextHop)) + if exists { + log.Printf("[DEBUG] openstack_networking_router_v2 %s already has route to %s via %s", routerID, dstCIDR, nextHop) + return resourceNetworkingRouterRouteV2Read(d, meta) + } - } else { - log.Printf("[DEBUG] Router %s has route already", routerId) + routes = append(routes, routers.Route{ + DestinationCIDR: dstCIDR, + NextHop: nextHop, + }) + updateOpts := routers.UpdateOpts{ + Routes: routes, } + log.Printf("[DEBUG] openstack_networking_router_v2 %s update options: %#v", routerID, updateOpts) + _, err = routers.Update(networkingClient, routerID, updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating openstack_networking_router_v2: %s", err) + } + + d.SetId(resourceNetworkingRouterRouteV2BuildID(routerID, dstCIDR, nextHop)) return resourceNetworkingRouterRouteV2Read(d, meta) } func resourceNetworkingRouterRouteV2Read(d *schema.ResourceData, meta interface{}) error { - - routerId := d.Get("router_id").(string) - config := meta.(*Config) networkingClient, err := config.networkingV2Client(GetRegion(d, config)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } - destCidr := d.Get("destination_cidr").(string) - nextHop := d.Get("next_hop").(string) - - routeIDParts := []string{} - if d.Id() != "" && strings.Contains(d.Id(), "-route-") { - routeIDParts = strings.Split(d.Id(), "-route-") - routeLastIDParts := strings.Split(routeIDParts[1], "-") + idFromResource, dstCIDR, nextHop, err := resourceNetworkingRouterRouteV2ParseID(d.Id()) + if err != nil { + return fmt.Errorf("Error reading openstack_networking_router_route_v2 ID %s: %s", d.Id(), err) + } - if routerId == "" { - routerId = routeIDParts[0] - d.Set("router_id", routerId) - } - if destCidr == "" { - destCidr = routeLastIDParts[0] - } - if nextHop == "" { - nextHop = routeLastIDParts[1] - } + routerID := d.Get("router_id").(string) + if routerID == "" { + routerID = idFromResource } + d.Set("router_id", routerID) - n, err := routers.Get(networkingClient, routerId).Extract() + r, err := routers.Get(networkingClient, routerID).Extract() if err != nil { - if _, ok := err.(gophercloud.ErrDefault404); ok { - d.SetId("") - return nil - } - - return fmt.Errorf("Error retrieving OpenStack Neutron Router: %s", err) + return CheckDeleted(d, err, "Error getting openstack_networking_router_v2") } - log.Printf("[DEBUG] Retrieved Router %s: %+v", routerId, n) - - d.Set("next_hop", "") - d.Set("destination_cidr", "") + log.Printf("[DEBUG] Retrieved openstack_networking_router_v2 %s: %#v", routerID, r) - for _, r := range n.Routes { - - if r.DestinationCIDR == destCidr && r.NextHop == nextHop { - d.Set("destination_cidr", destCidr) + for _, route := range r.Routes { + if route.DestinationCIDR == dstCIDR && route.NextHop == nextHop { + d.Set("destination_cidr", dstCIDR) d.Set("next_hop", nextHop) break } @@ -169,56 +139,46 @@ func resourceNetworkingRouterRouteV2Read(d *schema.ResourceData, meta interface{ } func resourceNetworkingRouterRouteV2Delete(d *schema.ResourceData, meta interface{}) error { - - routerId := d.Get("router_id").(string) - osMutexKV.Lock(routerId) - defer osMutexKV.Unlock(routerId) - config := meta.(*Config) - networkingClient, err := config.networkingV2Client(GetRegion(d, config)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } - n, err := routers.Get(networkingClient, routerId).Extract() - if err != nil { - if _, ok := err.(gophercloud.ErrDefault404); ok { - return nil - } + routerID := d.Get("router_id").(string) + osMutexKV.Lock(routerID) + defer osMutexKV.Unlock(routerID) - return fmt.Errorf("Error retrieving OpenStack Neutron Router: %s", err) + r, err := routers.Get(networkingClient, routerID).Extract() + if err != nil { + return CheckDeleted(d, err, "Error getting openstack_networking_router_v2") } - var updateOpts routers.UpdateOpts - - var destCidr string = d.Get("destination_cidr").(string) - var nextHop string = d.Get("next_hop").(string) + log.Printf("[DEBUG] Retrieved openstack_networking_router_v2 %s: %#v", routerID, r) - var oldRts []routers.Route = n.Routes - var newRts []routers.Route + dstCIDR := d.Get("destination_cidr").(string) + nextHop := d.Get("next_hop").(string) - for _, r := range oldRts { + oldRoutes := r.Routes + newRoute := []routers.Route{} - if r.DestinationCIDR != destCidr || r.NextHop != nextHop { - newRts = append(newRts, r) + for _, route := range oldRoutes { + if route.DestinationCIDR != dstCIDR || route.NextHop != nextHop { + newRoute = append(newRoute, route) } } - if len(oldRts) != len(newRts) { - r := routers.Route{DestinationCIDR: destCidr, NextHop: nextHop} - log.Printf( - "[INFO] Deleting route %s", r) - updateOpts.Routes = newRts - - log.Printf("[DEBUG] Updating Router %s with options: %+v", routerId, updateOpts) + if len(oldRoutes) == len(newRoute) { + return fmt.Errorf("Can't find route to %s via %s on openstack_networking_router_v2 %s", dstCIDR, nextHop, routerID) + } - _, err = routers.Update(networkingClient, routerId, updateOpts).Extract() - if err != nil { - return fmt.Errorf("Error updating OpenStack Neutron Router: %s", err) - } - } else { - return fmt.Errorf("Route did not exist already") + log.Printf("[DEBUG] Deleting openstack_networking_router_v2 %s route to %s via %s", routerID, dstCIDR, nextHop) + updateOpts := routers.UpdateOpts{ + Routes: newRoute, + } + _, err = routers.Update(networkingClient, routerID, updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating openstack_networking_router_v2: %s", err) } return nil diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_secgroup_rule_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_secgroup_rule_v2.go index 5cfa77a6d..b59bb7caa 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_secgroup_rule_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_secgroup_rule_v2.go @@ -3,14 +3,12 @@ package openstack import ( "fmt" "log" - "strconv" "strings" "time" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" - "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules" ) @@ -34,46 +32,54 @@ func resourceNetworkingSecGroupRuleV2() *schema.Resource { Computed: true, ForceNew: true, }, + "description": { Type: schema.TypeString, Optional: true, Computed: false, ForceNew: true, }, + "direction": { Type: schema.TypeString, Required: true, ForceNew: true, }, + "ethertype": { Type: schema.TypeString, Required: true, ForceNew: true, }, + "port_range_min": { Type: schema.TypeInt, Optional: true, ForceNew: true, Computed: true, }, + "port_range_max": { Type: schema.TypeInt, Optional: true, ForceNew: true, Computed: true, }, + "protocol": { Type: schema.TypeString, Optional: true, ForceNew: true, Computed: true, }, + "remote_group_id": { Type: schema.TypeString, Optional: true, ForceNew: true, Computed: true, }, + "remote_ip_prefix": { Type: schema.TypeString, Optional: true, @@ -83,11 +89,13 @@ func resourceNetworkingSecGroupRuleV2() *schema.Resource { return strings.ToLower(v.(string)) }, }, + "security_group_id": { Type: schema.TypeString, Required: true, ForceNew: true, }, + "tenant_id": { Type: schema.TypeString, Optional: true, @@ -99,7 +107,6 @@ func resourceNetworkingSecGroupRuleV2() *schema.Resource { } func resourceNetworkingSecGroupRuleV2Create(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) networkingClient, err := config.networkingV2Client(GetRegion(d, config)) if err != nil { @@ -112,7 +119,7 @@ func resourceNetworkingSecGroupRuleV2Create(d *schema.ResourceData, meta interfa if protocol == "" { if portRangeMin != 0 || portRangeMax != 0 { - return fmt.Errorf("A protocol must be specified when using port_range_min and port_range_max") + return fmt.Errorf("A protocol must be specified when using port_range_min and port_range_max for openstack_networking_secgroup_rule_v2") } } @@ -127,75 +134,86 @@ func resourceNetworkingSecGroupRuleV2Create(d *schema.ResourceData, meta interfa } if v, ok := d.GetOk("direction"); ok { - direction := resourceNetworkingSecGroupRuleV2DetermineDirection(v.(string)) + direction, err := resourceNetworkingSecGroupRuleV2Direction(v.(string)) + if err != nil { + return err + } opts.Direction = direction } if v, ok := d.GetOk("ethertype"); ok { - ethertype := resourceNetworkingSecGroupRuleV2DetermineEtherType(v.(string)) + ethertype, err := resourceNetworkingSecGroupRuleV2EtherType(v.(string)) + if err != nil { + return err + } opts.EtherType = ethertype } if v, ok := d.GetOk("protocol"); ok { - protocol := resourceNetworkingSecGroupRuleV2DetermineProtocol(v.(string)) + protocol, err := resourceNetworkingSecGroupRuleV2Protocol(v.(string)) + if err != nil { + return err + } opts.Protocol = protocol } - log.Printf("[DEBUG] Create OpenStack Neutron security group: %#v", opts) - security_group_rule, err := rules.Create(networkingClient, opts).Extract() + log.Printf("[DEBUG] openstack_networking_secgroup_rule_v2 create options: %#v", opts) + + sgRule, err := rules.Create(networkingClient, opts).Extract() if err != nil { - return err + return fmt.Errorf("Error creating openstack_networking_secgroup_rule_v2: %s", err) } - log.Printf("[DEBUG] OpenStack Neutron Security Group Rule created: %#v", security_group_rule) - - d.SetId(security_group_rule.ID) + d.SetId(sgRule.ID) + log.Printf("[DEBUG] Created openstack_networking_secgroup_rule_v2 %s: %#v", sgRule.ID, sgRule) return resourceNetworkingSecGroupRuleV2Read(d, meta) } func resourceNetworkingSecGroupRuleV2Read(d *schema.ResourceData, meta interface{}) error { - log.Printf("[DEBUG] Retrieve information about security group rule: %s", d.Id()) - config := meta.(*Config) networkingClient, err := config.networkingV2Client(GetRegion(d, config)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } - security_group_rule, err := rules.Get(networkingClient, d.Id()).Extract() - + sgRule, err := rules.Get(networkingClient, d.Id()).Extract() if err != nil { - return CheckDeleted(d, err, "OpenStack Security Group Rule") + return CheckDeleted(d, err, "Error getting openstack_networking_secgroup_rule_v2") } - d.Set("description", security_group_rule.Description) - d.Set("direction", security_group_rule.Direction) - d.Set("ethertype", security_group_rule.EtherType) - d.Set("protocol", security_group_rule.Protocol) - d.Set("port_range_min", security_group_rule.PortRangeMin) - d.Set("port_range_max", security_group_rule.PortRangeMax) - d.Set("remote_group_id", security_group_rule.RemoteGroupID) - d.Set("remote_ip_prefix", security_group_rule.RemoteIPPrefix) - d.Set("security_group_id", security_group_rule.SecGroupID) - d.Set("tenant_id", security_group_rule.TenantID) + + log.Printf("[DEBUG] Retrieved openstack_networking_secgroup_rule_v2 %s: %#v", d.Id(), sgRule) + + d.Set("description", sgRule.Description) + d.Set("direction", sgRule.Direction) + d.Set("ethertype", sgRule.EtherType) + d.Set("protocol", sgRule.Protocol) + d.Set("port_range_min", sgRule.PortRangeMin) + d.Set("port_range_max", sgRule.PortRangeMax) + d.Set("remote_group_id", sgRule.RemoteGroupID) + d.Set("remote_ip_prefix", sgRule.RemoteIPPrefix) + d.Set("security_group_id", sgRule.SecGroupID) + d.Set("tenant_id", sgRule.TenantID) d.Set("region", GetRegion(d, config)) return nil } func resourceNetworkingSecGroupRuleV2Delete(d *schema.ResourceData, meta interface{}) error { - log.Printf("[DEBUG] Destroy security group rule: %s", d.Id()) - config := meta.(*Config) networkingClient, err := config.networkingV2Client(GetRegion(d, config)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } + if err := rules.Delete(networkingClient, d.Id()).ExtractErr(); err != nil { + return CheckDeleted(d, err, "Error deleting openstack_networking_secgroup_rule_v2") + } + stateConf := &resource.StateChangeConf{ Pending: []string{"ACTIVE"}, Target: []string{"DELETED"}, - Refresh: waitForSecGroupRuleDelete(networkingClient, d.Id()), + Refresh: resourceNetworkingSecGroupRuleV2StateRefreshFunc(networkingClient, d.Id()), Timeout: d.Timeout(schema.TimeoutDelete), Delay: 5 * time.Second, MinTimeout: 3 * time.Second, @@ -203,120 +221,9 @@ func resourceNetworkingSecGroupRuleV2Delete(d *schema.ResourceData, meta interfa _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf("Error deleting OpenStack Neutron Security Group Rule: %s", err) + return fmt.Errorf("Error waiting for openstack_networking_secgroup_rule_v2 %s to delete: %s", d.Id(), err) } d.SetId("") - return err -} - -func resourceNetworkingSecGroupRuleV2DetermineDirection(v string) rules.RuleDirection { - var direction rules.RuleDirection - switch v { - case "ingress": - direction = rules.DirIngress - case "egress": - direction = rules.DirEgress - } - - return direction -} - -func resourceNetworkingSecGroupRuleV2DetermineEtherType(v string) rules.RuleEtherType { - var etherType rules.RuleEtherType - switch v { - case "IPv4": - etherType = rules.EtherType4 - case "IPv6": - etherType = rules.EtherType6 - } - - return etherType -} - -func resourceNetworkingSecGroupRuleV2DetermineProtocol(v string) rules.RuleProtocol { - var protocol rules.RuleProtocol - - // Check and see if the requested protocol matched a list of known protocol names. - switch v { - case "tcp": - protocol = rules.ProtocolTCP - case "udp": - protocol = rules.ProtocolUDP - case "icmp": - protocol = rules.ProtocolICMP - case "ah": - protocol = rules.ProtocolAH - case "dccp": - protocol = rules.ProtocolDCCP - case "egp": - protocol = rules.ProtocolEGP - case "esp": - protocol = rules.ProtocolESP - case "gre": - protocol = rules.ProtocolGRE - case "igmp": - protocol = rules.ProtocolIGMP - case "ipv6-encap": - protocol = rules.ProtocolIPv6Encap - case "ipv6-frag": - protocol = rules.ProtocolIPv6Frag - case "ipv6-icmp": - protocol = rules.ProtocolIPv6ICMP - case "ipv6-nonxt": - protocol = rules.ProtocolIPv6NoNxt - case "ipv6-opts": - protocol = rules.ProtocolIPv6Opts - case "ipv6-route": - protocol = rules.ProtocolIPv6Route - case "ospf": - protocol = rules.ProtocolOSPF - case "pgm": - protocol = rules.ProtocolPGM - case "rsvp": - protocol = rules.ProtocolRSVP - case "sctp": - protocol = rules.ProtocolSCTP - case "udplite": - protocol = rules.ProtocolUDPLite - case "vrrp": - protocol = rules.ProtocolVRRP - } - - // If the protocol wasn't matched above, see if it's an integer. - if protocol == "" { - _, err := strconv.Atoi(v) - if err == nil { - protocol = rules.RuleProtocol(v) - } - } - - return protocol -} - -func waitForSecGroupRuleDelete(networkingClient *gophercloud.ServiceClient, secGroupRuleId string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - log.Printf("[DEBUG] Attempting to delete OpenStack Security Group Rule %s.\n", secGroupRuleId) - - r, err := rules.Get(networkingClient, secGroupRuleId).Extract() - if err != nil { - if _, ok := err.(gophercloud.ErrDefault404); ok { - log.Printf("[DEBUG] Successfully deleted OpenStack Neutron Security Group Rule %s", secGroupRuleId) - return r, "DELETED", nil - } - return r, "ACTIVE", err - } - - err = rules.Delete(networkingClient, secGroupRuleId).ExtractErr() - if err != nil { - if _, ok := err.(gophercloud.ErrDefault404); ok { - log.Printf("[DEBUG] Successfully deleted OpenStack Neutron Security Group Rule %s", secGroupRuleId) - return r, "DELETED", nil - } - return r, "ACTIVE", err - } - - log.Printf("[DEBUG] OpenStack Neutron Security Group Rule %s still active.\n", secGroupRuleId) - return r, "ACTIVE", nil - } + return nil } diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_secgroup_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_secgroup_v2.go index ef826e242..ae2014a8e 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_secgroup_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_secgroup_v2.go @@ -235,10 +235,8 @@ func waitForSecGroupDelete(networkingClient *gophercloud.ServiceClient, secGroup log.Printf("[DEBUG] Successfully deleted OpenStack Neutron Security Group %s", secGroupId) return r, "DELETED", nil } - if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok { - if errCode.Actual == 409 { - return r, "ACTIVE", nil - } + if _, ok := err.(gophercloud.ErrDefault409); ok { + return r, "ACTIVE", nil } return r, "ACTIVE", err } diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_subnet_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_subnet_v2.go index 3e55dafb5..45680f1f1 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_subnet_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_networking_subnet_v2.go @@ -5,6 +5,7 @@ import ( "log" "time" + "github.com/hashicorp/terraform/helper/customdiff" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" @@ -41,10 +42,17 @@ func resourceNetworkingSubnetV2() *schema.Resource { ForceNew: true, }, "cidr": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, + Type: schema.TypeString, + ConflictsWith: []string{"prefix_length"}, + Optional: true, + Computed: true, + ForceNew: true, + }, + "prefix_length": { + Type: schema.TypeInt, + ConflictsWith: []string{"cidr"}, + Optional: true, + ForceNew: true, }, "name": { Type: schema.TypeString, @@ -63,9 +71,29 @@ func resourceNetworkingSubnetV2() *schema.Resource { Computed: true, }, "allocation_pools": { - Type: schema.TypeList, - Optional: true, - Computed: true, + Type: schema.TypeList, + Optional: true, + Computed: true, + ConflictsWith: []string{"allocation_pool"}, + Deprecated: "use allocation_pool instead", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "start": { + Type: schema.TypeString, + Required: true, + }, + "end": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "allocation_pool": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + ConflictsWith: []string{"allocation_pools"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "start": { @@ -164,6 +192,13 @@ func resourceNetworkingSubnetV2() *schema.Resource { Elem: &schema.Schema{Type: schema.TypeString}, }, }, + + CustomizeDiff: customdiff.Sequence( + // Clear the diff if the old and new allocation_pools are the same. + func(diff *schema.ResourceDiff, v interface{}) error { + return resourceSubnetV2AllocationPoolsCustomizeDiff(diff) + }, + ), } } @@ -186,7 +221,7 @@ func resourceNetworkingSubnetV2Create(d *schema.ResourceData, meta interface{}) TenantID: d.Get("tenant_id").(string), IPv6AddressMode: d.Get("ipv6_address_mode").(string), IPv6RAMode: d.Get("ipv6_ra_mode").(string), - AllocationPools: resourceSubnetAllocationPoolsV2(d), + AllocationPools: resourceSubnetAllocationPoolsCreateV2(d), DNSNameservers: resourceSubnetDNSNameserversV2(d), HostRoutes: resourceSubnetHostRoutesV2(d), SubnetPoolID: d.Get("subnetpool_id").(string), @@ -200,6 +235,14 @@ func resourceNetworkingSubnetV2Create(d *schema.ResourceData, meta interface{}) createOpts.CIDR = cidr } + if v, ok := d.GetOk("prefix_length"); ok { + if d.Get("subnetpool_id").(string) == "" { + return fmt.Errorf("'prefix_length' is only valid if 'subnetpool_id' is set") + } + prefixLength := v.(int) + createOpts.Prefixlen = prefixLength + } + if v, ok := d.GetOk("gateway_ip"); ok { gatewayIP := v.(string) createOpts.GatewayIP = &gatewayIP @@ -290,6 +333,7 @@ func resourceNetworkingSubnetV2Read(d *schema.ResourceData, meta interface{}) er allocationPools = append(allocationPools, pool) } d.Set("allocation_pools", allocationPools) + d.Set("allocation_pool", allocationPools) // Set the subnet's Gateway IP. gatewayIP := s.GatewayIP @@ -319,7 +363,8 @@ func resourceNetworkingSubnetV2Update(d *schema.ResourceData, meta interface{}) if d.HasChange("name") { hasChange = true - updateOpts.Name = d.Get("name").(string) + name := d.Get("name").(string) + updateOpts.Name = &name } if d.HasChange("description") { @@ -350,7 +395,8 @@ func resourceNetworkingSubnetV2Update(d *schema.ResourceData, meta interface{}) return err } hasChange = true - updateOpts.DNSNameservers = resourceSubnetDNSNameserversV2(d) + nameservers := resourceSubnetDNSNameserversV2(d) + updateOpts.DNSNameservers = &nameservers } if d.HasChange("host_routes") { @@ -365,9 +411,12 @@ func resourceNetworkingSubnetV2Update(d *schema.ResourceData, meta interface{}) updateOpts.EnableDHCP = &v } - if d.HasChange("allocation_pools") { + if d.HasChange("allocation_pool") { + hasChange = true + updateOpts.AllocationPools = resourceSubnetAllocationPoolUpdateV2(d) + } else if d.HasChange("allocation_pools") { hasChange = true - updateOpts.AllocationPools = resourceSubnetAllocationPoolsV2(d) + updateOpts.AllocationPools = resourceSubnetAllocationPoolsUpdateV2(d) } if hasChange { @@ -416,7 +465,38 @@ func resourceNetworkingSubnetV2Delete(d *schema.ResourceData, meta interface{}) return nil } -func resourceSubnetAllocationPoolsV2(d *schema.ResourceData) []subnets.AllocationPool { +// resourceSubnetAllocationPoolsCreateV2 returns a slice of allocation pools +// when creating a subnet. It takes into account both the old allocation_pools +// argument as well as the new allocation_pool argument. +// +// This can be modified to only account for allocation_pool when +// allocation_pools is removed. +func resourceSubnetAllocationPoolsCreateV2(d *schema.ResourceData) []subnets.AllocationPool { + // First check allocation_pool since that is the new argument. + rawAPs := d.Get("allocation_pool").(*schema.Set).List() + + if len(rawAPs) == 0 { + // If no allocation_pool was specified, check allocation_pools + // which is the older legacy argument. + rawAPs = d.Get("allocation_pools").([]interface{}) + } + + aps := make([]subnets.AllocationPool, len(rawAPs)) + for i, raw := range rawAPs { + rawMap := raw.(map[string]interface{}) + aps[i] = subnets.AllocationPool{ + Start: rawMap["start"].(string), + End: rawMap["end"].(string), + } + } + return aps +} + +// resourceSubnetAllocationPoolsUpdateV2 returns a slice of allocation pools +// when modifying a subnet using the old allocation_pools argument. +// +// This can be removed when allocation_pools is removed. +func resourceSubnetAllocationPoolsUpdateV2(d *schema.ResourceData) []subnets.AllocationPool { rawAPs := d.Get("allocation_pools").([]interface{}) aps := make([]subnets.AllocationPool, len(rawAPs)) for i, raw := range rawAPs { @@ -429,6 +509,21 @@ func resourceSubnetAllocationPoolsV2(d *schema.ResourceData) []subnets.Allocatio return aps } +// resourceSubnetAllocationPoolUpdateV2 returns a slice of allocation pools +// when modifying a subnet using the new allocation_pool argument. +func resourceSubnetAllocationPoolUpdateV2(d *schema.ResourceData) []subnets.AllocationPool { + rawAPs := d.Get("allocation_pool").(*schema.Set).List() + aps := make([]subnets.AllocationPool, len(rawAPs)) + for i, raw := range rawAPs { + rawMap := raw.(map[string]interface{}) + aps[i] = subnets.AllocationPool{ + Start: rawMap["start"].(string), + End: rawMap["end"].(string), + } + } + return aps +} + func resourceSubnetDNSNameserversV2(d *schema.ResourceData) []string { rawDNSN := d.Get("dns_nameservers").([]interface{}) dnsn := make([]string, len(rawDNSN)) @@ -508,10 +603,8 @@ func waitForSubnetDelete(networkingClient *gophercloud.ServiceClient, subnetId s log.Printf("[DEBUG] Successfully deleted OpenStack Subnet %s", subnetId) return s, "DELETED", nil } - if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok { - if errCode.Actual == 409 { - return s, "ACTIVE", nil - } + if _, ok := err.(gophercloud.ErrDefault409); ok { + return s, "ACTIVE", nil } return s, "ACTIVE", err } @@ -520,3 +613,21 @@ func waitForSubnetDelete(networkingClient *gophercloud.ServiceClient, subnetId s return s, "ACTIVE", nil } } + +func resourceSubnetV2AllocationPoolsCustomizeDiff(diff *schema.ResourceDiff) error { + if diff.Id() != "" && diff.HasChange("allocation_pools") { + o, n := diff.GetChange("allocation_pools") + oldPools := o.([]interface{}) + newPools := n.([]interface{}) + + samePools := networkingSubnetV2AllocationPoolsMatch(oldPools, newPools) + + if samePools { + log.Printf("[DEBUG] allocation_pools have not changed. clearing diff") + return diff.Clear("allocation_pools") + } + + } + + return nil +} diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_objectstorage_container_v1.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_objectstorage_container_v1.go index 6e0fe0e8c..6b9fdfd6e 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_objectstorage_container_v1.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_objectstorage_container_v1.go @@ -211,8 +211,8 @@ func resourceObjectStorageContainerV1Delete(d *schema.ResourceData, meta interfa _, err = containers.Delete(objectStorageClient, d.Id()).Extract() if err != nil { - gopherErr, ok := err.(gophercloud.ErrUnexpectedResponseCode) - if ok && gopherErr.Actual == 409 && d.Get("force_destroy").(bool) { + _, ok := err.(gophercloud.ErrDefault409) + if ok && d.Get("force_destroy").(bool) { // Container may have things. Delete them. log.Printf("[DEBUG] Attempting to forceDestroy Openstack container %+v", err) diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_sharedfilesystem_share_access_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_sharedfilesystem_share_access_v2.go index 23b6a5cad..7d11c0ed0 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_sharedfilesystem_share_access_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_sharedfilesystem_share_access_v2.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform/helper/validation" "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack/sharedfilesystems/apiversions" "github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/errors" "github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/shares" ) @@ -49,8 +50,8 @@ func resourceSharedFilesystemShareAccessV2() *schema.Resource { Required: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ - "ip", "user", "cert", - }, true), + "ip", "user", "cert", "cephx", + }, false), }, "access_to": { @@ -65,7 +66,13 @@ func resourceSharedFilesystemShareAccessV2() *schema.Resource { ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ "rw", "ro", - }, true), + }, false), + }, + + "access_key": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, }, }, } @@ -79,11 +86,15 @@ func resourceSharedFilesystemShareAccessV2Create(d *schema.ResourceData, meta in } sfsClient.Microversion = minManilaMicroversion + accessType := d.Get("access_type").(string) + if accessType == "cephx" { + sfsClient.Microversion = "2.13" + } shareID := d.Get("share_id").(string) grantOpts := shares.GrantAccessOpts{ - AccessType: d.Get("access_type").(string), + AccessType: accessType, AccessTo: d.Get("access_to").(string), AccessLevel: d.Get("access_level").(string), } @@ -132,13 +143,29 @@ func resourceSharedFilesystemShareAccessV2Read(d *schema.ResourceData, meta inte return fmt.Errorf("Error creating OpenStack sharedfilesystem client: %s", err) } + // Set the client to the minimum supported microversion. sfsClient.Microversion = minManilaMicroversion - shareID := d.Get("share_id").(string) + // Now check and see if the OpenStack environment supports microversion 2.21. + // If so, use that for the API request for access_key support. + apiInfo, err := apiversions.Get(sfsClient, "v2").Extract() + if err != nil { + return fmt.Errorf("Unable to query Shared Filesystem API endpoint: %s", err) + } + + compatible, err := compatibleMicroversion("min", "2.21", apiInfo.Version) + if err != nil { + return fmt.Errorf("Error comparing microversions for openstack_sharedfilesystem_share_access_v2 %s: %s", d.Id(), err) + } + if compatible { + sfsClient.Microversion = "2.21" + } + + shareID := d.Get("share_id").(string) access, err := shares.ListAccessRights(sfsClient, shareID).Extract() if err != nil { - return CheckDeleted(d, err, "share_access") + return CheckDeleted(d, err, "Error retrieving openstack_sharedfilesystem_share_access_v2") } for _, v := range access { @@ -150,6 +177,10 @@ func resourceSharedFilesystemShareAccessV2Read(d *schema.ResourceData, meta inte d.Set("access_level", v.AccessLevel) d.Set("region", GetRegion(d, config)) + // This will only be set if the Shared Filesystem environment supports + // microversion 2.21. + d.Set("access_key", v.AccessKey) + return nil } } @@ -238,11 +269,6 @@ func resourceSharedFilesystemShareAccessV2Import(d *schema.ResourceData, meta in d.SetId(accessID) d.Set("share_id", shareID) - d.Set("access_type", v.AccessType) - d.Set("access_to", v.AccessTo) - d.Set("access_level", v.AccessLevel) - d.Set("region", GetRegion(d, config)) - return []*schema.ResourceData{d}, nil } } diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_vpnaas_ipsec_policy_v2.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_vpnaas_ipsec_policy_v2.go index cfdafc3db..d90fdce4f 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_vpnaas_ipsec_policy_v2.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/resource_openstack_vpnaas_ipsec_policy_v2.go @@ -301,10 +301,8 @@ func waitForIPSecPolicyDeletion(networkingClient *gophercloud.ServiceClient, id return "", "DELETED", nil } - if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok { - if errCode.Actual == 409 { - return nil, "ACTIVE", nil - } + if _, ok := err.(gophercloud.ErrDefault409); ok { + return nil, "ACTIVE", nil } return nil, "ACTIVE", err diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/types.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/types.go index 51abc601d..24ff9ef51 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/types.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/types.go @@ -130,14 +130,25 @@ func (lrt *LogRoundTripper) logResponse(original io.ReadCloser, contentType stri // formatJSON will try to pretty-format a JSON body. // It will also mask known fields which contain sensitive information. func (lrt *LogRoundTripper) formatJSON(raw []byte) string { - var data map[string]interface{} + var rawData interface{} - err := json.Unmarshal(raw, &data) + err := json.Unmarshal(raw, &rawData) if err != nil { log.Printf("[DEBUG] Unable to parse OpenStack JSON: %s", err) return string(raw) } + data, ok := rawData.(map[string]interface{}) + if !ok { + pretty, err := json.MarshalIndent(rawData, "", " ") + if err != nil { + log.Printf("[DEBUG] Unable to re-marshal OpenStack JSON: %s", err) + return string(raw) + } + + return string(pretty) + } + // Mask known password fields if v, ok := data["auth"].(map[string]interface{}); ok { if v, ok := v["identity"].(map[string]interface{}); ok { diff --git a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/util.go b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/util.go index 484339978..2a68f8591 100644 --- a/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/util.go +++ b/pkg/terraform/exec/plugins/vendor/github.com/terraform-providers/terraform-provider-openstack/openstack/util.go @@ -103,16 +103,13 @@ func FormatHeaders(headers http.Header, seperator string) string { } func checkForRetryableError(err error) *resource.RetryError { - switch errCode := err.(type) { + switch err.(type) { case gophercloud.ErrDefault500: return resource.RetryableError(err) - case gophercloud.ErrUnexpectedResponseCode: - switch errCode.Actual { - case 409, 503: - return resource.RetryableError(err) - default: - return resource.NonRetryableError(err) - } + case gophercloud.ErrDefault409: + return resource.RetryableError(err) + case gophercloud.ErrDefault503: + return resource.RetryableError(err) default: return resource.NonRetryableError(err) } @@ -275,3 +272,65 @@ func sliceUnion(a, b []string) []string { } return res } + +// compatibleMicroversion will determine if an obtained microversion is +// compatible with a given microversion. +func compatibleMicroversion(direction, required, given string) (bool, error) { + if direction != "min" && direction != "max" { + return false, fmt.Errorf("Invalid microversion direction %s. Must be min or max", direction) + } + + if required == "" || given == "" { + return false, nil + } + + requiredParts := strings.Split(required, ".") + if len(requiredParts) != 2 { + return false, fmt.Errorf("Not a valid microversion: %s", required) + } + + givenParts := strings.Split(given, ".") + if len(givenParts) != 2 { + return false, fmt.Errorf("Not a valid microversion: %s", given) + } + + requiredMajor, requiredMinor := requiredParts[0], requiredParts[1] + givenMajor, givenMinor := givenParts[0], givenParts[1] + + requiredMajorInt, err := strconv.Atoi(requiredMajor) + if err != nil { + return false, fmt.Errorf("Unable to parse microversion: %s", required) + } + + requiredMinorInt, err := strconv.Atoi(requiredMinor) + if err != nil { + return false, fmt.Errorf("Unable to parse microversion: %s", required) + } + + givenMajorInt, err := strconv.Atoi(givenMajor) + if err != nil { + return false, fmt.Errorf("Unable to parse microversion: %s", given) + } + + givenMinorInt, err := strconv.Atoi(givenMinor) + if err != nil { + return false, fmt.Errorf("Unable to parse microversion: %s", given) + } + + switch direction { + case "min": + if requiredMajorInt == givenMajorInt { + if requiredMinorInt <= givenMinorInt { + return true, nil + } + } + case "max": + if requiredMajorInt == givenMajorInt { + if requiredMinorInt >= givenMinorInt { + return true, nil + } + } + } + + return false, nil +}