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() ) )
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() ) )
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() )
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()))
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() )
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)
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
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 )
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
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)
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')
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
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)
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
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)
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)
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
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
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)
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
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)
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)
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
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)
def normalise(self, meta, val): val = sb.dictionary_spec().normalise(meta, val) return self.formatted_dict(meta, val)
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) )
, 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())) )
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), )
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)
def templates_spec(self): """Spec for templates""" return dictof(string_spec(), dictionary_spec())
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), )
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) )
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)
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)
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)
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))