コード例 #1
0
ファイル: bespin_specs.py プロジェクト: jonhiggs/bespin
 def tasks_spec(self, available_actions, default_action="run"):
     """Tasks for a particular stack"""
     return dictof(
           self.task_name_spec
         , create_spec(task_objs.Task
             , action = defaulted(string_choice_spec(available_actions, "No such task"), default_action)
             , options = dictionary_spec()
             , overrides = dictionary_spec()
             , description = string_spec()
             )
         )
コード例 #2
0
ファイル: harpoon_specs.py プロジェクト: Atry/harpoon
 def tasks_spec(self, available_actions, default_action="run"):
     """Tasks for a particular image"""
     return dictof(
           self.task_name_spec
         , create_spec(task_objs.Task, validators.deprecated_key("spec", "Use ``action`` and ``options`` instead (note that ``action`` defaults to run)")
             , action = defaulted(string_choice_spec(available_actions, "No such task"), default_action)
             , options = dictionary_spec()
             , overrides = dictionary_spec()
             , description = string_spec()
             )
         )
コード例 #3
0
ファイル: bespin_specs.py プロジェクト: andriipetruk/bespin
 def tasks_spec(self, available_actions, default_action="run"):
     """Tasks for a particular stack"""
     return dictof(
           self.task_name_spec
         , create_spec(task_objs.Task
             , action = defaulted(string_choice_spec(available_actions, "No such task"), default_action)
             , options = dictionary_spec()
             , overrides = dictionary_spec()
             , description = string_spec()
             )
         )
コード例 #4
0
ファイル: bespin_specs.py プロジェクト: andriipetruk/bespin
    def password_spec(self):
        formatted_string = formatted(string_spec(), formatter=MergedOptionStringFormatter)
        return create_spec(stack_objs.Password
            , name = formatted(overridden("{_key_name_1}"), formatter=MergedOptionStringFormatter)
            , bespin = formatted(overridden("{bespin}"), formatter=MergedOptionStringFormatter)

            , KMSMasterKey = required(formatted_string)
            , encryption_context = optional_spec(dictionary_spec())
            , grant_tokens = optional_spec(listof(formatted_string))
            , crypto_text = required(formatted_string)

            , vars = dictionary_spec()
            )
コード例 #5
0
ファイル: bespin_specs.py プロジェクト: jonhiggs/bespin
    def password_spec(self):
        formatted_string = formatted(string_spec(), formatter=MergedOptionStringFormatter)
        return create_spec(stack_objs.Password
            , name = formatted(overridden("{_key_name_1}"), formatter=MergedOptionStringFormatter)
            , bespin = formatted(overridden("{bespin}"), formatter=MergedOptionStringFormatter)

            , KMSMasterKey = required(formatted_string)
            , encryption_context = optional_spec(dictionary_spec())
            , grant_tokens = optional_spec(listof(formatted_string))
            , crypto_text = required(formatted_string)

            , vars = dictionary_spec()
            )
コード例 #6
0
ファイル: harpoon_specs.py プロジェクト: Atry/harpoon
 def tasks_spec(self, available_actions, default_action="run"):
     """Tasks for a particular image"""
     return dictof(
         self.task_name_spec,
         create_spec(
             task_objs.Task,
             validators.deprecated_key(
                 "spec",
                 "Use ``action`` and ``options`` instead (note that ``action`` defaults to run)"
             ),
             action=defaulted(
                 string_choice_spec(available_actions, "No such task"),
                 default_action),
             options=dictionary_spec(),
             overrides=dictionary_spec(),
             description=string_spec()))
コード例 #7
0
ファイル: bespin_specs.py プロジェクト: jonhiggs/bespin
 def environment_spec(self):
     """Spec for each environment"""
     return create_spec(Environment
         , account_id = required(or_spec(string_spec(), valid_string_spec(validators.regexed("\d+"))))
         , region = defaulted(string_spec(), "ap-southeast-2")
         , vars = dictionary_spec()
         )
コード例 #8
0
ファイル: types.py プロジェクト: mic159/photons-core
    def pack(self, meta, val):
        if type(val) not in (bytes, bitarray):
            try:
                if type(val) is not list:
                    raise BadSpecValue("Not a list")

                items = sb.listof(sb.dictionary_spec()).normalise(meta, val)
            except BadSpecValue as error:
                raise BadSpecValue(
                    "Sorry, many fields only supports a list of dictionary of values",
                    error=error)
            else:
                res = []
                for i, v in enumerate(items):
                    nxt = self.kls(**v)
                    spec = self.bytes_spec_for(nxt)
                    if hasattr(self.kls.Meta, "cache"):
                        items = tuple(sorted(nxt.items()))
                        if items not in self.kls.Meta.cache:
                            self.kls.Meta.cache[items] = nxt.pack()
                        packd = self.kls.Meta.cache[items]
                    else:
                        packd = nxt.pack()
                    res.append(spec.normalise(meta.indexed_at(i), packd))
                val = functools.reduce(operator.add, res)

        # The spec is likely a T.Bytes and will ensure we have enough bytes length in the result
        return self.spec.normalise(meta, val)
コード例 #9
0
    def normalise(self, meta, val):
        if 'use' in val:
            template = val['use']
            if template not in meta.everything['templates']:
                available = list(meta.everything['templates'].keys())
                raise BadTemplate("Template doesn't exist!", wanted=template, available=available, meta=meta)

            val = MergedOptions.using(meta.everything['templates'][template], val)

        formatted_string = sb.formatted(sb.string_or_int_as_string_spec(), MergedOptionStringFormatter, expected_type=six.string_types)
        key_name = meta.key_names()['_key_name_0']

        key = sb.create_spec(EncryptionKey
            , name = sb.overridden(key_name)
            , location = sb.required(formatted_string)
            , description = formatted_string
            , grant = sb.listof(grant_statement_spec('key', key_name))
            , admin_users = sb.listof(sb.any_spec())
            , permission = sb.listof(sb.dictionary_spec())
            , no_root_access = sb.defaulted(sb.boolean(), False)
            ).normalise(meta, val)

        statements = key.permission
        if not key.no_root_access:
            statements.append({"principal": {"iam": "root"}, "action": "kms:*", "resource": "*", "Sid": ""})

        if key.admin_users:
            for admin_user in key.admin_users:
                statements.append({"principal": admin_user, "action": "kms:*", "resource": { "kms": "__self__" }, "Sid": ""})

        key.policy = sb.container_spec(Document, sb.listof(resource_policy_statement_spec('key', key_name))).normalise(meta.at("admin_users"), statements)
        return key
