def upsert_load_balancer(self):
        """Creates OperationContract for upsertLoadBalancer.

    Calls Spinnaker's upsertLoadBalancer with a configuration, then verifies
    that the expected resources and configurations are visible on AWS. See
    the contract builder for more info on what the expectations are.
    """
        detail_raw_name = 'katotestlb' + self.test_id
        self.__use_lb_name = detail_raw_name

        bindings = self.bindings
        region = bindings['TEST_AWS_REGION']
        avail_zones = [region + 'a', region + 'b']

        listener = {'Listener': {'InstancePort': 7001, 'LoadBalancerPort': 80}}
        health_check = {
            'HealthyThreshold': 8,
            'UnhealthyThreshold': 3,
            'Interval': 123,
            'Timeout': 12,
            'Target':
            'HTTP:%d/healthcheck' % listener['Listener']['InstancePort']
        }

        payload = self.agent.type_to_payload(
            'upsertAmazonLoadBalancerDescription', {
                'credentials':
                bindings['SPINNAKER_AWS_ACCOUNT'],
                'clusterName':
                bindings['TEST_APP'],
                'name':
                detail_raw_name,
                'availabilityZones': {
                    region: avail_zones
                },
                'listeners':
                [{
                    'internalProtocol': 'HTTP',
                    'internalPort': listener['Listener']['InstancePort'],
                    'externalProtocol': 'HTTP',
                    'externalPort': listener['Listener']['LoadBalancerPort']
                }],
                'healthCheck':
                health_check['Target'],
                'healthTimeout':
                health_check['Timeout'],
                'healthInterval':
                health_check['Interval'],
                'healthyThreshold':
                health_check['HealthyThreshold'],
                'unhealthyThreshold':
                health_check['UnhealthyThreshold']
            })

        builder = aws.AwsPythonContractBuilder(self.aws_observer)
        (builder.new_clause_builder(
            'Load Balancer Added', retryable_for_secs=30).call_method(
                self.elb_client.describe_load_balancers,
                LoadBalancerNames=[self.__use_lb_name]).EXPECT(
                    ov_factory.value_list_path_contains(
                        'LoadBalancerDescriptions',
                        jp.LIST_MATCHES([
                            jp.DICT_MATCHES({
                                'HealthCheck':
                                jp.DICT_MATCHES({
                                    key: jp.EQUIVALENT(value)
                                    for key, value in health_check.items()
                                }),
                                'AvailabilityZones':
                                jp.LIST_MATCHES([
                                    jp.STR_SUBSTR(zone) for zone in avail_zones
                                ]),
                                'ListenerDescriptions/Listener':
                                jp.DICT_MATCHES({
                                    key: jp.EQUIVALENT(value)
                                    for key, value in
                                    listener['Listener'].items()
                                })
                            })
                        ]))))

        return st.OperationContract(self.new_post_operation(
            title='upsert_amazon_load_balancer', data=payload, path='ops'),
                                    contract=builder.build())
 def delete_app(self):
     contract = jc.Contract()
     return st.OperationContract(self.agent.make_delete_app_operation(
         application=self.TEST_APP,
         account_name=self.bindings['SPINNAKER_GOOGLE_ACCOUNT']),
                                 contract=contract)
 def delete_app(self):
     """Creates OperationContract that deletes a new Spinnaker Application."""
     contract = jc.Contract()
     return st.OperationContract(self.agent.make_delete_app_operation(
         bindings=self.bindings, application=self.TEST_APP),
                                 contract=contract)
    def add_server_group(self):
        '''Adds a server group to the L7 LB.
    '''
        time.sleep(60)  # Wait for the L7 LB to be ready.
        bindings = self.bindings
        group_name = '{app}-{stack}-v000'.format(app=self.TEST_APP,
                                                 stack=bindings['TEST_STACK'])
        policy = {
            'balancingMode': 'UTILIZATION',
            'listeningPort': 80,
            'maxUtilization': 0.8,
            'capacityScaler': 0.8
        }

        payload = self.agent.make_json_payload_from_kwargs(
            job=[{
                'cloudProvider': 'gce',
                'application': self.TEST_APP,
                'credentials': bindings['SPINNAKER_GOOGLE_ACCOUNT'],
                'strategy': '',
                'capacity': {
                    'min': 1,
                    'max': 1,
                    'desired': 1
                },
                'targetSize': 1,
                'image': bindings['TEST_GCE_IMAGE_NAME'],
                'zone': bindings['TEST_GCE_ZONE'],
                'stack': bindings['TEST_STACK'],
                'instanceType': 'f1-micro',
                'type': 'createServerGroup',
                'tags': [self.__lb_name + '-tag'],
                'loadBalancers': [self.__lb_name],
                'backendServices': {
                    self.__lb_name: ['bs-' + self.TEST_APP]
                },
                'disableTraffic': False,
                'loadBalancingPolicy': {
                    'balancingMode': 'UTILIZATION',
                    'listeningPort': 80,
                    'maxUtilization': 0.8,
                    'capacityScaler': 0.8
                },
                'availabilityZones': {
                    bindings['TEST_GCE_REGION']: [bindings['TEST_GCE_ZONE']]
                },
                'instanceMetadata': {
                    'startup-script': ('sudo apt-get update'
                                       ' && sudo apt-get install apache2 -y'),
                    'global-load-balancer-names':
                    self.__lb_name,
                    'backend-service-names':
                    'bs-' + self.TEST_APP,
                    'load-balancing-policy':
                    json.dumps(policy)
                },
                'account': bindings['SPINNAKER_GOOGLE_ACCOUNT'],
                'authScopes': ['compute'],
                'user': '******'
            }],
            description='Create Server Group in ' + group_name,
            application=self.TEST_APP)

        builder = gcp.GcpContractBuilder(self.gcp_observer)
        (builder.new_clause_builder('Managed Instance Group Added',
                                    retryable_for_secs=30).inspect_resource(
                                        'instanceGroupManagers',
                                        group_name).contains_path_eq(
                                            'targetSize', 1))

        return st.OperationContract(self.new_post_operation(
            title='create server group', data=payload, path='tasks'),
                                    contract=builder.build())
Exemple #5
0
    def create_app(self):
        payload = self.agent.make_json_payload_from_object(
            self.initial_app_spec)
        expect = dict(self.initial_app_spec)
        expect['name'] = self.initial_app_spec['name'].upper()
        expect['lastModifiedBy'] = 'anonymous'

        contract = jc.Contract()

        # Note that curiosly the updated timestamp is not adjusted in the storage
        # file.
        gcs_builder = gcp.GcpStorageContractBuilder(self.gcs_observer)
        (gcs_builder.new_clause_builder(
            'Created Google Cloud Storage File',
            retryable_for_secs=5).list_bucket(
                self.BUCKET, '/'.join([self.BASE_PATH,
                                       'applications'])).EXPECT(
                                           ov_factory.value_list_path_contains(
                                               'name',
                                               jp.STR_SUBSTR(self.TEST_APP))))
        (gcs_builder.new_clause_builder('Wrote File Content').retrieve_content(
            self.BUCKET,
            '/'.join([
                self.BASE_PATH, 'applications', self.TEST_APP,
                'specification.json'
            ]),
            transform=json.JSONDecoder().decode).EXPECT(
                ov_factory.value_list_contains(
                    jp.DICT_MATCHES({
                        key: jp.EQUIVALENT(value)
                        for key, value in expect.items()
                    }))))
        for clause in gcs_builder.build().clauses:
            contract.add_clause(clause)

        # The update timestamp is determined by the server,
        # and we dont know what that is, so lets ignore it
        # and assume the unit tests verify it is properly updated.
        expect = dict(expect)
        del expect['updateTs']
        self.app_history.insert(0, expect)
        f50_builder = st.http_observer.HttpContractBuilder(self.agent)

        # These clauses are querying the Front50 http server directly
        # to verify that it returns the application we added.
        # We already verified the data was stored on GCS, but while we
        # are here we will verify that it is also being returned when queried.
        (f50_builder.new_clause_builder('Lists Application').get_url_path(
            '/v2/applications').EXPECT(
                ov_factory.value_list_path_contains(
                    'name', jp.STR_SUBSTR(self.TEST_APP.upper()))))
        (f50_builder.new_clause_builder('Returns Application').get_url_path(
            '/v2/applications').EXPECT(
                ov_factory.value_list_contains(
                    jp.DICT_MATCHES({
                        key: jp.EQUIVALENT(value)
                        for key, value in self.app_history[0].items()
                    }))))
        for clause in f50_builder.build().clauses:
            contract.add_clause(clause)

        path = '/v2/applications'
        return st.OperationContract(self.new_post_operation(title='create_app',
                                                            data=payload,
                                                            path=path),
                                    contract=contract)
    def create_server_group(self):
        """Creates OperationContract for createServerGroup.

    To verify the operation, we just check that the AWS Auto Scaling Group
    for the server group was created.
    """
        bindings = self.bindings

        # Spinnaker determines the group name created,
        # which will be the following:
        group_name = '{app}-{stack}-v000'.format(app=self.TEST_APP,
                                                 stack=bindings['TEST_STACK'])

        region = bindings['TEST_AWS_REGION']
        avail_zones = [region + 'a', region + 'b']

        payload = self.agent.make_json_payload_from_kwargs(
            job=[{
                'type': 'createServerGroup',
                'cloudProvider': 'aws',
                'application': self.TEST_APP,
                'credentials': bindings['SPINNAKER_AWS_ACCOUNT'],
                'strategy': '',
                'capacity': {
                    'min': 2,
                    'max': 2,
                    'desired': 2
                },
                'targetHealthyDeployPercentage': 100,
                'loadBalancers': [self.lb_name],
                'cooldown': 8,
                'healthCheckType': 'EC2',
                'healthCheckGracePeriod': 40,
                'instanceMonitoring': False,
                'ebsOptimized': False,
                'iamRole': bindings['AWS_IAM_ROLE'],
                'terminationPolicies': ['Default'],
                'availabilityZones': {
                    region: avail_zones
                },
                'keyPair': bindings['SPINNAKER_AWS_ACCOUNT'] + '-keypair',
                'suspendedProcesses': [],
                # TODO(ewiseblatt): Inquiring about how this value is determined.
                # It seems to be the "Name" tag value of one of the VPCs
                # but is not the default VPC, which is what we using as the VPC_ID.
                # So I suspect something is out of whack. This name comes from
                # spinnaker.io tutorial. But using the default vpc would probably
                # be more adaptive to the particular deployment.
                'subnetType': 'internal (defaultvpc)',
                'securityGroups': [bindings['TEST_AWS_SECURITY_GROUP_ID']],
                'virtualizationType': 'paravirtual',
                'stack': bindings['TEST_STACK'],
                'freeFormDetails': '',
                'amiName': bindings['TEST_AWS_AMI'],
                'instanceType': 'm1.small',
                'useSourceCapacity': False,
                'account': bindings['SPINNAKER_AWS_ACCOUNT'],
                'user': '******'
            }],
            description='Create Server Group in ' + group_name,
            application=self.TEST_APP)

        builder = aws.AwsContractBuilder(self.aws_observer)
        (builder.new_clause_builder(
            'Auto Server Group Added',
            retryable_for_secs=30).collect_resources(
                'autoscaling',
                'describe-auto-scaling-groups',
                args=['--auto-scaling-group-names', group_name
                      ]).contains_path_match('AutoScalingGroups',
                                             {'MaxSize': jp.NUM_EQ(2)}))

        return st.OperationContract(self.new_post_operation(
            title='create_server_group', data=payload, path='tasks'),
                                    contract=builder.build())
