def create_third_party_resource(): metadata = ObjectMeta(name="paasbeta-application.schibsted.io") paasbeta_application_resource = ThirdPartyResource.get_or_create( metadata=metadata, description='A paas application definition', versions=[APIVersion(name='v1beta')]) paasbeta_application_resource.save() LOG.debug("Created ThirdPartyResource with name PaasbetaApplication") metadata = ObjectMeta(name="paasbeta-status.schibsted.io") paasbeta_status_resource = ThirdPartyResource.get_or_create( metadata=metadata, description='A paas application status', versions=[APIVersion(name='v1beta')]) paasbeta_status_resource.save() LOG.debug("Created ThirdPartyResource with name PaasbetaStatus")
def test_create_blank_object_meta(self): meta = ObjectMeta(name=SERVICE_NAME, namespace=SERVICE_NAMESPACE, labels={"label": "value"}) assert not hasattr(meta, "_name") assert meta.name == SERVICE_NAME assert meta.namespace == SERVICE_NAMESPACE assert meta.labels == {"label": "value"} assert meta.as_dict() == { "name": SERVICE_NAME, "namespace": SERVICE_NAMESPACE, "labels": { "label": "value" } }
def deploy(self, target_namespace, release): """Create or update TPR for application""" application_name = release.application_name config = self.download_config(release.config_url) namespace = config["namespace"] if (config['version'] < 3) and ( "namespace" in config) else target_namespace deployment_id = self.create_deployment_id() labels = { "fiaas/deployment_id": deployment_id, "app": application_name } metadata = ObjectMeta(name=application_name, namespace=namespace, labels=labels) spec = self.spec_model(application=application_name, image=release.image, config=config) try: application = self.application_model.get(application_name, namespace) application.metadata = metadata application.spec = spec except NotFound: application = self.application_model(metadata=metadata, spec=spec) application.save() return namespace, application_name, deployment_id
def test_retry_on_conflict(self, get_or_create, save, app_spec, signal, signal_name, fail_times): def _fail(): response = mock.MagicMock(spec=Response) response.status_code = 409 # Conflict raise ClientError("Conflict", response=response) configure_mock_fail_then_success(save, fail=_fail, fail_times=fail_times) application_status = FiaasApplicationStatus( metadata=ObjectMeta(name=app_spec.name, namespace="default")) get_or_create.return_value = application_status status.connect_signals() try: signal(signal_name).send(app_name=app_spec.name, namespace=app_spec.namespace, deployment_id=app_spec.deployment_id) except UpsertConflict as e: if fail_times < CONFLICT_MAX_RETRIES: pytest.fail('Exception {} was raised when signaling {}'.format( e, signal_name)) save_calls = min(fail_times + 1, CONFLICT_MAX_RETRIES) assert save.call_args_list == [mock.call()] * save_calls
def test_apply_tls(self, tls, app_spec, spec_tls, issuer_type, tls_annotations): ingress = Ingress() ingress.metadata = ObjectMeta(name=app_spec.name) tls.apply(ingress, app_spec, self.HOSTS, issuer_type) assert ingress.metadata.annotations == tls_annotations assert ingress.spec.tls == spec_tls
def _create_default_configmap(): object_meta = ObjectMeta(name=NAME, namespace=NAMESPACE, labels={"test": "true"}) data = {"foo": "bar"} configmap = ConfigMap(metadata=object_meta, data=data) return configmap
def test_deployer_creates_object_of_given_type(self, get, k8s_model, object_types, config, target_namespace, expected_namespace): http_client = _given_config_url_response_content_is(config) _, spec_model = object_types deployer = Deployer(http_client, create_deployment_id=lambda: DEPLOYMENT_ID) returned_namespace, returned_name, returned_id = deployer.deploy( target_namespace=target_namespace, release=Release(VALID_IMAGE_NAME, VALID_DEPLOY_CONFIG_URL, APPLICATION_NAME, APPLICATION_NAME, SPINNAKER_TAGS, RAW_TAGS)) assert returned_namespace == expected_namespace assert returned_name == APPLICATION_NAME assert returned_id == DEPLOYMENT_ID http_client.get.assert_called_once_with(VALID_DEPLOY_CONFIG_URL) metadata = ObjectMeta(name=APPLICATION_NAME, namespace=expected_namespace, labels={ "fiaas/deployment_id": DEPLOYMENT_ID, "app": APPLICATION_NAME }) spec = spec_model(application=APPLICATION_NAME, image=VALID_IMAGE_NAME, config=yaml.safe_load(config)) get.assert_called_once_with(APPLICATION_NAME, expected_namespace) assert metadata == k8s_model.metadata assert spec == k8s_model.spec k8s_model.save.assert_called_once()
def test_lifecycle(self, logger): object_meta = ObjectMeta(name=NAME, namespace=NAMESPACE, labels={"test": "true"}) container_port = ContainerPort(name="http5000", containerPort=5000) http = HTTPGetAction(path="/", port="http5000") liveness = Probe(httpGet=http) tcp = TCPSocketAction(port=5000) readiness = Probe(tcpSocket=tcp) container = Container(name="container", image="dummy_image", ports=[container_port], livenessProbe=liveness, readinessProbe=readiness) image_pull_secret = LocalObjectReference(name="image_pull_secret") pod_spec = PodSpec(containers=[container], imagePullSecrets=[image_pull_secret], serviceAccountName="default") pod_template_spec = PodTemplateSpec(metadata=object_meta, spec=pod_spec) rc_spec = ReplicationControllerSpec(replicas=2, selector={"test": "true"}, template=pod_template_spec) first = ReplicationController(metadata=object_meta, spec=rc_spec) logger.debug(pformat(first.as_dict())) first.save() second = ReplicationController.get(NAME, NAMESPACE) assert first.metadata.name == second.metadata.name assert first.metadata.namespace == second.metadata.namespace
def _create_pod(): object_meta = ObjectMeta(name=NAME, namespace=NAMESPACE, labels={ "test": "true", "app": NAME }) container_port = ContainerPort(name="http5000", containerPort=5000) secrets_volume_mounts = [ VolumeMount( name=NAME, readOnly=True, mountPath="/var/run/secrets/kubernetes.io/kubernetes-secrets") ] secret_volumes = [ Volume(name=NAME, secret=SecretVolumeSource(secretName=NAME)) ] container = Container(name="container", image="dummy_image", ports=[container_port], volumeMounts=secrets_volume_mounts) image_pull_secret = LocalObjectReference(name="image_pull_secret") pod_spec = PodSpec(containers=[container], imagePullSecrets=[image_pull_secret], volumes=secret_volumes, serviceAccountName="default") first = Pod(metadata=object_meta, spec=pod_spec) return first
def deploy(self, app_spec, labels): if should_have_autoscaler(app_spec): LOG.info("Creating/updating %s for %s", self.name, app_spec.name) custom_labels = merge_dicts( app_spec.labels.horizontal_pod_autoscaler, labels) metadata = ObjectMeta( name=app_spec.name, namespace=app_spec.namespace, labels=custom_labels, annotations=app_spec.annotations.horizontal_pod_autoscaler) scale_target_ref = CrossVersionObjectReference( kind=u"Deployment", name=app_spec.name, apiVersion="apps/v1") spec = HorizontalPodAutoscalerSpec( scaleTargetRef=scale_target_ref, minReplicas=app_spec.autoscaler.min_replicas, maxReplicas=app_spec.autoscaler.max_replicas, targetCPUUtilizationPercentage=app_spec.autoscaler. cpu_threshold_percentage) autoscaler = HorizontalPodAutoscaler.get_or_create( metadata=metadata, spec=spec) self._owner_references.apply(autoscaler, app_spec) autoscaler.save() else: try: LOG.info("Deleting any pre-existing autoscaler for %s", app_spec.name) HorizontalPodAutoscaler.delete(app_spec.name, app_spec.namespace) except NotFound: pass
def test_pass_to_deployment(self, app_spec, k8s, deployment_deployer, resource_quota_list, resource_quota_specs, expect_strip_resources, has_resources): explicit_resources = ResourcesSpec( limits=ResourceRequirementSpec(cpu="200m", memory="128M"), requests=ResourceRequirementSpec(cpu="100m", memory="64M")) no_resources = ResourcesSpec( limits=ResourceRequirementSpec(cpu=None, memory=None), requests=ResourceRequirementSpec(cpu=None, memory=None)) app_spec = app_spec._replace( resources=explicit_resources if has_resources else no_resources) expected_app_spec = app_spec._replace( resources=no_resources) if expect_strip_resources else app_spec resource_quotas = [ ResourceQuota(metadata=ObjectMeta(name="quota-{}".format(i), namespace=app_spec.namespace), spec=ResourceQuotaSpec(**spec)) for i, spec in enumerate(resource_quota_specs) ] resource_quota_list.return_value = resource_quotas selector = _make_selector(app_spec) labels = k8s._make_labels(app_spec) k8s.deploy(app_spec) pytest.helpers.assert_any_call(deployment_deployer.deploy, expected_app_spec, selector, labels, expect_strip_resources)
def test_apply_with_no_uid(self, app_spec, owner_references): ingress = Ingress(metadata=ObjectMeta()) app_spec = app_spec._replace(uid=None) owner_references.apply(ingress, app_spec) assert ingress.metadata.ownerReferences == []
def _create_default_deployment(): labels = {"test": "true"} object_meta = ObjectMeta(name=NAME, namespace=NAMESPACE, labels=labels) container_port = ContainerPort(name="http5000", containerPort=5000) http = HTTPGetAction(path="/", port="http5000") liveness = Probe(httpGet=http) tcp = TCPSocketAction(port=5000) readiness = Probe(tcpSocket=tcp) container = Container(name="container", image="dummy_image", ports=[container_port], livenessProbe=liveness, readinessProbe=readiness) image_pull_secret = LocalObjectReference(name="image_pull_secret") pod_spec = PodSpec(containers=[container], imagePullSecrets=[image_pull_secret], serviceAccountName="default") pod_template_spec = PodTemplateSpec(metadata=object_meta, spec=pod_spec) deployer_spec = DeploymentSpec(replicas=2, selector=LabelSelector(matchLabels=labels), template=pod_template_spec, revisionHistoryLimit=5) deployment = Deployment(metadata=object_meta, spec=deployer_spec) return deployment
def custom_resource_definition(self, request, k8s_version): additional_labels = None if len(request.param) == 2: fiaas_path, expected = request.param elif len(request.param) == 3: fiaas_path, expected, additional_labels = request.param skip_if_crd_not_supported(k8s_version) fiaas_yml = read_yml( request.fspath.dirpath().join("specs").join(fiaas_path).strpath) expected = { kind: read_yml(request.fspath.dirpath().join(path).strpath) for kind, path in expected.items() } name = sanitize_resource_name(fiaas_path) metadata = ObjectMeta(name=name, namespace="default", labels={"fiaas/deployment_id": DEPLOYMENT_ID1}) spec = FiaasApplicationSpec(application=name, image=IMAGE1, config=fiaas_yml, additional_labels=additional_labels) request.addfinalizer(lambda: self._ensure_clean(name, expected)) return name, FiaasApplication(metadata=metadata, spec=spec), expected
def _create_pod_metadata(namespace, spec_config): pod_annotations = _get_pod_annotations(spec_config) pod_metadata = ObjectMeta(name=BOOTSTRAP_POD_NAME, annotations=pod_annotations, labels={"app": BOOTSTRAP_POD_NAME}, namespace=namespace) return pod_metadata
def test_create_blank_rc(self): object_meta = ObjectMeta(name=NAME, namespace=NAMESPACE, labels={"test": "true"}) rc = ReplicationController(metadata=object_meta) assert rc.metadata.name == NAME assert rc.as_dict()[u"metadata"][u"name"] == NAME
def _create(self, app_spec, selector, labels): LOG.info("Creating/updating service for %s with labels: %s", app_spec.name, labels) ports = [ self._make_service_port(port_spec) for port_spec in app_spec.ports ] try: svc = Service.get(app_spec.name, app_spec.namespace) ports = self._merge_ports(svc.spec.ports, ports) except NotFound: pass service_name = app_spec.name custom_labels = merge_dicts(app_spec.labels.service, labels) custom_annotations = merge_dicts( app_spec.annotations.service, self._make_tcp_port_annotation(app_spec)) metadata = ObjectMeta(name=service_name, namespace=app_spec.namespace, labels=custom_labels, annotations=custom_annotations) spec = ServiceSpec(selector=selector, ports=ports, type=self._service_type) svc = Service.get_or_create(metadata=metadata, spec=spec) self._owner_references.apply(svc, app_spec) svc.save()
def _create(self, app_spec, labels): LOG.info("Creating/updating ingress for %s", app_spec.name) annotations = { u"fiaas/expose": u"true" if _has_explicitly_set_host(app_spec) else u"false" } custom_labels = merge_dicts(app_spec.labels.ingress, labels) custom_annotations = merge_dicts(app_spec.annotations.ingress, annotations) metadata = ObjectMeta(name=app_spec.name, namespace=app_spec.namespace, labels=custom_labels, annotations=custom_annotations) per_host_ingress_rules = [ IngressRule(host=self._apply_host_rewrite_rules(ingress_item.host), http=self._make_http_ingress_rule_value( app_spec, ingress_item.pathmappings)) for ingress_item in app_spec.ingresses if ingress_item.host is not None ] default_host_ingress_rules = self._create_default_host_ingress_rules( app_spec) ingress_spec = IngressSpec(rules=per_host_ingress_rules + default_host_ingress_rules) ingress = Ingress.get_or_create(metadata=metadata, spec=ingress_spec) self._ingress_tls.apply(ingress, app_spec, self._get_hosts(app_spec)) ingress.save()
def _save_status(result, subject): (app_name, namespace, deployment_id, repository, labels, annotations) = subject LOG.info("Saving result %s for %s/%s deployment_id=%s", result, namespace, app_name, deployment_id) name = create_name(app_name, deployment_id) labels = labels or {} annotations = annotations or {} labels = merge_dicts(labels, { "app": app_name, "fiaas/deployment_id": deployment_id }) annotations = merge_dicts(annotations, {LAST_UPDATED_KEY: now()}) logs = _get_logs(app_name, namespace, deployment_id, result) try: status = FiaasApplicationStatus.get(name, namespace) status.metadata.labels = merge_dicts(status.metadata.labels, labels) status.metadata.annotations = merge_dicts(status.metadata.annotations, annotations) status.logs = logs status.result = result except NotFound: metadata = ObjectMeta(name=name, namespace=namespace, labels=labels, annotations=annotations) status = FiaasApplicationStatus.get_or_create(metadata=metadata, result=result, logs=logs) resource_version = status.metadata.resourceVersion LOG.debug("save()-ing %s for %s/%s deployment_id=%s resourceVersion=%s", result, namespace, app_name, deployment_id, resource_version) status.save()
def test_apply_tls(self, tls, app_spec, spec_tls, tls_annotations): ingress = Ingress() ingress.metadata = ObjectMeta() ingress.spec = IngressSpec() tls.apply(ingress, app_spec, self.HOSTS) assert ingress.metadata.annotations == tls_annotations assert ingress.spec.tls == spec_tls
def _create_deployment(available_replicas, namespace, image): container = Container(image=image) pod_spec = PodSpec(containers=[container]) pod_template_spec = PodTemplateSpec(spec=pod_spec) spec = DeploymentSpec(replicas=1, template=pod_template_spec) status = DeploymentStatus(availableReplicas=available_replicas) metadata = ObjectMeta(name=NAME, namespace=namespace) return Deployment(metadata=metadata, spec=spec, status=status)
def _create_default_resourcequota(): objectmeta = ObjectMeta(name=NAME, namespace=NAMESPACE, labels={"test": "true"}) resourcequotaspec = ResourceQuotaSpec(hard={"pods": "0"}, scopes=[NotBestEffort]) resourcequota = ResourceQuota(metadata=objectmeta, spec=resourcequotaspec) return resourcequota
def deployment(): main_container = Container( env=[EnvVar(name=CANARY_NAME, value=CANARY_VALUE)]) pod_spec = PodSpec(containers=[main_container]) pod_metadata = ObjectMeta(annotations={CANARY_NAME: CANARY_VALUE}) pod_template_spec = PodTemplateSpec(spec=pod_spec, metadata=pod_metadata) deployment_spec = DeploymentSpec(template=pod_template_spec) return Deployment(spec=deployment_spec)
def test_multiple_ingresses(self, request, kind_logger): with kind_logger(): fiaas_path = "v3/data/examples/multiple_ingress.yml" fiaas_yml = read_yml(request.fspath.dirpath().join("specs").join(fiaas_path).strpath) name = sanitize_resource_name(fiaas_path) expected = { name: read_yml(request.fspath.dirpath().join("e2e_expected/multiple_ingress1.yml").strpath), "{}-1".format(name): read_yml(request.fspath.dirpath().join("e2e_expected/multiple_ingress2.yml").strpath) } metadata = ObjectMeta(name=name, namespace="default", labels={"fiaas/deployment_id": DEPLOYMENT_ID1}) spec = FiaasApplicationSpec(application=name, image=IMAGE1, config=fiaas_yml) fiaas_application = FiaasApplication(metadata=metadata, spec=spec) fiaas_application.save() app_uid = fiaas_application.metadata.uid # Check that deployment status is RUNNING def _assert_status(): status = FiaasApplicationStatus.get(create_name(name, DEPLOYMENT_ID1)) assert status.result == u"RUNNING" assert len(status.logs) > 0 assert any("Saving result RUNNING for default/{}".format(name) in line for line in status.logs) wait_until(_assert_status, patience=PATIENCE) def _check_two_ingresses(): assert Ingress.get(name) assert Ingress.get("{}-1".format(name)) for ingress_name, expected_dict in expected.items(): actual = Ingress.get(ingress_name) assert_k8s_resource_matches(actual, expected_dict, IMAGE1, None, DEPLOYMENT_ID1, None, app_uid) wait_until(_check_two_ingresses, patience=PATIENCE) # Remove 2nd ingress to make sure cleanup works fiaas_application.spec.config["ingress"].pop() fiaas_application.metadata.labels["fiaas/deployment_id"] = DEPLOYMENT_ID2 fiaas_application.save() def _check_one_ingress(): assert Ingress.get(name) with pytest.raises(NotFound): Ingress.get("{}-1".format(name)) wait_until(_check_one_ingress, patience=PATIENCE) # Cleanup FiaasApplication.delete(name) def cleanup_complete(): for name, _ in expected.items(): with pytest.raises(NotFound): Ingress.get(name) wait_until(cleanup_complete, patience=PATIENCE)
def test_set_dict_field(self, mock_response, value): metadata = ObjectMeta(name="my-name", namespace="my-namespace") mock_response.json.return_value = { 'dict_field': { 'thing': 'otherthing' } } instance = ModelTest.get_or_create(metadata=metadata, dict_field=value) assert instance.dict_field == value
def _create_default_ingress(): object_meta = ObjectMeta(name=NAME, namespace=NAMESPACE, labels={"test": "true"}) ingress_backend = IngressBackend(serviceName="dummy", servicePort="http") http_ingress_path = HTTPIngressPath(path="/", backend=ingress_backend) http_ingress_rule = HTTPIngressRuleValue(paths=[http_ingress_path]) ingress_rule = IngressRule(host="dummy.example.com", http=http_ingress_rule) ingress_spec = IngressSpec(rules=[ingress_rule]) ingress = Ingress(metadata=object_meta, spec=ingress_spec) return ingress
def _event(id, event_type, rv, namespace="default"): metadict = { "name": "name{}".format(id), "namespace": namespace, "resourceVersion": rv } metadata = ObjectMeta.from_dict(metadict) wle = WatchListExample(metadata=metadata, value=(id * 100) + rv) return mock.NonCallableMagicMock(type=event_type, object=wle)
def _create_metadata(deployment_config): labels = { "app": deployment_config.name, "heritage": "FIAAS-Skipper", "fiaas/bootstrap": "true", "fiaas/deployment_id": str(uuid.uuid4()) } return ObjectMeta(name=deployment_config.name, namespace=deployment_config.namespace, labels=labels)
def _create_status(i, annotate=True): annotations = { LAST_UPDATED_KEY: "2020-12-12T23.59.{:02}".format(i) } if annotate else None metadata = ObjectMeta(name="name-{}".format(i), namespace="test", annotations=annotations) return FiaasApplicationStatus(new=False, metadata=metadata, result=u"SUCCESS")
def custom_resource_definition_test_case(self, fiaas_path, namespace, labels, expected): fiaas_yml = read_yml(file_relative_path(fiaas_path)) expected = {kind: read_yml_if_exists(path) for kind, path in expected.items()} name = sanitize_resource_name(fiaas_path) metadata = ObjectMeta(name=name, namespace=namespace, labels=merge_dicts(labels, {"fiaas/deployment_id": DEPLOYMENT_ID})) spec = FiaasApplicationSpec(application=name, image=IMAGE, config=fiaas_yml) return name, FiaasApplication(metadata=metadata, spec=spec), expected