Пример #1
0
def render(stackvars):

    # Terraform configuration.
    Terraform(required_version=stackvars.get("config.terraform.version"))

    # Backend configuration.
    Terraform(
        dict(backend=dict(gcs=dict(
            bucket=stackvars.get("config.terraform.backend.gcp.bucket"),
            prefix=stackvars.stack,
            credentials=stackvars.get("config.gcp.credentials"),
        ))))

    # Providers.
    Provider("google", **stackvars.get("config.gcp"))

    # Modules.

    # Resources.
    cluster = Resource(
        "google_container_cluster",
        "cluster",
        name="project-" + stackvars.environment,
        location=stackvars.get("config.gcp.region"),
        # The API requires a node pool or an initial count to be defined; that initial
        # count creates the "default node pool" with that # of nodes. So, we need to set
        # an initial_node_count of 1. This will make a default node pool with
        # server-defined defaults that Terraform will immediately delete as part of
        # Create. This leaves us in our desired state- with a cluster master with no
        # node pools.
        remove_default_node_pool=True,
        initial_node_count=1,
    )
    Resource(
        "google_container_node_pool",
        "preemptible_nodes",
        name="preemptible-node-pool",
        location=stackvars.get("config.gcp.region"),
        cluster=cluster.name,
        # `node_count` represents the number of nodes PER ZONE.
        node_count=1,
        node_config=dict(
            preemptible=True,
            machine_type="n1-standard-1",
            oauth_scopes=[
                "https://www.googleapis.com/auth/logging.write",
                "https://www.googleapis.com/auth/monitoring",
            ],
        ),
        # `node_count` represents the number of nodes PER ZONE.
        autoscaling=dict(
            min_node_count=1,
            max_node_count=3,
        ),
        management=dict(
            auto_repair=True,
            auto_upgrade=True,
        ),
    )
Пример #2
0
def test_interpolated():
    foo = Resource('aws_security_group', 'sg', name='sg')

    assert foo.name == 'sg'
    assert foo.interpolated('name') == '${aws_security_group.sg.name}'

    # call .name again to ensure ._frozen is reset correctly and we can still mutate the original
    assert foo.name == 'sg'
Пример #3
0
def test_interpolated():
    foo = Resource("aws_security_group", "sg", name="sg")

    assert foo.name == "sg"
    assert foo.interpolated("name") == "${aws_security_group.sg.name}"

    # call .name again to ensure ._frozen is reset correctly and we can still mutate the original
    assert foo.name == "sg"
Пример #4
0
def test_setattr():
    res1 = Resource('res1', 'foo', attr='value')

    assert res1.attr == "value"
    assert res1._values['attr'] == "value"

    res1.not_tf_attr = "value"
    assert res1.not_tf_attr == "value"
    assert 'not_tf_attr' not in res1._values
Пример #5
0
def test_setattr():
    res1 = Resource("res1", "foo", attr="value")

    assert res1.attr == "value"
    assert res1._values["attr"] == "value"

    res1.not_tf_attr = "value"
    assert res1.not_tf_attr == "value"
    assert "not_tf_attr" not in res1._values
Пример #6
0
def test_compile():
    TFObject.reset()

    Resource("res1", "foo", attr="value")
    Resource("res1", "bar", attr="other")
    Variable("var1", default="value")

    assert TFObject.compile() == {
        "resource": {"res1": {"foo": {"attr": "value",}, "bar": {"attr": "other",}},},
        "variable": {"var1": {"default": "value"}},
    }
Пример #7
0
def test_object_instances():
    res = Resource("res1", "foo", attr="value")
    var = Variable("var1", default="foo")

    assert TFObject._instances is None
    assert Resource._instances == [res]
    assert Variable._instances == [var]
Пример #8
0
def test_object_instances():
    res = Resource('res1', 'foo', attr='value')
    var = Variable('var1', default='foo')

    assert TFObject._instances is None
    assert Resource._instances == [res]
    assert Variable._instances == [var]
 def create_backend_service(self):
     self.backend_service_name = self.name + "-backend-service"
     self.backend_service = Resource(
         "google_compute_backend_service",
         self.backend_service_name,
         name=self.backend_service_name,
         health_checks=[self.health_check],
         backend={"group": self.managed_instance_group})
Пример #10
0
def test_getattr():
    res1 = Resource("res1", "foo", attr="value")
    assert res1.id == "${res1.foo.id}"

    var1 = Variable("var1", default="value")
    assert "{0}".format(var1) == "${var.var1}"
    with pytest.raises(AttributeError):
        assert var1.id, "nope!  vars do not have attrs!"
Пример #11
0
def test_explicit_provider():
    # When a resource is given an explicit provider argument it should take precendence
    # Even if we're in a provider resource block
    p1 = Provider("aws", region="us-west-2", alias="west2")
    with Provider("aws", region="us-east-1", alias="east1"):
        sg1 = Resource("aws_security_group",
                       "sg",
                       ingress=["foo"],
                       provider=p1.as_provider())
        sg2 = Resource("aws_security_group", "sg", ingress=["foo"])

        with Provider("aws", region="eu-west-2", alias="london"):
            sg3 = Resource("aws_security_group", "sg", ingress=["foo"])

    assert sg1.provider == "aws.west2"
    assert sg2.provider == "aws.east1"
    assert sg3.provider == "aws.london"
