Merge development branch (#44)

* VPN-HA module initial commit

* Added readme for net-vpn-ha module

* Update readme, add simple description

* Merge new modules list and environments foundation example (#30)

* gke-cluster

* net-vpc module and tests

* add TODO to net-vpc module

* add minimal README files with input/output variables to gke and net-vpc modules

* BigQuery Module (#24)

* Bigquery Module

* Added README file

* Added type hints

* gke-cluster

* net-vpc module and tests

* add TODO to net-vpc module

* add minimal README files with input/output variables to gke and net-vpc modules

* BigQuery Module (#24)

* Bigquery Module

* Added README file

* Added type hints

* GCS module

* net vpc module: improve secondary range outputs

* net vpc module: add serve project registration

* project module

* move bigquery module to not-ready folder

* folders module

* rename project module's iam variables

* slight tweak to folder module outputs

* gcs module

* simplify net-vpc module variables

* fix module tests configurations, fix net-vpc module tests

* add pydoc utility

* add/update module READMEs

* add/update module READMEs

* add/update module READMEs

* improve variable type summary generation in tfdoc

* tfdoc: add support for replacing doc in README.md files

* improve module READMEs

* net-vpc-firewall module

* add support for sensitive output attribute in tfdoc

* remove empty function from tfdoc

* render variable type as code in tfdoc

* update module READMEs

* net address module

* net cloudnat module

* remove redundant variable from net-cloudnat module

* vpc module: add support for peering, use network name as subnet name prefix

* net-vpn-static module

* net-vpn-static module README

* net-vpn-static module README

* tfdoc: fix error on undeclared variable type

* dns module

* set version for all modules

* kms module (untested)

* change kms key self links output to map, fix gcs and kms iam variable descriptions

* fix kms module

* update kms module readme

* simplify local iam pairs in modules

* service accounts module (unfinished)

* work on service accounts module

* project module: add gcr service account

* project module: update outputs in README

* first working version of the iam service accounts module

* iam service accounts module: extra checks in locals

* modules/net-cloudnat: reorder variables

* modules/net-vpn-dynamic: initial import (untested)

* modules/net-vpn-dynamic: first working version

* modules/net-vpn-dynamic: add outputs for auto-created router

* modules/net-vpn-dynamic: update README

* modules/net-[vpn,cloudnat]: clean up variable,s remove prefix

* modules/net-vpn-dynamic: add advertisement configuration to tunnel bgp peer, refactor variables

* tfdoc: add tooltips for variable types and defaults

* modules: update README variables and outputs

* tfdoc: improve variable default rendering

* modules: update README variables and outputs

* modules/net-vpc: minimal output refactoring

* modules/vm-cos: initial import, base resources working, no outputs

* modules/vm-cos: add variable descriptions

* tfdoc: fix parsing in type and default blocks

* modules/vm-cos: fix README

* tfdoc: fix parsing in type and default blocks

* modules/vm-cos: fix README

* modules/compute-vm: initial working import (not fully tested)

* modules/vm-cos: move to not-ready

* tfdoc: fix variable defaults formatting

* modules: update README files with tfdoc fixes

* modules: add initial examples

* gke-nodepool: initial import, untested

* gke nodepool: add README, fix location variable, set node count default to 1

* gke cluster: fix private cluster variables

* gke nodepool: fix README title

* gke cluster: add output for cluster location

* gke nodepool: add missing variables for project id and cluster name, remove default from location variable, fix gke version assignment

* gke nodepool: update README

* net-cloudnat: fix router name when creating default router

* fix variables used for address and router optional creation

* vpn dynamic: fix README

* modules/net-vpn-dynamic: fix router name output

* modules/compute-vm: remove unused variable

* modules/compute-vm-cos-coredns: initial import

* Update foundations modules versions (#26)

* update foundations modules versions

* update Terraform version to v0.12.19 in CI test configuration

* backport tfdoc from Ludo's branch (#27)

* Update docs using tfdoc format (#28)

* update README files

* set all types on variables

* foundations/environments: move log filter to a variable, use org for xpn by default

* foundations/environments: do not use liens by default

* modules/ntp-vpc: better shared_vpc_host variable description

* modules/logging-sinks: initial version

* modules/logging-sinks: streamline options in sinks variable

* modules/compute-vm-cos-coredns: add support for additional files

* modules/folders: rename from 'folder'

* modules/logging-sinks: fix circular dependencies and improve variables

* modules/project: remove extra variable

* modules/bigquery: new module with dataset support only

* foundations/environments: refactor using local modules

* modules/bigquery: better variables, README description and example

* modules: fix a few READMEs

Co-authored-by: Julio Castillo <juliocc@gmail.com>

* modules/net-vpc: README description and examples

* modules/net-vpc: tweak README description and examples

* modules/net-vpc: tweak README description and examples

* modules/net-vpc-firewall: change tag-based rule default ranges, improve README examples and description

* modules/compute-vm: README changes

* modules/compute-vm: use an object for the service account variable, update README

* modules/compute-vm: update README variables table

* modules/compute-vm: add TODO list to README

* modules/compute-vm: add TODO list to README

* modules/compute-vm: add outputs for service account

* modules/net-cloudnat: README

* modules/net-cloudnat: README

* modules/net-cloudnat: add router_create variable

* modules/compute-vm: simplify service account variables

* modules/net-vpn-dynamic: fix README example, use local secret for both empty string and null

* modules/net-vpn-dynamic: improve README example

* modules/gke-cluster: minimal README tweaks

* modules/kms: fix ephemeral keys resource name

* modules/iam-service-accounts: add storage roles

* modules/gke-nodepool: fix node default scopes

* New project variable to prevent deletion of default network (#32)

* New project variable to prevent deletion of default network

This is a workaround to fix
terraform-google-modules/cloud-foundation-fabric#31 while the GCP
terraform provider is fixed

* Add TODOs to remove workarounds in the project module

* Fix Cloud Build files

* modules/gke-nodepool: add monitoring scope to defaults

* modules/iam-service-accounts: add support for IAM bindings onthe service accounts

* playground module in sandbox, remove not ready modules

* Fix ci configurations in development branch (#33)

* try fixing ci confgurations

* add exclusion match to ci boilerplate check

* add skip boilerplate comment to compute-vm-cos-coredns template fragment

* modules/gke-cluster: fix boilerplate in outputs

* Simplify tests, re-enable CI

* add instance group support to compute-vm, start tests refactoring

* modules/compute-vm: group fixes, tests

* modules/compute-vm: minimal test beautification

* simplify top-level pytest fixture

* modules/dns: tests and minor tweaks

* fix missing boilerplate in tests

* re-add requirements file to tests folder

* re-enable tests in ci build configuration

* Folder module tests and fixes (#38)

* folder tests wip

* modules/folders: tests and tweaks

* update folders and compute-vm README files

* modules/gcs: tests and minor tweaks

* Create README.md

* Update README.md

* Update README.md

* Update README.md

* Added docker image for strongSwan

* Add support for routes and tests to net-vpc module (#39)

* modules/net-vpc: add routes (untested)

* initial tests

* modules/net-vpc: add test for flow logs

* modules/net-vpc: split tests into two separate files

* modules/net-vpc: routes test

* modules/net-vpc: test routes

* Add support for Terraform plugin cache in ci test build file (#40)

* add Terraform plugin caching to test ci build configuration

* fix mkdir in test build configuration

* trigger test check

* Refactor dynamic vpn configuration for on-prem-in-a-box module

* Fix dynamic vpn for onprem-in-a-box module

* Migrate Shared VPC example to local modules (#41)

* wip

* wip

* validated, untested

* modules/compute-vm: make service account email in locals resilient to destroy

* modules/project: make project id output depend on iam roles

* fixes

* shared-vpc tweaks

* update diagram

* update README input output tables

* modules/compute-vm: add service account IAM email output

* move GKE service account roles at the project level, add GCE service account roles

* update diagram and README

* modules/project: add extra output for IAM-dependent project id

* update modules READMEs

* minor tweaks

* modules/compute-vm: fix service account output

* remove static address from NAT

* fix container service agent binding dependency

* rename shared vpc

* Update README.md

* Update README.md

* Add static vpn gw to on-prem-in-a-box module

* Refactor hub and spoke to use new modules (#42)

* modules/compute-vm: saner defaults for service account scopes

* hub and spoke refactor, docs still missing

* complete hub and spoke

* Update README.md

* Add toolbox docker container, fix gw routing to the internet

* Add DNS Hybrid connectivity parameters

* Fix onprem dns zone for the static vpn configuration

* Added readme.md for on-prem module

* Add new line at the end of the files

* Add boilerplate for cloudbuild config files

* fix boilerplate in strongswan shell script

* Update README.md

* include missing file to fix merge conflict

* remove missing file to fix merge conflict

* include missing file to fix merge conflict (again)

* remove content from spurious file used to avoid merge conflicts

* Add net-vpc-peering module

* Initial commit for hub-and-spoke-peering infrastructure example

* Fix typos in infrastructure/ READMEs

* remove stale file

* use larger resolution version of hub and spoke diagram

* Update README.md

* Update hub-and-spoke-peerings example to use internal modules

* Add initial project tests (#46)

* modules/project: make prefix optional

* initial project module tests

* modules/project: use null for unset parent

* modules/dns: backport PR6 from the CFT dns module

* Add testing resources including on-prem-in-a-box to hub-and-spoke-peerings example

* Fix firewall rules to allow connectivity, switch to custom route advertisement for onprem -> spokes connectivity

* Move locals out of main.tf

* remove ssh tag from compute-vm variable default

* Add ssh tag to the test vms

* Update README.md

* Update README.md

* Update README.md

* Hub and spoke peering changes (#48)

* rename hub-and-spoke-vpn

* add ssh tag to shared-vpc-gke instance

* rename and rework hub and spoke peering

* fix test requirements

* align hub and spoke peering with module contents

* diagram

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* minimal fixes to onprem examples variable files

* onprem example stub, missing DNS zones and private.googleapis records onprem

* add missing boilerplate

* Update README.md

* Update README.md

* infra/onprem: add test instance and minimal outputs

* add DNS modules and resource

* infra/onprem: diagram and initial README

* minor changes to onprem module and example (#49)

* update toolbox image

* infra/onprem: add zone for private access, add metadata domain to onprem dns

* infra/onprem: onnprem service account, add testing procedure in README

* Update README.md

* infra/onprem: remove extra variable

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* infra/onprem: rename forwarder address variable

* Update README:

Added explicit --tunnel-through-iap for gcloud compute ssh commands

* Update top-level and section READMEs (#50)

* top-level README WIP

* rewrite top-level README

* change top-level README title

* remove initial quote in top-level README

* Update README.md

* Update README.md

* Update README.md

* foundations README

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* add experimental scheduled cloud function module

* scheduled cloud function module: allow disabling schedule

* business-units foundation example (#52)

* Added folder-units module.

* Business units example update (WIP)

* Update all BU modules to internal ones

* Refactoring business-units example, add billing and org IAM handling

* update projects tests for new iam additive naming

* update project README for new iam additive naming

* streamline bu example and module (#53)

Co-authored-by: Ludovico Magnocavallo <ludomagno@google.com>

* align net-vpn-ha interface with the other vpn modules

* update module README files

* Update README.md

* Update README.md

* Create CHANGELOG.md

* Refactor COS module to be generic (#51)

* Create generic COS module and update CoreDNS module to use it

* Update compute-vm-cos README

* Fix COS README

* Update COS example

* Skip boilerplate check for COS file template

* Make COS module more generic and provide preset configurations

* Update COS module documentation

* tfdoc: add support for multiple variables files

* compute-vm: split boot disk in separate variable file for cos module support

* Streamline cos modules (#54)

* tfdoc: fix bug in last commit

* compute-vm: add support for user-data

* compute-vm: restore noncos variable split

* remove compute-vm-cos-coredns

* compute-vm: revert to original state

* cos-container/coredns

* fix variables mess

* cos/coredns fixes

* cos/mysql

* remove stale compute-vm-cos module

* add test instance to cos modules

* tfdoc: add support for multiple output files

* cos: add initial READMEs

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* add test apply fixture

* cos-coredns: tested

* Update README.md

* Fix typo

* cos-coredns: refactor README

* Update README.md

* test yaml validity in cos modules tests

* cos mysql tests

* cos mysql: refactor and test (disk tests missing)

* onprem: fix Coredns

* cos mysql: additional disk working

* cos modules: fix instance disks for no instance

* update some modules READMEs

* update some modules READMEs

* Update README.md

* Update README.md

* add simple tests for foundations/environments

* change default for org id in foundations/environments to avoid errors when none is specified

* fix null/empty organization id in foundations/environments

* fix errors when destroying on empty state in foundations/environments

* fundations/bu: fix errors when destroying with empty state

* modules/gcs: make outputs resilient on destroy with empty state

* modules/folders: make outputs resilient on destroy with empty state

* switch organization_id variable to long form in foundations/bu and modules/folders-unit

* Update README.md

* infra/shared-vpc: remove duplicate tag attribute from bastion

Co-authored-by: Aleksandr Averbukh <averbukh@google.com>
Co-authored-by: Julio Castillo <juliocc@gmail.com>
Co-authored-by: Julio Castillo <jccb@google.com>
This commit is contained in:
Ludovico Magnocavallo
2020-04-03 14:06:48 +02:00
committed by GitHub
parent b278c4eae4
commit c486bfc66f
282 changed files with 14296 additions and 2759 deletions

View File

@@ -1,14 +1,13 @@
# Copyright 2019 Google LLC
#
# Copyright 2020 Google LLC
#
# 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
#
# https://www.apache.org/licenses/LICENSE-2.0
# 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.

View File

@@ -1,10 +1,10 @@
# Copyright 2019 Google LLC
# Copyright 2020 Google LLC
#
# 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
#
# https://www.apache.org/licenses/LICENSE-2.0
# 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,
@@ -12,25 +12,47 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"Shared fixtures."
"Shared fixtures"
import os
import pytest
import tftest
_BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
BASEDIR = os.path.dirname(os.path.dirname(__file__))
@pytest.fixture(scope='session')
def plan():
def plan_runner():
"Returns a function to run Terraform plan on a fixture."
def run_plan(testdir):
tfdir = testdir.replace('_', '-')
tf = tftest.TerraformTest(tfdir, _BASEDIR,
def run_plan(fixture_path, is_module=True, **tf_vars):
"Runs Terraform plan and returns parsed output"
tf = tftest.TerraformTest(fixture_path, BASEDIR,
os.environ.get('TERRAFORM', 'terraform'))
tf.setup(extra_files=['tests/{}/terraform.tfvars'.format(testdir)])
return tf.plan(output=True)
tf.setup()
plan = tf.plan(output=True, tf_vars=tf_vars)
root_module = plan.planned_values['root_module']['child_modules'][0]
if is_module:
return (plan, root_module['resources'])
modules = dict((mod['address'], mod['resources'])
for mod in root_module['child_modules'])
return (plan, modules)
return run_plan
@pytest.fixture(scope='session')
def apply_runner():
"Returns a function to run Terraform apply on a fixture."
def run_apply(fixture_path, **tf_vars):
"Runs Terraform apply and returns parsed output"
tf = tftest.TerraformTest(fixture_path, BASEDIR,
os.environ.get('TERRAFORM', 'terraform'))
tf.setup()
apply = tf.apply(tf_vars=tf_vars)
output = tf.output(json_format=True)
return (apply, output)
return run_apply

View File

@@ -1,14 +1,13 @@
# Copyright 2019 Google LLC
#
# Copyright 2020 Google LLC
#
# 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
#
# https://www.apache.org/licenses/LICENSE-2.0
# 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.

View File

@@ -1,27 +0,0 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
"Plan fixture."
import os
import pytest
_TFDIR = os.path.sep.join(os.path.abspath(__file__).split(os.path.sep)[-3:-1])
@pytest.fixture(scope='package')
def plan(plan):
return plan(_TFDIR)

View File

@@ -1,9 +0,0 @@
billing_account_id = "012345-ABCDEF-012345"
business_unit_1_name = "infra"
business_unit_2_name = "analytics"
business_unit_3_name = "data"
environments = ["dev", "test"]
generate_service_account_keys = true
organization_id = "012345678919"
prefix = "fabric-org-env-3"
root_node = "folders/0123456789"

View File

@@ -1,42 +0,0 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
"Test shared and business-units folders"
import pytest
def test_shared_folder(plan):
"Shared folder resource attributes must match variables."
root_node = plan.variables['root_node']
resource = plan.modules['module.shared-folder'].resources['google_folder.folders[0]']
assert resource['values']['parent'] == root_node
assert resource['values']['display_name'] == 'shared'
def test_business_unit_folders(plan):
"Business Unit folder resource attributes must match variables."
address_tpl = (
'module.business-unit-%s-folders.module.business-unit-folder'
'.google_folder.folders[0]'
)
count = range(1, 4)
business_unit_names = [
plan.variables['business_unit_%s_name' % i] for i in count]
root_node = plan.variables['root_node']
for address in [address_tpl % i for i in count]:
resource = plan.resource_changes[address]
assert resource['change']['after']['parent'] == root_node
assert resource['change']['after']['display_name'] in business_unit_names

View File

@@ -1,48 +0,0 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
"Test root module outputs."
def test_project_ids(plan):
"Project ids should use prefix and match expected values."
prefix = plan.variables['prefix']
assert plan.outputs['audit_logs_project'] == '%s-audit' % prefix
assert plan.outputs['shared_resources_project'] == '%s-shared' % prefix
assert plan.outputs['terraform_project'] == '%s-terraform' % prefix
def test_bucket_names(plan):
"GCS bucket names should use prefix and location and match expected values."
location = plan.variables['gcs_location'].lower()
prefix = plan.variables['prefix']
bootstrap_bucket = plan.outputs['bootstrap_tf_gcs_bucket']
assert bootstrap_bucket.startswith(prefix)
assert bootstrap_bucket.endswith('tf-bootstrap')
assert '-%s-' % location in bootstrap_bucket
def test_environment_buckets(plan):
"One GCS bucket should be created for each environment."
buckets = plan.outputs['environment_tf_gcs_buckets']
for environment in plan.variables['environments']:
assert environment in buckets
assert buckets[environment].endswith(environment)
def test_bq_dataset(plan):
"Bigquery dataset name should be based on root node type and id."
node_type, node_id = plan.variables['root_node'].split('/')
assert plan.outputs['audit_logs_bq_dataset'] == 'logs_audit_%s_%s' % (
node_type[:-1], node_id)

View File

@@ -1,46 +0,0 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
"Test project creation in root module."
import pytest
@pytest.fixture(scope='module')
def project_modules(plan):
names = ['module.project-%s' %
name for name in ('audit', 'shared-resources', 'tf')]
return dict((name, plan.modules[name]) for name in names)
def test_project_resource(plan, project_modules):
"Project resource attributes must match variables."
names = ('shared', 'terraform', 'audit')
prefix = plan.variables['prefix']
billing_account = plan.variables['billing_account_id']
project_names = ['%s-%s' % (prefix, name) for name in names]
for mod in project_modules.values():
resource = mod.resources['google_project.project']
assert resource['values']['billing_account'] == billing_account
assert resource['values']['name'] in project_names
def test_project_services(plan, project_modules):
"Project service resource must enable APIs specified in the variable."
num_services = len(plan.variables['project_services'])
for mod in project_modules.values():
project_services = [r for r in mod.resources if r.startswith(
'google_project_service.project_services')]
assert len(project_services) >= num_services

View File

@@ -1,34 +0,0 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
"Test service account creation in root module."
import pytest
@pytest.fixture(scope='module')
def mod(plan):
return plan.modules['module.service-accounts-tf-environments']
def test_accounts(plan, mod):
"One service account per environment should be created."
environments = plan.variables['environments']
prefix = plan.variables['prefix']
resources = [
v for k, v in mod.resources.items() if 'google_service_account.' in k]
assert len(resources) == len(environments)
assert sorted([res['values']['account_id'] for res in resources]) == sorted([
'%s-%s' % (prefix, env) for env in environments])

View File

@@ -1,14 +1,13 @@
# Copyright 2019 Google LLC
#
# Copyright 2020 Google LLC
#
# 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
#
# https://www.apache.org/licenses/LICENSE-2.0
# 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.

View File

@@ -1,27 +0,0 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
"Plan fixture."
import os
import pytest
_TFDIR = os.path.sep.join(os.path.abspath(__file__).split(os.path.sep)[-3:-1])
@pytest.fixture(scope='package')
def plan(plan):
return plan(_TFDIR)

View File

@@ -0,0 +1,30 @@
/**
* Copyright 2020 Google LLC
*
* 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.
*/
module "test" {
source = "../../../../foundations/environments"
billing_account_id = var.billing_account_id
environments = var.environments
iam_assets_editors = var.iam_assets_editors
iam_assets_owners = var.iam_assets_owners
iam_audit_viewers = var.iam_audit_viewers
iam_sharedsvc_owners = var.iam_sharedsvc_owners
iam_terraform_owners = var.iam_terraform_owners
iam_xpn_config = var.iam_xpn_config
organization_id = var.organization_id
prefix = var.prefix
root_node = var.root_node
}

View File

@@ -0,0 +1,76 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
variable "billing_account_id" {
type = string
default = "1234-5678-9012"
}
variable "environments" {
type = list(string)
default = ["test", "prod"]
}
variable "iam_assets_editors" {
type = list(string)
default = ["user:assets-ed-1@example.org", "user:assets-ed-2@example.org"]
}
variable "iam_assets_owners" {
type = list(string)
default = ["user:assets-own-1@example.org", "user:assets-own-2@example.org"]
}
variable "iam_audit_viewers" {
type = list(string)
default = ["user:audit-1@example.org", "user:audit2@example.org"]
}
variable "iam_sharedsvc_owners" {
type = list(string)
default = ["user:shared-1@example.org", "user:shared-2@example.org"]
}
variable "iam_terraform_owners" {
type = list(string)
default = ["user:tf-1@example.org", "user:tf-2@example.org"]
}
variable "iam_xpn_config" {
type = object({
grant = bool
target_org = bool
})
default = {
grant = true
target_org = false
}
}
variable "organization_id" {
type = string
default = ""
}
variable "prefix" {
description = "Prefix used for resources that need unique names."
type = string
default = "test"
}
variable "root_node" {
description = "Root node for the new hierarchy, either 'organizations/org_id' or 'folders/folder_id'."
type = string
default = "folders/1234567890"
}

View File

@@ -1,7 +0,0 @@
billing_account_id = "012345-ABCDEF-012345"
environments = ["dev", "test"]
generate_service_account_keys = true
grant_xpn_roles = true
organization_id = "012345678919"
prefix = "fabric-org-env-3"
root_node = "folders/0123456789"

View File

@@ -1,47 +0,0 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
"Test root module outputs."
def test_project_ids(plan):
"Project ids should use prefix and match expected values."
prefix = plan.variables['prefix']
assert plan.outputs['audit_logs_project'] == prefix + '-audit'
assert plan.outputs['shared_resources_project'] == prefix + '-shared'
assert plan.outputs['terraform_project'] == prefix + '-terraform'
def test_bucket_names(plan):
"GCS bucket names should use prefix and location and match expected values."
location = plan.variables['gcs_location'].lower()
prefix = plan.variables['prefix']
bootstrap_bucket = plan.outputs['bootstrap_tf_gcs_bucket']
assert bootstrap_bucket.startswith(prefix)
assert bootstrap_bucket.endswith('tf-bootstrap')
assert '-%s-' % location in bootstrap_bucket
def test_environment_buckets(plan):
"One GCS bucket should be created for each environment."
buckets = plan.outputs['environment_tf_gcs_buckets']
for environment in plan.variables['environments']:
assert environment in buckets
assert buckets[environment].endswith(environment)
def test_bq_dataset(plan):
"Bigquery dataset should be named after the first environment."
assert plan.outputs['audit_logs_bq_dataset'].endswith(
plan.variables['environments'][0])

View File

@@ -0,0 +1,53 @@
# Copyright 2020 Google LLC
#
# 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.
import os
import pytest
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
def test_folder_roles(plan_runner):
"Test folder roles."
_, modules = plan_runner(FIXTURES_DIR, is_module=False)
resources = modules['module.test.module.environment-folders']
folders = [r for r in resources if r['type'] == 'google_folder']
assert len(folders) == 2
assert set(r['values']['display_name']
for r in folders) == set(['prod', 'test'])
bindings = [r['index'].split('-')
for r in resources if r['type'] == 'google_folder_iam_binding']
assert len(bindings) == 10
assert set(b[0] for b in bindings) == set(['prod', 'test'])
assert len(set(b[1] for b in bindings)) == 5
def test_org_roles(plan_runner):
"Test folder roles."
vars = {
'organization_id': 'organizations/123',
'iam_xpn_config': '{grant = true, target_org = true}'
}
_, modules = plan_runner(FIXTURES_DIR, is_module=False, **vars)
resources = modules['module.test.module.environment-folders']
folder_bindings = [r['index'].split('-')
for r in resources if r['type'] == 'google_folder_iam_binding']
assert len(folder_bindings) == 8
resources = modules['module.test.module.tf-service-accounts']
org_bindings = [r['index'].split('-')
for r in resources if r['type'] == 'google_organization_iam_member']
assert len(org_bindings) == 4
assert set(b[0] for b in org_bindings) == set(['prod', 'test'])

View File

@@ -1,44 +0,0 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
"Test project creation in root module."
import pytest
@pytest.fixture(scope='module')
def project_modules(plan):
names = ['module.project-%s' %
name for name in ('audit', 'shared-resources', 'tf')]
return dict((name, plan.modules[name]) for name in names)
def test_project_resource(plan, project_modules):
"Project resource attributes must match variables."
root_node = plan.variables['root_node'].split('/')[1]
billing_account = plan.variables['billing_account_id']
for name, mod in project_modules.items():
resource = mod.resources['google_project.project']
assert resource['values']['folder_id'] == root_node
assert resource['values']['billing_account'] == billing_account
def test_project_services(plan, project_modules):
"Project service resource must enable APIs specified in the variable."
num_services = len(plan.variables['project_services'])
for mod in project_modules.values():
project_services = [r for r in mod.resources if r.startswith(
'google_project_service.project_services')]
assert len(project_services) >= num_services

View File

@@ -1,34 +0,0 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
"Test service account creation in root module."
import pytest
@pytest.fixture(scope='module')
def mod(plan):
return plan.modules['module.service-accounts-tf-environments']
def test_accounts(plan, mod):
"One service account per environment should be created."
environments = plan.variables['environments']
prefix = plan.variables['prefix']
resources = [
v for k, v in mod.resources.items() if 'google_service_account.' in k]
assert len(resources) == len(environments)
assert sorted([res['values']['account_id'] for res in resources]) == sorted([
'%s-%s' % (prefix, env) for env in environments])

View File

@@ -1,27 +0,0 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
"Plan fixture."
import os
import pytest
_TFDIR = os.path.sep.join(os.path.abspath(__file__).split(os.path.sep)[-3:-1])
@pytest.fixture(scope='package')
def plan(plan):
return plan(_TFDIR)

View File

@@ -1,3 +0,0 @@
hub_project_id = "automation-examples"
spoke_1_project_id = "automation-examples"
spoke_2_project_id = "automation-examples"

View File

@@ -1,38 +0,0 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
"Test cloud routers resources creation in root module."
def test_hub_custom_routers(plan):
"Hub to spoke routers should match input variables."
for i in (1, 2):
router = plan.resources['google_compute_router.hub-to-spoke-%s-custom[0]' % i]
bgp = router['values']['bgp'][0]
assert bgp['advertise_mode'] == 'CUSTOM'
assert bgp['advertised_groups'] == ['ALL_SUBNETS']
assert bgp['asn'] == plan.variables['hub_bgp_asn']
subnet_ranges = [s['subnet_ip']
for s in plan.variables['spoke_%s_subnets' % (3 - i)]]
assert [r['range'] for r in bgp['advertised_ip_ranges']] == subnet_ranges
def test_spoke_routers(plan):
"Spoke routers should match input variables."
for i in (1, 2):
router = plan.resources['google_compute_router.spoke-%s' % i]
bgp = router['values']['bgp'][0]
assert bgp['advertise_mode'] == 'DEFAULT'
assert bgp['advertised_groups'] == None
assert bgp['asn'] == plan.variables['spoke_%s_bgp_asn' % i]

View File

@@ -1,37 +0,0 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
"Test firewall resources creation in root module."
import pytest
@pytest.fixture(scope='module')
def firewall_modules(plan):
return [v for k, v in plan.modules.items() if k.startswith('module.firewall-')]
def test_firewall_rules(plan, firewall_modules):
"Test that the hub and spoke VPCs have allow-admin firewall rules"
source_ranges = []
for k in plan.variables:
if not k.endswith('_subnets'):
continue
source_ranges += [s['subnet_ip'] for s in plan.variables[k]]
for mod in firewall_modules:
allow_admins_resource = mod.resources['google_compute_firewall.allow-admins[0]']
allow_ssh = mod.resources['google_compute_firewall.allow-tag-ssh[0]']
assert allow_admins_resource['values']['source_ranges'] == source_ranges
assert allow_ssh['values']['source_ranges'] == ['0.0.0.0/0']

View File

@@ -1,34 +0,0 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
"Test root module outputs."
def test_hub_outputs(plan):
"Hub VPC ranges and regions should match input variables."
output = plan.outputs['hub']
for subnet in plan.variables['hub_subnets']:
name = subnet['subnet_name']
assert output['subnets_ips'][name] == subnet['subnet_ip']
assert output['subnets_regions'][name] == subnet['subnet_region']
def test_spokes_outputs(plan):
"Spokes VPC ranges and regions should match input variables."
for i in (1, 2):
output = plan.outputs['spoke-%s' % i]
for subnet in plan.variables['spoke_%s_subnets' % i]:
name = subnet['subnet_name']
assert output['subnets_ips'][name] == subnet['subnet_ip']
assert output['subnets_regions'][name] == subnet['subnet_region']

View File

@@ -1,35 +0,0 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
"Test VPN BGP ASNs in root module."
import pytest
def test_spokes_peer_asn(plan):
"Test that the spoke-to-hub VPNs mach input variables"
mods = [v for k, v in plan.modules.items() if k.startswith('module.vpn-spoke')]
for mod in mods:
bgp_peer = mod.resources['google_compute_router_peer.bgp_peer[0]']
assert bgp_peer['values']['peer_asn'] == plan.variables['hub_bgp_asn']
def test_hub_peer_asns(plan):
"Test that the hub-to-spoke VPNs mach input variables"
mods = [v for k, v in plan.modules.items() if k.startswith('module.vpn-hub')]
for mod in mods:
bgp_peer = mod.resources['google_compute_router_peer.bgp_peer[0]']
asn_varname = 'spoke_%s_bgp_asn' % mod['address'][-1]
assert bgp_peer['values']['peer_asn'] == plan.variables[asn_varname]

View File

@@ -1,27 +0,0 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
"Plan fixture."
import os
import pytest
_TFDIR = os.path.sep.join(os.path.abspath(__file__).split(os.path.sep)[-3:-1])
@pytest.fixture(scope='package')
def plan(plan):
return plan(_TFDIR)

View File

@@ -1,4 +0,0 @@
root_node = "folders/1234567890"
prefix = "fabric-svpc"
billing_account_id = "012345-012345-012345"
owners_gce = ["user:user@example.com"]

View File

@@ -1,29 +0,0 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
"Test root module outputs."
def test_vpc_ranges(plan):
"VPC ranges should match input variables."
ranges = plan.outputs['vpc_subnets']
for subnet in plan.variables['subnets']:
assert ranges[subnet['subnet_name']] == subnet['subnet_ip']
def test_project_ids(plan):
"Project ids should use prefix and match expected values."
prefix = plan.variables['prefix']
assert plan.outputs['host_project_id'] == prefix + '-vpc-host'
assert plan.outputs['service_project_ids']['gce'] == prefix + '-gce'

View File

@@ -1,62 +0,0 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
"Test shared vpc resources in root module."
import pytest
@pytest.fixture(scope='module')
def mod(plan):
return plan.modules['module.net-svpc-access']
def test_host_vpc(plan):
"Test that the vpc project is set as shared vpc host."
mod = plan.modules['module.net-vpc-host']
resources = [v['values'] for v in mod.resources.values() if v['type'] ==
'google_compute_shared_vpc_host_project']
assert resources[0]['project'] == plan.outputs['host_project_id']
def test_service_projects(plan, mod):
"Test that service projects are registered with the shared vpc."
resources = [v['values'] for v in mod.resources.values() if v['type'] ==
'google_compute_shared_vpc_service_project']
assert len(resources) == 2
assert set([r['host_project'] for r in resources]) == set(
[plan.outputs['host_project_id']])
assert sorted([r['service_project'] for r in resources]) == sorted(
plan.outputs['service_project_ids'].values())
def test_subnet_users(plan, mod):
"Test that the network user role is assigned on subnets."
resources = [v['values'] for v in mod.resources.values() if v['type'] ==
'google_compute_subnetwork_iam_binding']
assert len(resources) == 2
assert set([r['project'] for r in resources]) == set(
[plan.outputs['host_project_id']])
assert sorted([r['subnetwork'] for r in resources]) == ['gce', 'gke']
def test_service_agent(plan, mod):
"Test that the service agent role is assigned for gke only."
resources = [v['values'] for v in mod.resources.values() if v['type'] ==
'google_project_iam_binding']
assert resources[0] == {
'project': plan.outputs['host_project_id'],
'role': 'roles/container.hostServiceAgentUser'
}

15
tests/modules/__init__.py Normal file
View File

@@ -0,0 +1,15 @@
# Copyright 2020 Google LLC
#
# 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.

View File

@@ -1,10 +1,10 @@
# Copyright 2019 Google LLC
# Copyright 2020 Google LLC
#
# 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
#
# https://www.apache.org/licenses/LICENSE-2.0
# 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,

View File

@@ -0,0 +1,34 @@
/**
* Copyright 2020 Google LLC
*
* 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.
*/
module "test" {
source = "../../../../modules/compute-vm"
project_id = "my-project"
region = "europe-west1"
zone = "europe-west1-b"
name = "test"
network_interfaces = [{
network = "https://www.googleapis.com/compute/v1/projects/my-project/global/networks/default",
subnetwork = "https://www.googleapis.com/compute/v1/projects/my-project/regions/europe-west1/subnetworks/default-default",
nat = false,
addresses = null
}]
service_account_create = var.service_account_create
instance_count = var.instance_count
use_instance_template = var.use_instance_template
group = var.group
group_manager = var.group_manager
}

View File

@@ -0,0 +1,40 @@
/**
* Copyright 2020 Google LLC
*
* 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.
*/
variable "group" {
type = any
default = null
}
variable "group_manager" {
type = any
default = null
}
variable "instance_count" {
type = number
default = 1
}
variable "use_instance_template" {
type = bool
default = false
}
variable "service_account_create" {
type = bool
default = false
}

View File

@@ -0,0 +1,46 @@
# Copyright 2020 Google LLC
#
# 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.
import os
import pytest
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
def test_single_instance(plan_runner):
plan, resources = plan_runner(FIXTURES_DIR)
assert len(resources) == 1
assert resources[0]['type'] == 'google_compute_instance'
def test_multiple_instances(plan_runner):
plan, resources = plan_runner(FIXTURES_DIR, instance_count=2)
assert len(resources) == 2
assert set(r['type'] for r in resources) == set(['google_compute_instance'])
def test_service_account(plan_runner):
plan, resources = plan_runner(FIXTURES_DIR, instance_count=2,
service_account_create='true')
assert len(resources) == 3
assert 'google_service_account' in [r['type'] for r in resources]
def test_template(plan_runner):
plan, resources = plan_runner(FIXTURES_DIR, use_instance_template='true')
assert len(resources) == 1
assert resources[0]['type'] == 'google_compute_instance_template'
assert resources[0]['values']['name_prefix'] == 'test-'

View File

@@ -0,0 +1,44 @@
# Copyright 2020 Google LLC
#
# 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.
import os
import pytest
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
def test_unmanaged(plan_runner):
plan, resources = plan_runner(FIXTURES_DIR, instance_count=2,
group='{named_ports={}}')
assert len(resources) == 3
assert set(r['type'] for r in resources) == set([
'google_compute_instance_group', 'google_compute_instance'
])
def test_managed(plan_runner):
plan, resources = plan_runner(
FIXTURES_DIR, use_instance_template='true', group_manager=(
'{ '
'auto_healing_policies=null, named_ports={}, options=null, '
'regional=false, target_size=1, update_policy=null, versions=null'
' }'
)
)
assert len(resources) == 2
assert set(r['type'] for r in resources) == set([
'google_compute_instance_group_manager', 'google_compute_instance_template'
])

View File

@@ -1,10 +1,10 @@
# Copyright 2019 Google LLC
# Copyright 2020 Google LLC
#
# 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
#
# https://www.apache.org/licenses/LICENSE-2.0
# 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,

View File

@@ -0,0 +1,24 @@
/**
* Copyright 2020 Google LLC
*
* 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.
*/
module "test" {
source = "../../../../modules/cos-container/coredns"
cloud_config = var.cloud_config
config_variables = var.config_variables
coredns_config = var.coredns_config
file_defaults = var.file_defaults
files = var.files
}

View File

@@ -0,0 +1,19 @@
/**
* Copyright 2020 Google LLC
*
* 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.
*/
output "cloud_config" {
value = module.test.cloud_config
}

View File

@@ -0,0 +1,50 @@
/**
* Copyright 2019 Google LLC
*
* 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.
*/
variable "cloud_config" {
type = string
default = null
}
variable "config_variables" {
type = map(any)
default = {}
}
variable "coredns_config" {
type = string
default = null
}
variable "file_defaults" {
type = object({
owner = string
permissions = string
})
default = {
owner = "root"
permissions = "0644"
}
}
variable "files" {
type = map(object({
content = string
owner = string
permissions = string
}))
default = {}
}

View File

@@ -0,0 +1,34 @@
# Copyright 2020 Google LLC
#
# 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.
import os
import pytest
import re
import yaml
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
def test_defaults(apply_runner):
"Test defalt configuration."
_, output = apply_runner(FIXTURES_DIR)
cloud_config = output['cloud_config']
yaml.safe_load(cloud_config)
assert cloud_config.startswith('#cloud-config')
assert re.findall(r'(?m)^\s+\-\s*path:\s*(\S+)', cloud_config) == [
'/var/lib/docker/daemon.json', '/etc/systemd/resolved.conf',
'/etc/coredns/Corefile', '/etc/systemd/system/coredns.service'
]

View File

@@ -1,10 +1,10 @@
# Copyright 2019 Google LLC
# Copyright 2020 Google LLC
#
# 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
#
# https://www.apache.org/licenses/LICENSE-2.0
# 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,

View File

@@ -0,0 +1,26 @@
/**
* Copyright 2020 Google LLC
*
* 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.
*/
module "test" {
source = "../../../../modules/cos-container/mysql"
cloud_config = var.cloud_config
config_variables = var.config_variables
image = var.image
kms_config = var.kms_config
mysql_config = var.mysql_config
mysql_data_disk = var.mysql_data_disk
mysql_password = var.mysql_password
}

View File

@@ -0,0 +1,19 @@
/**
* Copyright 2020 Google LLC
*
* 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.
*/
output "cloud_config" {
value = module.test.cloud_config
}

View File

@@ -0,0 +1,54 @@
/**
* Copyright 2019 Google LLC
*
* 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.
*/
variable "cloud_config" {
type = string
default = null
}
variable "config_variables" {
type = map(any)
default = {}
}
variable "image" {
type = string
default = "mysql:5.7"
}
variable "kms_config" {
type = object({
project_id = string
keyring = string
location = string
key = string
})
default = null
}
variable "mysql_config" {
type = string
default = null
}
variable "mysql_data_disk" {
type = string
default = null
}
variable "mysql_password" {
type = string
}

View File

@@ -0,0 +1,55 @@
# Copyright 2020 Google LLC
#
# 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.
import os
import pytest
import re
import yaml
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
def test_defaults(apply_runner):
"Test defalt configuration."
_, output = apply_runner(FIXTURES_DIR, mysql_password='foo')
cloud_config = output['cloud_config']
yaml.safe_load(cloud_config)
assert cloud_config.startswith('#cloud-config')
assert re.findall(r'(?m)^\s+\-\s*path:\s*(\S+)', cloud_config) == [
'/var/lib/docker/daemon.json',
'/run/mysql/secrets/mysql-passwd.txt',
'/etc/systemd/system/mysql.service'
]
assert 'gcloud' not in cloud_config
def test_kms(apply_runner):
"Test KMS configuration."
kms_config = (
'{project_id="my-project", keyring="my-keyring", location="eu", key="foo"}'
)
_, output = apply_runner(
FIXTURES_DIR, mysql_password='foo', kms_config=kms_config)
cloud_config = output['cloud_config']
yaml.safe_load(cloud_config)
assert cloud_config.startswith('#cloud-config')
assert re.findall(r'(?m)^\s+\-\s*path:\s*(\S+)', cloud_config) == [
'/var/lib/docker/daemon.json',
'/run/mysql/secrets/mysql-passwd-cipher.txt',
'/run/mysql/passwd.sh',
'/etc/systemd/system/mysql.service'
]
assert 'gcloud' in cloud_config

View File

@@ -1,10 +1,10 @@
# Copyright 2019 Google LLC
#
# Copyright 2020 Google LLC
#
# 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
#
# https://www.apache.org/licenses/LICENSE-2.0
# 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,

View File

@@ -0,0 +1,29 @@
/**
* Copyright 2020 Google LLC
*
* 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.
*/
module "test" {
source = "../../../../modules/dns"
project_id = "my-project"
name = "test"
domain = "test.example."
client_networks = [
"https://www.googleapis.com/compute/v1/projects/my-project/global/networks/default"
]
type = var.type
forwarders = var.forwarders
peer_network = var.peer_network
recordsets = var.recordsets
}

View File

@@ -0,0 +1,43 @@
/**
* Copyright 2020 Google LLC
*
* 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.
*/
variable "forwarders" {
type = list(string)
default = null
}
variable "peer_network" {
type = string
default = null
}
variable "recordsets" {
type = list(object({
name = string
type = string
ttl = number
records = list(string)
}))
default = [
{ name = "localhost", type = "A", ttl = 300, records = ["127.0.0.1"] },
{ name = "local-host", type = "A", ttl = 300, records = ["127.0.0.2"] }
]
}
variable "type" {
type = string
default = "private"
}

View File

@@ -0,0 +1,80 @@
# Copyright 2020 Google LLC
#
# 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.
import os
import pytest
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
def test_private(plan_runner):
"Test private zone with two recordsets."
_, resources = plan_runner(FIXTURES_DIR)
assert len(resources) == 3
assert set(r['type'] for r in resources) == set([
'google_dns_record_set', 'google_dns_managed_zone'
])
for r in resources:
if r['type'] != 'google_dns_managed_zone':
continue
assert r['values']['visibility'] == 'private'
assert len(r['values']['private_visibility_config']) == 1
def test_forwarding_recordsets_null_forwarders(plan_runner):
"Test forwarding zone with wrong set of attributes does not break."
_, resources = plan_runner(FIXTURES_DIR, type='forwarding')
assert len(resources) == 1
resource = resources[0]
assert resource['type'] == 'google_dns_managed_zone'
assert resource['values']['forwarding_config'] == []
def test_forwarding(plan_runner):
"Test forwarding zone with single forwarder."
_, resources = plan_runner(
FIXTURES_DIR, type='forwarding', recordsets='null',
forwarders='["dummy-vpc-self-link"]')
assert len(resources) == 1
resource = resources[0]
assert resource['type'] == 'google_dns_managed_zone'
assert resource['values']['forwarding_config'] == [{'target_name_servers': [
{'forwarding_path': '', 'ipv4_address': 'dummy-vpc-self-link'}]}]
def test_peering(plan_runner):
"Test peering zone."
_, resources = plan_runner(FIXTURES_DIR, type='peering',
recordsets='null', peer_network='dummy-vpc-self-link')
assert len(resources) == 1
resource = resources[0]
assert resource['type'] == 'google_dns_managed_zone'
assert resource['values']['peering_config'] == [
{'target_network': [{'network_url': 'dummy-vpc-self-link'}]}]
def test_public(plan_runner):
"Test public zone with two recordsets."
_, resources = plan_runner(FIXTURES_DIR, type='public')
assert len(resources) == 3
assert set(r['type'] for r in resources) == set([
'google_dns_record_set', 'google_dns_managed_zone'
])
for r in resources:
if r['type'] != 'google_dns_managed_zone':
continue
assert r['values']['visibility'] == 'public'
assert r['values']['private_visibility_config'] == []

View File

@@ -0,0 +1,13 @@
# Copyright 2020 Google LLC
#
# 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.

View File

@@ -0,0 +1,23 @@
/**
* Copyright 2020 Google LLC
*
* 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.
*/
module "test" {
source = "../../../../modules/folders"
parent = "organizations/12345678"
names = ["folder-a", "folder-b"]
iam_members = var.iam_members
iam_roles = var.iam_roles
}

View File

@@ -0,0 +1,25 @@
/**
* Copyright 2020 Google LLC
*
* 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.
*/
variable "iam_members" {
type = map(map(list(string)))
default = null
}
variable "iam_roles" {
type = map(list(string))
default = null
}

View File

@@ -0,0 +1,49 @@
# Copyright 2020 Google LLC
#
# 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.
import os
import pytest
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
def test_folder(plan_runner):
"Test folder resources."
_, resources = plan_runner(FIXTURES_DIR)
assert len(resources) == 2
assert set(r['type'] for r in resources) == set(['google_folder'])
assert set(r['values']['display_name'] for r in resources) == set([
'folder-a', 'folder-b'
])
assert set(r['values']['parent'] for r in resources) == set([
'organizations/12345678'
])
def test_iam_roles_only(plan_runner):
"Test folder resources with only iam roles passed."
_, resources = plan_runner(
FIXTURES_DIR, iam_roles='{folder-a = [ "roles/owner"]}')
assert len(resources) == 3
def test_iam(plan_runner):
"Test folder resources with iam roles and members."
iam_roles = '{folder-a = ["roles/owner"], folder-b = ["roles/viewer"]}'
iam_members = '{folder-a = { "roles/owner" = ["user:a@b.com"] }}'
_, resources = plan_runner(
FIXTURES_DIR, iam_roles=iam_roles, iam_members=iam_members)
assert len(resources) == 4

View File

@@ -0,0 +1,13 @@
# Copyright 2020 Google LLC
#
# 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.

View File

@@ -0,0 +1,28 @@
/**
* Copyright 2020 Google LLC
*
* 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.
*/
module "test" {
source = "../../../../modules/gcs"
project_id = "my-project"
names = ["bucket-a", "bucket-b"]
prefix = var.prefix
iam_members = var.iam_members
iam_roles = var.iam_roles
labels = var.labels
bucket_policy_only = var.bucket_policy_only
force_destroy = var.force_destroy
versioning = var.versioning
}

View File

@@ -0,0 +1,55 @@
/**
* Copyright 2020 Google LLC
*
* 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.
*/
variable "bucket_policy_only" {
type = map(bool)
default = { bucket-a = false }
}
variable "force_destroy" {
type = map(bool)
default = { bucket-a = true }
}
variable "iam_members" {
type = map(map(list(string)))
default = null
}
variable "iam_roles" {
type = map(list(string))
default = null
}
variable "labels" {
type = map(string)
default = { environment = "test" }
}
variable "prefix" {
type = string
default = ""
}
variable "storage_class" {
type = string
default = "MULTI_REGIONAL"
}
variable "versioning" {
type = map(bool)
default = { bucket-a = true }
}

View File

@@ -0,0 +1,81 @@
# Copyright 2020 Google LLC
#
# 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.
import os
import pytest
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
def test_buckets(plan_runner):
"Test bucket resources."
_, resources = plan_runner(FIXTURES_DIR)
assert len(resources) == 2
assert set(r['type'] for r in resources) == set(['google_storage_bucket'])
assert set(r['values']['name'] for r in resources) == set([
'bucket-a', 'bucket-b'
])
assert set(r['values']['project'] for r in resources) == set([
'my-project'
])
def test_prefix(plan_runner):
"Test bucket name when prefix is set."
_, resources = plan_runner(FIXTURES_DIR, prefix='foo')
assert set(r['values']['name'] for r in resources) == set([
'foo-eu-bucket-a', 'foo-eu-bucket-b'
])
def test_map_values(plan_runner):
"Test that map values set the correct attributes on buckets."
_, resources = plan_runner(FIXTURES_DIR)
bpo = dict((r['values']['name'], r['values']['bucket_policy_only'])
for r in resources)
assert bpo == {'bucket-a': False, 'bucket-b': True}
force_destroy = dict((r['values']['name'], r['values']['force_destroy'])
for r in resources)
assert force_destroy == {'bucket-a': True, 'bucket-b': False}
versioning = dict((r['values']['name'], r['values']['versioning'])
for r in resources)
assert versioning == {
'bucket-a': [{'enabled': True}], 'bucket-b': [{'enabled': False}]
}
for r in resources:
assert r['values']['labels'] == {
'environment': 'test', 'location': 'eu',
'storage_class': 'multi_regional', 'name': r['values']['name']
}
def test_iam_roles_only(plan_runner):
"Test bucket resources with only iam roles passed."
_, resources = plan_runner(
FIXTURES_DIR, iam_roles='{bucket-a = [ "roles/storage.admin"]}')
assert len(resources) == 3
def test_iam(plan_runner):
"Test bucket resources with iam roles and members."
iam_roles = (
'{bucket-a = ["roles/storage.admin"], '
'bucket-b = ["roles/storage.objectAdmin"]}'
)
iam_members = '{folder-a = { "roles/storage.admin" = ["user:a@b.com"] }}'
_, resources = plan_runner(
FIXTURES_DIR, iam_roles=iam_roles, iam_members=iam_members)
assert len(resources) == 4

View File

@@ -0,0 +1,13 @@
# Copyright 2020 Google LLC
#
# 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.

View File

@@ -0,0 +1,34 @@
/**
* Copyright 2020 Google LLC
*
* 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.
*/
module "test" {
source = "../../../../modules/net-vpc"
project_id = var.project_id
name = var.name
iam_members = var.iam_members
iam_roles = var.iam_roles
log_configs = var.log_configs
log_config_defaults = var.log_config_defaults
peering_config = var.peering_config
routes = var.routes
shared_vpc_host = var.shared_vpc_host
shared_vpc_service_projects = var.shared_vpc_service_projects
subnets = var.subnets
subnet_descriptions = var.subnet_descriptions
subnet_flow_logs = var.subnet_flow_logs
subnet_private_access = var.subnet_private_access
auto_create_subnetworks = var.auto_create_subnetworks
}

View File

@@ -0,0 +1,124 @@
/**
* Copyright 2020 Google LLC
*
* 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.
*/
variable "project_id" {
type = string
default = "my-project"
}
variable "name" {
type = string
default = "my-vpc"
}
variable "auto_create_subnetworks" {
type = bool
default = false
}
variable "iam_roles" {
type = map(list(string))
default = null
}
variable "iam_members" {
type = map(map(list(string)))
default = null
}
variable "log_configs" {
type = map(map(string))
default = null
}
variable "log_config_defaults" {
type = object({
aggregation_interval = string
flow_sampling = number
metadata = string
})
default = {
aggregation_interval = "INTERVAL_5_SEC"
flow_sampling = 0.5
metadata = "INCLUDE_ALL_METADATA"
}
}
variable "peering_config" {
type = object({
peer_vpc_self_link = string
export_routes = bool
import_routes = bool
})
default = null
}
variable "routes" {
type = map(object({
dest_range = string
priority = number
tags = list(string)
next_hop_type = string # gateway, instance, ip, vpn_tunnel, ilb
next_hop = string
}))
default = null
}
variable "routing_mode" {
description = "The network routing mode (default 'GLOBAL')"
type = string
default = "GLOBAL"
}
variable "shared_vpc_host" {
description = "Enable shared VPC for this project."
type = bool
default = false
}
variable "shared_vpc_service_projects" {
description = "Shared VPC service projects to register with this host"
type = list(string)
default = []
}
variable "subnets" {
description = "The list of subnets being created"
type = map(object({
ip_cidr_range = string
region = string
secondary_ip_range = map(string)
}))
default = null
}
variable "subnet_descriptions" {
description = "Optional map of subnet descriptions, keyed by subnet name."
type = map(string)
default = {}
}
variable "subnet_flow_logs" {
description = "Optional map of boolean to control flow logs (default is disabled), keyed by subnet name."
type = map(bool)
default = {}
}
variable "subnet_private_access" {
description = "Optional map of boolean to control private Google access (default is enabled), keyed by subnet name."
type = map(bool)
default = {}
}

View File

@@ -0,0 +1,90 @@
# Copyright 2020 Google LLC
#
# 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.
import os
import pytest
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
_VAR_PEER_VPC_CONFIG = (
'{'
'peer_vpc_self_link="projects/my-project/global/networks/my-peer-vpc", '
'export_routes=true, import_routes=null'
'}'
)
_VAR_ROUTES_TEMPLATE = (
'{'
' next-hop-test = {'
' dest_range="192.168.128.0/24", priority=1000, tags=null, '
' next_hop_type="%s", next_hop="%s"},'
' gateway-test = {'
' dest_range="0.0.0.0/0", priority=100, tags=["tag-a"], '
' next_hop_type="gateway", '
' next_hop="global/gateways/default-internet-gateway"}'
'}'
)
_VAR_ROUTES_NEXT_HOPS = {
'gateway': 'global/gateways/default-internet-gateway',
'instance': 'zones/europe-west1-b/test',
'ip': '192.168.0.128',
'ilb': 'regions/europe-west1/forwardingRules/test',
'vpn_tunnel': 'regions/europe-west1/vpnTunnels/foo'
}
def test_vpc_simple(plan_runner):
"Test vpc with no extra options."
_, resources = plan_runner(FIXTURES_DIR)
assert len(resources) == 1
assert [r['type'] for r in resources] == ['google_compute_network']
assert [r['values']['name'] for r in resources] == ['my-vpc']
assert [r['values']['project'] for r in resources] == ['my-project']
def test_vpc_shared(plan_runner):
"Test shared vpc variables."
_, resources = plan_runner(FIXTURES_DIR, shared_vpc_host='true',
shared_vpc_service_projects='["tf-a", "tf-b"]')
assert len(resources) == 4
assert set(r['type'] for r in resources) == set([
'google_compute_network', 'google_compute_shared_vpc_host_project',
'google_compute_shared_vpc_service_project'
])
def test_vpc_peering(plan_runner):
"Test vpc peering variables."
_, resources = plan_runner(FIXTURES_DIR, peering_config=_VAR_PEER_VPC_CONFIG)
assert len(resources) == 3
assert set(r['type'] for r in resources) == set([
'google_compute_network', 'google_compute_network_peering'
])
peerings = [r['values']
for r in resources if r['type'] == 'google_compute_network_peering']
assert [p['name'] for p in peerings] == [
'my-vpc-my-peer-vpc', 'my-peer-vpc-my-vpc']
assert [p['export_custom_routes'] for p in peerings] == [True, False]
assert [p['import_custom_routes'] for p in peerings] == [False, True]
def test_vpc_routes(plan_runner):
"Test vpc routes."
for next_hop_type, next_hop in _VAR_ROUTES_NEXT_HOPS.items():
_var_routes = _VAR_ROUTES_TEMPLATE % (next_hop_type, next_hop)
_, resources = plan_runner(FIXTURES_DIR, routes=_var_routes)
assert len(resources) == 3
resource = [r for r in resources if r['values']
['name'] == 'next-hop-test'][0]
assert resource['values']['next_hop_%s' % next_hop_type]

View File

@@ -0,0 +1,79 @@
# Copyright 2020 Google LLC
#
# 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.
import os
import pytest
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
_VAR_SUBNETS = (
'{ '
'a={region = "europe-west1", ip_cidr_range = "10.0.0.0/24",'
' secondary_ip_range=null},'
'b={region = "europe-west1", ip_cidr_range = "10.0.1.0/24",'
' secondary_ip_range=null},'
'c={region = "europe-west1", ip_cidr_range = "10.0.2.0/24",'
' secondary_ip_range={a="192.168.0.0/24", b="192.168.1.0/24"}},'
'}'
)
_VAR_LOG_CONFIG = '{a = { flow_sampling = 0.1 }}'
_VAR_LOG_CONFIG_DEFAULTS = (
'{'
'aggregation_interval = "INTERVAL_10_MIN", '
'flow_sampling = 0.5, '
'metadata = "INCLUDE_ALL_METADATA"'
'}'
)
def test_subnets_simple(plan_runner):
"Test subnets variable."
_, resources = plan_runner(FIXTURES_DIR, subnets=_VAR_SUBNETS)
assert len(resources) == 4
subnets = [r['values']
for r in resources if r['type'] == 'google_compute_subnetwork']
assert set(s['name'] for s in subnets) == set(
['my-vpc-a', 'my-vpc-b', 'my-vpc-c'])
assert set(len(s['secondary_ip_range']) for s in subnets) == set([0, 0, 2])
def test_subnet_log_configs(plan_runner):
"Test subnets flow logs configuration and defaults."
_, resources = plan_runner(FIXTURES_DIR, subnets=_VAR_SUBNETS,
log_configs=_VAR_LOG_CONFIG,
log_config_defaults=_VAR_LOG_CONFIG_DEFAULTS,
subnet_flow_logs='{a=true, b=true}')
assert len(resources) == 4
flow_logs = {}
for r in resources:
if r['type'] != 'google_compute_subnetwork':
continue
flow_logs[r['values']['name']] = r['values']['log_config']
assert flow_logs == {
# enable, override one default option
'my-vpc-a': [{
'aggregation_interval': 'INTERVAL_10_MIN',
'flow_sampling': 0.1,
'metadata': 'INCLUDE_ALL_METADATA'
}],
# enable, use defaults
'my-vpc-b': [{
'aggregation_interval': 'INTERVAL_10_MIN',
'flow_sampling': 0.5,
'metadata': 'INCLUDE_ALL_METADATA'
}],
# don't enable
'my-vpc-c': []
}

View File

@@ -0,0 +1,13 @@
# Copyright 2020 Google LLC
#
# 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.

View File

@@ -0,0 +1,35 @@
/**
* Copyright 2020 Google LLC
*
* 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.
*/
module "test" {
source = "../../../../modules/project"
name = "my-project"
billing_account = "12345-12345-12345"
auto_create_network = var.auto_create_network
custom_roles = var.custom_roles
iam_members = var.iam_members
iam_roles = var.iam_roles
iam_additive_members = var.iam_additive_members
iam_additive_roles = var.iam_additive_roles
labels = var.labels
lien_reason = var.lien_reason
oslogin = var.oslogin
oslogin_admins = var.oslogin_admins
oslogin_users = var.oslogin_users
parent = var.parent
prefix = var.prefix
services = var.services
}

View File

@@ -0,0 +1,85 @@
/**
* Copyright 2020 Google LLC
*
* 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.
*/
variable "auto_create_network" {
type = bool
default = false
}
variable "custom_roles" {
type = map(list(string))
default = {}
}
variable "iam_members" {
type = map(list(string))
default = {}
}
variable "iam_roles" {
type = list(string)
default = []
}
variable "iam_additive_members" {
type = map(list(string))
default = {}
}
variable "iam_additive_roles" {
type = list(string)
default = []
}
variable "labels" {
type = map(string)
default = {}
}
variable "lien_reason" {
type = string
default = ""
}
variable "oslogin" {
type = bool
default = false
}
variable "oslogin_admins" {
type = list(string)
default = []
}
variable "oslogin_users" {
type = list(string)
default = []
}
variable "parent" {
type = string
default = "folders/12345678"
}
variable "prefix" {
type = string
default = null
}
variable "services" {
type = list(string)
default = []
}

View File

@@ -0,0 +1,42 @@
# Copyright 2020 Google LLC
#
# 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.
import os
import pytest
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
def test_prefix(plan_runner):
"Test project id prefix."
_, resources = plan_runner(FIXTURES_DIR)
assert len(resources) == 1
assert resources[0]['values']['name'] == 'my-project'
_, resources = plan_runner(FIXTURES_DIR, prefix='foo')
assert len(resources) == 1
assert resources[0]['values']['name'] == 'foo-my-project'
def test_parent(plan_runner):
"Test project parent."
_, resources = plan_runner(FIXTURES_DIR)
assert len(resources) == 1
assert resources[0]['values']['folder_id'] == '12345678'
assert resources[0]['values'].get('org_id') == None
_, resources = plan_runner(FIXTURES_DIR, parent='organizations/12345678')
assert len(resources) == 1
assert resources[0]['values']['org_id'] == '12345678'
assert resources[0]['values'].get('folder_id') == None

View File

@@ -1,3 +1,3 @@
pytest>=4.3.1
pytest-tldr>=0.2.1
tftest>=1.2.0
pytest>=4.6.0
PyYAML>=5.3
tftest>=1.5.0