コード例 #10
0
ファイル: bespin_specs.py プロジェクト: andriipetruk/bespin
 def environment_spec(self):
     """Spec for each environment"""
     return create_spec(stack_objs.Environment
         , account_id = required(or_spec(valid_string_spec(validators.regexed("\d+")), integer_spec()))
         , region = defaulted(string_spec(), "ap-southeast-2")
         , vars = dictionary_spec()
         , tags = self.tags_spec
         )
コード例 #11
0
ファイル: apigateway.py プロジェクト: delfick/aws_syncr
    def normalise(self, meta, val):
        return sb.create_spec(MockMethod
            , http_method = sb.overridden(self.method)
            , resource_name = sb.overridden(self.resource_name)

            , request_mapping = sb.defaulted(mapping_spec(), Mapping("application/json", '{"statusCode": 200}'))
            , mapping = mapping_spec()
            , require_api_key = sb.defaulted(sb.boolean(), False)
            , sample_event = sb.or_spec(sb.dictionary_spec(), sb.string_spec())
            , desired_output_for_test = sb.or_spec(sb.dictionary_spec(), sb.string_spec())
            ).normalise(meta, val)

        for key in ('sample_event', 'desired_output_for_test'):
            if isinstance(result[key], six.string_types):
                v = result[key]
                if v.startswith("{") and v.endswith("}"):
                    v = sb.formatted(sb.string_spec(), formatter=MergedOptionStringFormatter).normalise(meta.at(key), v)
                    result[key] = v
コード例 #12
0
ファイル: stack_specs.py プロジェクト: CaseyLeask/bespin
    def normalise_filled(self, meta, val):
        val = sb.dictionary_spec().normalise(meta, val)
        provider_type = val["provider_type"]
        available = ["ultradns"]
        if provider_type not in available:
            raise BadConfiguration("Specified provider type isn't supported", supported=available, wanted=provider_type, meta=meta)

        if provider_type == "ultradns":
            return self.ultradns_provider_spec.normalise(meta, val)
コード例 #13
0
ファイル: main.py プロジェクト: realestate-com-au/dashmat
 def normalise(self, meta, val):
     val = sb.dictionary_spec().normalise(meta, val)
     if "plain" in val:
         return val["plain"]
     elif "kms" in val:
         val = sb.set_options(
               kms = sb.required(sb.string_spec())
             , location = sb.required(sb.string_spec())
             ).normalise(meta, val)
         return lambda: __import__("boto3").client("kms", val['location']).decrypt(CiphertextBlob=base64.b64decode(val['kms']))['Plaintext'].decode('utf-8')
コード例 #14
0
ファイル: statements.py プロジェクト: delfick/aws_syncr
    def normalise(self, meta, val):
        if isinstance(val, MergedOptions):
            val = val.as_dict()
        val = sb.dictionary_spec().normalise(meta, val)
        if self.effect is not NotSpecified:
            if val.get('effect', self.effect) != self.effect or val.get('Effect', self.effect) != self.effect:
                raise BadOption("Defaulted effect is being overridden", default=self.effect, overridden=val.get("Effect", val.get("effect")), meta=meta)

            if val.get('effect', NotSpecified) is NotSpecified and val.get("Effect", NotSpecified) is NotSpecified:
                val['Effect'] = self.effect
        return val
コード例 #15
0
ファイル: statements.py プロジェクト: stilianouly/aws_syncr
class resource_policy_statement_spec(statement_spec):
    args = lambda s, self_type, self_name: {
        'sid': sb.string_spec(),
        'effect': sb.string_choice_spec(choices=["Deny", "Allow"]),
        'action': sb.listof(sb.string_spec()),
        ("not", "action"): sb.listof(sb.string_spec()),
        'resource': resource_spec(self_type, self_name),
        ('not', 'resource'): resource_spec(self_type, self_name),
        'principal': sb.listof(principal_spec(self_type, self_name)),
        ('not', 'principal'): sb.listof(principal_spec(self_type, self_name)),
        'condition': sb.dictionary_spec(),
        ('not', 'condition'): sb.dictionary_spec()
    }
    validators = [
        validators.deprecated_key('allow', "Use 'effect: Allow|Deny' instead"),
        validators.deprecated_key('disallow',
                                  "Use 'effect: Allow|Deny' instead")
    ]
    final_kls = lambda s, *args, **kwargs: ResourcePolicyStatement(
        *args, **kwargs)
コード例 #16
0
    def normalise_filled(self, meta, val):
        val = sb.dictionary_spec().normalise(meta, val)
        provider_type = val["provider_type"]
        available = ["ultradns"]
        if provider_type not in available:
            raise BadConfiguration("Specified provider type isn't supported",
                                   supported=available,
                                   wanted=provider_type,
                                   meta=meta)

        if provider_type == "ultradns":
            return self.ultradns_provider_spec.normalise(meta, val)
コード例 #17
0
    def validate(self, meta, val):
        val = sb.dictionary_spec().normalise(meta, val)
        if 'plain' in val and 'kms' in val:
            raise BadSpecValue("Please only specify plain or kms", got=list(val.keys()), meta=meta)

        if 'plain' not in val and 'kms' not in val:
            raise BadSpecValue("Please specify plain or kms", got=list(val.keys()), meta=meta)

        if 'kms' in val and ('location' not in val or 'kms_data_key' not in val):
            raise BadSpecValue("Please specify location and kms_data_key if you specify kms", got=list(val.keys()), meta=meta)

        return val
コード例 #18
0
ファイル: stack_specs.py プロジェクト: CaseyLeask/bespin
    def normalise_filled(self, meta, val):
        log.info("Normalising dns site %s", meta.path)
        val = sb.dictionary_spec().normalise(meta, val)
        provider = val["provider"]
        available = meta.everything["stacks"][meta.everything["__stack_name__"]]["dns"]["providers"]
        if provider not in available.keys():
            raise BadConfiguration("Specified provider isn't defined in {dns.providers}", available=list(available.keys()), wanted=provider, meta=meta)

        val["provider"] = lambda: meta.everything["stacks"][meta.everything["__stack_name__"]]["dns"]["providers"][provider]
        if available[provider]["provider_type"] == "ultradns":
            return self.ultradns_site_spec(val).normalise(meta, val)
        else:
            raise BadConfiguration("Unknown dns provider type", available=["ultradns"], wanted=val["provider"].provider_type, meta=meta)
