diff --git a/.ci/unit-tests/inspec.sh b/.ci/unit-tests/inspec.sh index eb1427683a1f..e286d8b65f1c 100755 --- a/.ci/unit-tests/inspec.sh +++ b/.ci/unit-tests/inspec.sh @@ -3,4 +3,9 @@ set -e set -x -echo 'TODO slevenick write tests' \ No newline at end of file +pushd "magic-modules/build/inspec/test/unit" + +bundle install +rspec -I ../../libraries * + +popd \ No newline at end of file diff --git a/build/inspec b/build/inspec index d31d39e09041..b470d72f2e3d 160000 --- a/build/inspec +++ b/build/inspec @@ -1 +1 @@ -Subproject commit d31d39e09041f5eff544a4b0905ad8bb947707b5 +Subproject commit b470d72f2e3d4f459941897c7bfd7a8322f36c7c diff --git a/build/terraform b/build/terraform index 4a1f514df616..1646a7a8e4e0 160000 --- a/build/terraform +++ b/build/terraform @@ -1 +1 @@ -Subproject commit 4a1f514df61699258b5f57daea3c403fff44ad66 +Subproject commit 1646a7a8e4e089477b8cee1cd033b0a67717c8c4 diff --git a/build/terraform-beta b/build/terraform-beta index e1fbfbfbaf1f..181c7ede8752 160000 --- a/build/terraform-beta +++ b/build/terraform-beta @@ -1 +1 @@ -Subproject commit e1fbfbfbaf1ff54e9cedd80d8a77b187956f1b72 +Subproject commit 181c7ede8752c2da8368d8d44d398545e846eb26 diff --git a/products/compute/inspec.yaml b/products/compute/inspec.yaml index bcd603cee34d..6bf91a6580cc 100644 --- a/products/compute/inspec.yaml +++ b/products/compute/inspec.yaml @@ -20,85 +20,81 @@ manifest: !ruby/object:Provider::Inspec::Manifest description: | InSpec resources for verifying GCP infrastructure overrides: !ruby/object:Provider::ResourceOverrides - Address: !ruby/object:Provider::Chef::ResourceOverride + Address: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Autoscaler: !ruby/object:Provider::Chef::ResourceOverride + Autoscaler: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - BackendBucket: !ruby/object:Provider::Chef::ResourceOverride + BackendBucket: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - BackendService: !ruby/object:Provider::Chef::ResourceOverride + BackendService: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Disk: !ruby/object:Provider::Chef::ResourceOverride + Disk: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - DiskType: !ruby/object:Provider::Chef::ResourceOverride + DiskType: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Firewall: !ruby/object:Provider::Chef::ResourceOverride + ForwardingRule: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - ForwardingRule: !ruby/object:Provider::Chef::ResourceOverride + GlobalAddress: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - GlobalAddress: !ruby/object:Provider::Chef::ResourceOverride + GlobalForwardingRule: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - GlobalForwardingRule: !ruby/object:Provider::Chef::ResourceOverride + HealthCheck: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - HealthCheck: !ruby/object:Provider::Chef::ResourceOverride + HttpHealthCheck: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - HttpHealthCheck: !ruby/object:Provider::Chef::ResourceOverride + HttpsHealthCheck: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - HttpsHealthCheck: !ruby/object:Provider::Chef::ResourceOverride + Image: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Image: !ruby/object:Provider::Chef::ResourceOverride + InstanceGroup: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Instance: !ruby/object:Provider::Chef::ResourceOverride + InstanceGroupManager: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - InstanceGroup: !ruby/object:Provider::Chef::ResourceOverride + InstanceTemplate: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - InstanceGroupManager: !ruby/object:Provider::Chef::ResourceOverride + InterconnectAttachment: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - InstanceTemplate: !ruby/object:Provider::Chef::ResourceOverride + License: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - InterconnectAttachment: !ruby/object:Provider::Chef::ResourceOverride + MachineType: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - License: !ruby/object:Provider::Chef::ResourceOverride + Network: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - MachineType: !ruby/object:Provider::Chef::ResourceOverride + Region: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Network: !ruby/object:Provider::Chef::ResourceOverride + RegionAutoscaler: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Region: !ruby/object:Provider::Chef::ResourceOverride + RegionDisk: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - RegionAutoscaler: !ruby/object:Provider::Chef::ResourceOverride + RegionDiskType: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - RegionDisk: !ruby/object:Provider::Chef::ResourceOverride + Route: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - RegionDiskType: !ruby/object:Provider::Chef::ResourceOverride + Router: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Route: !ruby/object:Provider::Chef::ResourceOverride + Snapshot: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Router: !ruby/object:Provider::Chef::ResourceOverride + SslCertificate: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Snapshot: !ruby/object:Provider::Chef::ResourceOverride + SslPolicy: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - SslCertificate: !ruby/object:Provider::Chef::ResourceOverride + Subnetwork: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - SslPolicy: !ruby/object:Provider::Chef::ResourceOverride + TargetHttpProxy: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Subnetwork: !ruby/object:Provider::Chef::ResourceOverride + TargetHttpsProxy: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - TargetHttpProxy: !ruby/object:Provider::Chef::ResourceOverride + TargetPool: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - TargetHttpsProxy: !ruby/object:Provider::Chef::ResourceOverride + TargetTcpProxy: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - TargetPool: !ruby/object:Provider::Chef::ResourceOverride + TargetVpnGateway: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - TargetTcpProxy: !ruby/object:Provider::Chef::ResourceOverride + TargetSslProxy: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - TargetVpnGateway: !ruby/object:Provider::Chef::ResourceOverride + UrlMap: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - TargetSslProxy: !ruby/object:Provider::Chef::ResourceOverride - exclude: true - UrlMap: !ruby/object:Provider::Chef::ResourceOverride - exclude: true - VpnTunnel: !ruby/object:Provider::Chef::ResourceOverride + VpnTunnel: !ruby/object:Provider::Inspec::ResourceOverride exclude: true files: !ruby/object:Provider::Config::Files style: diff --git a/provider/inspec.rb b/provider/inspec.rb index 589e7fa56739..8758ffde9cf5 100644 --- a/provider/inspec.rb +++ b/provider/inspec.rb @@ -43,7 +43,7 @@ def property_override # This function uses the resource templates to create singular and plural # resources that can be used by InSpec def generate_resource(data) - target_folder = File.join(data[:output_folder], 'inspec') + target_folder = File.join(data[:output_folder], 'libraries') FileUtils.mkpath target_folder name = data[:object].name.underscore generate_resource_file data.clone.merge( @@ -74,8 +74,12 @@ def format_url(url) url.split("\n").join('') end - # TODO? - def generate_resource_tests(data) end + # Copies InSpec unit tests to build folder + def generate_resource_tests(data) + target_folder = File.join(data[:output_folder], 'test/unit') + FileUtils.mkpath target_folder + FileUtils.cp_r 'templates/inspec/tests/.', target_folder + end def generate_base_property(data) end @@ -189,7 +193,6 @@ def sub_property_descriptions(property) def markdown_format(property) " * `#{property.name}`: #{property.description.split("\n").join(' ')}" end - # rubocop:enable Style/GuardClause end # rubocop:enable Metrics/ClassLength end diff --git a/provider/terraform/resources/resource_compute_instance.go b/provider/terraform/resources/resource_compute_instance.go index 0719c777a7af..037515e780b0 100644 --- a/provider/terraform/resources/resource_compute_instance.go +++ b/provider/terraform/resources/resource_compute_instance.go @@ -200,13 +200,10 @@ func resourceComputeInstance() *schema.Resource { ValidateFunc: validation.StringInSlice([]string{"PREMIUM", "STANDARD"}, false), }, - // It's unclear why this field exists, as - // nat_ip can be both optional and computed. - // Consider deprecating it. "assigned_nat_ip": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Deprecated: "Use network_interface.access_config.nat_ip instead.", + Type: schema.TypeString, + Computed: true, + Removed: "Use network_interface.access_config.nat_ip instead.", }, "public_ptr_domain_name": &schema.Schema{ diff --git a/provider/terraform/resources/resource_compute_instance_template.go b/provider/terraform/resources/resource_compute_instance_template.go index b268748605fe..f69658188c23 100644 --- a/provider/terraform/resources/resource_compute_instance_template.go +++ b/provider/terraform/resources/resource_compute_instance_template.go @@ -263,14 +263,10 @@ func resourceComputeInstanceTemplate() *schema.Resource { Computed: true, ValidateFunc: validation.StringInSlice([]string{"PREMIUM", "STANDARD"}, false), }, - // Instance templates will never have an - // 'assigned NAT IP', but we need this in - // the schema to allow us to share flatten - // code with an instance, which could. "assigned_nat_ip": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - Deprecated: "Use network_interface.access_config.nat_ip instead.", + Type: schema.TypeString, + Computed: true, + Removed: "Use network_interface.access_config.nat_ip instead.", }, }, }, diff --git a/provider/terraform/resources/resource_storage_default_object_acl.go b/provider/terraform/resources/resource_storage_default_object_acl.go index a88d08231a73..1bb76b49e380 100644 --- a/provider/terraform/resources/resource_storage_default_object_acl.go +++ b/provider/terraform/resources/resource_storage_default_object_acl.go @@ -2,185 +2,109 @@ package google import ( "fmt" - "log" - "github.com/hashicorp/terraform/helper/schema" "google.golang.org/api/storage/v1" ) func resourceStorageDefaultObjectAcl() *schema.Resource { return &schema.Resource{ - Create: resourceStorageDefaultObjectAclCreate, - Read: resourceStorageDefaultObjectAclRead, - Update: resourceStorageDefaultObjectAclUpdate, - Delete: resourceStorageDefaultObjectAclDelete, - CustomizeDiff: resourceStorageRoleEntityCustomizeDiff, + Create: resourceStorageDefaultObjectAclCreateUpdate, + Read: resourceStorageDefaultObjectAclRead, + Update: resourceStorageDefaultObjectAclCreateUpdate, + Delete: resourceStorageDefaultObjectAclDelete, Schema: map[string]*schema.Schema{ - "bucket": &schema.Schema{ + "bucket": { Type: schema.TypeString, Required: true, ForceNew: true, }, - "role_entity": &schema.Schema{ - Type: schema.TypeList, + "role_entity": { + Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - MinItems: 1, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validateRoleEntityPair, + }, }, }, } } -func resourceStorageDefaultObjectAclCreate(d *schema.ResourceData, meta interface{}) error { +func resourceStorageDefaultObjectAclCreateUpdate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) bucket := d.Get("bucket").(string) - roleEntity := d.Get("role_entity").([]interface{}) - - for _, v := range roleEntity { - pair, err := getRoleEntityPair(v.(string)) - - ObjectAccessControl := &storage.ObjectAccessControl{ + defaultObjectAcl := []*storage.ObjectAccessControl{} + for _, v := range d.Get("role_entity").(*schema.Set).List() { + pair := getValidatedRoleEntityPair(v.(string)) + defaultObjectAcl = append(defaultObjectAcl, &storage.ObjectAccessControl{ Role: pair.Role, Entity: pair.Entity, - } - - log.Printf("[DEBUG]: setting role = %s, entity = %s on bucket %s", pair.Role, pair.Entity, bucket) - - _, err = config.clientStorage.DefaultObjectAccessControls.Insert(bucket, ObjectAccessControl).Do() - - if err != nil { - return fmt.Errorf("Error setting Default Object ACL for %s on bucket %s: %v", pair.Entity, bucket, err) - } + }) } - d.SetId(bucket) - return resourceStorageDefaultObjectAclRead(d, meta) -} - -func resourceStorageDefaultObjectAclRead(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - - bucket := d.Get("bucket").(string) - - roleEntities := make([]interface{}, 0) - reLocal := d.Get("role_entity").([]interface{}) - reLocalMap := make(map[string]string) - for _, v := range reLocal { - res, err := getRoleEntityPair(v.(string)) - - if err != nil { - return fmt.Errorf( - "Old state has malformed Role/Entity pair: %v", err) - } - - reLocalMap[res.Entity] = res.Role - } - - res, err := config.clientStorage.DefaultObjectAccessControls.List(bucket).Do() + res, err := config.clientStorage.Buckets.Get(bucket).Do() if err != nil { - return handleNotFoundError(err, d, fmt.Sprintf("Storage Default Object ACL for bucket %q", d.Get("bucket").(string))) + return fmt.Errorf("Error reading bucket %s: %v", bucket, err) } - for _, v := range res.Items { - role := v.Role - entity := v.Entity - // We only store updates to the locally defined access controls - if _, in := reLocalMap[entity]; in { - roleEntities = append(roleEntities, fmt.Sprintf("%s:%s", role, entity)) - log.Printf("[DEBUG]: saving re %s-%s", v.Role, v.Entity) + // Even with ForceSendFields the empty array wasn't working. Luckily, this is the same thing + if len(defaultObjectAcl) == 0 { + _, err = config.clientStorage.Buckets.Update(bucket, res).IfMetagenerationMatch(res.Metageneration).PredefinedDefaultObjectAcl("private").Do() + if err != nil { + return fmt.Errorf("Error updating default object acl to empty for bucket %s: %v", bucket, err) + } + } else { + res.DefaultObjectAcl = defaultObjectAcl + _, err = config.clientStorage.Buckets.Update(bucket, res).IfMetagenerationMatch(res.Metageneration).Do() + if err != nil { + return fmt.Errorf("Error updating default object acl for bucket %s: %v", bucket, err) } } - d.Set("role_entity", roleEntities) - - return nil + return resourceStorageDefaultObjectAclRead(d, meta) } -func resourceStorageDefaultObjectAclUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceStorageDefaultObjectAclRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) bucket := d.Get("bucket").(string) - - if !d.HasChange("role_entity") { - return nil - } - o, n := d.GetChange("role_entity") - oldRe := o.([]interface{}) - newRe := n.([]interface{}) - - oldReMap := make(map[string]string) - for _, v := range oldRe { - res, err := getRoleEntityPair(v.(string)) - - if err != nil { - return fmt.Errorf( - "Old state has malformed Role/Entity pair: %v", err) - } - - oldReMap[res.Entity] = res.Role + res, err := config.clientStorage.Buckets.Get(bucket).Projection("full").Do() + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("Default Storage Object ACL for Bucket %q", d.Get("bucket").(string))) } - for _, v := range newRe { - pair, err := getRoleEntityPair(v.(string)) - - ObjectAccessControl := &storage.ObjectAccessControl{ - Role: pair.Role, - Entity: pair.Entity, - } - - // If the old state is present for the entity, it is updated - // If the old state is missing, it is inserted - if _, ok := oldReMap[pair.Entity]; ok { - _, err = config.clientStorage.DefaultObjectAccessControls.Update( - bucket, pair.Entity, ObjectAccessControl).Do() - } else { - _, err = config.clientStorage.DefaultObjectAccessControls.Insert( - bucket, ObjectAccessControl).Do() - } - - // Now we only store the keys that have to be removed - delete(oldReMap, pair.Entity) - - if err != nil { - return fmt.Errorf("Error updating Storage Default Object ACL for bucket %s: %v", bucket, err) - } + var roleEntities []string + for _, roleEntity := range res.DefaultObjectAcl { + role := roleEntity.Role + entity := roleEntity.Entity + roleEntities = append(roleEntities, fmt.Sprintf("%s:%s", role, entity)) } - for entity := range oldReMap { - log.Printf("[DEBUG]: removing entity %s", entity) - err := config.clientStorage.DefaultObjectAccessControls.Delete(bucket, entity).Do() - - if err != nil { - return fmt.Errorf("Error updating Storage Default Object ACL for bucket %s: %v", bucket, err) - } + err = d.Set("role_entity", roleEntities) + if err != nil { + return err } - return resourceStorageDefaultObjectAclRead(d, meta) + d.SetId(bucket) + return nil } func resourceStorageDefaultObjectAclDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) bucket := d.Get("bucket").(string) + res, err := config.clientStorage.Buckets.Get(bucket).Do() + if err != nil { + return fmt.Errorf("Error reading bucket %s: %v", bucket, err) + } - reLocal := d.Get("role_entity").([]interface{}) - for _, v := range reLocal { - res, err := getRoleEntityPair(v.(string)) - if err != nil { - return err - } - - log.Printf("[DEBUG]: removing entity %s", res.Entity) - - err = config.clientStorage.DefaultObjectAccessControls.Delete(bucket, res.Entity).Do() - - if err != nil { - return fmt.Errorf("Error deleting entity %s ACL: %s", res.Entity, err) - } + _, err = config.clientStorage.Buckets.Update(bucket, res).IfMetagenerationMatch(res.Metageneration).PredefinedDefaultObjectAcl("private").Do() + if err != nil { + return fmt.Errorf("Error deleting (updating to private) default object acl for bucket %s: %v", bucket, err) } return nil diff --git a/provider/terraform/tests/resource_compute_forwarding_rule_test.go b/provider/terraform/tests/resource_compute_forwarding_rule_test.go.erb similarity index 98% rename from provider/terraform/tests/resource_compute_forwarding_rule_test.go rename to provider/terraform/tests/resource_compute_forwarding_rule_test.go.erb index 1e5d5b876a48..3fe0d1737620 100644 --- a/provider/terraform/tests/resource_compute_forwarding_rule_test.go +++ b/provider/terraform/tests/resource_compute_forwarding_rule_test.go.erb @@ -1,3 +1,4 @@ +<% autogen_exception -%> package google import ( @@ -154,7 +155,9 @@ resource "google_compute_forwarding_rule" "foobar" { name = "%s" port_range = "80-81" target = "${google_compute_target_pool.foo-tp.self_link}" +<% unless version.nil? || version == 'ga' -%> labels = {"foo" = "bar"} +<% end -%> } `, poolName, ruleName) } @@ -177,7 +180,9 @@ resource "google_compute_forwarding_rule" "foobar" { name = "%s" port_range = "80-81" target = "${google_compute_target_pool.bar-tp.self_link}" +<% unless version.nil? || version == 'ga' -%> labels = {"baz" = "qux"} +<% end -%> } `, poolName, poolName, ruleName) } diff --git a/provider/terraform/tests/resource_storage_default_object_acl_test.go b/provider/terraform/tests/resource_storage_default_object_acl_test.go index bf4de1b9ff40..f0688149f663 100644 --- a/provider/terraform/tests/resource_storage_default_object_acl_test.go +++ b/provider/terraform/tests/resource_storage_default_object_acl_test.go @@ -12,7 +12,6 @@ func TestAccStorageDefaultObjectAcl_basic(t *testing.T) { t.Parallel() bucketName := testBucketName() - resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -29,6 +28,22 @@ func TestAccStorageDefaultObjectAcl_basic(t *testing.T) { }) } +func TestAccStorageDefaultObjectAcl_noRoleEntity(t *testing.T) { + t.Parallel() + + bucketName := testBucketName() + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccStorageDefaultObjectAclDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testGoogleStorageDefaultObjectsAclNoRoleEntity(bucketName), + }, + }, + }) +} + func TestAccStorageDefaultObjectAcl_upgrade(t *testing.T) { t.Parallel() @@ -178,6 +193,19 @@ func testAccCheckGoogleStorageDefaultObjectAclDelete(bucket, roleEntityS string) } } +func testGoogleStorageDefaultObjectsAclBasic(bucketName, roleEntity1, roleEntity2 string) string { + return fmt.Sprintf(` +resource "google_storage_bucket" "bucket" { + name = "%s" +} + +resource "google_storage_default_object_acl" "acl" { + bucket = "${google_storage_bucket.bucket.name}" + role_entity = ["%s", "%s"] +} +`, bucketName, roleEntity1, roleEntity2) +} + func testGoogleStorageDefaultObjectsAclBasicDelete(bucketName, roleEntity string) string { return fmt.Sprintf(` resource "google_storage_bucket" "bucket" { @@ -191,7 +219,7 @@ resource "google_storage_default_object_acl" "acl" { `, bucketName, roleEntity) } -func testGoogleStorageDefaultObjectsAclBasic(bucketName, roleEntity1, roleEntity2 string) string { +func testGoogleStorageDefaultObjectsAclNoRoleEntity(bucketName string) string { return fmt.Sprintf(` resource "google_storage_bucket" "bucket" { name = "%s" @@ -199,9 +227,9 @@ resource "google_storage_bucket" "bucket" { resource "google_storage_default_object_acl" "acl" { bucket = "${google_storage_bucket.bucket.name}" - role_entity = ["%s", "%s"] + role_entity = [] } -`, bucketName, roleEntity1, roleEntity2) +`, bucketName) } func testGoogleStorageDefaultObjectAclUnordered(bucketName string) string { diff --git a/provider/terraform/utils/compute_instance_helpers.go b/provider/terraform/utils/compute_instance_helpers.go index 902fcb52b478..7ef6674d6b9a 100644 --- a/provider/terraform/utils/compute_instance_helpers.go +++ b/provider/terraform/utils/compute_instance_helpers.go @@ -48,9 +48,8 @@ func flattenAccessConfigs(accessConfigs []*computeBeta.AccessConfig) ([]map[stri natIP := "" for i, ac := range accessConfigs { flattened[i] = map[string]interface{}{ - "nat_ip": ac.NatIP, - "network_tier": ac.NetworkTier, - "assigned_nat_ip": ac.NatIP, + "nat_ip": ac.NatIP, + "network_tier": ac.NetworkTier, } if ac.SetPublicPtr { flattened[i]["public_ptr_domain_name"] = ac.PublicPtrDomainName diff --git a/provider/terraform/website/docs/d/datasource_compute_instance.html.markdown b/provider/terraform/website/docs/d/datasource_compute_instance.html.markdown index d3bca44d88cd..719e05f8620e 100644 --- a/provider/terraform/website/docs/d/datasource_compute_instance.html.markdown +++ b/provider/terraform/website/docs/d/datasource_compute_instance.html.markdown @@ -92,9 +92,6 @@ This attribute has been deprecated. Use `network_interface.0.network_ip` instead * `network_interface.0.access_config.0.nat_ip` - If the instance has an access config, either the given external ip (in the `nat_ip` field) or the ephemeral (generated) ip (if you didn't provide one). -* `network_interface.0.access_config.0.assigned_nat_ip` - (Deprecated) If the instance has an access config, either the given external ip (in the `nat_ip` field) or the ephemeral (generated) ip (if you didn't provide one). -This attribute has been deprecated. Use `network_interface.0.access_config.0.nat_ip` instead. - * `attached_disk.0.disk_encryption_key_sha256` - The [RFC 4648 base64](https://tools.ietf.org/html/rfc4648#section-4) encoded SHA-256 hash of the [customer-supplied encryption key] (https://cloud.google.com/compute/docs/disks/customer-supplied-encryption) that protects this resource. diff --git a/provider/terraform/website/docs/r/compute_instance.html.markdown b/provider/terraform/website/docs/r/compute_instance.html.markdown index 744b900c90bb..ce68cdcc1780 100644 --- a/provider/terraform/website/docs/r/compute_instance.html.markdown +++ b/provider/terraform/website/docs/r/compute_instance.html.markdown @@ -295,9 +295,6 @@ This attribute has been deprecated. Use `network_interface.0.network_ip`instead. * `network_interface.0.access_config.0.nat_ip` - If the instance has an access config, either the given external ip (in the `nat_ip` field) or the ephemeral (generated) ip (if you didn't provide one). -* `network_interface.0.access_config.0.assigned_nat_ip` - (Deprecated) If the instance has an access config, either the given external ip (in the `nat_ip` field) or the ephemeral (generated) ip (if you didn't provide one). -This attribute has been deprecated. Use `network_interface.0.access_config.0.nat_ip` instead. - * `attached_disk.0.disk_encryption_key_sha256` - The [RFC 4648 base64](https://tools.ietf.org/html/rfc4648#section-4) encoded SHA-256 hash of the [customer-supplied encryption key] (https://cloud.google.com/compute/docs/disks/customer-supplied-encryption) that protects this resource. diff --git a/provider/terraform/website/docs/r/storage_default_object_acl.html.markdown b/provider/terraform/website/docs/r/storage_default_object_acl.html.markdown index 96f05e616d17..9295575f9cc1 100644 --- a/provider/terraform/website/docs/r/storage_default_object_acl.html.markdown +++ b/provider/terraform/website/docs/r/storage_default_object_acl.html.markdown @@ -3,12 +3,19 @@ layout: "google" page_title: "Google: google_storage_default_object_acl" sidebar_current: "docs-google-storage-default-object-acl" description: |- - Creates a new default object ACL in Google Cloud Storage. + Authoritatively manages the default object ACLs for a Google Cloud Storage bucket --- # google\_storage\_default\_object\_acl -Creates a new default object ACL in Google Cloud Storage service (GCS). For more information see +Authoritatively manages the default object ACLs for a Google Cloud Storage bucket +without managing the bucket itself. + +-> Note that for each object, its creator will have the `"OWNER"` role in addition +to the default ACL that has been defined. + + +For more information see [the official documentation](https://cloud.google.com/storage/docs/access-control/lists) and [API](https://cloud.google.com/storage/docs/json_api/v1/defaultObjectAccessControls). @@ -36,7 +43,11 @@ resource "google_storage_default_object_acl" "image-store-default-acl" { * `bucket` - (Required) The name of the bucket it applies to. -* `role_entity` - (Required) List of role/entity pairs in the form `ROLE:entity`. See [GCS Object ACL documentation](https://cloud.google.com/storage/docs/json_api/v1/objectAccessControls) for more details. +--- + +* `role_entity` - (Optional) List of role/entity pairs in the form `ROLE:entity`. +See [GCS Object ACL documentation](https://cloud.google.com/storage/docs/json_api/v1/objectAccessControls) for more details. +Omitting the field is the same as providing an empty list. ## Attributes Reference diff --git a/templates/inspec/doc-template.md.erb b/templates/inspec/doc-template.md.erb index d0c3849c9f8b..073ce1395134 100644 --- a/templates/inspec/doc-template.md.erb +++ b/templates/inspec/doc-template.md.erb @@ -1,3 +1,18 @@ +<%# The license inside this block applies to this file. +# Copyright 2017 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. +-%> + <% autogen_exception -%> --- diff --git a/templates/inspec/nested_object.erb b/templates/inspec/nested_object.erb index 9a20dd7bb7b1..42f810a8bedc 100644 --- a/templates/inspec/nested_object.erb +++ b/templates/inspec/nested_object.erb @@ -37,7 +37,7 @@ module Google <% nested_properties.each do |prop| -%> <% if time?(prop) - init = "Time.new(args['#{prop.api_name}'])" + init = "DateTime.parse(args['#{prop.api_name}'])" elsif primitive?(prop) init = "args['#{prop.api_name}']" elsif typed_array?(prop) diff --git a/templates/inspec/plural_resource.erb b/templates/inspec/plural_resource.erb index f56ea78f27ae..ea1a43a4f2bf 100644 --- a/templates/inspec/plural_resource.erb +++ b/templates/inspec/plural_resource.erb @@ -16,6 +16,7 @@ <%= lines(autogen_notice :ruby) -%> +require 'inspec/resource' class <%= object.name -%>s < Inspec.resource(1) <% diff --git a/templates/inspec/singular_resource.erb b/templates/inspec/singular_resource.erb index d5e59709f0ae..8dded4bbc9e6 100644 --- a/templates/inspec/singular_resource.erb +++ b/templates/inspec/singular_resource.erb @@ -23,7 +23,6 @@ requires = generate_requires(object.all_user_properties) requires << 'inspec/resource' - requires << 'google/hash_utils' -%> <%= lines(emit_requires(requires)) -%> @@ -84,7 +83,7 @@ class <%= object.name -%> < Inspec.resource(1) name = prop.out_name if time?(prop) - init = "Time.new(@fetched['#{prop.api_name}'])" + init = "DateTime.parse(@fetched['#{prop.api_name}'])" elsif primitive?(prop) init = "@fetched['#{prop.api_name}']" elsif typed_array?(prop) diff --git a/templates/inspec/tests/firewall_test.rb b/templates/inspec/tests/firewall_test.rb new file mode 100644 index 000000000000..93bbd8c1d8bf --- /dev/null +++ b/templates/inspec/tests/firewall_test.rb @@ -0,0 +1,53 @@ +# Copyright 2017 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. + +require 'google_compute_firewall' +require 'json' + +class FirewallTest < Firewall + def initialize(data) + @fetched = data + end +end + +firewall_fixture = JSON.parse(File.read('fixtures/firewall_fixture.json')) + +RSpec.describe Firewall, '#parse' do + before do + @firewall_mock = FirewallTest.new(firewall_fixture) + @firewall_mock.parse + end + context 'firewall attributes' do + it { expect(@firewall_mock.exists?).to be true } + it { expect(@firewall_mock.creation_timestamp).to eq Time.at(1539322976).to_datetime } + it { expect(@firewall_mock.description).to eq 'description' } + it { expect(@firewall_mock.allowed.size).to be 1 } + it { expect(@firewall_mock.allowed[0].ip_protocol).to eq 'tcp' } + it { expect(@firewall_mock.allowed[0].ports).to include "443" } + it { expect(@firewall_mock.denied.size).to be 1 } + it { expect(@firewall_mock.denied[0].ip_protocol).to eq 'udp' } + it { expect(@firewall_mock.denied[0].ports).to include "555" } + it { expect(@firewall_mock.direction).to eq 'INGRESS' } + it { expect(@firewall_mock.network).to match('/default$') } + it { expect(@firewall_mock.source_ranges).to include "113.197.104.0/22" } + + end +end + + +no_firewall = FirewallTest.new(nil) +RSpec.describe Firewall, "#parse" do + it "does not exist" do + expect(no_firewall.exists?).to be false + end +end \ No newline at end of file diff --git a/templates/inspec/tests/firewalls_test.rb b/templates/inspec/tests/firewalls_test.rb new file mode 100644 index 000000000000..db66693db955 --- /dev/null +++ b/templates/inspec/tests/firewalls_test.rb @@ -0,0 +1,45 @@ +# Copyright 2017 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. + +require 'google_compute_firewalls' +require 'json' + +class FirewallsTest < Firewalls + def fetch_resource(data) + return data + end +end + +firewalls_fixture = JSON.parse(File.read('fixtures/firewalls_fixture.json')) + +RSpec.describe Firewalls, '#fetch_resource' do + before do + @firewalls_mock = FirewallsTest.new(firewalls_fixture) + end + context 'firewalls plural' do + it { expect(@firewalls_mock.names.size).to eq 3 } + it { expect(@firewalls_mock.names).to include 'default-knsku4qwwbtr3bhcf3y6vcmu' } + it { expect(@firewalls_mock.names).to include 'default-7mzjmae3tlidh4yoidvnpe53' } + it { expect(@firewalls_mock.names).to include 'default-2wnao3jebww7ldrn463stwke' } + end +end + +no_firewalls_fixture = JSON.parse(File.read('fixtures/firewalls_fixture.json')) + +no_firewalls_fixture['items'] = [] +no_firewalls = FirewallsTest.new(no_firewalls_fixture) +RSpec.describe Firewalls, "#fetch_resource" do + it "no firewalls" do + expect(no_firewalls.names.size).to eq 0 + end +end \ No newline at end of file diff --git a/templates/inspec/tests/fixtures/firewall_fixture.json b/templates/inspec/tests/fixtures/firewall_fixture.json new file mode 100644 index 000000000000..962b837d8c3e --- /dev/null +++ b/templates/inspec/tests/fixtures/firewall_fixture.json @@ -0,0 +1,22 @@ +{"kind":"compute#firewall", + "id":"960238098441931407", + "creationTimestamp":"2018-10-11T22:42:56.000-07:00", + "name":"default-uuaca3r2wn7yqlbdyzue5lrn", + "description":"description", + "network": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/networks/default", + "priority":1000, + "sourceRanges": + ["103.104.152.0/22", + "104.132.0.0/14", + "113.197.104.0/22", + "185.25.28.0/22", + "193.200.222.0/24", + "89.207.224.0/21"], + "targetTags":["https-server"], + "allowed":[{"IPProtocol":"tcp", "ports":["443"]}], + "denied":[{"IPProtocol":"udp", "ports":["555"]}], + "direction":"INGRESS", + "disabled":false, + "selfLink": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/firewalls/default-uuaca3r2wn7yqlbdyzue5lrn"} \ No newline at end of file diff --git a/templates/inspec/tests/fixtures/firewalls_fixture.json b/templates/inspec/tests/fixtures/firewalls_fixture.json new file mode 100644 index 000000000000..b2cae7c8d03f --- /dev/null +++ b/templates/inspec/tests/fixtures/firewalls_fixture.json @@ -0,0 +1,88 @@ +{"kind":"compute#firewallList", + "id":"projects/sam-inspec/global/firewalls", + "items": + [{"kind":"compute#firewall", + "id":"2182788659368790689", + "creationTimestamp":"2018-10-11T22:42:38.647-07:00", + "name":"default-2wnao3jebww7ldrn463stwke", + "description": + "Desc", + "network": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/networks/default", + "priority":1000, + "sourceRanges": + ["103.104.152.0/22", + "104.132.0.0/14", + "113.197.104.0/22", + "185.25.28.0/22", + "193.200.222.0/24", + "89.207.224.0/21"], + "allowed":[{"IPProtocol":"tcp", "ports":["22", "3389"]}], + "direction":"INGRESS", + "disabled":false, + "selfLink": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/firewalls/default-2wnao3jebww7ldrn463stwke"}, + {"kind":"compute#firewall", + "id":"8832388878237010597", + "creationTimestamp":"2018-10-11T22:42:34.846-07:00", + "name":"default-7mzjmae3tlidh4yoidvnpe53", + "description": + "Description 2", + "network": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/networks/default", + "priority":1000, + "sourceRanges": + ["108.170.224.0/19", + "108.177.8.0/21", + "108.177.80.0/20", + "108.177.96.0/19", + "172.102.8.0/21", + "172.217.0.0/19", + "172.217.128.0/19", + "172.217.160.0/20", + "172.217.176.1/32", + "172.217.176.2/32", + "172.217.192.0/19", + "172.217.64.0/18", + "172.253.50.0/23", + "172.253.64.0/20", + "173.194.0.0/16", + "185.150.148.0/22", + "192.104.160.0/23", + "209.107.176.0/20", + "209.85.128.0/17", + "216.239.32.0/19", + "216.252.220.0/22", + "216.58.192.0/19", + "64.233.160.0/19", + "66.102.0.0/20", + "66.249.64.0/19", + "72.14.192.0/18", + "74.125.0.0/16", + "8.8.4.0/24", + "8.8.8.0/24"], + "targetTags":["https-server"], + "allowed":[{"IPProtocol":"tcp", "ports":["443"]}], + "direction":"INGRESS", + "disabled":false, + "selfLink": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/firewalls/default-7mzjmae3tlidh4yoidvnpe53"}, + {"kind":"compute#firewall", + "id":"8107033807488387752", + "creationTimestamp":"2018-10-11T22:42:31.919-07:00", + "name":"default-knsku4qwwbtr3bhcf3y6vcmu", + "description": + "Another description", + "network": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/networks/default", + "priority":1000, + "sourceRanges":["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"], + "allowed":[{"IPProtocol":"tcp"}, {"IPProtocol":"udp"}], + "direction":"INGRESS", + "disabled":false, + "selfLink": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/firewalls/default-knsku4qwwbtr3bhcf3y6vcmu"} + ], + + "selfLink": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/firewalls"} \ No newline at end of file diff --git a/templates/inspec/tests/fixtures/instance_fixture.json b/templates/inspec/tests/fixtures/instance_fixture.json new file mode 100644 index 000000000000..264e13d3276d --- /dev/null +++ b/templates/inspec/tests/fixtures/instance_fixture.json @@ -0,0 +1,71 @@ +{"kind":"compute#instance", + "id":"1154794430415066980", + "creationTimestamp":"2018-10-24T14:52:15.794-07:00", + "name":"gcp-inspec-app-mig3-4pp8", + "tags": + {"items":["allow-gcp-inspec-app-mig3", "allow-ssh"], + "fingerprint":"rOcaWmVHbAQ="}, + "machineType": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/europe-west2-c/machineTypes/f1-micro", + "status":"RUNNING", + "zone": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/europe-west2-c", + "networkInterfaces": + [{"kind":"compute#networkInterface", + "network": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/networks/default", + "subnetwork": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/regions/europe-west2/subnetworks/default", + "networkIP":"10.154.0.7", + "name":"nic0", + "accessConfigs": + [{"kind":"compute#accessConfig", + "type":"ONE_TO_ONE_NAT", + "name":"external-nat", + "natIP":"35.242.153.92", + "networkTier":"PREMIUM"}], + "fingerprint":"gqa1nAlsW2g="}], + "disks": + [{"kind":"compute#attachedDisk", + "type":"PERSISTENT", + "mode":"READ_WRITE", + "source": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/europe-west2-c/disks/gcp-inspec-app-mig3-4pp8", + "deviceName":"persistent-disk-0", + "index":0, + "boot":true, + "autoDelete":true, + "licenses": + ["https://www.googleapis.com/compute/v1/projects/debian-cloud/global/licenses/debian-9-stretch"], + "interface":"SCSI", + "guestOsFeatures":[{"type":"VIRTIO_SCSI_MULTIQUEUE"}]}], + "metadata": + {"kind":"compute#metadata", + "fingerprint":"8sKIPG5hwJ8=", + "items": + [{"key":"instance-template", + "value": + "projects/577278241961/global/instanceTemplates/default-20181011161843755000000001"}, + {"key":"created-by", + "value": + "projects/577278241961/zones/europe-west2-c/instanceGroupManagers/gcp-inspec-app-mig3"}, + {"key":"tf_depends_id", "value":""}, + {"key":"startup-script", + "value":"val"}]}, + "serviceAccounts": + [{"email":"577278241961-compute@developer.gserviceaccount.com", + "scopes": + ["https://www.googleapis.com/auth/devstorage.full_control", + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/monitoring.write"]}], + "selfLink": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/europe-west2-c/instances/gcp-inspec-app-mig3-4pp8", + "scheduling": + {"onHostMaintenance":"MIGRATE", + "automaticRestart":true, + "preemptible":false}, + "cpuPlatform":"Intel Broadwell", + "labelFingerprint":"42WmSpB8rSM=", + "startRestricted":false, + "deletionProtection":false} \ No newline at end of file diff --git a/templates/inspec/tests/fixtures/instances_fixture.json b/templates/inspec/tests/fixtures/instances_fixture.json new file mode 100644 index 000000000000..ad9dcd8fbd90 --- /dev/null +++ b/templates/inspec/tests/fixtures/instances_fixture.json @@ -0,0 +1,265 @@ +{"kind":"compute#instanceList", + "id":"projects/sam-inspec/zones/us-west1-a/instances", + "items": + [{"kind":"compute#instance", + "id":"4098088814882506478", + "creationTimestamp":"2018-10-11T09:19:13.657-07:00", + "name":"gcp-inspec-ext-linux-vm", + "tags":{"fingerprint":"42WmSpB8rSM="}, + "machineType": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a/machineTypes/f1-micro", + "status":"RUNNING", + "zone": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a", + "canIpForward":false, + "networkInterfaces": + [{"kind":"compute#networkInterface", + "network": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/networks/default", + "subnetwork": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/regions/us-west1/subnetworks/default", + "networkIP":"10.138.0.5", + "name":"nic0", + "accessConfigs": + [{"kind":"compute#accessConfig", + "type":"ONE_TO_ONE_NAT", + "name":"external-nat", + "natIP":"35.197.85.27", + "networkTier":"PREMIUM"}], + "fingerprint":"AFwTnwxTDzE="}], + "disks": + [{"kind":"compute#attachedDisk", + "type":"PERSISTENT", + "mode":"READ_WRITE", + "source": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a/disks/gcp-inspec-ext-linux-vm", + "deviceName":"persistent-disk-0", + "index":0, + "boot":true, + "autoDelete":true, + "licenses": + ["https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/licenses/ubuntu-1604-xenial"], + "interface":"SCSI", + "guestOsFeatures":[{"type":"VIRTIO_SCSI_MULTIQUEUE"}]}], + "metadata":{"kind":"compute#metadata", "fingerprint":"d2SnEfYPfPw="}, + "selfLink": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a/instances/gcp-inspec-ext-linux-vm", + "scheduling": + {"onHostMaintenance":"MIGRATE", + "automaticRestart":false, + "preemptible":false}, + "cpuPlatform":"Intel Broadwell", + "labelFingerprint":"42WmSpB8rSM=", + "startRestricted":false, + "deletionProtection":false}, + {"kind":"compute#instance", + "id":"2745409369181177570", + "creationTimestamp":"2018-10-11T09:19:26.305-07:00", + "name":"gcp-inspec-generic-ext-linux-vm-data-disk", + "tags":{"fingerprint":"42WmSpB8rSM="}, + "machineType": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a/machineTypes/f1-micro", + "status":"RUNNING", + "zone": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a", + "canIpForward":false, + "networkInterfaces": + [{"kind":"compute#networkInterface", + "network": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/networks/default", + "subnetwork": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/regions/us-west1/subnetworks/default", + "networkIP":"10.138.0.6", + "name":"nic0", + "accessConfigs": + [{"kind":"compute#accessConfig", + "type":"ONE_TO_ONE_NAT", + "name":"external-nat", + "natIP":"35.233.212.32", + "networkTier":"PREMIUM"}], + "fingerprint":"QjXFGM0KG10="}], + "disks": + [{"kind":"compute#attachedDisk", + "type":"PERSISTENT", + "mode":"READ_WRITE", + "source": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a/disks/gcp-inspec-generic-ext-linux-vm-data-disk", + "deviceName":"persistent-disk-0", + "index":0, + "boot":true, + "autoDelete":true, + "licenses": + ["https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/licenses/ubuntu-1604-xenial"], + "interface":"SCSI", + "guestOsFeatures":[{"type":"VIRTIO_SCSI_MULTIQUEUE"}]}, + {"kind":"compute#attachedDisk", + "type":"PERSISTENT", + "mode":"READ_WRITE", + "source": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a/disks/gcp-inspec-compute-disk-name", + "deviceName":"gcp-inspec-compute-disk-name", + "index":1, + "boot":false, + "autoDelete":false, + "licenses": + ["https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/licenses/ubuntu-1604-xenial"], + "interface":"SCSI", + "guestOsFeatures":[{"type":"VIRTIO_SCSI_MULTIQUEUE"}]}], + "metadata":{"kind":"compute#metadata", "fingerprint":"d2SnEfYPfPw="}, + "selfLink": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a/instances/gcp-inspec-generic-ext-linux-vm-data-disk", + "scheduling": + {"onHostMaintenance":"MIGRATE", + "automaticRestart":false, + "preemptible":false}, + "cpuPlatform":"Intel Broadwell", + "labelFingerprint":"42WmSpB8rSM=", + "startRestricted":false, + "deletionProtection":false}, + {"kind":"compute#instance", + "id":"1527432115200903435", + "creationTimestamp":"2018-10-11T09:18:45.217-07:00", + "name":"gcp-inspec-int-linux-vm", + "tags":{"fingerprint":"42WmSpB8rSM="}, + "machineType": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a/machineTypes/f1-micro", + "status":"RUNNING", + "zone": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a", + "canIpForward":false, + "networkInterfaces": + [{"kind":"compute#networkInterface", + "network": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/networks/default", + "subnetwork": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/regions/us-west1/subnetworks/default", + "networkIP":"10.138.0.3", + "name":"nic0", + "fingerprint":"A3VqEvo68PM="}], + "disks": + [{"kind":"compute#attachedDisk", + "type":"PERSISTENT", + "mode":"READ_WRITE", + "source": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a/disks/gcp-inspec-int-linux-vm", + "deviceName":"persistent-disk-0", + "index":0, + "boot":true, + "autoDelete":true, + "licenses": + ["https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/licenses/ubuntu-1604-xenial"], + "interface":"SCSI", + "guestOsFeatures":[{"type":"VIRTIO_SCSI_MULTIQUEUE"}]}], + "metadata":{"kind":"compute#metadata", "fingerprint":"d2SnEfYPfPw="}, + "selfLink": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a/instances/gcp-inspec-int-linux-vm", + "scheduling": + {"onHostMaintenance":"MIGRATE", + "automaticRestart":false, + "preemptible":false}, + "cpuPlatform":"Intel Broadwell", + "labelFingerprint":"42WmSpB8rSM=", + "startRestricted":false, + "deletionProtection":false}, + {"kind":"compute#instance", + "id":"4819361437611903243", + "creationTimestamp":"2018-10-11T09:18:44.717-07:00", + "name":"gcp-inspec-int-windows-vm", + "tags":{"fingerprint":"42WmSpB8rSM="}, + "machineType": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a/machineTypes/g1-small", + "status":"RUNNING", + "zone": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a", + "canIpForward":false, + "networkInterfaces": + [{"kind":"compute#networkInterface", + "network": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/networks/default", + "subnetwork": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/regions/us-west1/subnetworks/default", + "networkIP":"10.138.0.2", + "name":"nic0", + "fingerprint":"9OQCl4IJ4Q4="}], + "disks": + [{"kind":"compute#attachedDisk", + "type":"PERSISTENT", + "mode":"READ_WRITE", + "source": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a/disks/gcp-inspec-int-windows-vm", + "deviceName":"persistent-disk-0", + "index":0, + "boot":true, + "autoDelete":true, + "licenses": + ["https://www.googleapis.com/compute/v1/projects/windows-cloud/global/licenses/windows-server-2016-dc", + "https://www.googleapis.com/compute/v1/projects/windows-cloud/global/licenses/windows-server-core"], + "interface":"SCSI", + "guestOsFeatures": + [{"type":"WINDOWS"}, + {"type":"VIRTIO_SCSI_MULTIQUEUE"}, + {"type":"MULTI_IP_SUBNET"}]}], + "metadata":{"kind":"compute#metadata", "fingerprint":"d2SnEfYPfPw="}, + "selfLink": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a/instances/gcp-inspec-int-windows-vm", + "scheduling": + {"onHostMaintenance":"MIGRATE", + "automaticRestart":false, + "preemptible":false}, + "cpuPlatform":"Intel Broadwell", + "labelFingerprint":"42WmSpB8rSM=", + "startRestricted":false, + "deletionProtection":false}, + {"kind":"compute#instance", + "id":"473310539327654168", + "creationTimestamp":"2018-10-11T09:19:04.092-07:00", + "name":"gcp-inspec-logging-vm", + "tags":{"fingerprint":"42WmSpB8rSM="}, + "machineType": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a/machineTypes/f1-micro", + "status":"RUNNING", + "zone": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a", + "canIpForward":false, + "networkInterfaces": + [{"kind":"compute#networkInterface", + "network": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/networks/default", + "subnetwork": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/regions/us-west1/subnetworks/default", + "networkIP":"10.138.0.4", + "name":"nic0", + "accessConfigs": + [{"kind":"compute#accessConfig", + "type":"ONE_TO_ONE_NAT", + "name":"external-nat", + "natIP":"35.233.178.27", + "networkTier":"PREMIUM"}], + "fingerprint":"pO_f1M2dtYQ="}], + "disks": + [{"kind":"compute#attachedDisk", + "type":"PERSISTENT", + "mode":"READ_WRITE", + "source": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a/disks/gcp-inspec-logging-vm", + "deviceName":"persistent-disk-0", + "index":0, + "boot":true, + "autoDelete":true, + "licenses": + ["https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/licenses/ubuntu-1604-xenial"], + "interface":"SCSI", + "guestOsFeatures":[{"type":"VIRTIO_SCSI_MULTIQUEUE"}]}], + "metadata":{"kind":"compute#metadata", "fingerprint":"d2SnEfYPfPw="}, + "selfLink": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a/instances/gcp-inspec-logging-vm", + "scheduling": + {"onHostMaintenance":"MIGRATE", + "automaticRestart":false, + "preemptible":false}, + "cpuPlatform":"Intel Broadwell", + "labelFingerprint":"42WmSpB8rSM=", + "startRestricted":false, + "deletionProtection":false}], + "selfLink": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-west1-a/instances"} \ No newline at end of file diff --git a/templates/inspec/tests/fixtures/zone_fixture.json b/templates/inspec/tests/fixtures/zone_fixture.json new file mode 100644 index 000000000000..1e68b2a0346b --- /dev/null +++ b/templates/inspec/tests/fixtures/zone_fixture.json @@ -0,0 +1,12 @@ +{"kind":"compute#zone", + "id":"2231", + "creationTimestamp":"1989-11-28T00:00:00-05:00", + "name":"us-east1-b", + "description":"us-east1-b", + "status":"UP", + "region": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/regions/us-east1", + "selfLink": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-east1-b", + "availableCpuPlatforms": + ["Intel Skylake", "Intel Broadwell", "Intel Haswell"]} \ No newline at end of file diff --git a/templates/inspec/tests/fixtures/zones_fixture.json b/templates/inspec/tests/fixtures/zones_fixture.json new file mode 100644 index 000000000000..32a8bc2aeedf --- /dev/null +++ b/templates/inspec/tests/fixtures/zones_fixture.json @@ -0,0 +1,39 @@ +{"kind":"compute#zoneList", + "id":"projects/sam-inspec/zones", + "items": + [{"kind":"compute#zone", + "id":"2231", + "creationTimestamp":"1969-12-31T16:00:00.000-08:00", + "name":"us-east1-b", + "description":"us-east1-b", + "status":"UP", + "region": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/regions/us-east1", + "selfLink": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-east1-b", + "availableCpuPlatforms": + ["Intel Skylake", "Intel Broadwell", "Intel Haswell"]}, + {"kind":"compute#zone", + "id":"2233", + "creationTimestamp":"1969-12-31T16:00:00.000-08:00", + "name":"us-east1-c", + "description":"us-east1-c", + "status":"UP", + "region": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/regions/us-east1", + "selfLink": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-east1-c", + "availableCpuPlatforms": + ["Intel Skylake", "Intel Broadwell", "Intel Haswell"]}, + {"kind":"compute#zone", + "id":"2234", + "creationTimestamp":"1969-12-31T16:00:00.000-08:00", + "name":"us-east1-d", + "description":"us-east1-d", + "status":"UP", + "region": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/regions/us-east1", + "selfLink": + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-east1-d", + "availableCpuPlatforms": + ["Intel Skylake", "Intel Broadwell", "Intel Haswell"]}]} \ No newline at end of file diff --git a/templates/inspec/tests/instance_test.rb b/templates/inspec/tests/instance_test.rb new file mode 100644 index 000000000000..80ba67f3b67b --- /dev/null +++ b/templates/inspec/tests/instance_test.rb @@ -0,0 +1,47 @@ +# Copyright 2017 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. + +require 'google_compute_instance' +require 'json' + +class InstanceTest < Instance + def initialize(data) + @fetched = data + end +end + +instance_fixture = JSON.parse(File.read('fixtures/instance_fixture.json')) + +RSpec.describe Instance, "#parse" do + it "compute instance parse" do + instance_mock = InstanceTest.new(instance_fixture) + instance_mock.parse + expect(instance_mock.exists?).to be true + expect(instance_mock.disks.size).to eq 1 + expect(instance_mock.disks[0].mode).to eq 'READ_WRITE' + expect(instance_mock.disks[0].auto_delete).to be true + expect(instance_mock.scheduling.preemptible).to be false + expect(instance_mock.scheduling.automatic_restart).to be true + expect(instance_mock.service_accounts.size).to eq 1 + expect(instance_mock.service_accounts[0].email).to eq "577278241961-compute@developer.gserviceaccount.com" + expect(instance_mock.service_accounts[0].scopes).to include "https://www.googleapis.com/auth/compute" + + end +end + +RSpec.describe Instance, "none" do + it "no result" do + instance_mock = InstanceTest.new(nil) + expect(instance_mock.exists?).to be false + end +end \ No newline at end of file diff --git a/templates/inspec/tests/instances_test.rb b/templates/inspec/tests/instances_test.rb new file mode 100644 index 000000000000..a36ff1909483 --- /dev/null +++ b/templates/inspec/tests/instances_test.rb @@ -0,0 +1,43 @@ +# Copyright 2017 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. + +require 'google_compute_instances' +require 'json' + +class InstancesTest < Instances + def fetch_resource(data) + return data + end +end + +instances_fixture = JSON.parse(File.read('fixtures/instances_fixture.json')) + +instances_mock = InstancesTest.new(instances_fixture) +RSpec.describe Instances, '#fetch_resource' do + context 'instances plural' do + it { expect(instances_mock.names.size).to eq 5 } + it { expect(instances_mock.ids).to include '4819361437611903243' } + it { expect(instances_mock.names).to include 'gcp-inspec-ext-linux-vm' } + end +end + + +no_instances_fixture = JSON.parse(File.read('fixtures/instances_fixture.json')) +no_instances_fixture['items'] = [] + +RSpec.describe Instance, "none" do + it "no result" do + no_instances_mock = InstancesTest.new(no_instances_fixture) + expect(no_instances_mock.names.size).to eq 0 + end +end \ No newline at end of file diff --git a/templates/inspec/tests/zone_test.rb b/templates/inspec/tests/zone_test.rb new file mode 100644 index 000000000000..77369717128f --- /dev/null +++ b/templates/inspec/tests/zone_test.rb @@ -0,0 +1,44 @@ +# Copyright 2017 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. + +require 'google_compute_zone' +require 'json' + +class ZoneTest < Zone + def initialize(data) + @fetched = data + end +end + +zone_fixture = JSON.parse(File.read('fixtures/zone_fixture.json')) + +RSpec.describe Zone, "parse" do + it "zone attributes" do + zone_mock = ZoneTest.new(zone_fixture) + zone_mock.parse + expect(zone_mock.exists?).to be true + expect(zone_mock.name).to eq 'us-east1-b' + expect(zone_mock.status).to eq 'UP' + expect(zone_mock.deprecated.obsolete).to eq nil + time = Time.at(628232400).to_datetime + expect(zone_mock.creation_timestamp).to eq time + end + +end + +RSpec.describe Zone, "#parse" do + it "no result" do + no_zone_resource = ZoneTest.new(nil) + expect(no_zone_resource.exists?).to be false + end +end diff --git a/templates/inspec/tests/zones_test.rb b/templates/inspec/tests/zones_test.rb new file mode 100644 index 000000000000..a3f08d9028c8 --- /dev/null +++ b/templates/inspec/tests/zones_test.rb @@ -0,0 +1,47 @@ +# Copyright 2017 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. + +require 'google_compute_zones' +require 'json' + +class ZonesTest < Zones + def fetch_resource(data) + return data + end +end + +zones_fixture = JSON.parse(File.read('fixtures/zones_fixture.json')) + +RSpec.describe Zones, "zones" do + it "plural test" do + zones_mock_resource = ZonesTest.new(zones_fixture) + expect(zones_mock_resource.names.size).to eq 3 + expect(zones_mock_resource.names).to include 'us-east1-d' + expect(zones_mock_resource.names).to include 'us-east1-b' + expect(zones_mock_resource.names).to include 'us-east1-c' + expect(zones_mock_resource.statuses).to include 'UP' + expect(zones_mock_resource.statuses.size).to eq 3 + expect(zones_mock_resource.ids).to include '2231' + expect(zones_mock_resource.ids).to include '2234' + expect(zones_mock_resource.ids).to include '2233' + end +end + +no_zones_fixture = JSON.parse(File.read('fixtures/zones_fixture.json')) +no_zones_fixture['items'] = [] +no_zones = ZonesTest.new(no_zones_fixture) +RSpec.describe Zones, "#fetch_resource" do + it "no zones" do + expect(no_zones.names.size).to eq 0 + end +end \ No newline at end of file