Exemple #7
0
  def create_http_load_balancer(self):
    logical_http_lb_name = 'katotest-httplb-' + self.test_id
    self.__use_http_lb_name = logical_http_lb_name

    # TODO(ewiseblatt): 20150530
    # This needs to be abbreviated to hc.
    self.__use_http_lb_hc_name = logical_http_lb_name + '-health-check'

    # TODO(ewiseblatt): 20150530
    # This needs to be abbreviated to bs.
    self.__use_http_lb_bs_name = logical_http_lb_name + '-backend-service'
    self.__use_http_lb_fr_name = logical_http_lb_name

    # TODO(ewiseblatt): 20150530
    # This should be abbreviated (um?).
    self.__use_http_lb_map_name = logical_http_lb_name + '-url-map'

    # TODO(ewiseblatt): 20150530
    # This should be abbreviated (px)?.
    self.__use_http_lb_proxy_name = logical_http_lb_name + '-target-http-proxy'

    interval = 231
    healthy = 8
    unhealthy = 9
    timeout = 65
    path = '/hello/world'

    # TODO(ewiseblatt): 20150530
    # This field might be broken. 123-456 still resolves to 80-80
    # Changing it for now so the test passes.
    port_range = "80-80"

    # TODO(ewiseblatt): 20150530
    # Specify explicit backends?

    health_check = {
        'checkIntervalSec': interval,
        'healthyThreshold': healthy,
        'unhealthyThreshold': unhealthy,
        'timeoutSec': timeout,
        'requestPath': path
        }

    # pylint: disable=bad-continuation
    payload = self.agent.type_to_payload(
        'createGoogleHttpLoadBalancerDescription',
        {
          'healthCheck': health_check,
          'portRange': port_range,
          'loadBalancerName': logical_http_lb_name,
          'credentials': self.bindings['SPINNAKER_GOOGLE_ACCOUNT']
        })

    hc_dict = dict(health_check)
    del hc_dict['requestPath']
    hc_match = {name: jp.NUM_EQ(value)
                for name, value in health_check.items()}
    hc_match['requestPath'] = jp.STR_EQ(path)
    hc_match['name'] = jp.STR_SUBSTR(self.__use_http_lb_hc_name),
    builder = gcp.GcpContractBuilder(self.gcp_observer)
    (builder.new_clause_builder('Http Health Check Added')
        .list_resource('httpHealthChecks')
        .contains_match(hc_match))
    (builder.new_clause_builder('Global Forwarding Rule Added',
                                retryable_for_secs=15)
       .list_resource('globalForwardingRules')
       .contains_match({
          'name': jp.STR_SUBSTR(self.__use_http_lb_fr_name),
          'portRante': jp.STR_EQ(port_range)}))
    (builder.new_clause_builder('Backend Service Added')
       .list_resource('backendServices')
       .contains_match({
           'name': jp.STR_SUBSTR(self.__use_http_lb_bs_name),
           'healthChecks': jp.STR_SUBSTR(self.__use_http_lb_hc_name)}))
    (builder.new_clause_builder('Url Map Added')
       .list_resource('urlMaps')
       .contains_match({
          'name': jp.STR_SUBSTR(self.__use_http_lb_map_name),
          'defaultService': jp.STR_SUBSTR(self.__use_http_lb_bs_name)}))
    (builder.new_clause_builder('Target Http Proxy Added')
       .list_resource('targetHttpProxies')
       .contains_match({
          'name': jp.STR_SUBSTR(self.__use_http_lb_proxy_name),
          'urlMap': jp.STR_SUBSTR(self.__use_http_lb_map_name)}))

    return st.OperationContract(
        self.new_post_operation(
            title='create_http_load_balancer', data=payload, path='ops'),
        contract=builder.build())
    def create_instances(self):
        """Creates test adding instances to GCE.

         Create three instances.
           * The first two are of different types and zones, which
             we'll check. Future tests will also be using these
             from different zones (but same region).

           * The third is a duplicate in the same zone as another
             so we can check duplicate deletes (which limit one zone per call).

         We'll set the class properties use_instance_names and use_instance_zones
         so that they can be communicated to future tests to reference.

        Returns:
          st.OperationContract
        """
        # We're going to make specific instances so we can refer to them later
        # in tests involving instances. The instances are decorated to trace back
        # to this particular run so as not to conflict with other tests that may
        # be running.
        self.use_instance_names = [
            "katotest%sa" % self.test_id,
            "katotest%sb" % self.test_id,
            "katotest%sc" % self.test_id,
        ]

        # Put the instance in zones. Force one zone to be different
        # to ensure we're testing zone placement. We arent bothering
        # with different regions at this time.
        test_zone = self.bindings["TEST_GCE_ZONE"]
        other_zone = self.bindings["TEST_GCE_REGION"] + (
            "-b" if test_zone[-1] != "b" else "-c")

        self.use_instance_zones = [test_zone, other_zone, test_zone]

        # Give the instances images and machine types. Again we're forcing
        # one to be different to ensure that we're using the values.
        image_name = [
            self.bindings["TEST_GCE_IMAGE_NAME"],
            "debian-9-stretch-v20190116",
            self.bindings["TEST_GCE_IMAGE_NAME"],
        ]
        if image_name[0] == image_name[1]:
            image_name[1] = "ubuntu-minimal-1604-xenial-v20190122"
        machine_type = ["f1-micro", "g1-small", "f1-micro"]

        # The instance_spec will turn into the payload of instances we request.
        instance_spec = []
        builder = gcp.GcpContractBuilder(self.gcp_observer)
        for i in range(3):
            # pylint: disable=bad-continuation
            instance_spec.append({
                "createGoogleInstanceDescription": {
                    "instanceName": self.use_instance_names[i],
                    "image": image_name[i],
                    "instanceType": machine_type[i],
                    "zone": self.use_instance_zones[i],
                    "credentials": self.bindings["SPINNAKER_GOOGLE_ACCOUNT"],
                }
            })

            # Verify we created an instance, whether or not it boots.
            (builder.new_clause_builder(
                "Instance %d Created" % i,
                retryable_for_secs=90).aggregated_list_resource(
                    "instances").EXPECT(
                        ov_factory.value_list_path_contains(
                            "name",
                            jp.STR_SUBSTR(self.use_instance_names[i]))))
            if i < 2:
                # Verify the details are what we asked for.
                # Since we've finished the created clause, this already exists.
                # Note we're only checking the first two since they are different
                # from one another. Anything after that isnt necessary for the test.
                # The clause above already checked that they were all created so we
                # can assume from this test that the details are ok as well.
                (builder.new_clause_builder(
                    "Instance %d Details" % i).inspect_resource(
                        "instances",
                        self.use_instance_names[i],
                        zone=self.use_instance_zones[i],
                    ).contains_path_value("machineType", machine_type[i]))
                # Verify the instance eventually boots up.
                # We can combine this with above, but we'll probably need
                # to retry this, but not the above, so this way if the
                # above is broken (wrong), we wont retry thinking it isnt there yet.
                (builder.new_clause_builder(
                    "Instance %d Is Running" % i,
                    retryable_for_secs=360).inspect_resource(
                        "instances",
                        self.use_instance_names[i],
                        zone=self.use_instance_zones[i],
                    ).EXPECT(
                        ov_factory.value_list_path_contains(
                            "status", jp.STR_EQ("RUNNING"))))

        payload = self.agent.make_json_payload_from_object(instance_spec)

        return st.OperationContract(
            self.new_post_operation(title="create_instances",
                                    data=payload,
                                    path="ops"),
            contract=builder.build(),
        )
    def create_http_load_balancer(self):
        logical_http_lb_name = "katotest-httplb-" + self.test_id
        self.__use_http_lb_name = logical_http_lb_name

        self.__use_http_lb_hc_name = logical_http_lb_name + "-health-check"
        self.__use_http_lb_bs_name = logical_http_lb_name + "-backend-service"
        self.__use_http_lb_fr_name = logical_http_lb_name
        self.__use_http_lb_map_name = logical_http_lb_name + "-url-map"
        self.__use_http_lb_proxy_name = logical_http_lb_name + "-target-http-proxy"

        interval = 231
        healthy = 8
        unhealthy = 9
        timeout = 65
        path = "/hello/world"
        port_range = "123-456"

        health_check = {
            "checkIntervalSec": interval,
            "healthyThreshold": healthy,
            "unhealthyThreshold": unhealthy,
            "timeoutSec": timeout,
            "requestPath": path,
        }

        # pylint: disable=bad-continuation
        payload = self.agent.type_to_payload(
            "createGoogleHttpLoadBalancerDescription",
            {
                "healthCheck": health_check,
                "portRange": port_range,
                "loadBalancerName": logical_http_lb_name,
                "credentials": self.bindings["SPINNAKER_GOOGLE_ACCOUNT"],
            },
        )

        hc_dict = dict(health_check)
        del hc_dict["requestPath"]
        hc_match = {
            name: jp.NUM_EQ(value)
            for name, value in health_check.items()
        }
        hc_match["requestPath"] = jp.STR_EQ(path)
        hc_match["name"] = (jp.STR_SUBSTR(self.__use_http_lb_hc_name), )
        builder = gcp.GcpContractBuilder(self.gcp_observer)
        (builder.new_clause_builder("Http Health Check Added").list_resource(
            "httpHealthChecks").EXPECT(
                ov_factory.value_list_contains(jp.DICT_MATCHES(hc_match))))
        (builder.new_clause_builder(
            "Global Forwarding Rule Added",
            retryable_for_secs=15).list_resource(
                "globalForwardingRules").EXPECT(
                    ov_factory.value_list_contains(
                        jp.DICT_MATCHES({
                            "name":
                            jp.STR_SUBSTR(self.__use_http_lb_fr_name),
                            "portRange":
                            jp.STR_EQ(port_range),
                        }))))
        (builder.new_clause_builder("Backend Service Added").list_resource(
            "backendServices").EXPECT(
                ov_factory.value_list_contains(
                    jp.DICT_MATCHES({
                        "name":
                        jp.STR_SUBSTR(self.__use_http_lb_bs_name),
                        "healthChecks":
                        jp.STR_SUBSTR(self.__use_http_lb_hc_name),
                    }))))
        (builder.new_clause_builder("Url Map Added").list_resource(
            "urlMaps").EXPECT(
                ov_factory.value_list_contains(
                    jp.DICT_MATCHES({
                        "name":
                        jp.STR_SUBSTR(self.__use_http_lb_map_name),
                        "defaultService":
                        jp.STR_SUBSTR(self.__use_http_lb_bs_name),
                    }))))
        (builder.new_clause_builder("Target Http Proxy Added").list_resource(
            "targetHttpProxies").EXPECT(
                ov_factory.value_list_contains(
                    jp.DICT_MATCHES({
                        "name":
                        jp.STR_SUBSTR(self.__use_http_lb_proxy_name),
                        "urlMap":
                        jp.STR_SUBSTR(self.__use_http_lb_map_name),
                    }))))

        return st.OperationContract(
            self.new_post_operation(title="create_http_load_balancer",
                                    data=payload,
                                    path="ops"),
            contract=builder.build(),
        )