Пример #12
0
def test_getattr():
    res1 = Resource('res1', 'foo', attr='value')
    assert res1.id == '${res1.foo.id}'

    var1 = Variable('var1', default='value')
    assert '{0}'.format(var1) == '${var.var1}'
    with pytest.raises(AttributeError):
        assert var1.id, 'nope!  vars do not have attrs!'
Пример #13
0
def test_access_before_compile():
    sg = Resource('aws_security_group', 'sg', ingress=['foo'])

    assert sg.id == '${aws_security_group.sg.id}'
    assert sg.ingress == ['foo']

    TFObject._frozen = True

    assert sg.ingress == '${aws_security_group.sg.ingress}'
Пример #14
0
def test_access_before_compile():
    sg = Resource("aws_security_group", "sg", ingress=["foo"])

    assert sg.id == "${aws_security_group.sg.id}"
    assert sg.ingress == ["foo"]

    TFObject._frozen = True

    assert sg.ingress == "${aws_security_group.sg.ingress}"
Пример #15
0
def test_equality():
    # NamedObject
    p1 = Provider("mysql", host="db")
    p2 = Provider("mysql", host="db")
    v1 = Variable("mysql", host="db")
    assert p1 == p2
    assert p1 != v1

    # TypedObject
    r1 = Resource("aws_security_group", "sg", name="sg")
    r2 = Resource("aws_security_group", "sg", name="sg")
    d1 = Data("aws_security_group", "sg", name="sg")
    assert r1 == r2
    assert r1 != d1

    # Invalid comparisons
    assert r1 != "string"
    assert r1 != 0
Пример #16
0
 def create_frontend_service(self):
     self.frontend_service_name = self.name + "-frontend-service"
     self.frontend_service = Resource(
         "google_compute_global_forwarding_rule",
         self.frontend_service_name,
         name=self.frontend_service_name,
         target=self.http_proxy.self_link,
         port_range="8080",
         load_balancing_scheme="EXTERNAL",
         ip_address=self.global_ip_address.address)
Пример #17
0
def test_object_variants():
    with Variant('foo', default='value'):
        sg = Resource('aws_security_group',
                      'sg',
                      foo_variant=dict(ingress=['foo']),
                      bar_variant=dict(ingress=['bar']))

        assert sg.ingress == ['foo']

        # objects do not pickup defaults from variants
        assert sg.default != 'value'
Пример #18
0
 def create_managed_instance_group(self):
     self.managed_instance_group_name = self.instance_template + "-group"
     self.managed_instance_group = Resource(
         "google_compute_instance_group_manager",
         self.managed_instance_group_name,
         name=self.managed_instance_group_name,
         base_instance_name=self.instance_template.name,
         zone=self.zone,
         version={
             "instance_template": self.instance_template.self_link,
             "initial_delay_sec": 180
         })
Пример #19
0
def test_typed_object_hooks(mocker):
    """Ensure that our hooks work as expected and can modify resource data during compilation"""
    TFObject.reset()

    def attr_always_true(object_id, object_attrs):
        """attr_always_true is a contrived hook that ensures `attr` of `some_type` resources is always True"""
        object_attrs = object_attrs.copy()
        for attr_name in object_attrs:
            if attr_name == "attr":
                object_attrs[attr_name] = True
        return object_attrs

    # Make our hook a mock so we can assert on calls
    mock_hook = mocker.MagicMock(side_effect=attr_always_true)

    # Add the hook for resources
    Resource.add_hook("some_type", mock_hook)

    Resource("some_type", "some_id", attr=True)
    Resource("some_type", "other_id", attr=False)

    compiled = TFObject.compile()

    assert mock_hook.mock_calls == [
        mocker.call("some_id", {"attr": True}),
        mocker.call("other_id", {"attr": False}),
    ]

    assert compiled == {
        "resource": {
            "some_type": {
                "some_id": {
                    "attr": True,
                },
                "other_id": {
                    "attr": True,
                },
            }
        }
    }
Пример #20
0
 def create_health_check(self):
     self.health_check_name = self.instance_template + "-health-check"
     self.health_check = Resource("google_compute_health_check",
                                  self.health_check_name,
                                  name=self.health_check_name,
                                  check_interval_sec=10,
                                  timeout_sec=10,
                                  healthy_threshold=3,
                                  unhealthy_threshold=3,
                                  http_health_check={
                                      "request_path": "/api/v1/healthcheck",
                                      "port": 8080
                                  })