コード例 #19
0
ファイル: buckets.py プロジェクト: sanjaypanditc/aws_syncr
class website_statement_spec(statement_spec):
    formatted_string = sb.formatted(sb.string_spec(),
                                    formatter=MergedOptionStringFormatter)
    args = lambda s, self_type, self_name: {
        (("sep", "_"), ("parts", ("index", "document"))):
        made_up_dict(s.formatted_string, ("Suffix", )),
        (("sep", "_"), ("parts", ("error", "document"))):
        made_up_dict(s.formatted_string, ("Key", )),
        (("sep", "_"), ("parts", ("redirect", "all", "requests", "to"))):
        redirect_all_requests_to_spec(s.formatted_string),
        (("sep", "_"), ("parts", ("routing", "rules"))):
        sb.listof(sb.dictionary_spec())
    }
    final_kls = lambda s, *args, **kwargs: WebsiteConfig(*args, **kwargs)
コード例 #20
0
ファイル: apigateway.py プロジェクト: sanjaypanditc/aws_syncr
    def normalise(self, meta, val):
        return sb.create_spec(
            MockMethod,
            http_method=sb.overridden(self.method),
            resource_name=sb.overridden(self.resource_name),
            request_mapping=sb.defaulted(
                mapping_spec(),
                Mapping("application/json", '{"statusCode": 200}')),
            mapping=mapping_spec(),
            require_api_key=sb.defaulted(sb.boolean(), False),
            sample_event=sb.or_spec(sb.dictionary_spec(), sb.string_spec()),
            desired_output_for_test=sb.or_spec(sb.dictionary_spec(),
                                               sb.string_spec())).normalise(
                                                   meta, val)

        for key in ('sample_event', 'desired_output_for_test'):
            if isinstance(result[key], six.string_types):
                v = result[key]
                if v.startswith("{") and v.endswith("}"):
                    v = sb.formatted(
                        sb.string_spec(),
                        formatter=MergedOptionStringFormatter).normalise(
                            meta.at(key), v)
                    result[key] = v
コード例 #21
0
ファイル: statements.py プロジェクト: stilianouly/aws_syncr
    def normalise(self, meta, val):
        if isinstance(val, MergedOptions):
            val = val.as_dict()
        val = sb.dictionary_spec().normalise(meta, val)
        if self.effect is not NotSpecified:
            if val.get('effect', self.effect) != self.effect or val.get(
                    'Effect', self.effect) != self.effect:
                raise BadOption("Defaulted effect is being overridden",
                                default=self.effect,
                                overridden=val.get("Effect",
                                                   val.get("effect")),
                                meta=meta)

            if val.get('effect', NotSpecified) is NotSpecified and val.get(
                    "Effect", NotSpecified) is NotSpecified:
                val['Effect'] = self.effect
        return val
コード例 #22
0
    def normalise(self, meta, val):
        val = dictionary_spec().normalise(meta, val)
        if val.get("is_index"):
            index_items = []
            for path, dashboard in meta.everything["dashboards"].items():
                if not dashboard.get("is_index"):
                    index_items.append('<IndexItem href="{0}" desc="{1}" />'.format(path, dashboard.get("description")))

            val["layout"] = dedent(
                """
                <Index>
                    {0}
                </Index>
            """.format(
                    "\n".join(index_items)
                )
            )

            val["imports"] = [[["Index", "IndexItem"], {"import_path": "dashmat.core_modules.index.main:Index"}]]

        return Dashboard.FieldSpec(formatter=MergedOptionStringFormatter).normalise(meta, val)
コード例 #23
0
ファイル: statements.py プロジェクト: delfick/aws_syncr
    def normalise(self, meta, val):
        if isinstance(val, MergedOptions):
            val = val.as_dict()
        val = sb.dictionary_spec().normalise(meta, val)
        if self.principal == "notprincipal":
            opposite = "principal"
        else:
            opposite = ("not", "principal")
        opposite, cap_opposite = capitalize(opposite)
        if opposite in val or cap_opposite in val:
            raise BadPolicy("Specifying opposite principal type in statement", wanted=self.principal, got=opposite, meta=meta)

        capitalized = self.principal
        if capitalized in ("principal", "Principal"):
            arg, capitalized = "principal", "Principal"
        else:
            arg, capitalized = "notprincipal", "NotPrincipal"

        if arg not in val and capitalized not in val:
            return {self.principal: val}
        return val
コード例 #24
0
    def normalise_filled(self, meta, val):
        log.info("Normalising dns site %s", meta.path)
        val = sb.dictionary_spec().normalise(meta, val)
        provider = val["provider"]
        available = meta.everything["stacks"][
            meta.everything["__stack_name__"]]["dns"]["providers"]
        if provider not in available.keys():
            raise BadConfiguration(
                "Specified provider isn't defined in {dns.providers}",
                available=list(available.keys()),
                wanted=provider,
                meta=meta)

        val["provider"] = lambda: meta.everything["stacks"][meta.everything[
            "__stack_name__"]]["dns"]["providers"][provider]
        if available[provider]["provider_type"] == "ultradns":
            return self.ultradns_site_spec(val).normalise(meta, val)
        else:
            raise BadConfiguration("Unknown dns provider type",
                                   available=["ultradns"],
                                   wanted=val["provider"].provider_type,
                                   meta=meta)
コード例 #25
0
ファイル: types.py プロジェクト: mic159/photons-core
    def normalise(self, meta, val):
        if self.unpacking:
            if type(val) in (bitarray, bytes):
                return self.kls.unpack(self.spec.normalise(meta, val))
            elif isinstance(val, self.kls):
                return val
            else:
                raise BadSpecValue("Expected to unpack bytes",
                                   found=val,
                                   transforming_into=self.kls)
        else:
            if type(val) not in (bytes, bitarray):
                try:
                    fields = sb.dictionary_spec().normalise(meta, val)
                except BadSpecValue as error:
                    raise BadSpecValue(
                        "Sorry, dynamic fields only supports a dictionary of values",
                        error=error)
                else:
                    val = self.kls.empty_normalise(**fields).pack()

            # The spec is likely a T.Bytes and will ensure we have enough bytes length in the result
            return self.spec.normalise(meta, val)
コード例 #26
0
ファイル: command_specs.py プロジェクト: delfick/harpoon
    def normalise(self, meta, val):
        val = sb.dictof(sb.string_spec(), sb.dictionary_spec()).normalise(meta, val)
        if len(val) != 1:
            raise BadSpecValue("Commands specified as [COMMAND, {options}] may only have one option (either ADD or COPY)", got=val, meta=meta)

        items = list(val.items())[0]
        if items[0] not in ("ADD", "COPY"):
            raise BadSpecValue("Commands specified as [COMMAND, {options}] may only have one option (either ADD or COPY)", got=items[0], meta=meta)

        if items[0] == "ADD":
            spec = complex_ADD_spec()
        else:
            spec = complex_COPY_spec()

        result = []

        for val in spec.normalise(meta.at(items[0]), items[1]):
            if isinstance(val, Command):
                result.append(val)
            else:
                result.extend(val)

        return result