Exemple #10
0
    def delete_load_balancer(self):
        """Creates OperationContract for deleteLoadBalancer.

        To verify the operation, we just check that the GCP resources
        created by upsert_load_balancer are no longer visible on GCP.
        """
        bindings = self.bindings
        payload = self.agent.make_json_payload_from_kwargs(
            job=[
                {
                    "type": "deleteLoadBalancer",
                    "cloudProvider": "gce",
                    "loadBalancerName": self.__lb_name,
                    "region": bindings["TEST_GCE_REGION"],
                    "regions": [bindings["TEST_GCE_REGION"]],
                    "credentials": bindings["SPINNAKER_GOOGLE_ACCOUNT"],
                    "user": "******",
                }
            ],
            description="Delete Load Balancer: {0} in {1}:{2}".format(
                self.__lb_name,
                bindings["SPINNAKER_GOOGLE_ACCOUNT"],
                bindings["TEST_GCE_REGION"],
            ),
            application=self.TEST_APP,
        )

        builder = gcp.GcpContractBuilder(self.gcp_observer)
        (
            builder.new_clause_builder("Health Check Removed", retryable_for_secs=30)
            .list_resource("httpHealthChecks")
            .EXPECT(
                ov_factory.value_list_path_excludes(
                    "name", jp.STR_SUBSTR("%s-hc" % self.__lb_name)
                )
            )
        )
        (
            builder.new_clause_builder("TargetPool Removed")
            .list_resource("targetPools")
            .EXPECT(
                ov_factory.value_list_path_excludes(
                    "name", jp.STR_SUBSTR("%s-tp" % self.__lb_name)
                )
            )
        )
        (
            builder.new_clause_builder("Forwarding Rule Removed")
            .list_resource("forwardingRules")
            .EXPECT(
                ov_factory.value_list_path_excludes(
                    "name", jp.STR_SUBSTR(self.__lb_name)
                )
            )
        )

        return st.OperationContract(
            self.new_post_operation(
                title="delete_load_balancer", data=payload, path="tasks"
            ),
            contract=builder.build(),
        )
Exemple #11
0
    def trigger_bake_and_deploy_pipeline(self):
        """Create OperationContract that manually trigger the bake and deploy pipeline
        This create a new server group below the given load balancer.

        To verify the operation, we check that the spinnaker server group
        for the given load balancer was created in correct size.
        """

        pipeline_id = self.bake_pipeline_id
        payload = self.agent.make_json_payload_from_kwargs(
            job=[{
                "dryRun": False,
                "type": "manual",
                "user": "******"
            }],
            description="Test - begin bake and deploy: {pl}".format(
                pl=pipeline_id),
            application=self.TEST_APP,
        )

        builder = az.AzContractBuilder(self.az_observer)
        (builder.new_clause_builder(
            "Has Virtual Machine Scale Set",
            retryable_for_secs=30).collect_resources(
                az_resource="vmss",
                command="list",
                args=[
                    "--resource-group",
                    "{app}-{rg}".format(app=self.TEST_APP,
                                        rg=self.__rg_location),
                ],
            ).EXPECT(
                ov_factory.value_list_contains(
                    jp.DICT_MATCHES({
                        "name":
                        jp.STR_EQ("{lb}-v000".format(lb=self.__full_lb_name)),
                        "provisioningState":
                        jp.STR_EQ("Succeeded"),
                        "tags":
                        jp.DICT_MATCHES(
                            {"appGatewayName":
                             jp.STR_EQ(self.__full_lb_name)}),
                        "sku":
                        jp.DICT_MATCHES({
                            "name":
                            jp.STR_EQ(self.__sku["name"]),
                            "tier":
                            jp.STR_EQ(self.__sku["tier"]),
                            "capacity":
                            jp.NUM_EQ(self.__sku["capacity"]),
                        }),
                    }))))

        return st.OperationContract(
            self.new_post_operation(
                title="bake and deploy",
                data=payload,
                # TODO: cannot use v2 url: pipelines/v2/{app}/{pl}
                path="pipelines/{app}/{pl}".format(app=self.TEST_APP,
                                                   pl=pipeline_id),
                max_wait_secs=3600,
            ),
            contract=builder.build(),
        )