Пример #21
0
def test_provider_context():
    with Provider("aws", region="us-east-1", alias="east1"):
        sg1 = Resource("aws_security_group", "sg", ingress=["foo"])

        # Since thing1 is not an aws_ resource it will not get the provider by default
        thing1 = Resource("some_thing", "foo", bar="baz")

        # var1 is not a typedobject so it will not get a provider either
        var1 = Variable("var1", default="foo")

        with Provider("aws", region="us-west-2", alias="west2"):
            sg2 = Resource("aws_security_group", "sg", ingress=["foo"])

    assert sg1.provider == "aws.east1"
    assert sg2.provider == "aws.west2"

    # thing1's provider is the default interpolation string
    assert thing1.provider == "${some_thing.foo.provider}"

    # var1 will raise a AttributeError
    with pytest.raises(AttributeError):
        assert var1.provider
Пример #22
0
def test_object_variants():
    with Variant("foo", default="value"):
        sg = Resource(
            "aws_security_group",
            "sg",
            foo_variant=dict(ingress=["foo"]),
            bar_variant=dict(ingress=["bar"]),
        )

        assert sg.ingress == ["foo"]

        # objects do not pickup defaults from variants
        assert sg.default != "value"
Пример #23
0
def test_provider_context():
    with Provider("aws", region="us-east-1", alias="east1"):
        sg1 = Resource('aws_security_group', 'sg', ingress=['foo'])

        # Since thing1 is not an aws_ resource it will not get the provider by default
        thing1 = Resource('some_thing', 'foo', bar='baz')

        # var1 is not a typedobject so it will not get a provider either
        var1 = Variable('var1', default='foo')

        with Provider("aws", region="us-west-2", alias="west2"):
            sg2 = Resource('aws_security_group', 'sg', ingress=['foo'])

    assert sg1.provider == 'aws.east1'
    assert sg2.provider == 'aws.west2'

    # thing1's provider is the default interpolation string
    assert thing1.provider == '${some_thing.foo.provider}'

    # var1 will raise a AttributeError
    with pytest.raises(AttributeError):
        assert var1.provider
Пример #24
0
 def create_autoscaler(self):
     self.autoscaler_name = self.instance_template + "-autoscaler"
     self.autoscaler = Resource("google_compute_autoscaler",
                                self.autoscaler_name,
                                name=self.autoscaler_name,
                                zone=self.zone,
                                target=self.managed_instance_group.id,
                                autoscaling_policy={
                                    "max_replicas": 5,
                                    "min_replicas": 2,
                                    "cooldown_period": 60,
                                    "cpu_utilization": {
                                        "target": 0.75
                                    }
                                })
Пример #25
0
def test_compile():
    TFObject.reset()

    Resource('res1', 'foo', attr='value')
    Resource('res1', 'bar', attr='other')
    Variable('var1', default='value')

    assert TFObject.compile() == {
        'resource': {
            'res1': {
                'foo': {
                    'attr': 'value',
                },
                'bar': {
                    'attr': 'other',
                }
            },
        },
        'variable': {
            'var1': {
                'default': 'value'
            }
        }
    }
Пример #26
0
 def create_resources(self):
     self.instance_template = Resource(
         "google_compute_instance_template",
         self.name,
         name=self.name,
         machine_type="f1-micro",
         disk={
             "source_image":"cos-cloud/cos-stable-81-12871-69-0",
             "disk_size_gb":5
         },
         metadata={
             "gce-container-declaration":"spec:\n  containers:\n    - name: {}\n      image: '{}'\n      stdin: false\n      tty: false\n  restartPolicy: Always\n".format(self.name, self.container)
         },
         network_interface={
             "network":"development_network",
             "subnetwork":"development_subnet",
             "access_config":{}
         },
         tags=self.tags
     )
Пример #27
0
 def create_external_ip_address(self):
     self.global_ip_address_name = self.name + "-ip-address"
     self.global_ip_address = Resource("google_compute_global_address",
                                       self.global_ip_address_name,
                                       name=self.global_ip_address_name)
Пример #28
0
 def create_url_map(self):
     self.url_map_name = self.name + "-url-map"
     self.url_map = Resource("google_compute_url_map",
                             self.url_map_name,
                             name=self.url_map_name,
                             default_service=self.backend_service.self_link)
Пример #29
0
 def create_http_proxy(self):
     self.http_proxy_name = self.name + "-http-proxy"
     self.http_proxy = Resource("google_compute_target_http_proxy",
                                self.http_proxy_name,
                                name=self.http_proxy_name,
                                url_map=self.url_map.self_link)
Пример #30
0
ami = Data('aws_ami',
           'ecs_ami',
           most_recent=True,
           filter=[
               dict(name='name', values=['*amazon-ecs-optimized']),
               dict(name='owner-alias', values=['amazon'])
           ])

spot_fleet_role = Resource('aws_iam_role',
                           'spot_fleet',
                           name='spot_fleet',
                           assume_role_policy='''{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "spotfleet.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}''')

Resource(
    'aws_iam_policy_attachment',
    'spot_fleet',
    name='spot_fleet',
    roles=[spot_fleet_role.name],
    policy_arn='arn:aws:iam::aws:policy/service-role/AmazonEC2SpotFleetRole')