コード例 #27
0
ファイル: statements.py プロジェクト: stilianouly/aws_syncr
    def normalise(self, meta, val):
        if isinstance(val, MergedOptions):
            val = val.as_dict()
        val = sb.dictionary_spec().normalise(meta, val)
        if self.principal == "notprincipal":
            opposite = "principal"
        else:
            opposite = ("not", "principal")
        opposite, cap_opposite = capitalize(opposite)
        if opposite in val or cap_opposite in val:
            raise BadPolicy("Specifying opposite principal type in statement",
                            wanted=self.principal,
                            got=opposite,
                            meta=meta)

        capitalized = self.principal
        if capitalized in ("principal", "Principal"):
            arg, capitalized = "principal", "Principal"
        else:
            arg, capitalized = "notprincipal", "NotPrincipal"

        if arg not in val and capitalized not in val:
            return {self.principal: val}
        return val
コード例 #28
0
ファイル: lambdas.py プロジェクト: stilianouly/aws_syncr
    def normalise(self, meta, val):
        if 'use' in val:
            template = val['use']
            if template not in meta.everything['templates']:
                available = list(meta.everything['templates'].keys())
                raise BadTemplate("Template doesn't exist!", wanted=template, available=available, meta=meta)

            val = MergedOptions.using(meta.everything['templates'][template], val)

        formatted_string = sb.formatted(sb.string_or_int_as_string_spec(), MergedOptionStringFormatter, expected_type=six.string_types)
        function_name = meta.key_names()['_key_name_0']

        return sb.create_spec(Lambda
            , name = sb.overridden(function_name)
            , role = sb.required(only_one_spec(resource_spec("lambda", function_name, only=["iam"])))
            , code = sb.required(function_code_spec())
            , handler = function_handler_spec()
            , timeout = sb.integer_spec()
            , runtime = sb.required(formatted_string)
            , location = sb.required(formatted_string)
            , description = formatted_string
            , sample_event = sb.defaulted(sb.or_spec(sb.dictionary_spec(), sb.string_spec()), "")
            , memory_size = sb.defaulted(divisible_by_spec(64), 128)
            ).normalise(meta, val)
コード例 #29
0
ファイル: apigateway.py プロジェクト: sanjaypanditc/aws_syncr
 def normalise(self, meta, val):
     val = sb.dictionary_spec().normalise(meta, val)
     return self.formatted_dict(meta, val)
コード例 #30
0
ファイル: bespin_specs.py プロジェクト: jonhiggs/bespin
    def stack_spec(self):
        """Spec for each stack"""
        return create_spec(stack_objs.Stack
            , validators.deprecated_key("url_checker", "Use ``confirm_deployment.url_checker1``")
            , validators.deprecated_key("deploys_s3_path", "Use ``confirm_deployment.deploys_s3_path``")
            , validators.deprecated_key("sns_confirmation", "Use ``confirm_deployment.sns_confirmation``")
            , validators.deprecated_key("autoscaling_group_id", "Use ``auto_scaling_group_name``")
            , validators.deprecated_key("instance_count_limit", "Use ``scaling_options.instance_count_limit``")

            , bespin = any_spec()

            , name = formatted(defaulted(string_spec(), "{_key_name_1}"), formatter=MergedOptionStringFormatter)
            , key_name = formatted(overridden("{_key_name_1}"), formatter=MergedOptionStringFormatter)
            , stack_name = formatted(defaulted(string_spec(), "{_key_name_1}"), formatter=MergedOptionStringFormatter)
            , environment = formatted(overridden("{environment}"), formatter=MergedOptionStringFormatter)

            , env = listof(stack_specs.env_spec(), expect=stack_objs.Environment)
            , build_env = listof(stack_specs.env_spec(), expect=stack_objs.Environment)
            , stack_name_env = listof(stack_specs.env_spec(), expect=stack_objs.Environment)

            , tags = dictionary_spec()

            , stack_json = valid_stack_json(default="{config_root}/{_key_name_1}.json")

            , params_json = valid_params_json(default="{config_root}/{environment}/{_key_name_1}-params.json")
            , params_yaml = valid_params_yaml(default="{config_root}/{environment}/{_key_name_1}-params.yaml")

            , build_first = listof(formatted(string_spec(), formatter=MergedOptionStringFormatter))
            , build_after = listof(formatted(string_spec(), formatter=MergedOptionStringFormatter))
            , build_timeout = defaulted(integer_spec(), 1200)
            , ignore_deps = defaulted(boolean(), False)

            , vars = dictof(string_spec(), stack_specs.var_spec(), nested=True)

            , skip_update_if_equivalent = listof(stack_specs.skipper_spec())

            , suspend_actions = defaulted(boolean(), False)
            , auto_scaling_group_name = optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter))

            , artifact_retention_after_deployment = defaulted(boolean(), False)

            , command = optional_spec(string_spec())

            , netscaler = optional_spec(self.netscaler_spec)

            , dns = optional_spec(stack_specs.dns_spec(create_spec(stack_objs.DNS
                , vars = dictof(string_spec(), formatted(string_spec(), formatter=MergedOptionStringFormatter), nested=True)
                , providers = dictof(string_spec(), stack_specs.dns_provider_spec())
                , sites = delayed(dictof(string_spec(), stack_specs.dns_site_spec()))
                )))

            , scaling_options = create_spec(ScalingOptions
                , highest_min = defaulted(integer_spec(), 2)
                , instance_count_limit = defaulted(integer_spec(), 10)
                )

            , artifacts = container_spec(artifact_objs.ArtifactCollection, dictof(string_spec(), create_spec(artifact_objs.Artifact
                , not_created_here = defaulted(boolean(), False)
                , compression_type = string_choice_spec(["gz", "xz"])
                , history_length = integer_spec()
                , cleanup_prefix = optional_spec(string_spec())
                , upload_to = formatted(string_spec(), formatter=MergedOptionStringFormatter)
                , commands = listof(stack_specs.artifact_command_spec(), expect=artifact_objs.ArtifactCommand)
                , paths = listof(stack_specs.artifact_path_spec(), expect=artifact_objs.ArtifactPath)
                , files = listof(create_spec(artifact_objs.ArtifactFile, validators.has_either(["content", "task"])
                    , content = optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter))
                    , task = optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter))
                    , path = formatted(string_spec(), formatter=MergedOptionStringFormatter)
                    , task_runner = formatted(always_same_spec("{task_runner}"), formatter=MergedOptionStringFormatter)
                    ))
                )))

            , newrelic = optional_spec(create_spec(stack_objs.NewRelic
                , api_key = required(formatted(string_spec(), formatter=MergedOptionStringFormatter))
                , account_id = required(formatted(string_spec(), formatter=MergedOptionStringFormatter))
                , application_id = required(formatted(string_spec(), formatter=MergedOptionStringFormatter))

                , env = listof(stack_specs.env_spec(), expect=stack_objs.Environment)
                , deployed_version = required(formatted(string_spec(), formatter=MergedOptionStringFormatter))
                ))

            , downtimer_options = optional_spec(dictof(valid_string_spec(valid_alerting_system())
                , create_spec(stack_objs.DowntimerOptions
                    , hosts = listof(formatted(string_spec(), formatter=MergedOptionStringFormatter))
                    )
                ))

            , alerting_systems = optional_spec(dictof(string_spec(), self.alerting_system_spec))

            , ssh = optional_spec(create_spec(stack_objs.SSH
                , validators.deprecated_key("autoscaling_group_id", "Use ``auto_scaling_group_name``")

                , user = required(formatted(string_spec(), formatter=MergedOptionStringFormatter))
                , bastion = optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter))
                , bastion_user = required(formatted(string_spec(), formatter=MergedOptionStringFormatter))
                , bastion_key_location = optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter))
                , instance_key_location = optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter))

                , address = optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter))
                , instance = optional_spec(listof(formatted(string_spec(), formatter=MergedOptionStringFormatter)))
                , auto_scaling_group_name = optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter))

                , bastion_key_path = formatted(defaulted(string_spec(), "{config_root}/{environment}/bastion_ssh_key.pem"), formatter=MergedOptionStringFormatter)
                , instance_key_path = formatted(defaulted(string_spec(), "{config_root}/{environment}/ssh_key.pem"), formatter=MergedOptionStringFormatter)

                , storage_type = formatted(defaulted(string_choice_spec(["url", "rattic"]), "url"), formatter=MergedOptionStringFormatter)
                , storage_host = optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter))
                ))

            , confirm_deployment = optional_spec(self.confirm_deployment_spec)
            )