Exemple #12
0
    def upsert_load_balancer(self):
        """Creates OperationContract for upsertLoadBalancer.

        Calls Spinnaker's upsertLoadBalancer with a configuration, then verifies
        that the expected resources and configurations are visible on GCE. See
        the contract builder for more info on what the expectations are.
        """
        bindings = self.bindings
        target_pool_name = "{0}/targetPools/{1}-tp".format(
            bindings["TEST_GCE_REGION"], self.__lb_name
        )

        spec = {
            "checkIntervalSec": 9,
            "healthyThreshold": 3,
            "unhealthyThreshold": 5,
            "timeoutSec": 2,
            "port": 80,
        }

        payload = self.agent.make_json_payload_from_kwargs(
            job=[
                {
                    "cloudProvider": "gce",
                    "provider": "gce",
                    "stack": bindings["TEST_STACK"],
                    "detail": self.__lb_detail,
                    "credentials": bindings["SPINNAKER_GOOGLE_ACCOUNT"],
                    "region": bindings["TEST_GCE_REGION"],
                    "ipProtocol": "TCP",
                    "portRange": spec["port"],
                    "loadBalancerName": self.__lb_name,
                    "name": self.__lb_name,
                    "healthCheck": {
                        "port": spec["port"],
                        "timeoutSec": spec["timeoutSec"],
                        "checkIntervalSec": spec["checkIntervalSec"],
                        "healthyThreshold": spec["healthyThreshold"],
                        "unhealthyThreshold": spec["unhealthyThreshold"],
                    },
                    "type": "upsertLoadBalancer",
                    "availabilityZones": {bindings["TEST_GCE_REGION"]: []},
                    "user": "******",
                }
            ],
            description="Create Load Balancer: " + self.__lb_name,
            application=self.TEST_APP,
        )

        hc_match_spec = {key: jp.NUM_EQ(value) for key, value in spec.items()}
        hc_match_spec["name"] = jp.STR_SUBSTR("%s-hc" % self.__lb_name)
        builder = gcp.GcpContractBuilder(self.gcp_observer)
        (
            builder.new_clause_builder("Health Check Added", retryable_for_secs=30)
            .list_resource("httpHealthChecks")
            .EXPECT(ov_factory.value_list_contains(jp.DICT_MATCHES(hc_match_spec)))
        )
        (
            builder.new_clause_builder("Target Pool Added", retryable_for_secs=30)
            .list_resource("targetPools")
            .EXPECT(
                ov_factory.value_list_path_contains(
                    "name", jp.STR_SUBSTR("%s-tp" % self.__lb_name)
                )
            )
        )
        (
            builder.new_clause_builder("Forwarding Rules Added", retryable_for_secs=30)
            .list_resource("forwardingRules")
            .EXPECT(
                ov_factory.value_list_contains(
                    jp.DICT_MATCHES(
                        {
                            "name": jp.STR_SUBSTR(self.__lb_name),
                            "target": jp.STR_SUBSTR(target_pool_name),
                        }
                    )
                )
            )
        )

        return st.OperationContract(
            self.new_post_operation(
                title="upsert_load_balancer", data=payload, path="tasks"
            ),
            contract=builder.build(),
        )
    def create_a_security_group(self):
        """Creates AzContract for createServerGroup.

        To verify the operation, we just check that the spinnaker security group
        for the given application was created.
        This will create a Network Security Group in a Resource Group on your azure Subscription
        """
        rules = [{
            "access": "Allow",
            "destinationAddressPrefix": "*",
            "destinationPortRange": "80-80",
            "direction": "InBound",
            "endPort": 80,
            "name": self.TEST_SECURITY_GROUP_RULE_1,
            "priority": 100,
            "protocol": "tcp",
            "sourceAddressPrefix": "*",
            "sourcePortRange": "*",
            "startPort": 80,
        }]
        job = [{
            "provider":
            "azure",
            "application":
            self.bindings["TEST_APP"],
            "appName":
            self.bindings["TEST_APP"],
            "region":
            self.bindings["TEST_AZURE_RG_LOCATION"],
            "stack":
            self.bindings["TEST_STACK"],
            "description":
            "Test - create security group for {app}".format(
                app=self.bindings["TEST_APP"]),
            "detail":
            "",
            "credentials":
            self.bindings["SPINNAKER_AZURE_ACCOUNT"],
            "securityRules":
            rules,
            "name":
            self.TEST_SECURITY_GROUP,
            "securityGroupName":
            self.TEST_SECURITY_GROUP,
            "cloudProvider":
            "azure",
            "type":
            "upsertSecurityGroup",
            "user":
            "******",
        }]
        builder = az.AzContractBuilder(self.az_observer)
        (builder.new_clause_builder("Security Group Created",
                                    retryable_for_secs=30).collect_resources(
                                        az_resource="network",
                                        command="nsg",
                                        args=[
                                            "show",
                                            "--name",
                                            self.TEST_SECURITY_GROUP,
                                            "--resource-group",
                                            self.TEST_SECURITY_GROUP_RG,
                                        ],
                                    ).
         EXPECT(
             ov_factory.error_list_contains(
                 jp.ExceptionMatchesPredicate(
                     klass=st.CliAgentRunError,
                     regex=
                     "(?:.* operation: Cannot find .*)|(?:.*\(.*NotFound\).*)",
                 ))).OR(
                     ov_factory.value_list_contains(
                         # sec grp name matches expected
                         jp.DICT_MATCHES({
                             "name":
                             jp.STR_SUBSTR(self.TEST_SECURITY_GROUP),
                             "securityRules":
                             jp.LIST_MATCHES(
                                 [
                                     jp.DICT_MATCHES({
                                         "protocol":
                                         jp.STR_EQ("tcp"),
                                         "name":
                                         jp.STR_EQ(
                                             self.TEST_SECURITY_GROUP_RULE_1),
                                     })
                                 ],
                                 strict=True,
                             ),
                         }))))

        payload = self.agent.make_json_payload_from_kwargs(
            job=job,
            description=" Test - create security group for {app}".format(
                app=self.bindings["TEST_APP"]),
            application=self.bindings["TEST_APP"],
        )

        return st.OperationContract(
            self.new_post_operation(
                title="create_security_group",
                data=payload,
                path="applications/{app}/tasks".format(
                    app=self.bindings["TEST_APP"]),
            ),
            contract=builder.build(),
        )
    def create_load_balancer(self):
        bindings = self.bindings
        load_balancer_name = self.__full_lb_name

        spec = {
            "checkIntervalSec": 5,
            "healthyThreshold": 2,
            "unhealthyThreshold": 2,
            "timeoutSec": 5,
            "port": 80,
        }

        payload = self.agent.make_json_payload_from_kwargs(
            job=[{
                "cloudProvider": "gce",
                "provider": "gce",
                "stack": bindings["TEST_STACK"],
                "detail": self.__short_lb_name,
                "credentials": bindings["SPINNAKER_GOOGLE_ACCOUNT"],
                "region": bindings["TEST_GCE_REGION"],
                "ipProtocol": "TCP",
                "portRange": spec["port"],
                "loadBalancerName": load_balancer_name,
                "healthCheck": {
                    "port": spec["port"],
                    "timeoutSec": spec["timeoutSec"],
                    "checkIntervalSec": spec["checkIntervalSec"],
                    "healthyThreshold": spec["healthyThreshold"],
                    "unhealthyThreshold": spec["unhealthyThreshold"],
                },
                "type": "upsertLoadBalancer",
                "availabilityZones": {
                    bindings["TEST_GCE_REGION"]: []
                },
                "user": "******",
            }],
            description="Create Load Balancer: " + load_balancer_name,
            application=self.TEST_APP,
        )

        # We arent testing load balancers, so assume it is working,
        # but we'll look for at the health check to know it is ready.
        builder = gcp.GcpContractBuilder(self.gcp_observer)
        (builder.new_clause_builder(
            "Health Check Added", retryable_for_secs=30).list_resource(
                "httpHealthChecks").contains_path_value(
                    "name", load_balancer_name + "-hc"))

        (builder.new_clause_builder("Load Balancer Created",
                                    retryable_for_secs=60).list_resource(
                                        "forwardingRules").contains_path_value(
                                            "name", self.__full_lb_name))

        return st.OperationContract(
            self.new_post_operation(
                title="create_load_balancer",
                data=payload,
                path=("applications/{app}/tasks").format(app=self.TEST_APP),
            ),
            contract=builder.build(),
        )
