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..2a7788961 100644 --- a/data/data/baremetal/masters/main.tf +++ b/data/data/baremetal/masters/main.tf @@ -1,31 +1,48 @@ -resource "ironic_node_v1" "openshift-master" { +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")}" + 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..dbac534d9 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 = "d22b78927a1972802d37493a0b914e5761ae1237" + version = "v0.1.1" [[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..477e45b0a 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.1" 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 +}