コード例 #31
0
ファイル: stack_specs.py プロジェクト: CaseyLeask/bespin
            , name = sb.formatted(sb.overridden("{_key_name_1}"), formatter=MergedOptionStringFormatter)
            , provider_type = sb.required(sb.string_spec())
            , username = sb.required(formatted_string)
            , password = sb.required(formatted_string)
            )

formatted_string = sb.formatted(sb.string_spec(), formatter=MergedOptionStringFormatter)

artifact_command_spec = lambda : sb.create_spec(ArtifactCommand
    , copy = sb.listof(artifact_path_spec())
    , modify = sb.dictof(sb.string_spec(), sb.set_options(append=sb.listof(formatted_string)))
    , command = sb.listof(formatted_string)
    , timeout = sb.defaulted(sb.integer_spec(), 600)
    , temp_dir = sb.defaulted(formatted_string, None)
    , add_into_tar = sb.listof(artifact_path_spec())
    )

params_json_spec = lambda: sb.listof(sb.set_options(
      ParameterKey = sb.required(sb.any_spec())
    , ParameterValue = sb.required(sb.any_spec())
    ))

params_yaml_spec = lambda: sb.dictionary_spec()

stack_json_spec = lambda: sb.set_options(
      Resources = sb.required(sb.dictof(sb.string_spec(), sb.set_options(Type=sb.required(sb.string_spec()), Properties=sb.optional_spec(sb.dictionary_spec()))))
    , Parameters = sb.optional_spec(sb.dictof(sb.string_spec(), sb.dictionary_spec()))
    , Outputs = sb.optional_spec(sb.dictof(sb.string_spec(), sb.dictionary_spec()))
    )

コード例 #32
0
ファイル: harpoon_specs.py プロジェクト: henrikhch/harpoon
    def image_spec(self):
        """Spec for each image"""
        from harpoon.option_spec import image_specs as specs
        from harpoon.option_spec import image_objs

        return create_spec(
            image_objs.Image
            # Change the context options
            ,
            validators.deprecated_key("exclude_context", "Use ``context.exclude``"),
            validators.deprecated_key("use_git_timestamps", "Use ``context.use_git_timestamps``"),
            validators.deprecated_key("respect_gitignore", "Use ``context.use_gitignore``"),
            validators.deprecated_key("parent_dir", "Use ``context.parent_dir``"),
            validators.deprecated_key("recursive", "Use ``persistence``")
            # Changed how volumes_from works
            ,
            validators.deprecated_key("volumes_from", "Use ``volumes.share_with``")
            # Deprecated link
            ,
            validators.deprecated_key("link", "Use ``links``")
            # Harpoon options
            ,
            harpoon=any_spec()
            # default the name to the key of the image
            ,
            name=formatted(defaulted(string_spec(), "{_key_name_1}"), formatter=MergedOptionStringFormatter),
            key_name=formatted(overridden("{_key_name_1}"), formatter=MergedOptionStringFormatter),
            image_name=optional_spec(string_spec()),
            image_index=defaulted(string_spec(), ""),
            container_name=optional_spec(string_spec()),
            image_name_prefix=defaulted(string_spec(), ""),
            user=defaulted(string_spec(), None),
            mtime=defaulted(any_spec(), time.time()),
            configuration=any_spec(),
            vars=dictionary_spec(),
            deleteable_image=defaulted(boolean(), False)
            # The spec itself
            ,
            bash=delayed(optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter))),
            command=delayed(optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter))),
            commands=required(container_spec(Commands, listof(command_spec()))),
            squash_after=optional_spec(or_spec(boolean(), container_spec(Commands, listof(command_spec())))),
            squash_before_push=optional_spec(or_spec(boolean(), container_spec(Commands, listof(command_spec())))),
            persistence=optional_spec(
                create_spec(
                    image_objs.Persistence,
                    validators.deprecated_key("persist", "Use ``folders``"),
                    action=required(formatted(string_spec(), formatter=MergedOptionStringFormatter)),
                    folders=required(listof(formatted(string_spec(), formatter=MergedOptionStringFormatter))),
                    cmd=optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter)),
                    shell=defaulted(formatted(string_spec(), formatter=MergedOptionStringFormatter), "/bin/bash"),
                    image_name=delayed(
                        many_format(
                            overridden("images.{_key_name_2}.image_name"), formatter=MergedOptionStringFormatter
                        )
                    ),
                )
            ),
            links=listof(specs.link_spec(), expect=image_objs.Link),
            context=self.context_spec,
            wait_condition=optional_spec(self.wait_condition_spec),
            lxc_conf=defaulted(filename_spec(), None),
            volumes=create_spec(
                image_objs.Volumes,
                mount=listof(specs.mount_spec(), expect=image_objs.Mount),
                share_with=listof(
                    formatted(string_spec(), MergedOptionStringFormatter, expected_type=image_objs.Image)
                ),
            ),
            dependency_options=dictof(
                specs.image_name_spec(),
                create_spec(
                    image_objs.DependencyOptions,
                    attached=defaulted(boolean(), False),
                    wait_condition=optional_spec(self.wait_condition_spec),
                ),
            ),
            env=listof(specs.env_spec(), expect=image_objs.Environment),
            ports=listof(specs.port_spec(), expect=image_objs.Port),
            ulimits=defaulted(listof(dictionary_spec()), None),
            log_config=defaulted(listof(dictionary_spec()), None),
            security_opt=defaulted(listof(string_spec()), None),
            read_only_rootfs=defaulted(boolean(), False),
            other_options=create_spec(
                other_options,
                start=dictionary_spec(),
                build=dictionary_spec(),
                create=dictionary_spec(),
                host_config=dictionary_spec(),
            ),
            network=create_spec(
                image_objs.Network,
                dns=defaulted(listof(string_spec()), None),
                mode=defaulted(string_spec(), None),
                hostname=defaulted(string_spec(), None),
                domainname=defaulted(string_spec(), None),
                disabled=defaulted(boolean(), False),
                dns_search=defaulted(listof(string_spec()), None),
                extra_hosts=listof(string_spec()),
                network_mode=defaulted(string_spec(), None),
                publish_all_ports=defaulted(boolean(), False),
            ),
            cpu=create_spec(
                image_objs.Cpu,
                cap_add=defaulted(boolean(), None),
                cpuset=defaulted(listof(string_spec()), None),
                cap_drop=defaulted(boolean(), None),
                mem_limit=defaulted(integer_spec(), 0),
                cpu_shares=defaulted(integer_spec(), None),
                memswap_limit=defaulted(integer_spec(), 0),
            ),
            devices=defaulted(listof(dictionary_spec()), None),
            privileged=defaulted(boolean(), False),
            restart_policy=defaulted(string_spec(), None),
        )
