diff --git a/products/activedirectory/api.yaml b/products/activedirectory/api.yaml new file mode 100644 index 000000000000..f63f88d9f02b --- /dev/null +++ b/products/activedirectory/api.yaml @@ -0,0 +1,107 @@ +# Copyright 2020 Google Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- !ruby/object:Api::Product +name: ActiveDirectory +display_name: Managed Microsoft Active Directory +versions: + - !ruby/object:Api::Product::Version + name: ga + base_url: https://managedidentities.googleapis.com/v1/ +scopes: + - https://www.googleapis.com/auth/cloud-platform +async: !ruby/object:Api::OpAsync + operation: !ruby/object:Api::OpAsync::Operation + path: 'name' + base_url: '{{op_id}}' + wait_ms: 1000 + # It takes about 35-40 mins to get the resource created + timeouts: !ruby/object:Api::Timeouts + insert_minutes: 60 + update_minutes: 60 + delete_minutes: 60 + result: !ruby/object:Api::OpAsync::Result + path: 'response' + resource_inside_response: true + status: !ruby/object:Api::OpAsync::Status + path: 'done' + complete: true + allowed: + - true + - false + error: !ruby/object:Api::OpAsync::Error + path: 'error' + message: 'message' +objects: + - !ruby/object:Api::Resource + name: 'Domain' + kind: 'activedirectory#domain' + base_url : projects/{{project}}/locations/global/domains?domainName={{domain_name}} + update_verb: :PATCH + update_mask: true + self_link: '{{name}}' + description: Creates a Microsoft AD domain + references: !ruby/object:Api::Resource::ReferenceLinks + guides: + 'Managed Microsoft Active Directory Quickstart': 'https://cloud.google.com/managed-microsoft-ad/docs/quickstarts' + api: 'https://cloud.google.com/managed-microsoft-ad/reference/rest/v1/projects.locations.global.domains' + parameters: + - !ruby/object:Api::Type::String + name: domainName + required: true + url_param_only: true + input: true + description: | + The fully qualified domain name. e.g. mydomain.myorganization.com, with the restrictions, + https://cloud.google.com/managed-microsoft-ad/reference/rest/v1/projects.locations.global.domains. + properties: + - !ruby/object:Api::Type::String + name: 'name' + output: true + description: 'The unique name of the domain using the format: `projects/{project}/locations/global/domains/{domainName}`.' + - !ruby/object:Api::Type::KeyValuePairs + name: 'labels' + description: 'Resource labels that can contain user-provided metadata' + - !ruby/object:Api::Type::Array + name: 'authorizedNetworks' + item_type: Api::Type::String + description: | + The full names of the Google Compute Engine networks the domain instance is connected to. The domain is only available on networks listed in authorizedNetworks. + If CIDR subnets overlap between networks, domain creation will fail. + - !ruby/object:Api::Type::String + name: 'reservedIpRange' + required: true + input: true + description: | + The CIDR range of internal addresses that are reserved for this domain. Reserved networks must be /24 or larger. + Ranges must be unique and non-overlapping with existing subnets in authorizedNetworks + - !ruby/object:Api::Type::Array + name: 'locations' + required: true + item_type: Api::Type::String + description: | + Locations where domain needs to be provisioned. [regions][compute/docs/regions-zones/] + e.g. us-west1 or us-east4 Service supports up to 4 locations at once. Each location will use a /26 block. + - !ruby/object:Api::Type::String + name: 'admin' + default_value: 'setupadmin' + input: true + description: | + The name of delegated administrator account used to perform Active Directory operations. + If not specified, setupadmin will be used. + - !ruby/object:Api::Type::String + name: 'fqdn' + output: true + description: | + The fully-qualified domain name of the exposed domain used by clients to connect to the service. + Similar to what would be chosen for an Active Directory set up on an internal network. \ No newline at end of file diff --git a/products/activedirectory/terraform.yaml b/products/activedirectory/terraform.yaml new file mode 100644 index 000000000000..8ff5dfbda36c --- /dev/null +++ b/products/activedirectory/terraform.yaml @@ -0,0 +1,39 @@ +# Copyright 2020 Google Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- !ruby/object:Provider::Terraform::Config +overrides: !ruby/object:Overrides::ResourceOverrides + Domain: !ruby/object:Overrides::Terraform::ResourceOverride + id_format: "{{name}}" + import_format: ["{{name}}"] + autogen_async: true + properties: + authorizedNetworks: !ruby/object:Overrides::Terraform::PropertyOverride + is_set: true + domainName: !ruby/object:Overrides::Terraform::PropertyOverride + required: true + validation: !ruby/object:Provider::Terraform::Validation + function: 'validateADDomainName()' + custom_code: !ruby/object:Provider::Terraform::CustomCode + custom_import: templates/terraform/custom_import/self_link_as_name.erb + examples: + - !ruby/object:Provider::Terraform::Examples + name: "active_directory_domain_basic" + primary_resource_id: "ad-domain" + vars: + name: "myorg" +files: !ruby/object:Provider::Config::Files + # These files have templating (ERB) code that will be run. + # This is usually to add licensing info, autogeneration notices, etc. + compile: +<%= lines(indent(compile('provider/terraform/product~compile.yaml'), 4)) -%> diff --git a/templates/terraform/examples/active_directory_domain_basic.tf.erb b/templates/terraform/examples/active_directory_domain_basic.tf.erb new file mode 100644 index 000000000000..caf8f8871c7c --- /dev/null +++ b/templates/terraform/examples/active_directory_domain_basic.tf.erb @@ -0,0 +1,5 @@ +resource "google_active_directory_domain" "ad-domain" { + domain_name = "mydomain.org.com" + locations = ["us-central1"] + reserved_ip_range = "192.168.255.0/24" +} \ No newline at end of file diff --git a/third_party/terraform/tests/resource_active_directory_domain_update_test.go b/third_party/terraform/tests/resource_active_directory_domain_update_test.go new file mode 100644 index 000000000000..9a6bfcc369c6 --- /dev/null +++ b/third_party/terraform/tests/resource_active_directory_domain_update_test.go @@ -0,0 +1,78 @@ +package google + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccActiveDirectoryDomain_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "domain": "mydomain.org1.com", + "resource_name": "ad-domain", + } + + resourceName := Nprintf("google_active_directory_domain.%{resource_name}", context) + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckActiveDirectoryDomainDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccADDomainBasic(context), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"domain_name"}, + }, + { + Config: testAccADDomainUpdate(context), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"domain_name"}, + }, + { + Config: testAccADDomainBasic(context), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"domain_name"}, + }, + }, + }) +} + +func testAccADDomainBasic(context map[string]interface{}) string { + + return Nprintf(` + resource "google_active_directory_domain" "%{resource_name}" { + domain_name = "%{domain}" + locations = ["us-central1"] + reserved_ip_range = "192.168.255.0/24" + } + `, context) +} + +func testAccADDomainUpdate(context map[string]interface{}) string { + return Nprintf(` + resource "google_active_directory_domain" "%{resource_name}" { + domain_name = "%{domain}" + locations = ["us-central1", "us-west1"] + reserved_ip_range = "192.168.255.0/24" + labels = { + env = "test" + } + } + `, context) + +} diff --git a/third_party/terraform/utils/validation.go b/third_party/terraform/utils/validation.go index 0fa957c91207..2b145de95c41 100644 --- a/third_party/terraform/utils/validation.go +++ b/third_party/terraform/utils/validation.go @@ -30,6 +30,9 @@ const ( // https://cloud.google.com/iam/docs/understanding-custom-roles#naming_the_role IAMCustomRoleIDRegex = "^[a-zA-Z0-9_\\.]{3,64}$" + + // https://cloud.google.com/managed-microsoft-ad/reference/rest/v1/projects.locations.global.domains/create#query-parameters + ADDomainNameRegex = "^[a-z][a-z0-9-]{0,14}\\.[a-z0-9-\\.]*[a-z]+[a-z0-9]*$" ) var ( @@ -311,3 +314,15 @@ func validateRFC3339Date(v interface{}, k string) (warnings []string, errors []e } return } + +func validateADDomainName() schema.SchemaValidateFunc { + return func(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + + if len(value) > 64 || !regexp.MustCompile(ADDomainNameRegex).MatchString(value) { + errors = append(errors, fmt.Errorf( + "%q (%q) doesn't match regexp %q, domain_name must be 2 to 64 with lowercase letters, digits, hyphens, dots and start with a letter", k, value, ADDomainNameRegex)) + } + return + } +}