Exemple #15
0
  def upsert_load_balancer(self):
    """Creates OperationContract for upsertLoadBalancer.

    Calls Spinnaker's upsertLoadBalancer with a configuration, then verifies
    that the expected resources and configurations are visible on AWS. See
    the contract builder for more info on what the expectations are.
    """
    detail_raw_name = 'katotestlb' + self.test_id
    self.__use_lb_name = detail_raw_name

    bindings = self.bindings
    region = bindings['TEST_AWS_REGION']
    avail_zones = [region + 'a', region + 'b']

    listener = {
        'Listener': {
            'InstancePort':7001,
            'LoadBalancerPort':80
        }
    }
    health_check = {
        'HealthyThreshold':8,
        'UnhealthyThreshold':3,
        'Interval':123,
        'Timeout':12,
        'Target':'HTTP:%d/healthcheck' % listener['Listener']['InstancePort']
    }

    payload = self.agent.type_to_payload(
        'upsertAmazonLoadBalancerDescription',
        {
            'credentials': bindings['SPINNAKER_AWS_ACCOUNT'],
            'clusterName': bindings['TEST_APP'],
            'name': detail_raw_name,
            'availabilityZones': {region: avail_zones},
            'listeners': [{
                'internalProtocol': 'HTTP',
                'internalPort': listener['Listener']['InstancePort'],
                'externalProtocol': 'HTTP',
                'externalPort': listener['Listener']['LoadBalancerPort']
            }],
            'healthCheck': health_check['Target'],
            'healthTimeout': health_check['Timeout'],
            'healthInterval': health_check['Interval'],
            'healthyThreshold': health_check['HealthyThreshold'],
            'unhealthyThreshold': health_check['UnhealthyThreshold']
        })

    builder = aws.AwsContractBuilder(self.aws_observer)
    (builder.new_clause_builder('Load Balancer Added', retryable_for_secs=30)
     .collect_resources(
         aws_module='elb',
         command='describe-load-balancers',
         args=['--load-balancer-names', self.__use_lb_name])
     .contains_pred_list([
         jp.PathContainsPredicate(
             'LoadBalancerDescriptions/HealthCheck', health_check),
         jp.PathPredicate(
             'LoadBalancerDescriptions/AvailabilityZones{0}'.format(
                 jp.DONT_ENUMERATE_TERMINAL),
             jp.LIST_SIMILAR(avail_zones)),
         jp.PathElementsContainPredicate(
             'LoadBalancerDescriptions/ListenerDescriptions', listener)
         ])
    )

    return st.OperationContract(
        self.new_post_operation(
            title='upsert_amazon_load_balancer', data=payload, path='ops'),
        contract=builder.build())
    def upsert_load_balancer(self):
        self.__use_lb_name = "katotest-lb-" + self.test_id
        self.__use_lb_hc_name = "%s-hc" % self.__use_lb_name
        self.__use_lb_tp_name = "%s-tp" % self.__use_lb_name
        self.__use_lb_target = "{0}/targetPools/{1}".format(
            self.bindings["TEST_GCE_REGION"], self.__use_lb_tp_name)

        interval = 123
        healthy = 4
        unhealthy = 5
        timeout = 78
        path = "/" + self.__use_lb_target

        health_check = {
            "checkIntervalSec": interval,
            "healthyThreshold": healthy,
            "unhealthyThreshold": unhealthy,
            "timeoutSec": timeout,
            "requestPath": path,
        }

        # pylint: disable=bad-continuation
        payload = self.agent.type_to_payload(
            "upsertGoogleLoadBalancerDescription",
            {
                "healthCheck": health_check,
                "region": self.bindings["TEST_GCE_REGION"],
                "credentials": self.bindings["SPINNAKER_GOOGLE_ACCOUNT"],
                "loadBalancerName": self.__use_lb_name,
            },
        )

        builder = gcp.GcpContractBuilder(self.gcp_observer)
        (builder.new_clause_builder(
            "Forwarding Rules Added",
            retryable_for_secs=30).list_resource("forwardingRules").EXPECT(
                ov_factory.value_list_contains(
                    jp.DICT_MATCHES({
                        "name":
                        jp.STR_SUBSTR(self.__use_lb_name),
                        "target":
                        jp.STR_SUBSTR(self.__use_lb_target),
                    }))))
        (builder.new_clause_builder(
            "Target Pool Added",
            retryable_for_secs=15).list_resource("targetPools").EXPECT(
                ov_factory.value_list_path_contains(
                    "name", jp.STR_SUBSTR(self.__use_lb_tp_name))))

        # We list the resources here because the name isnt exact
        # and the list also returns the details we need.
        hc_dict = dict(health_check)
        del hc_dict["requestPath"]

        hc_match = {name: jp.NUM_EQ(value) for name, value in hc_dict.items()}
        hc_match["requestPath"] = jp.STR_EQ(path)
        hc_match["name"] = jp.STR_SUBSTR(self.__use_http_lb_hc_name)
        (builder.new_clause_builder(
            "Health Check Added",
            retryable_for_secs=15).list_resource("httpHealthChecks").EXPECT(
                ov_factory.value_list_contains(jp.DICT_MATCHES(hc_match))))

        return st.OperationContract(
            self.new_post_operation(title="upsert_load_balancer",
                                    data=payload,
                                    path="ops"),
            contract=builder.build(),
        )
    def upsert_load_balancer(self, use_vpc):
        """Creates OperationContract for upsertLoadBalancer.

    Calls Spinnaker's upsertLoadBalancer with a configuration, then verifies
    that the expected resources and configurations are visible on AWS. See
    the contract builder for more info on what the expectations are.

    Args:
      use_vpc: [bool] if True configure a VPC otherwise dont.
    """
        bindings = self.bindings
        context = citest.base.ExecutionContext()

        # We're assuming that the given region has 'A' and 'B' availability
        # zones. This seems conservative but might be brittle since we permit
        # any region.
        region = bindings['TEST_AWS_REGION']
        avail_zones = [region + 'a', region + 'b']
        load_balancer_name = self.lb_name

        if use_vpc:
            # TODO(ewiseblatt): 20160301
            # We're hardcoding the VPC here, but not sure which we really want.
            # I think this comes from the spinnaker.io installation instructions.
            # What's interesting about this is that it is a 10.* CidrBlock,
            # as opposed to the others, which are public IPs. All this is sensitive
            # as to where the TEST_AWS_VPC_ID came from so this is going to be
            # brittle. Ideally we only need to know the vpc_id and can figure the
            # rest out based on what we have available.
            subnet_type = 'internal (defaultvpc)'
            vpc_id = bindings['TEST_AWS_VPC_ID']

            # Not really sure how to determine this value in general.
            security_groups = ['default']

            # The resulting load balancer will only be available in the zone of
            # the subnet we are using. We'll figure that out by looking up the
            # subnet we want.
            subnet_details = self.aws_observer.get_resource_list(
                context,
                root_key='Subnets',
                aws_command='describe-subnets',
                aws_module='ec2',
                args=[
                    '--filters', 'Name=vpc-id,Values={vpc_id}'
                    ',Name=tag:Name,Values=defaultvpc.internal.{region}'.
                    format(vpc_id=vpc_id, region=region)
                ])
            try:
                expect_avail_zones = [subnet_details[0]['AvailabilityZone']]
            except KeyError:
                raise ValueError(
                    'vpc_id={0} appears to be unknown'.format(vpc_id))
        else:
            subnet_type = ""
            vpc_id = None
            security_groups = None
            expect_avail_zones = avail_zones

            # This will be a second load balancer not used in other tests.
            # Decorate the name so as not to confuse it.
            load_balancer_name += '-pub'

        listener = {'Listener': {'InstancePort': 80, 'LoadBalancerPort': 80}}
        health_check = {
            'HealthyThreshold': 8,
            'UnhealthyThreshold': 3,
            'Interval': 12,
            'Timeout': 6,
            'Target': 'HTTP:%d/' % listener['Listener']['InstancePort']
        }

        payload = self.agent.make_json_payload_from_kwargs(
            job=[{
                'type':
                'upsertLoadBalancer',
                'cloudProvider':
                'aws',
                # 'loadBalancerName': load_balancer_name,
                'credentials':
                bindings['SPINNAKER_AWS_ACCOUNT'],
                'name':
                load_balancer_name,
                'stack':
                bindings['TEST_STACK'],
                'detail':
                self.lb_detail,
                'region':
                bindings['TEST_AWS_REGION'],
                'availabilityZones': {
                    region: avail_zones
                },
                'regionZones':
                avail_zones,
                'listeners': [{
                    'internalProtocol':
                    'HTTP',
                    'internalPort':
                    listener['Listener']['InstancePort'],
                    'externalProtocol':
                    'HTTP',
                    'externalPort':
                    listener['Listener']['LoadBalancerPort']
                }],
                'healthCheck':
                health_check['Target'],
                'healthCheckProtocol':
                'HTTP',
                'healthCheckPort':
                listener['Listener']['LoadBalancerPort'],
                'healthCheckPath':
                '/',
                'healthTimeout':
                health_check['Timeout'],
                'healthInterval':
                health_check['Interval'],
                'healthyThreshold':
                health_check['HealthyThreshold'],
                'unhealthyThreshold':
                health_check['UnhealthyThreshold'],
                'user':
                '******',
                'usePreferredZones':
                True,
                'vpcId':
                vpc_id,
                'subnetType':
                subnet_type,
                # If I set security group to this then I get an error it is missing.
                # bindings['TEST_AWS_SECURITY_GROUP_ID']],
                'securityGroups':
                security_groups
            }],
            description='Create Load Balancer: ' + load_balancer_name,
            application=self.TEST_APP)

        builder = aws.AwsContractBuilder(self.aws_observer)
        (builder.new_clause_builder(
            'Load Balancer Added', retryable_for_secs=10).collect_resources(
                aws_module='elb',
                command='describe-load-balancers',
                args=[
                    '--load-balancer-names', load_balancer_name
                ]).contains_path_match(
                    'LoadBalancerDescriptions', {
                        'HealthCheck':
                        jp.DICT_MATCHES({
                            key: jp.EQUIVALENT(value)
                            for key, value in health_check.items()
                        }),
                        'AvailabilityZones':
                        jp.LIST_SIMILAR(expect_avail_zones),
                        'ListenerDescriptions/Listener':
                        jp.DICT_MATCHES({
                            key: jp.NUM_EQ(value)
                            for key, value in listener['Listener'].items()
                        })
                    }))

        title_decorator = '_with_vpc' if use_vpc else '_without_vpc'
        return st.OperationContract(self.new_post_operation(
            title='upsert_load_balancer' + title_decorator,
            data=payload,
            path='tasks'),
                                    contract=builder.build())
    def upsert_load_balancer(self):
        self.__use_lb_name = 'katotest-lb-' + self.test_id
        self.__use_lb_hc_name = '%s-hc' % self.__use_lb_name
        self.__use_lb_tp_name = '%s-tp' % self.__use_lb_name
        self.__use_lb_target = '{0}/targetPools/{1}'.format(
            self.bindings['TEST_GCE_REGION'], self.__use_lb_tp_name)

        interval = 123
        healthy = 4
        unhealthy = 5
        timeout = 78
        path = '/' + self.__use_lb_target

        health_check = {
            'checkIntervalSec': interval,
            'healthyThreshold': healthy,
            'unhealthyThreshold': unhealthy,
            'timeoutSec': timeout,
            'requestPath': path
        }

        # pylint: disable=bad-continuation
        payload = self.agent.type_to_payload(
            'upsertGoogleLoadBalancerDescription', {
                'healthCheck': health_check,
                'region': self.bindings['TEST_GCE_REGION'],
                'credentials': self.bindings['SPINNAKER_GOOGLE_ACCOUNT'],
                'loadBalancerName': self.__use_lb_name
            })

        builder = gcp.GcpContractBuilder(self.gcp_observer)
        (builder.new_clause_builder(
            'Forwarding Rules Added',
            retryable_for_secs=30).list_resource('forwardingRules').EXPECT(
                ov_factory.value_list_contains(
                    jp.DICT_MATCHES({
                        'name':
                        jp.STR_SUBSTR(self.__use_lb_name),
                        'target':
                        jp.STR_SUBSTR(self.__use_lb_target)
                    }))))
        (builder.new_clause_builder(
            'Target Pool Added',
            retryable_for_secs=15).list_resource('targetPools').EXPECT(
                ov_factory.value_list_path_contains(
                    'name', jp.STR_SUBSTR(self.__use_lb_tp_name))))

        # We list the resources here because the name isnt exact
        # and the list also returns the details we need.
        hc_dict = dict(health_check)
        del hc_dict['requestPath']

        hc_match = {name: jp.NUM_EQ(value) for name, value in hc_dict.items()}
        hc_match['requestPath'] = jp.STR_EQ(path)
        hc_match['name'] = jp.STR_SUBSTR(self.__use_http_lb_hc_name)
        (builder.new_clause_builder(
            'Health Check Added',
            retryable_for_secs=15).list_resource('httpHealthChecks').EXPECT(
                ov_factory.value_list_contains(jp.DICT_MATCHES(hc_match))))

        return st.OperationContract(self.new_post_operation(
            title='upsert_load_balancer', data=payload, path='ops'),
                                    contract=builder.build())