コード例 #33
0
ファイル: lambdas.py プロジェクト: delfick/aws_syncr
 def normalise(self, meta, val):
     val = sb.dictionary_spec().normalise(meta, val)
     return self.formatted_dict(meta, val)
コード例 #34
0
    def validate(self, meta, val):
        """Complain if we don't have a valid group"""
        if val is NotSpecified:
            val = None

        val = sb.dictionary_spec().normalise(meta, val)
        errors = []
        associates = []
        perfect_association = []

        for index, group in enumerate(self.choices):
            other_choices = list(chain.from_iterable([self.choices[i] for i in range(len(self.choices)) if i != index]))

            found = []
            missing = []
            for key in group:
                if key not in val:
                    missing.append(key)
                else:
                    found.append(key)

            if found:
                associates.append(index)
                if not missing:
                    perfect_association.append(index)

        if len(perfect_association) == 0:
            if len(associates) == 0:
                raise BadSpecValue("Value associates with no groups", val=val, choices=self.choices, meta=meta)

            elif len(associates) == 1:
                group = self.choices[associates[0]]
                other_choices = list(chain.from_iterable([self.choices[i] for i in range(len(self.choices)) if i != associates[0]]))

                found = []
                invalid = []
                missing = []
                for key in group:
                    if key not in val:
                        missing.append(key)
                    else:
                        found.append(key)

                for key in other_choices:
                    if key in val:
                        invald.append(key)

                raise BadSpecValue("Missing keys from this group", group=group, found=found, invalid=invalid, missing=missing, meta=meta)

            else:
                raise BadSpecValue("Value associates with multiple groups", associates=[self.choices[i] for i in associates], got=val, meta=meta)

        elif len(perfect_association) == 1:
            other_choices = list(chain.from_iterable([self.choices[i] for i in range(len(self.choices)) if i != perfect_association[0]]))
            invalid = []
            for key in other_choices:
                if key in val:
                    invalid.append(key)

            if invalid:
                raise BadSpecValue("Value associates with a group but has keys from other groups", associates_with=self.choices[perfect_association[0]], invalid=invalid, meta=meta)
            else:
                return val

        else:
            raise BadSpecValue("Value associates with multiple groups", associates=[self.choices[i] for i in perfect_association], got=val, meta=meta)
コード例 #35
0
 def templates_spec(self):
     """Spec for templates"""
     return dictof(string_spec(), dictionary_spec())
コード例 #36
0
    compiled_static_folder = dictobj.Field(
        string_spec,
        default="{config_root}/compiled_static",
        formatted=True,
        wrapper=directory_spec,
        help="Folder to cache compiled javascript",
    )


class ModuleOptions(dictobj.Spec):
    active = dictobj.Field(boolean, default=True, formatted=True, help="Is this module active?")

    import_path = dictobj.Field(
        lambda: module_import_spec(Module), formatted=True, wrapper=required, help="Import path to the module to load"
    )

    server_options = dictobj.Field(
        lambda: dictof(string_spec(), formatted_dict_or_string_or_list()),
        wrapper=delayed,
        help="Options to pass into creating the Server class",
    )


DashMatConverters = lambda: dict(
    modules=dictof(string_spec(), ModuleOptions.FieldSpec(formatter=MergedOptionStringFormatter)),
    templates=dictof(string_spec(), dictionary_spec()),
    dashboards=dashboards_spec(),
    dashmat=DashMat.FieldSpec(formatter=MergedOptionStringFormatter),
)
コード例 #37
0
ファイル: harpoon_specs.py プロジェクト: delfick/harpoon
    def image_spec(self):
        """Spec for each image"""
        from harpoon.option_spec import image_specs as specs
        from harpoon.option_spec import image_objs
        class persistence_shell_spec(Spec):
            """Make the persistence shell default to the shell on the image"""
            def normalise(self, meta, val):
                shell = defaulted(string_spec(), "/bin/bash").normalise(meta, meta.everything[["images", meta.key_names()["_key_name_2"]]].get("shell", NotSpecified))
                shell = defaulted(formatted(string_spec(), formatter=MergedOptionStringFormatter), shell).normalise(meta, val)
                return shell

        return create_spec(image_objs.Image
            , validators.deprecated_key("persistence", "The persistence feature has been removed")
            , validators.deprecated_key("squash_after", "The squash feature has been removed")
            , validators.deprecated_key("squash_before_push", "The squash feature has been removed")

            # Changed how volumes_from works
            , validators.deprecated_key("volumes_from", "Use ``volumes.share_with``")

            # Deprecated link
            , validators.deprecated_key("link", "Use ``links``")

            # Harpoon options
            , harpoon = any_spec()

            # default the name to the key of the image
            , tag = optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter))
            , name = formatted(defaulted(string_spec(), "{_key_name_1}"), formatter=MergedOptionStringFormatter)
            , key_name = formatted(overridden("{_key_name_1}"), formatter=MergedOptionStringFormatter)
            , image_name = optional_spec(string_spec())
            , image_index = formatted(defaulted(string_spec(), ""), formatter=MergedOptionStringFormatter)
            , container_name = optional_spec(string_spec())
            , image_name_prefix = defaulted(string_spec(), "")

            , no_tty_option = defaulted(formatted(boolean(), formatter=MergedOptionStringFormatter), False)

            , user = defaulted(string_spec(), None)
            , configuration = any_spec()

            , vars = dictionary_spec()
            , assume_role = optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter))
            , deleteable_image = defaulted(boolean(), False)

            , authentication = self.authentications_spec

            # The spec itself
            , shell = defaulted(formatted(string_spec(), formatter=MergedOptionStringFormatter), "/bin/bash")
            , bash = delayed(optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter)))
            , command = delayed(optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter)))
            , commands = required(container_spec(Commands, listof(command_spec())))
            , cache_from = delayed(or_spec(boolean(), listof(formatted(string_spec(), formatter=MergedOptionStringFormatter))))
            , cleanup_intermediate_images = defaulted(boolean(), True)

            , links = listof(specs.link_spec(), expect=image_objs.Link)

            , context = self.context_spec
            , wait_condition = optional_spec(self.wait_condition_spec)

            , lxc_conf = defaulted(filename_spec(), None)

            , volumes = create_spec(image_objs.Volumes
                , mount = listof(specs.mount_spec(), expect=image_objs.Mount)
                , share_with = listof(formatted(string_spec(), MergedOptionStringFormatter, expected_type=image_objs.Image))
                )

            , dependency_options = dictof(specs.image_name_spec()
                , create_spec(image_objs.DependencyOptions
                  , attached = defaulted(boolean(), False)
                  , wait_condition = optional_spec(self.wait_condition_spec)
                  )
                )

            , env = listof(specs.env_spec(), expect=image_objs.Environment)
            , ports = listof(specs.port_spec(), expect=image_objs.Port)
            , ulimits = defaulted(listof(dictionary_spec()), None)
            , log_config = defaulted(listof(dictionary_spec()), None)
            , security_opt = defaulted(listof(string_spec()), None)
            , read_only_rootfs = defaulted(boolean(), False)

            , other_options = create_spec(other_options
                , start = dictionary_spec()
                , build = dictionary_spec()
                , create = dictionary_spec()
                , host_config = dictionary_spec()
                )

            , network = create_spec(image_objs.Network
                , dns = defaulted(listof(string_spec()), None)
                , mode = defaulted(string_spec(), None)
                , hostname = defaulted(string_spec(), None)
                , domainname = defaulted(string_spec(), None)
                , disabled = defaulted(boolean(), False)
                , dns_search = defaulted(listof(string_spec()), None)
                , extra_hosts = listof(string_spec())
                , network_mode = defaulted(string_spec(), None)
                , publish_all_ports = defaulted(boolean(), False)
                )

            , cpu = create_spec(image_objs.Cpu
                , cap_add = defaulted(listof(string_spec()), None)
                , cpuset_cpus = defaulted(string_spec(), None)
                , cpuset_mems = defaulted(string_spec(), None)
                , cap_drop = defaulted(listof(string_spec()), None)
                , mem_limit = defaulted(integer_spec(), 0)
                , cpu_shares = defaulted(integer_spec(), None)
                , memswap_limit = defaulted(integer_spec(), 0)
                )

            , devices = defaulted(listof(dictionary_spec()), None)
            , privileged = defaulted(boolean(), False)
            , restart_policy = defaulted(string_spec(), None)
            )
コード例 #38
0
    add_into_tar=sb.listof(artifact_path_spec()))

params_json_spec = lambda: sb.listof(
    sb.set_options(ParameterKey=sb.required(sb.any_spec()),
                   ParameterValue=sb.required(sb.any_spec())))

params_yaml_spec = lambda: sb.dictof(
    sb.string_spec(),
    sb.formatted(sb.string_or_int_as_string_spec(),
                 formatter=MergedOptionStringFormatter))

stack_json_spec = lambda: sb.set_options(Resources=sb.required(
    sb.dictof(
        sb.string_spec(),
        sb.set_options(Type=sb.required(sb.string_spec()),
                       Properties=sb.optional_spec(sb.dictionary_spec())))),
                                         Parameters=sb.optional_spec(
                                             sb.dictof(sb.string_spec(),
                                                       sb.dictionary_spec())),
                                         Outputs=sb.optional_spec(
                                             sb.dictof(sb.string_spec(),
                                                       sb.dictionary_spec())))


class policy_set_options(sb.set_options):
    """
    Strip ``NotSpecified`` values from normalised dictionary
    and ensure only one of the 'Not' options are specified
    """
    def normalise_filled(self, meta, val):
        result = super(policy_set_options, self).normalise_filled(meta, val)
コード例 #39
0
 def normalise(self, meta, val):
     val = dictionary_spec().normalise(meta, val).as_dict()
     if "/" not in val:
         val["/"] = {"is_index": True}
     return dictof(string_spec(), dashboard_spec()).normalise(meta, val)