Exemple #19
0
  def create_instances(self):
    """Creates test adding instances to GCE.

     Create three instances.
       * The first two are of different types and zones, which
         we'll check. Future tests will also be using these
         from different zones (but same region).

       * The third is a duplicate in the same zone as another
         so we can check duplicate deletes (which limit one zone per call).

     We'll set the class properties use_instance_names and use_instance_zones
     so that they can be communicated to future tests to reference.

    Returns:
      st.OperationContract
    """
    # We're going to make specific instances so we can refer to them later
    # in tests involving instances. The instances are decorated to trace back
    # to this particular run so as not to conflict with other tests that may
    # be running.
    self.use_instance_names = [
        'katotest%sa' % self.test_id,
        'katotest%sb' % self.test_id,
        'katotest%sc' % self.test_id]

    # Put the instance in zones. Force one zone to be different
    # to ensure we're testing zone placement. We arent bothering
    # with different regions at this time.
    self.use_instance_zones = [
        self.bindings['TEST_GCE_ZONE'],
        'us-central1-b',
        self.bindings['TEST_GCE_ZONE']]
    if self.use_instance_zones[0] == self.use_instance_zones[1]:
      self.use_instance_zones[1] = 'us-central1-c'

    # Give the instances images and machine types. Again we're forcing
    # one to be different to ensure that we're using the values.
    image_name = [self.bindings['TEST_GCE_IMAGE_NAME'],
                  'debian-7-wheezy-v20150818',
                  self.bindings['TEST_GCE_IMAGE_NAME']]
    if image_name[0] == image_name[1]:
      image_name[1] = 'ubuntu-1404-trusty-v20150805'
    machine_type = ['f1-micro', 'g1-small', 'f1-micro']

    # The instance_spec will turn into the payload of instances we request.
    instance_spec = []
    builder = gcp.GcpContractBuilder(self.gcp_observer)
    for i in range(3):
      # pylint: disable=bad-continuation
      instance_spec.append(
        {
          'createGoogleInstanceDescription': {
            'instanceName': self.use_instance_names[i],
            'image': image_name[i],
            'instanceType': machine_type[i],
            'zone': self.use_instance_zones[i],
            'credentials': self.bindings['SPINNAKER_GOOGLE_ACCOUNT']
            }
        })

      # Verify we created an instance, whether or not it boots.
      (builder.new_clause_builder(
          'Instance %d Created' % i, retryable_for_secs=90)
            .aggregated_list_resource('instances')
            .contains_path_value('name', self.use_instance_names[i]))
      if i < 2:
        # Verify the details are what we asked for.
        # Since we've finished the created clause, this already exists.
        # Note we're only checking the first two since they are different
        # from one another. Anything after that isnt necessary for the test.
        # The clause above already checked that they were all created so we
        # can assume from this test that the details are ok as well.
        (builder.new_clause_builder('Instance %d Details' % i)
            .inspect_resource('instances', self.use_instance_names[i],
                              zone=self.use_instance_zones[i])
            .contains_path_value('machineType', machine_type[i]))
        # Verify the instance eventually boots up.
        # We can combine this with above, but we'll probably need
        # to retry this, but not the above, so this way if the
        # above is broken (wrong), we wont retry thinking it isnt there yet.
        (builder.new_clause_builder('Instance %d Is Running' % i,
                             retryable_for_secs=90)
            .inspect_resource('instances', self.use_instance_names[i],
                              zone=self.use_instance_zones[i])
            .contains_path_eq('status', 'RUNNING'))

    payload = self.agent.make_json_payload_from_object(instance_spec)

    return st.OperationContract(
        self.new_post_operation(
            title='create_instances', data=payload, path='ops'),
        contract=builder.build())
Exemple #20
0
    def clone_server_group(self):
        job = [{
            "application": self.TEST_APP,
            "stack": self.TEST_STACK,
            "credentials": self.bindings["SPINNAKER_GOOGLE_ACCOUNT"],
            "loadBalancers": [self.__lb_name],
            "targetSize": 1,
            "capacity": {
                "min": 1,
                "max": 1,
                "desired": 1
            },
            "zone": self.TEST_ZONE,
            "network": "default",
            "instanceMetadata": {
                "load-balancer-names": self.__lb_name
            },
            "availabilityZones": {
                self.TEST_REGION: [self.TEST_ZONE]
            },
            "cloudProvider": "gce",
            "source": {
                "account": self.bindings["SPINNAKER_GOOGLE_ACCOUNT"],
                "region": self.TEST_REGION,
                "zone": self.TEST_ZONE,
                "serverGroupName": self.__server_group_name,
                "asgName": self.__server_group_name,
            },
            "instanceType": "f1-micro",
            "image": self.bindings["TEST_GCE_IMAGE_NAME"],
            "initialNumReplicas": 1,
            "loadBalancers": [self.__lb_name],
            "type": "cloneServerGroup",
            "account": self.bindings["SPINNAKER_GOOGLE_ACCOUNT"],
            "user": "******",
        }]
        job[0].update(self.__mig_payload_extra)

        builder = gcp.GcpContractBuilder(self.gcp_observer)
        (builder.new_clause_builder(
            self.__mig_title + " Cloned", retryable_for_secs=90).list_resource(
                self.__mig_manager_name, **self.__mig_manager_kwargs).EXPECT(
                    ov_factory.value_list_path_contains(
                        "baseInstanceName",
                        jp.STR_SUBSTR(self.__cloned_server_group_name))))
        (builder.new_clause_builder(
            "Instance template preserved",
            retryable_for_secs=150).list_resource("instanceTemplates").EXPECT(
                ov_factory.value_list_path_contains(
                    "properties/metadata/items",
                    jp.LIST_MATCHES([
                        jp.DICT_MATCHES({
                            "key":
                            jp.EQUIVALENT(self.__custom_user_data_key),
                            "value":
                            jp.EQUIVALENT(self.__custom_user_data_value),
                        })
                    ]),
                )))

        payload = self.agent.make_json_payload_from_kwargs(
            job=job,
            description=self.__mig_title + " Test - clone server group",
            application=self.TEST_APP,
        )

        return st.OperationContract(
            self.new_post_operation(title="clone_server_group",
                                    data=payload,
                                    path=self.__path),
            contract=builder.build(),
        )
    def add_security_group(self):
        '''Associates a security group with the L7 load balancer.
    '''
        bindings = self.bindings
        sec_group_payload = self.agent.make_json_payload_from_kwargs(
            job=[{
                'allowed': [{
                    'ipProtocol': 'tcp',
                    'portRanges': ['80-80']
                }, {
                    'ipProtocol': 'tcp',
                    'portRanges': ['8080-8080']
                }, {
                    'ipProtocol': 'tcp',
                    'portRanges': ['443-443']
                }],
                'backingData': {
                    'networks': ['default']
                },
                'cloudProvider':
                'gce',
                'application':
                self.TEST_APP,
                'credentials':
                bindings['SPINNAKER_GOOGLE_ACCOUNT'],
                'description':
                '',
                'detail':
                'http',
                'ipIngress': [{
                    'type': 'tcp',
                    'startPort': 80,
                    'endPort': 80,
                }, {
                    'type': 'tcp',
                    'startPort': 8080,
                    'endPort': 8080,
                }, {
                    'type': 'tcp',
                    'startPort': 443,
                    'endPort': 443,
                }],
                'name':
                self.__lb_name + '-rule',
                'network':
                'default',
                'region':
                'global',
                'securityGroupName':
                self.__lb_name + '-rule',
                'sourceRanges': ['0.0.0.0/0'],
                'targetTags': [self.__lb_name + '-tag'],
                'type':
                'upsertSecurityGroup',
                'user':
                '******'
            }],
            description='Create a Security Group for L7 operations.',
            application=self.TEST_APP)
        builder = gcp.GcpContractBuilder(self.gcp_observer)
        (builder.new_clause_builder('Security Group Created',
                                    retryable_for_secs=30).list_resource(
                                        'firewalls').contains_path_value(
                                            'name', self.__lb_name + '-rule'))

        return st.OperationContract(self.new_post_operation(
            title='create security group',
            data=sec_group_payload,
            path='tasks'),
                                    contract=builder.build())
Exemple #22
0
    def clone_server_group(self):
        job = [{
            'application': self.TEST_APP,
            'stack': self.TEST_STACK,
            'credentials': self.bindings['SPINNAKER_GOOGLE_ACCOUNT'],
            'loadBalancers': [self.__lb_name],
            'targetSize': 1,
            'capacity': {
                'min': 1,
                'max': 1,
                'desired': 1
            },
            'zone': self.TEST_ZONE,
            'network': 'default',
            'instanceMetadata': {
                'load-balancer-names': self.__lb_name
            },
            'availabilityZones': {
                self.TEST_REGION: [self.TEST_ZONE]
            },
            'cloudProvider': 'gce',
            'source': {
                'account': self.bindings['SPINNAKER_GOOGLE_ACCOUNT'],
                'region': self.TEST_REGION,
                'zone': self.TEST_ZONE,
                'serverGroupName': self.__server_group_name,
                'asgName': self.__server_group_name
            },
            'instanceType': 'f1-micro',
            'image': self.bindings['TEST_GCE_IMAGE_NAME'],
            'initialNumReplicas': 1,
            'loadBalancers': [self.__lb_name],
            'type': 'cloneServerGroup',
            'account': self.bindings['SPINNAKER_GOOGLE_ACCOUNT'],
            'user': '******'
        }]
        job[0].update(self.__mig_payload_extra)

        builder = gcp.GcpContractBuilder(self.gcp_observer)
        (builder.new_clause_builder(
            self.__mig_title + ' Cloned', retryable_for_secs=90).list_resource(
                self.__mig_manager_name, **self.__mig_manager_kwargs).EXPECT(
                    ov_factory.value_list_path_contains(
                        'baseInstanceName',
                        jp.STR_SUBSTR(self.__cloned_server_group_name))))
        (builder.new_clause_builder(
            'Instance template preserved',
            retryable_for_secs=150).list_resource('instanceTemplates').EXPECT(
                ov_factory.value_list_path_contains(
                    'properties/metadata/items',
                    jp.LIST_MATCHES([
                        jp.DICT_MATCHES({
                            'key':
                            jp.EQUIVALENT(self.__custom_user_data_key),
                            'value':
                            jp.EQUIVALENT(self.__custom_user_data_value)
                        })
                    ]))))

        payload = self.agent.make_json_payload_from_kwargs(
            job=job,
            description=self.__mig_title + ' Test - clone server group',
            application=self.TEST_APP)

        return st.OperationContract(self.new_post_operation(
            title='clone_server_group', data=payload, path=self.__path),
                                    contract=builder.build())