コード例 #40
0
    def validate(self, meta, val):
        """Complain if we don't have a valid group"""
        if val is NotSpecified:
            val = None

        val = sb.dictionary_spec().normalise(meta, val)
        errors = []
        associates = []
        perfect_association = []

        for index, group in enumerate(self.choices):
            other_choices = list(
                chain.from_iterable([
                    self.choices[i] for i in range(len(self.choices))
                    if i != index
                ]))

            found = []
            missing = []
            for key in group:
                if key not in val:
                    missing.append(key)
                else:
                    found.append(key)

            if found:
                associates.append(index)
                if not missing:
                    perfect_association.append(index)

        if len(perfect_association) == 0:
            if len(associates) == 0:
                raise BadSpecValue("Value associates with no groups",
                                   val=val,
                                   choices=self.choices,
                                   meta=meta)

            elif len(associates) == 1:
                group = self.choices[associates[0]]
                other_choices = list(
                    chain.from_iterable([
                        self.choices[i] for i in range(len(self.choices))
                        if i != associates[0]
                    ]))

                found = []
                invalid = []
                missing = []
                for key in group:
                    if key not in val:
                        missing.append(key)
                    else:
                        found.append(key)

                for key in other_choices:
                    if key in val:
                        invald.append(key)

                raise BadSpecValue("Missing keys from this group",
                                   group=group,
                                   found=found,
                                   invalid=invalid,
                                   missing=missing,
                                   meta=meta)

            else:
                raise BadSpecValue(
                    "Value associates with multiple groups",
                    associates=[self.choices[i] for i in associates],
                    got=val,
                    meta=meta)

        elif len(perfect_association) == 1:
            other_choices = list(
                chain.from_iterable([
                    self.choices[i] for i in range(len(self.choices))
                    if i != perfect_association[0]
                ]))
            invalid = []
            for key in other_choices:
                if key in val:
                    invalid.append(key)

            if invalid:
                raise BadSpecValue(
                    "Value associates with a group but has keys from other groups",
                    associates_with=self.choices[perfect_association[0]],
                    invalid=invalid,
                    meta=meta)
            else:
                return val

        else:
            raise BadSpecValue(
                "Value associates with multiple groups",
                associates=[self.choices[i] for i in perfect_association],
                got=val,
                meta=meta)
コード例 #41
0
 def templates_spec(self):
     """Spec for templates"""
     return dictof(string_spec(), dictionary_spec())
コード例 #42
0
ファイル: harpoon_specs.py プロジェクト: Atry/harpoon
    def image_spec(self):
        """Spec for each image"""
        from harpoon.option_spec import image_specs as specs
        from harpoon.option_spec import image_objs
        return create_spec(
            image_objs.Image
            # Change the context options
            ,
            validators.deprecated_key("exclude_context",
                                      "Use ``context.exclude``"),
            validators.deprecated_key("use_git_timestamps",
                                      "Use ``context.use_git_timestamps``"),
            validators.deprecated_key("respect_gitignore",
                                      "Use ``context.use_gitignore``"),
            validators.deprecated_key("parent_dir",
                                      "Use ``context.parent_dir``")

            # Changed how volumes_from works
            ,
            validators.deprecated_key("volumes_from",
                                      "Use ``volumes.share_with``")

            # Deprecated link
            ,
            validators.deprecated_key("link", "Use ``links``")

            # Harpoon options
            ,
            harpoon=any_spec()

            # default the name to the key of the image
            ,
            name=formatted(defaulted(string_spec(), "{_key_name_1}"),
                           formatter=MergedOptionStringFormatter),
            key_name=formatted(overridden("{_key_name_1}"),
                               formatter=MergedOptionStringFormatter),
            image_name=optional_spec(string_spec()),
            image_index=defaulted(string_spec(), ""),
            container_name=optional_spec(string_spec()),
            image_name_prefix=defaulted(string_spec(), ""),
            user=defaulted(string_spec(), None),
            mtime=defaulted(any_spec(), time.time()),
            configuration=any_spec(),
            vars=dictionary_spec(),
            deleteable_image=defaulted(boolean(), False)

            # The spec itself
            ,
            bash=delayed(
                optional_spec(
                    formatted(string_spec(),
                              formatter=MergedOptionStringFormatter))),
            command=delayed(
                optional_spec(
                    formatted(string_spec(),
                              formatter=MergedOptionStringFormatter))),
            commands=required(container_spec(Commands,
                                             listof(command_spec()))),
            squash_after=optional_spec(
                or_spec(boolean(),
                        container_spec(Commands, listof(command_spec())))),
            squash_before_push=optional_spec(
                or_spec(boolean(),
                        container_spec(Commands, listof(command_spec())))),
            recursive=optional_spec(
                create_spec(
                    image_objs.Recursive,
                    action=required(
                        formatted(string_spec(),
                                  formatter=MergedOptionStringFormatter)),
                    persist=required(
                        listof(
                            formatted(string_spec(),
                                      formatter=MergedOptionStringFormatter))),
                    image_name=delayed(
                        many_format(
                            overridden("images.{_key_name_2}.image_name"),
                            formatter=MergedOptionStringFormatter)))),
            links=listof(specs.link_spec(), expect=image_objs.Link),
            context=self.context_spec,
            wait_condition=optional_spec(self.wait_condition_spec),
            lxc_conf=defaulted(filename_spec(), None),
            volumes=create_spec(image_objs.Volumes,
                                mount=listof(specs.mount_spec(),
                                             expect=image_objs.Mount),
                                share_with=listof(
                                    formatted(
                                        string_spec(),
                                        MergedOptionStringFormatter,
                                        expected_type=image_objs.Image))),
            dependency_options=dictof(
                specs.image_name_spec(),
                create_spec(image_objs.DependencyOptions,
                            attached=defaulted(boolean(), False),
                            wait_condition=optional_spec(
                                self.wait_condition_spec))),
            env=listof(specs.env_spec(), expect=image_objs.Environment),
            ports=listof(specs.port_spec(), expect=image_objs.Port),
            ulimits=defaulted(listof(dictionary_spec()), None),
            log_config=defaulted(listof(dictionary_spec()), None),
            security_opt=defaulted(listof(string_spec()), None),
            read_only_rootfs=defaulted(boolean(), False),
            other_options=create_spec(other_options,
                                      start=dictionary_spec(),
                                      build=dictionary_spec(),
                                      create=dictionary_spec(),
                                      host_config=dictionary_spec()),
            network=create_spec(image_objs.Network,
                                dns=defaulted(listof(string_spec()), None),
                                mode=defaulted(string_spec(), None),
                                hostname=defaulted(string_spec(), None),
                                domainname=defaulted(string_spec(), None),
                                disabled=defaulted(boolean(), False),
                                dns_search=defaulted(listof(string_spec()),
                                                     None),
                                extra_hosts=listof(string_spec()),
                                network_mode=defaulted(string_spec(), None),
                                publish_all_ports=defaulted(boolean(), False)),
            cpu=create_spec(image_objs.Cpu,
                            cap_add=defaulted(boolean(), None),
                            cpuset=defaulted(listof(string_spec()), None),
                            cap_drop=defaulted(boolean(), None),
                            mem_limit=defaulted(integer_spec(), 0),
                            cpu_shares=defaulted(integer_spec(), None),
                            memswap_limit=defaulted(integer_spec(), 0)),
            devices=defaulted(listof(dictionary_spec()), None),
            privileged=defaulted(boolean(), False),
            restart_policy=defaulted(string_spec(), None))