Exemple #23
0
    def create_server_group(self):
        """Creates OperationContract for createServerGroup.

    To verify the operation, we just check that the server group was created.
    """
        bindings = self.bindings

        # Spinnaker determines the group name created,
        # which will be the following:
        group_name = frigga.Naming.server_group(app=self.TEST_APP,
                                                stack=bindings['TEST_STACK'],
                                                version='v000')

        payload = self.agent.make_json_payload_from_kwargs(
            job=[{
                'cloudProvider':
                'kubernetes',
                'application':
                self.TEST_APP,
                'account':
                bindings['SPINNAKER_KUBERNETES_ACCOUNT'],
                'strategy':
                '',
                'targetSize':
                1,
                'containers': [{
                    'name':
                    'validated',
                    'imageDescription': {
                        'repository': self.__image_repository,
                        'tag': self.__desired_image_tag,
                        'imageId': self.__desired_image_id,
                        'registry': self.__image_registry
                    },
                    'requests': {
                        'memory': None,
                        'cpu': None
                    },
                    'limits': {
                        'memory': None,
                        'cpu': None
                    },
                    'ports': [{
                        'name': 'http',
                        'containerPort': 80,
                        'protocol': 'TCP',
                        'hostPort': None,
                        'hostIp': None
                    }]
                },
                               {
                                   'name':
                                   'broken',
                                   'imageDescription': {
                                       'repository': self.__image_repository,
                                       'tag': self.__undesired_image_tag,
                                       'imageId': self.__undesired_image_id,
                                       'registry': self.__image_registry
                                   },
                                   'requests': {
                                       'memory': None,
                                       'cpu': None
                                   },
                                   'limits': {
                                       'memory': None,
                                       'cpu': None
                                   },
                                   'ports': [{
                                       'name': 'http',
                                       'containerPort': 80,
                                       'protocol': 'TCP',
                                       'hostPort': None,
                                       'hostIp': None
                                   }]
                               }],
                'stack':
                bindings['TEST_STACK'],
                'loadBalancers': [self.__lb_name],
                'type':
                'createServerGroup',
                'region':
                'default',
                'user':
                '******'
            }],
            description='Create Server Group in ' + group_name,
            application=self.TEST_APP)

        builder = kube.KubeContractBuilder(self.kube_observer)
        (builder.new_clause_builder(
            'Replica Set Added', retryable_for_secs=15).get_resources(
                'rs',
                extra_args=[group_name]).contains_path_eq('spec/replicas', 1))

        return st.OperationContract(self.new_post_operation(
            title='create_server_group', data=payload, path='tasks'),
                                    contract=builder.build())
 def delete_app(self):
     """Creates OperationContract that deletes a new Spinnaker Application."""
     return st.OperationContract(self.agent.make_delete_app_operation(
         application=self.TEST_APP, account_name=self.ACCOUNT),
                                 contract=jc.Contract(),
                                 cleanup=self.delete_resource_group)
Exemple #25
0
    def update_app(self):
        contract = jc.Contract()

        spec = {}
        for name, value in self.initial_app_spec.items():
            if name == 'name':
                spec[name] = value
            elif name == 'cloudProviders':
                spec[name] = value + ',kubernetes'
            elif name in ['updateTs', 'createTs']:
                spec[name] = str(int(value) + 1)
            elif isinstance(value, basestring):
                spec[name] = 'NEW_' + value
        payload = self.agent.make_json_payload_from_object(spec)
        expectUpdate = dict(spec)

        # The actual update is determined by front50.
        # The createTs we gave ignored.
        # As before, the name is upper-cased.
        del expectUpdate['updateTs']
        expectUpdate['createTs'] = self.initial_app_spec['createTs']
        expectUpdate['name'] = self.initial_app_spec['name'].upper()
        self.app_history.insert(0, expectUpdate)

        # TODO(ewiseblatt) 20160524:
        # Add clauses that observe Front50 to verify the history method works
        # and that the get method is the current version.
        num_versions = 2 if self.versioning_enabled else 1
        gcs_builder = gcp.GcpStorageContractBuilder(self.gcs_observer)
        (gcs_builder.new_clause_builder(
            'Google Cloud Storage Contains File',
            retryable_for_secs=5).list_bucket(
                self.BUCKET,
                '/'.join([self.BASE_PATH, 'applications', self.TEST_APP]),
                with_versions=True).contains_path_value('name',
                                                        self.TEST_APP,
                                                        min=num_versions,
                                                        max=num_versions))
        (gcs_builder.new_clause_builder(
            'Updated File Content', retryable_for_secs=5).retrieve_content(
                self.BUCKET,
                '/'.join([
                    self.BASE_PATH, 'applications', self.TEST_APP,
                    'specification.json'
                ]),
                transform=json.JSONDecoder().decode).contains_match({
                    key: jp.EQUIVALENT(value)
                    for key, value in expectUpdate.items()
                }))

        for clause in gcs_builder.build().clauses:
            contract.add_clause(clause)

        f50_builder = st.http_observer.HttpContractBuilder(self.agent)
        (f50_builder.new_clause_builder(
            'History Records Changes').get_url_path(
                '/v2/applications/{app}/history'.format(
                    app=self.TEST_APP)).contains_path_match(
                        '[0]', {
                            key: jp.EQUIVALENT(value)
                            for key, value in self.app_history[0].items()
                        }).contains_path_match(
                            '[1]', {
                                key: jp.EQUIVALENT(value)
                                for key, value in self.app_history[1].items()
                            }))

        for clause in f50_builder.build().clauses:
            contract.add_clause(clause)

        # TODO(ewiseblatt): 20160524
        # Add a mechanism here to check the previous version
        # so that we can verify version recovery as well.
        path = '/'.join(['/v2/applications', self.TEST_APP])
        return st.OperationContract(self.new_patch_operation(
            title='update_app', data=payload, path=path),
                                    contract=contract)
    def create_load_balancer(self):
        """Create OperationContract that create a new Load Balancer

        To verify the operation, we just check that the spinnaker load balancer
        for the given application was created.
        """
        self.__lb_type = "Azure Load Balancer"
        healthyCheck = [{
            "probeName":
            "{lb}-probe".format(lb=self.__full_lb_name),
            "probeProtocol":
            "TCP",
            "probePort":
            "80",
            "probeInterval":
            30,
            "unhealthyThreshold":
            8,
            "timeout":
            120
        }]
        rules = [{
            "ruleName": "{lb}-rule0".format(lb=self.__full_lb_name),
            "protocol": "TCP",
            "externalPort": 80,
            "backendPort": 80,
            "probeName": "{lb}-probe".format(lb=self.__full_lb_name),
            "persistence": "None",
            "idleTimeout": 4
        }]
        payload = self.agent.make_json_payload_from_kwargs(
            job=[{
                "stack": self.__stack,
                "detail": self.__detail,
                "credentials": self.ACCOUNT,
                "region": self.__rg_location,
                "cloudProvider": "azure",
                "vnet": None,
                "subnet": None,
                "probes": healthyCheck,
                "securityGroups": [],
                "loadBalancingRules": rules,
                "name": self.__full_lb_name,
                "selectedVnet": None,
                "vnetResourceGroup": None,
                "selectedSubnet": None,
                "type": "upsertLoadBalancer",
                "loadBalancerType": self.__lb_type,
                "appName": self.TEST_APP,
                "loadBalancerName": self.__full_lb_name,
                "user": "******"
            }],
            description="Test - Create load balancer: {lb}".format(
                lb=self.__full_lb_name),
            application=self.TEST_APP)

        builder = az.AzContractBuilder(self.az_observer)
        (builder.new_clause_builder(
            'Load Balancer Created', retryable_for_secs=30).collect_resources(
                az_resource='network',
                command='lb',
                args=[
                    'list', '--resource-group',
                    '{app}-{rg}'.format(app=self.TEST_APP,
                                        rg=self.__rg_location)
                ]).EXPECT(
                    ov_factory.value_list_contains(
                        jp.DICT_MATCHES({
                            'name':
                            jp.STR_EQ(self.__full_lb_name),
                            'location':
                            jp.STR_EQ(self.__rg_location)
                        }))))

        return st.OperationContract(self.new_post_operation(
            title="create_load_balancer",
            data=payload,
            path=('applications/{app}/tasks').format(app=self.TEST_APP),
            max_wait_secs=2400),
                                    contract=builder.build())
 def delete_app(self):
     contract = jc.Contract()
     return st.OperationContract(self.agent.make_delete_app_operation(
         bindings=self.bindings, application=self.TEST_APP),
                                 contract=contract)
    def create_application_gateway(self):
        """Create OperationContract that create a new Application gateway

        To verify the operation, we just check that the spinnaker load balancer
        for the given application was created.
        """
        self.__lb_type = "Azure Application Gateway"
        healthyCheck = [{
            "probeName":
            "{lb}-probe".format(lb=self.__full_lb_name),
            "probeProtocol":
            "HTTP",
            "probePort":
            "80",
            "probePath":
            "/",
            "probeInterval":
            30,
            "unhealthyThreshold":
            8,
            "timeout":
            120
        }]
        rules = [{
            "ruleName": "{lb}-rule0".format(lb=self.__full_lb_name),
            "protocol": "HTTP",
            "externalPort": 80,
            "backendPort": 80,
            "probeName": "{lb}-probe".format(lb=self.__full_lb_name),
            "persistence": "None",
            "idleTimeout": 4
        }]
        subnets = [{
            "account":
            self.ACCOUNT,
            "addressPrefix":
            self.__subnet[0]['ADDRESS'],
            "device": [],
            "id":
            '/subscriptions/{id}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{name}'
            .format(id=self.__subscription_id,
                    rg=self.__rg_name,
                    vnet=self.__vnet_name,
                    name=self.__subnet[0]['NAME']),
            "name":
            self.__subnet[0]['NAME'],
            "purpose":
            'TBD',
            "region":
            self.__rg_location,
            "type":
            'azure',
            "vnet":
            self.__vnet_name
        }, {
            "account":
            self.ACCOUNT,
            "addressPrefix":
            self.__subnet[1]['ADDRESS'],
            "device": [],
            "id":
            '/subscriptions/{id}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{name}'
            .format(id=self.__subscription_id,
                    rg=self.__rg_name,
                    vnet=self.__vnet_name,
                    name=self.__subnet[1]['NAME']),
            "name":
            self.__subnet[1]['NAME'],
            "purpose":
            'TBD',
            "region":
            self.__rg_location,
            "type":
            'azure',
            "vnet":
            self.__vnet_name
        }]
        vnet = {
            "account": self.ACCOUNT,
            "cloudProvider": "azure",
            "id": self.__vnet_name,
            "name": self.__vnet_name,
            "region": self.__rg_location,
            "resourceGroup": self.__rg_name,
            "subnets": subnets
        }

        payload = self.agent.make_json_payload_from_kwargs(
            job=[{
                "stack": self.__stack,
                "detail": self.__detail,
                "credentials": self.ACCOUNT,
                "region": self.__rg_location,
                "cloudProvider": "azure",
                "vnet": self.__vnet_name,
                "subnet": self.__subnet[1]['NAME'],
                "probes": healthyCheck,
                "securityGroups": [],
                "loadBalancingRules": rules,
                "name": self.__full_lb_name,
                "selectedVnet": vnet,
                "vnetResourceGroup": self.__rg_name,
                "selectedSubnet": subnets[1],
                "type": "upsertLoadBalancer",
                "loadBalancerType": self.__lb_type,
                "appName": self.TEST_APP,
                "loadBalancerName": self.__full_lb_name,
                "user": "******"
            }],
            description="Test - Create application gateway: {lb}".format(
                lb=self.__full_lb_name),
            application=self.TEST_APP)

        builder = az.AzContractBuilder(self.az_observer)
        (builder.new_clause_builder(
            'Application Gateway Created',
            retryable_for_secs=30).collect_resources(
                az_resource='network',
                command='application-gateway',
                args=[
                    'list', '--resource-group',
                    '{app}-{rg}'.format(app=self.TEST_APP,
                                        rg=self.__rg_location)
                ]).EXPECT(
                    ov_factory.value_list_contains(
                        jp.DICT_MATCHES({
                            'name':
                            jp.STR_EQ(self.__full_lb_name),
                            'tags':
                            jp.DICT_MATCHES({
                                'vnet':
                                jp.STR_EQ(self.__vnet_name),
                                'subnet':
                                jp.STR_EQ(self.__subnet[1]['NAME'])
                            })
                        }))))

        return st.OperationContract(self.new_post_operation(
            title="create_application_gateway",
            data=payload,
            path=('applications/{app}/tasks').format(app=self.TEST_APP),
            max_wait_secs=3600),
                                    contract=builder.build())
    def upsert_load_balancer(self):
        """Creates OperationContract for upsertLoadBalancer.

    Calls Spinnaker's upsertLoadBalancer with a configuration, then verifies
    that the expected resources and configurations are visible on GCE. See
    the contract builder for more info on what the expectations are.
    """
        bindings = self.bindings
        target_pool_name = '{0}/targetPools/{1}-tp'.format(
            bindings['TEST_GCE_REGION'], self.__lb_name)

        spec = {
            'checkIntervalSec': 9,
            'healthyThreshold': 3,
            'unhealthyThreshold': 5,
            'timeoutSec': 2,
            'port': 80
        }

        payload = self.agent.make_json_payload_from_kwargs(
            job=[{
                'cloudProvider': 'gce',
                'provider': 'gce',
                'stack': bindings['TEST_STACK'],
                'detail': self.__lb_detail,
                'credentials': bindings['SPINNAKER_GOOGLE_ACCOUNT'],
                'region': bindings['TEST_GCE_REGION'],
                'ipProtocol': 'TCP',
                'portRange': spec['port'],
                'loadBalancerName': self.__lb_name,
                'healthCheck': {
                    'port': spec['port'],
                    'timeoutSec': spec['timeoutSec'],
                    'checkIntervalSec': spec['checkIntervalSec'],
                    'healthyThreshold': spec['healthyThreshold'],
                    'unhealthyThreshold': spec['unhealthyThreshold'],
                },
                'type': 'upsertLoadBalancer',
                'availabilityZones': {
                    bindings['TEST_GCE_REGION']: []
                },
                'user': '******'
            }],
            description='Create Load Balancer: ' + self.__lb_name,
            application=self.TEST_APP)

        builder = gcp.GcpContractBuilder(self.gcp_observer)
        (builder.new_clause_builder(
            'Health Check Added', retryable_for_secs=30).list_resource(
                'httpHealthChecks').contains_pred_list([
                    jp.PathContainsPredicate('name', '%s-hc' % self.__lb_name),
                    jp.DICT_SUBSET(spec)
                ]))
        (builder.new_clause_builder('Target Pool Added',
                                    retryable_for_secs=30).list_resource(
                                        'targetPools').contains_path_value(
                                            'name', '%s-tp' % self.__lb_name))
        (builder.new_clause_builder(
            'Forwarding Rules Added', retryable_for_secs=30).list_resource(
                'forwardingRules').contains_pred_list([
                    jp.PathContainsPredicate('name', self.__lb_name),
                    jp.PathContainsPredicate('target', target_pool_name)
                ]))

        return st.OperationContract(self.new_post_operation(
            title='upsert_load_balancer', data=payload, path='tasks'),
                                    contract=builder.build())
Exemple #30
0
    def create_http_load_balancer(self):
        logical_http_lb_name = 'katotest-httplb-' + self.test_id
        self.__use_http_lb_name = logical_http_lb_name

        self.__use_http_lb_hc_name = logical_http_lb_name + '-health-check'
        self.__use_http_lb_bs_name = logical_http_lb_name + '-backend-service'
        self.__use_http_lb_fr_name = logical_http_lb_name
        self.__use_http_lb_map_name = logical_http_lb_name + '-url-map'
        self.__use_http_lb_proxy_name = logical_http_lb_name + '-target-http-proxy'

        interval = 231
        healthy = 8
        unhealthy = 9
        timeout = 65
        path = '/hello/world'
        port_range = "123-456"

        health_check = {
            'checkIntervalSec': interval,
            'healthyThreshold': healthy,
            'unhealthyThreshold': unhealthy,
            'timeoutSec': timeout,
            'requestPath': path
        }

        # pylint: disable=bad-continuation
        payload = self.agent.type_to_payload(
            'createGoogleHttpLoadBalancerDescription', {
                'healthCheck': health_check,
                'portRange': port_range,
                'loadBalancerName': logical_http_lb_name,
                'credentials': self.bindings['SPINNAKER_GOOGLE_ACCOUNT']
            })

        hc_dict = dict(health_check)
        del hc_dict['requestPath']
        hc_match = {
            name: jp.NUM_EQ(value)
            for name, value in health_check.items()
        }
        hc_match['requestPath'] = jp.STR_EQ(path)
        hc_match['name'] = jp.STR_SUBSTR(self.__use_http_lb_hc_name),
        builder = gcp.GcpContractBuilder(self.gcp_observer)
        (builder.new_clause_builder('Http Health Check Added').list_resource(
            'httpHealthChecks').EXPECT(
                ov_factory.value_list_contains(jp.DICT_MATCHES(hc_match))))
        (builder.new_clause_builder(
            'Global Forwarding Rule Added',
            retryable_for_secs=15).list_resource(
                'globalForwardingRules').EXPECT(
                    ov_factory.value_list_contains(
                        jp.DICT_MATCHES({
                            'name':
                            jp.STR_SUBSTR(self.__use_http_lb_fr_name),
                            'portRange':
                            jp.STR_EQ(port_range)
                        }))))
        (builder.new_clause_builder('Backend Service Added').list_resource(
            'backendServices').EXPECT(
                ov_factory.value_list_contains(
                    jp.DICT_MATCHES({
                        'name':
                        jp.STR_SUBSTR(self.__use_http_lb_bs_name),
                        'healthChecks':
                        jp.STR_SUBSTR(self.__use_http_lb_hc_name)
                    }))))
        (builder.new_clause_builder('Url Map Added').list_resource(
            'urlMaps').EXPECT(
                ov_factory.value_list_contains(
                    jp.DICT_MATCHES({
                        'name':
                        jp.STR_SUBSTR(self.__use_http_lb_map_name),
                        'defaultService':
                        jp.STR_SUBSTR(self.__use_http_lb_bs_name)
                    }))))
        (builder.new_clause_builder('Target Http Proxy Added').list_resource(
            'targetHttpProxies').EXPECT(
                ov_factory.value_list_contains(
                    jp.DICT_MATCHES({
                        'name':
                        jp.STR_SUBSTR(self.__use_http_lb_proxy_name),
                        'urlMap':
                        jp.STR_SUBSTR(self.__use_http_lb_map_name)
                    }))))

        return st.OperationContract(self.new_post_operation(
            title='create_http_load_balancer', data=payload, path='ops'),
                                    contract=builder.build())