def normalise(self, meta, val): pairs = [] has_self = False for account_id in self.accounts(meta): users = sb.listof(sb.string_spec()).normalise(meta.at("users"), self.resource.get('users', NotSpecified)) for index, name in enumerate(sb.listof(sb.any_spec()).normalise(meta, val)): if name == "__self__": if self.self_type != 'role': raise BadPolicy("No __self__ iam role for this policy", meta=meta) else: has_self = True else: if isinstance(name, six.string_types): name = sb.formatted(sb.string_spec(), formatter=MergedOptionStringFormatter).normalise(meta.indexed_at(index), name) pairs.append((name, account_id)) if has_self: pairs.append(("role/{0}".format(self.self_name), self.default_account_id(meta))) for name, account_id in pairs: service = "sts" if name.startswith("assumed-role") else "iam" arn = "arn:aws:{0}::{1}:{2}".format(service, account_id, name) if not users: yield arn else: for user in users: yield "{0}/{1}".format(arn, user)
def normalise(self, meta, val): iam_spec = iam_specs(val, self.self_type, self.self_name) result = sb.set_options( Service = sb.listof(sb.string_spec()) , Federated = sb.listof(sb.string_spec()) , AWS = sb.listof(sb.string_spec()) ).normalise(meta, val) special = sb.set_options( service = sb.listof(principal_service_spec()) , federated = resource_spec(self.self_type, self.self_name) , iam = iam_spec ).normalise(meta, val) for arg, lst in special.items(): capitalized = arg.capitalize() if arg == 'iam': capitalized = "AWS" result[capitalized].extend(lst) for key, val in list(result.items()): if not val: del result[key] continue # Amazon gets rid of the lists if only one item # And this mucks around with the diffing.... if len(val) is 1: result[key] = val[0] else: result[key] = sorted(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) gateway_name = meta.key_names()['_key_name_0'] gateway_location = formatted_string().normalise( meta.at('location'), val.get('location', '')) return sb.create_spec( Gateway, name=sb.overridden(gateway_name), location=sb.required(formatted_string()), stages=sb.listof(formatted_string()), api_keys=sb.listof(api_key_spec()), domain_names=sb.dictof(sb.string_spec(), custom_domain_name_spec(gateway_location)), resources=sb.dictof(sb.string_spec(), gateway_resource_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 normalise_filled(self, meta, val): typ = formatted(overridden("{_key_name_1}"), formatter=MergedOptionStringFormatter).normalise(meta, val) name = formatted(overridden("{_key_name_0}"), formatter=MergedOptionStringFormatter).normalise(meta, val) special = {} kls = special.get(typ, GenericNetscalerConfig) formatted_string = formatted(string_spec(), formatter=MergedOptionStringFormatter) formatted_options = dictof(string_spec(), match_spec((six.string_types, formatted_string), fallback=any_spec())) options = dict( typ=overridden(typ) , name=overridden(name) , bindings=dictof(string_spec() , netscaler_binding_spec()) , tags=listof(string_spec()) , options=formatted_options , overrides=formatted_options , binding_options=formatted_options , environments=optional_spec(listof(valid_environment_spec())) ) if typ == "sslcertkey": options["link"] = listof(string_spec()) as_dict = set_options(**options).normalise(meta, val) return kls(**dict((name, as_dict[name]) for name in options))
def normalise(self, meta, val): iam_spec = iam_specs(val, self.self_type, self.self_name) result = sb.set_options(Service=sb.listof(sb.string_spec()), Federated=sb.listof(sb.string_spec()), AWS=sb.listof(sb.string_spec())).normalise( meta, val) special = sb.set_options(service=sb.listof(principal_service_spec()), federated=resource_spec( self.self_type, self.self_name), iam=iam_spec).normalise(meta, val) for arg, lst in special.items(): capitalized = arg.capitalize() if arg == 'iam': capitalized = "AWS" result[capitalized].extend(lst) for key, val in list(result.items()): if not val: del result[key] continue # Amazon gets rid of the lists if only one item # And this mucks around with the diffing.... if len(val) is 1: result[key] = val[0] else: result[key] = sorted(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 ) 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()), ).normalise(meta, val) statements = [{"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 normalise(self, meta, val): pairs = [] has_self = False for account_id in self.accounts(meta): users = sb.listof(sb.string_spec()).normalise( meta.at("users"), self.resource.get('users', NotSpecified)) for name in sb.listof(sb.any_spec()).normalise(meta, val): if name == "__self__": if self.self_type != 'role': raise BadPolicy("No __self__ iam role for this policy", meta=meta) else: has_self = True else: pairs.append((name, account_id)) if has_self: pairs.append(("role/{0}".format(self.self_name), self.default_account_id(meta))) for name, account_id in pairs: service = "sts" if name.startswith("assumed-role") else "iam" arn = "arn:aws:{0}::{1}:{2}".format(service, account_id, name) if not users: yield arn else: for user in users: yield "{0}/{1}".format(arn, user)
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) bucket_name = meta.key_names()['_key_name_0'] original_permission = sb.listof(resource_policy_dict()).normalise(meta.at("permission"), NotSpecified if "permission" not in val else val["permission"]) deny_permission = sb.listof(resource_policy_dict(effect='Deny')).normalise(meta.at("deny_permission"), NotSpecified if "deny_permission" not in val else val["deny_permission"]) allow_permission = sb.listof(resource_policy_dict(effect='Allow')).normalise(meta.at("allow_permission"), NotSpecified if "allow_permission" not in val else val["allow_permission"]) # require_mfa_to_delete is an alias for this permission if val.get("require_mfa_to_delete") is True: delete_policy = {"action": "s3:DeleteBucket", "resource": { "s3": "__self__" }, "Condition": { "Bool": { "aws:MultiFactorAuthPresent": True } } } normalised_delete_policy = resource_policy_dict(effect='Allow').normalise(meta.at("require_mfa_to_delete"), delete_policy) allow_permission.append(normalised_delete_policy) val = val.wrapped() val['permission'] = original_permission + deny_permission + allow_permission return sb.create_spec(Bucket , acl = sb.defaulted(sb.match_spec((six.string_types, canned_acl_spec()), (dict, acl_statement_spec('acl', 'acl'))), None) , name = sb.overridden(bucket_name) , location = sb.defaulted(formatted_string, None) , permission = sb.container_spec(Document, sb.listof(resource_policy_statement_spec('bucket', bucket_name))) , tags = sb.dictof(sb.string_spec(), formatted_string) , website = sb.defaulted(website_statement_spec("website", "website"), None) , logging = sb.defaulted(logging_statement_spec("logging", "logging"), None) , lifecycle = sb.defaulted(sb.listof(lifecycle_statement_spec("lifecycle", "lifecycle")), None) ).normalise(meta, val)
def __init__(self, extras=sb.NotSpecified, post_register=False): self.post_register = post_register if post_register and extras not in (None, {}, sb.NotSpecified): msg = "Sorry, can't specify ``extras`` and ``post_register`` at the same time" raise ProgrammerError(msg) spec = sb.listof( sb.tuple_spec(sb.string_spec(), sb.listof(sb.string_spec()))) self.extras = spec.normalise(Meta({}, []), extras)
async def set_chain_state(collector, target, reference, artifact, **kwargs): """ Set the state of colors on your tile ``lan:set_chain_state d073d5f09124 -- '{"colors": [[[0, 0, 0, 3500], [0, 0, 0, 3500], ...], [[0, 0, 1, 3500], ...], ...], "tile_index": 1, "length": 1, "x": 0, "y": 0, "width": 8}'`` Where the colors is a grid of 8 rows of 8 ``[h, s, b, k]`` values. """ options = collector.configuration["photons_app"].extra_as_json if "colors" in options: spec = sb.listof( sb.listof( list_spec(sb.integer_spec(), sb.float_spec(), sb.float_spec(), sb.integer_spec()))) colors = spec.normalise(Meta.empty().at("colors"), options["colors"]) row_lengths = [len(row) for row in colors] if len(set(row_lengths)) != 1: raise PhotonsAppError( "Please specify colors as a grid with the same length rows", got=row_lengths) num_cells = sum(len(row) for row in colors) if num_cells != 64: raise PhotonsAppError("Please specify 64 colors", got=num_cells) cells = [] for row in colors: for col in row: cells.append({ "hue": col[0], "saturation": col[1], "brightness": col[2], "kelvin": col[3] }) options["colors"] = cells else: raise PhotonsAppError( "Please specify colors in options after -- as a grid of [h, s, b, k]" ) missing = [] for field in TileMessages.SetState64.Payload.Meta.all_names: if field not in options and field not in ("duration", "reserved6"): missing.append(field) if missing: raise PhotonsAppError("Missing options for the SetTileState message", missing=missing) options["res_required"] = False msg = TileMessages.SetState64.empty_normalise(**options) await target.script(msg).run_with_all(reference)
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_spec(), MergedOptionStringFormatter, expected_type=six.string_types) role_name = meta.key_names()['_key_name_0'] original_permission = sb.listof(permission_dict()).normalise(meta.at("permission"), NotSpecified if "permission" not in val else val["permission"]) deny_permission = sb.listof(permission_dict(effect='Deny')).normalise(meta.at("deny_permission"), NotSpecified if "deny_permission" not in val else val["deny_permission"]) allow_permission = sb.listof(permission_dict(effect='Allow')).normalise(meta.at("allow_permission"), NotSpecified if "allow_permission" not in val else val["allow_permission"]) allow_to_assume_me = sb.listof(trust_dict("principal")).normalise(meta.at("allow_to_assume_me"), val.get("allow_to_assume_me", NotSpecified)) disallow_to_assume_me = sb.listof(trust_dict("notprincipal")).normalise(meta.at("disallow_to_assume_me"), val.get("disallow_to_assume_me", NotSpecified)) if not allow_to_assume_me and not disallow_to_assume_me: raise BadSpecValue("Roles must have either allow_to_assume_me or disallow_to_assume_me specified", meta=meta) val = val.wrapped() val['trust'] = allow_to_assume_me + disallow_to_assume_me val['permission'] = original_permission + deny_permission + allow_permission return sb.create_spec(Role , name = sb.overridden(role_name) , description = formatted_string , attached_policies = sb.listof(formatted_string) , trust = sb.container_spec(Document, sb.listof(trust_statement_spec('role', role_name))) , permission = sb.container_spec(Document, sb.listof(permission_statement_spec('role', role_name))) , make_instance_profile = sb.defaulted(sb.boolean(), False) ).normalise(meta, val)
def context_spec(self): """Spec for specifying context options""" from harpoon.option_spec import image_objs return dict_from_bool_spec(lambda meta, val: {"enabled": val} , create_spec(image_objs.Context , include = listof(string_spec()) , exclude = listof(string_spec()) , enabled = defaulted(boolean(), True) , parent_dir = directory_spec(formatted(defaulted(string_spec(), "{config_root}"), formatter=MergedOptionStringFormatter)) , use_gitignore = defaulted(boolean(), False) , use_git_timestamps = defaulted(or_spec(boolean(), listof(string_spec())), False) ) )
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 netscaler_spec(self): class to_boolean(Spec): def setup(self, spec): self.spec = spec def normalise_either(self, meta, val): val = self.spec.normalise(meta, val) if type(val) is bool: return val if val == 'False': return False elif val == 'True': return True raise BadConfiguration("Expected a boolean", got=val, meta=meta) return create_spec(netscaler_specs.NetScaler , host = required(formatted(string_spec(), formatter=MergedOptionStringFormatter)) , dry_run = to_boolean(formatted(overridden("{bespin.dry_run}"), formatter=MergedOptionStringFormatter)) , username = required(formatted(string_spec(), formatter=MergedOptionStringFormatter)) , configuration_username = optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter)) , password = delayed(required(formatted(string_spec(), formatter=MergedOptionStringFormatter))) , configuration_password = optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter)) , verify_ssl = defaulted(boolean(), True) , nitro_api_version = defaulted(formatted(string_spec(), formatter=MergedOptionStringFormatter), "v1") , configuration = optional_spec(netscaler_specs.configuration_spec()) , syncable_environments = optional_spec(listof(valid_environment_spec())) )
def normalise(self, meta, val): from harpoon.option_spec.harpoon_specs import HarpoonSpec if "content" in val or "context" in val: spec = sb.set_options(mtime=sb.optional_spec(sb.integer_spec()), dest=sb.required(sb.formatted(sb.string_spec(), formatter=MergedOptionStringFormatter)), content=sb.string_spec(), context=sb.optional_spec(HarpoonSpec().context_spec)) result = spec.normalise(meta, val) if result["content"] != "" and result["context"] is not NotSpecified: raise BadOption("Please don't specify both context and content") mtime = result["mtime"] if mtime is NotSpecified: ctxt = type("Context", (object, ), {"use_git": True})() mtime = meta.everything["mtime"](ctxt) context_name = "{0}-{1}-mtime({2})".format(hashlib.md5(result['content'].encode('utf-8')).hexdigest(), result["dest"].replace("/", "-").replace(" ", "--"), mtime) extra_context = (result["content"], context_name) if result["context"] is not NotSpecified: context_name = "{0}.tar".format(context_name) extra_context = ({"context": result["context"]}, context_name) return Command(("ADD", "{0} {1}".format(context_name, result["dest"])), extra_context) else: spec = sb.set_options( get=sb.required(sb.listof(sb.formatted(sb.string_spec(), formatter=MergedOptionStringFormatter))) , prefix = sb.defaulted(sb.string_spec(), "") ) result = spec.normalise(meta, val) final = [] for val in result["get"]: final.append(Command(("ADD", "{0} {1}/{2}".format(val, result["prefix"], val)))) return final
def get_from_env(wanted): """Get environment variables from the env""" env = sb.listof(env_spec()).normalise(Meta({}, []), wanted) missing = [e.env_name for e in env if e.missing] if missing: raise BespinError("Missing environment variables", missing=missing) return dict(e.pair for e in env)
def normalise(self, meta, val): accounts = list(self.accounts(meta)) if not accounts: accounts = [self.default_account_id(meta)] for account_id in accounts: string_or_dict = sb.or_spec(sb.string_spec(), sb.dictof(sb.string_choice_spec(["key_id", "alias"]), sb.string_spec())) for key_id in sb.listof(string_or_dict).normalise(meta, val): alias = None if key_id == "__self__" or (isinstance(key_id, dict) and (key_id.get("alias") == "__self__" or key_id.get("key_id") == "__self__")): if self.self_type != "key": raise BadPolicy("No __self__ key for this policy", meta=meta) else: alias = self.self_name location = self.default_location(meta) else: location = self.location(meta) if not alias: if isinstance(key_id, six.string_types): alias = key_id else: alias = key_id.get("alias") key_id = key_id.get("key_id") if alias: yield "arn:aws:kms:{0}:{1}:alias/{2}".format(location, account_id, alias) else: yield "arn:aws:kms:{0}:{1}:key/{2}".format(location, account_id, key_id)
def bespin_spec(self): """Spec for bespin options""" formatted_string = formatted(string_spec(), MergedOptionStringFormatter, expected_type=six.string_types) formatted_boolean = formatted(boolean(), MergedOptionStringFormatter, expected_type=bool) return create_spec(Bespin, validators.deprecated_key( "region", "Please use ``environments.<env>.region``"), config=file_spec(), configuration=any_spec(), assume_role=optional_spec(string_spec()), extra=defaulted(string_spec(), ""), dry_run=defaulted(boolean(), False), flat=defaulted(boolean(), False), environment=optional_spec(string_spec()), no_assume_role=defaulted(formatted_boolean, False), chosen_task=defaulted(formatted_string, "list_tasks"), chosen_stack=defaulted(formatted_string, ""), chosen_artifact=defaulted(formatted_string, ""), extra_imports=listof(imports.import_spec()))
def normalise(self, meta, val): result = [] for index, item in enumerate( sb.listof(sb.any_spec()).normalise(meta, val)): s3_spec = s3_specs(item, self.self_type, self.self_name) iam_spec = iam_specs(item, self.self_type, self.self_name) kms_spec = kms_specs(item, self.self_type, self.self_name) arn_spec = arn_specs(item, self.self_type, self.self_name) if isinstance(item, six.string_types): result.append(item) else: types = (("iam", iam_spec), ("kms", kms_spec), ("s3", s3_spec), ("arn", arn_spec)) for typ, spec in types: if typ in item: if self.only and typ not in self.only: raise BadPolicy( "Sorry, don't support this resource type here", wanted=typ, available=self.only, meta=meta) for found in spec.normalise( meta.indexed_at(index).at(typ), item[typ]): result.append(found) return sorted(result)
def setup_addon_register(self, photons_app, __main__): """Setup our addon register""" # Create the addon getter and register the crosshair namespace self.addon_getter = AddonGetter() self.addon_getter.add_namespace("lifx.photons", Result.FieldSpec(), Addon.FieldSpec()) # Initiate the addons from our configuration register = Register(self.addon_getter, self) if "addons" in photons_app: addons = photons_app["addons"] if type(addons) in (MergedOptions, dict) or getattr( addons, "is_dict", False): spec = sb.dictof(sb.string_spec(), sb.listof(sb.string_spec())) meta = Meta(photons_app, []).at("addons") for namespace, adns in spec.normalise(meta, addons).items(): register.add_pairs(*[(namespace, adn) for adn in adns]) elif photons_app.get("default_activate_all_modules"): register.add_pairs(("lifx.photons", "__all__")) if __main__ is not None: register.add_pairs(("lifx.photons", "__main__")) # Import our addons register.recursive_import_known() # Resolve our addons register.recursive_resolve_imported() return register
def wait_condition_spec(self): """Spec for a wait_condition block""" from harpoon.option_spec import image_objs formatted_string = formatted(string_spec(), formatter=MergedOptionStringFormatter) return create_spec(image_objs.WaitCondition , harpoon = formatted(overridden("{harpoon}"), formatter=MergedOptionStringFormatter) , timeout = defaulted(integer_spec(), 300) , wait_between_attempts = defaulted(float_spec(), 5) , greps = optional_spec(dictof(formatted_string, formatted_string)) , command = optional_spec(listof(formatted_string)) , port_open = optional_spec(listof(integer_spec())) , file_value = optional_spec(dictof(formatted_string, formatted_string)) , curl_result = optional_spec(dictof(formatted_string, formatted_string)) , file_exists = optional_spec(listof(formatted_string)) )
class Result(dictobj.Spec): specs = dictobj.Field(sb.dictof(spec_key_spec(), sb.has("normalise"))) extra = dictobj.Field( no_such_key_spec("Use extras instead (notice the s!)")) extras = dictobj.Field( sb.listof(sb.tuple_spec(sb.string_spec(), sb.tupleof(sb.string_spec()))))
class array_command_spec(many_item_formatted_spec): value_name = "Command" specs = [ # First item is just a string sb.string_spec() # Second item is a required list of either dicts or strings , sb.required( sb.listof( sb.match_spec( (dict, complex_ADD_spec()), (six.string_types + (list, ), sb.formatted(sb.string_spec(), formatter=MergedOptionStringFormatter))))) ] def create_result(self, action, command, meta, val, dividers): if callable(command) or isinstance(command, six.string_types): command = [command] result = [] for cmd in command: if not isinstance(cmd, list): cmd = [cmd] for c in cmd: if isinstance(c, Command): result.append(c) else: result.append(Command((action, c))) return result
def normalise(self, meta, val): if "content" in val: spec = sb.set_options(dest=sb.required( sb.formatted(sb.string_spec(), formatter=MergedOptionStringFormatter)), content=sb.string_spec()) result = spec.normalise(meta, val) context_name = "{0}-{1}".format( hashlib.md5(result['content'].encode('utf-8')).hexdigest(), result["dest"].replace("/", "-").replace(" ", "--")) return Command( ("ADD", "{0} {1}".format(context_name, result["dest"])), (result["content"], context_name)) else: spec = sb.set_options(get=sb.required( sb.listof( sb.formatted(sb.string_spec(), formatter=MergedOptionStringFormatter))), prefix=sb.defaulted(sb.string_spec(), "")) result = spec.normalise(meta, val) final = [] for val in result["get"]: final.append( Command( ("ADD", "{0} {1}/{2}".format(val, result["prefix"], val)))) return final
def bespin_spec(self): """Spec for bespin options""" formatted_string = formatted(string_spec(), MergedOptionStringFormatter, expected_type=six.string_types) formatted_boolean = formatted(boolean(), MergedOptionStringFormatter, expected_type=bool) return create_spec(Bespin , validators.deprecated_key("region", "Please use ``environments.<env>.region``") , config = file_spec() , configuration = any_spec() , assume_role = optional_spec(string_spec()) , dry_run = defaulted(boolean(), False) , flat = defaulted(boolean(), False) , environment = optional_spec(string_spec()) , no_assume_role = defaulted(formatted_boolean, False) , chosen_task = defaulted(formatted_string, "list_tasks") , chosen_stack = defaulted(formatted_string, "") , chosen_artifact = defaulted(formatted_string, "") , extra_imports = listof(imports.import_spec()) )
def context_spec(self): """Spec for specifying context options""" from harpoon.option_spec import image_objs return dict_from_bool_spec( lambda meta, val: {"enabled": val}, create_spec(image_objs.Context, include=listof(string_spec()), exclude=listof(string_spec()), enabled=defaulted(boolean(), True), parent_dir=directory_spec( formatted(defaulted(string_spec(), "{config_root}"), formatter=MergedOptionStringFormatter)), use_gitignore=defaulted(boolean(), False), use_git_timestamps=defaulted( or_spec(boolean(), listof(string_spec())), False)))
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_spec(), MergedOptionStringFormatter, expected_type=six.string_types) role_name = meta.key_names()['_key_name_0'] original_permission = sb.listof(permission_dict()).normalise( meta.at("permission"), NotSpecified if "permission" not in val else val["permission"]) deny_permission = sb.listof(permission_dict(effect='Deny')).normalise( meta.at("deny_permission"), NotSpecified if "deny_permission" not in val else val["deny_permission"]) allow_permission = sb.listof( permission_dict(effect='Allow')).normalise( meta.at("allow_permission"), NotSpecified if "allow_permission" not in val else val["allow_permission"]) allow_to_assume_me = sb.listof(trust_dict("principal")).normalise( meta.at("allow_to_assume_me"), val.get("allow_to_assume_me", NotSpecified)) disallow_to_assume_me = sb.listof( trust_dict("notprincipal")).normalise( meta.at("disallow_to_assume_me"), val.get("disallow_to_assume_me", NotSpecified)) if not allow_to_assume_me and not disallow_to_assume_me: raise BadSpecValue( "Roles must have either allow_to_assume_me or disallow_to_assume_me specified", meta=meta) val = val.wrapped() val['trust'] = allow_to_assume_me + disallow_to_assume_me val['permission'] = original_permission + deny_permission + allow_permission return sb.create_spec( Role, name=sb.overridden(role_name), description=formatted_string, attached_policies=sb.listof(formatted_string), trust=sb.container_spec( Document, sb.listof(trust_statement_spec('role', role_name))), permission=sb.container_spec( Document, sb.listof(permission_statement_spec('role', role_name))), make_instance_profile=sb.defaulted(sb.boolean(), False)).normalise(meta, val)
def add_configuration(self, configuration, collect_another_source, done, result, src): """Used to add a file to the configuration, result here is the yaml.load of the src""" def make_mtime_func(source): """Lazily calculate the mtime to avoid wasted computation""" return lambda context: self.get_committime_or_mtime( context, source) if "harpoon" in result: if "extra_files" in result["harpoon"]: spec = sb.listof( sb.formatted(sb.string_spec(), formatter=MergedOptionStringFormatter)) meta = Meta(MergedOptions.using(result), []).at("harpoon").at("extra_files") for extra in spec.normalise(meta, result["harpoon"]["extra_files"]): if os.path.abspath(extra) not in done: if not os.path.exists(extra): raise BadConfiguration( "Specified extra file doesn't exist", extra=extra, source=src) collect_another_source(extra) if "images" in result and "__images_from__" in result["images"]: images_from_path = result["images"]["__images_from__"] if isinstance(images_from_path, six.string_types): images_from_path = [images_from_path] for ifp in images_from_path: if not ifp.startswith("/"): ifp = os.path.join(os.path.dirname(src), ifp) if not os.path.exists(ifp) or not os.path.isdir(ifp): raise self.BadConfigurationErrorKls( "Specified folder for other configuration files points to a folder that doesn't exist", path="images.__images_from__", value=ifp) for root, dirs, files in os.walk(ifp): for fle in files: location = os.path.join(root, fle) if fle.endswith(".yml") or fle.endswith(".yaml"): collect_another_source( location, prefix=[ "images", os.path.splitext(os.path.basename(fle))[0] ], extra={"mtime": make_mtime_func(location)}) del result["images"]["__images_from__"] if "mtime" not in result: result["mtime"] = make_mtime_func(src) configuration.update(result, source=src)
def context_spec(self): """Spec for specifying context options""" from harpoon.option_spec import image_objs return dict_from_bool_spec(lambda meta, val: {"enabled": val} , create_spec(image_objs.Context , validators.deprecated_key("use_git_timestamps", "Since docker 1.8, timestamps no longer invalidate the docker layer cache") , include = listof(string_spec()) , exclude = listof(string_spec()) , enabled = defaulted(boolean(), True) , find_options = string_spec() , parent_dir = directory_spec(formatted(defaulted(string_spec(), "{config_root}"), formatter=MergedOptionStringFormatter)) , use_gitignore = defaulted(boolean(), False) , ignore_find_errors = defaulted(boolean(), False) ) )
class Addon(dictobj.Spec): name = dictobj.Field(sb.string_spec) extras = dictobj.Field( sb.listof(sb.tuple_spec(sb.string_spec(), sb.string_spec()))) resolver = dictobj.Field(sb.any_spec) namespace = dictobj.Field(sb.string_spec) class BadHook(DelfickError): desc = "Bad Hook" @property def resolved(self): errors = [] if getattr(self, "_resolved", None) is None: try: self._resolved = list(self.resolver()) except Exception as error: errors.append( self.BadHook("Failed to resolve a hook", name=self.name, namespace=self.namespace, error=str(error))) if errors: raise self.BadHook(_errors=errors) return self._resolved def process(self, collector): for result in self.resolved: if collector is not None: collector.register_converters(result.get("specs", {}), Meta, collector.configuration, sb.NotSpecified) def post_register(self, **kwargs): list(self.resolver(post_register=True, **kwargs)) def unresolved_dependencies(self): for namespace, name in self.extras: yield (namespace, name) def resolved_dependencies(self): for result in self.resolved: for namespace, names in result.get("extras", []): if not isinstance(names, (tuple, list)): names = (names, ) for name in names: yield (namespace, name) def dependencies(self, all_deps): for dep in self.unresolved_dependencies(): yield dep if hasattr(self, "_resolved"): for dep in self.resolved_dependencies(): yield dep
def wait_condition_spec(self): """Spec for a wait_condition block""" from harpoon.option_spec import image_objs formatted_string = formatted(string_spec(), formatter=MergedOptionStringFormatter) return create_spec( image_objs.WaitCondition, harpoon=formatted(overridden("{harpoon}"), formatter=MergedOptionStringFormatter), timeout=defaulted(integer_spec(), 300), wait_between_attempts=defaulted(float_spec(), 5), greps=optional_spec(dictof(formatted_string, formatted_string)), command=optional_spec(listof(formatted_string)), port_open=optional_spec(listof(integer_spec())), file_value=optional_spec(dictof(formatted_string, formatted_string)), curl_result=optional_spec( dictof(formatted_string, formatted_string)), file_exists=optional_spec(listof(formatted_string)))
class acl_statement_spec(statement_spec): args = lambda s, self_type, self_name: { "grants": sb.listof(acl_grant_spec("grant", "grant")) } required = ["grants"] final_kls = lambda s, *args, **kwargs: lambda owner: { "AccessControlPolicy": { "Grants": [g(owner) for g in kwargs["grants"]] } }
class grant_statement_spec(statement_spec): args = lambda s, self_type, self_name: { 'grantee': sb.required(resource_spec(self_type, self_name, only="iam") ), 'retiree': resource_spec(self_type, self_name, only="iam"), 'operations': sb.required(sb.listof(sb.string_spec())), 'constraints': sb.any_spec(), 'grant_tokens': sb.any_spec() } final_kls = lambda s, *args, **kwargs: GrantStatement(*args, **kwargs)
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) bucket_name = meta.key_names()['_key_name_0'] original_permission = sb.listof(resource_policy_dict()).normalise( meta.at("permission"), NotSpecified if "permission" not in val else val["permission"]) deny_permission = sb.listof( resource_policy_dict(effect='Deny')).normalise( meta.at("deny_permission"), NotSpecified if "deny_permission" not in val else val["deny_permission"]) allow_permission = sb.listof( resource_policy_dict(effect='Allow')).normalise( meta.at("allow_permission"), NotSpecified if "allow_permission" not in val else val["allow_permission"]) val = val.wrapped() val['permission'] = original_permission + deny_permission + allow_permission return sb.create_spec( Bucket, name=sb.overridden(bucket_name), location=sb.required(formatted_string), permission=sb.container_spec( Document, sb.listof(resource_policy_statement_spec( 'bucket', bucket_name))), tags=sb.dictof(sb.string_spec(), formatted_string)).normalise(meta, val)
def add_configuration(self, configuration, collect_another_source, done, result, src): """Used to add a file to the configuration, result here is the yaml.load of the src""" configuration.update(result, dont_prefix=[dictobj], source=src) if "bespin" in configuration: if "extra_files" in configuration["bespin"]: for extra in sb.listof(sb.formatted(sb.string_spec(), formatter=MergedOptionStringFormatter)).normalise(Meta(configuration, [("bespin", ""), ("extra_files", "")]), configuration["bespin"]["extra_files"]): if os.path.abspath(extra) not in done: if not os.path.exists(extra): raise BadConfiguration("Specified extra file doesn't exist", extra=extra, source=src) collect_another_source(extra)
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) gateway_name = meta.key_names()['_key_name_0'] gateway_location = formatted_string().normalise(meta.at('location'), val.get('location', '')) return sb.create_spec(Gateway , name = sb.overridden(gateway_name) , location = sb.required(formatted_string()) , stages = sb.listof(formatted_string()) , api_keys = sb.listof(api_key_spec()) , domain_names = sb.dictof(sb.string_spec(), custom_domain_name_spec(gateway_location)) , resources = sb.listof(gateway_resource_spec()) ).normalise(meta, 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 normalise(self, meta, val): default_location = "" if "identity" not in self.resource: raise BadPolicy("Generic arn specified without specifying 'identity'", meta=meta) location = self.location(meta) identities = sb.listof(sb.formatted(sb.string_spec(), formatter=MergedOptionStringFormatter)).normalise(meta.at("identity"), self.resource.get("identity")) for account_id in self.accounts(meta): for identity in identities: yield "arn:aws:{0}:{1}:{2}:{3}".format(val, location, account_id, identity)
async def set_tile_positions(collector, target, reference, **kwargs): """ Set the positions of the tiles in your chain. ``lan:set_tile_positions d073d5f09124 -- '[[0, 0], [-1, 0], [-1, 1]]'`` """ extra = collector.configuration["photons_app"].extra_as_json positions = sb.listof(sb.listof(sb.float_spec())).normalise( Meta.empty(), extra) if any(len(position) != 2 for position in positions): raise PhotonsAppError( "Please enter positions as a list of two item lists of user_x, user_y" ) async with target.session() as afr: for i, (user_x, user_y) in enumerate(positions): msg = TileMessages.SetUserPosition(tile_index=i, user_x=user_x, user_y=user_y, res_required=False) await target.script(msg).run_with_all(reference, afr)
def normalise_filled(self, meta, val): val = sb.dictof(sb.string_choice_spec(["s3", "inline", "directory"]), sb.any_spec()).normalise(meta, val) if not val: raise BadSpecValue( "Please specify s3, inline or directory for your code", meta=meta) if len(val) > 1: raise BadSpecValue( "Please only specify one of s3, inline or directory for your code", got=list(val.keys()), meta=meta) formatted_string = sb.formatted(sb.string_spec(), formatter=MergedOptionStringFormatter) if "s3" in val: return sb.create_spec( S3Code, key=formatted_string, bucket=formatted_string, version=sb.defaulted(sb.string_spec(), NotSpecified)).normalise(meta, val['s3']) elif "inline" in val: path = [p for p, _ in meta._path] path.pop() runtime = meta.everything['.'.join(path)].get("runtime", "python") runtime = sb.formatted( sb.string_spec(), formatter=MergedOptionStringFormatter).normalise( meta.at("runtime"), runtime) return sb.create_spec(InlineCode, code=sb.string_spec(), runtime=sb.overridden(runtime)).normalise( meta, {"code": val['inline']}) else: directory = val['directory'] if isinstance(val['directory'], six.string_types): directory = {"directory": val['directory']} if 'directory' in directory: formatted_string = sb.formatted( sb.string_spec(), formatter=MergedOptionStringFormatter) directory['directory'] = formatted_string.normalise( meta.at("directory").at("directory"), directory['directory']) return sb.create_spec(DirectoryCode, directory=sb.directory_spec(), exclude=sb.listof( sb.string_spec())).normalise( meta, directory)
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() )
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 setup(self, **kwargs): account_spec = sb.set_options( account_id = sb.required(sb.string_spec()) , role_to_assume = sb.required(sb.string_spec()) ) kwargs = sb.set_options( accounts = sb.required(sb.dictof(sb.string_spec(), account_spec)) , ordered_accounts = sb.required(sb.listof(sb.string_spec())) , cloudability_auth_token = sb.required(sb.any_spec()) ).normalise(Meta({}, []), kwargs) for key, val in kwargs.items(): setattr(self, key, val)
def normalise(self, meta, val): for bucket_key in sb.listof(sb.formatted(sb.string_spec(), formatter=MergedOptionStringFormatter)).normalise(meta, val): if bucket_key == "__self__" or bucket_key.startswith("__self__"): if self.self_type != "bucket": raise BadPolicy("No __self__ bucket for this policy", meta=meta) else: path = "" if "/" in bucket_key: path = bucket_key[bucket_key.find('/'):] bucket_key = "{0}{1}".format(self.self_name, path) yield "arn:aws:s3:::{0}".format(bucket_key) if '/' not in bucket_key: yield "arn:aws:s3:::{0}/*".format(bucket_key)
def normalise(self, meta, val): for bucket_key in sb.listof(sb.string_spec()).normalise(meta, val): if bucket_key == "__self__" or bucket_key.startswith("__self__"): if self.self_type != "bucket": raise BadPolicy("No __self__ bucket for this policy", meta=meta) else: path = "" if "/" in bucket_key: path = bucket_key[bucket_key.find('/'):] bucket_key = "{0}{1}".format(self.self_name, path) yield "arn:aws:s3:::{0}".format(bucket_key) if '/' not in bucket_key: yield "arn:aws:s3:::{0}/*".format(bucket_key)
def harpoon_spec(self): """Spec for harpoon options""" formatted_string = formatted(string_spec(), MergedOptionStringFormatter, expected_type=six.string_types) formatted_boolean = formatted(boolean(), MergedOptionStringFormatter, expected_type=bool) return create_spec(Harpoon , config = optional_spec(file_spec()) , tag = optional_spec(string_spec()) , extra = defaulted(formatted_string, "") , debug = defaulted(boolean(), False) , addons = dictof(string_spec(), listof(string_spec())) , artifact = optional_spec(formatted_string) , extra_files = listof(string_spec()) , chosen_task = defaulted(formatted_string, "list_tasks") , chosen_image = defaulted(formatted_string, "") , flat = defaulted(formatted_boolean, False) , no_cleanup = defaulted(formatted_boolean, False) , interactive = defaulted(formatted_boolean, True) , silent_build = defaulted(formatted_boolean, False) , keep_replaced = defaulted(formatted_boolean, False) , ignore_missing = defaulted(formatted_boolean, False) , no_intervention = defaulted(formatted_boolean, False) , intervene_afterwards = defaulted(formatted_boolean, False) , do_push = defaulted(formatted_boolean, False) , only_pushable = defaulted(formatted_boolean, False) , docker_context = any_spec() , docker_context_maker = any_spec() , stdout = defaulted(any_spec(), sys.stdout) , tty_stdin = defaulted(any_spec(), None) , tty_stdout = defaulted(any_spec(), lambda: sys.stdout) , tty_stderr = defaulted(any_spec(), lambda: sys.stderr) )
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) bucket_name = meta.key_names()['_key_name_0'] original_permission = sb.listof(resource_policy_dict()).normalise(meta.at("permission"), NotSpecified if "permission" not in val else val["permission"]) deny_permission = sb.listof(resource_policy_dict(effect='Deny')).normalise(meta.at("deny_permission"), NotSpecified if "deny_permission" not in val else val["deny_permission"]) allow_permission = sb.listof(resource_policy_dict(effect='Allow')).normalise(meta.at("allow_permission"), NotSpecified if "allow_permission" not in val else val["allow_permission"]) val = val.wrapped() val['permission'] = original_permission + deny_permission + allow_permission return sb.create_spec(Bucket , name = sb.overridden(bucket_name) , location = sb.required(formatted_string) , permission = sb.container_spec(Document, sb.listof(resource_policy_statement_spec('bucket', bucket_name))) , tags = sb.dictof(sb.string_spec(), formatted_string) ).normalise(meta, val)
def harpoon_spec(self): """Spec for harpoon options""" formatted_string = formatted(string_spec(), MergedOptionStringFormatter, expected_type=six.string_types) formatted_boolean = formatted(boolean(), MergedOptionStringFormatter, expected_type=bool) return create_spec( Harpoon, config=optional_spec(file_spec()), tag=optional_spec(string_spec()), extra=defaulted(formatted_string, ""), debug=defaulted(boolean(), False), addons=dictof(string_spec(), listof(string_spec())), artifact=optional_spec(formatted_string), extra_files=listof(string_spec()), chosen_task=defaulted(formatted_string, "list_tasks"), chosen_image=defaulted(formatted_string, ""), flat=defaulted(formatted_boolean, False), no_cleanup=defaulted(formatted_boolean, False), interactive=defaulted(formatted_boolean, True), silent_build=defaulted(formatted_boolean, False), keep_replaced=defaulted(formatted_boolean, False), ignore_missing=defaulted(formatted_boolean, False), no_intervention=defaulted(formatted_boolean, False), intervene_afterwards=defaulted(formatted_boolean, False), do_push=defaulted(formatted_boolean, False), only_pushable=defaulted(formatted_boolean, False), docker_context=any_spec(), docker_context_maker=any_spec(), stdout=defaulted(any_spec(), sys.stdout), tty_stdin=defaulted(any_spec(), None), tty_stdout=defaulted(any_spec(), lambda: sys.stdout), tty_stderr=defaulted(any_spec(), lambda: sys.stderr))
def confirm_deployment_spec(self): return create_spec(deployment_check.ConfirmDeployment , deploys_s3_path = optional_spec(listof(stack_specs.s3_address())) , zero_instances_is_ok = defaulted(boolean(), False) , auto_scaling_group_name = optional_spec(formatted(string_spec(), formatter=MergedOptionStringFormatter)) , url_checker = optional_spec(self.url_checker_spec) , sns_confirmation = optional_spec(create_spec(deployment_check.SNSConfirmation , validators.deprecated_key("auto_scaling_group_id", "Use ``confirm_deployment.auto_scaling_group_name``") , validators.deprecated_key("env", "Use ``stack.<stack>.env`` instead``") , timeout = defaulted(integer_spec(), 300) , version_message = required(formatted(string_spec(), formatter=MergedOptionStringFormatter)) , deployment_queue = required(formatted(string_spec(), formatter=MergedOptionStringFormatter)) )) )
def accounts(self, meta): accounts = meta.everything["accounts"] default_account_id = self.default_account_id(meta) provided_accounts = sb.listof(sb.string_spec()).normalise(meta.at("account"), self.resource.get("account", [])) if not provided_accounts: yield default_account_id for provided_account in provided_accounts: if not provided_account: yield "" else: if provided_account not in accounts: raise BadPolicy("Unknown account specified", account=provided_account, meta=meta) else: account_id = accounts[provided_account] yield account_id
def normalise(self, meta, val): result = [] for index, item in enumerate(sb.listof(sb.any_spec()).normalise(meta, val)): s3_spec = s3_specs(item, self.self_type, self.self_name) iam_spec = iam_specs(item, self.self_type, self.self_name) kms_spec = kms_specs(item, self.self_type, self.self_name) arn_spec = arn_specs(item, self.self_type, self.self_name) if isinstance(item, six.string_types): result.append(item) else: types = (("iam", iam_spec), ("kms", kms_spec), ("s3", s3_spec), ("arn", arn_spec)) for typ, spec in types: if typ in item: if self.only and typ not in self.only: raise BadPolicy("Sorry, don't support this resource type here", wanted=typ, available=self.only, meta=meta) for found in spec.normalise(meta.indexed_at(index).at(typ), item[typ]): result.append(found) return sorted(result)
def downtime(collector, stack, method="downtime", **kwargs): """Downtime this stack in alerting systems""" if stack.downtimer_options is NotSpecified: raise BespinError("Nothing to downtime!") env = sb.listof(env_spec()).normalise(Meta({}, []), ["USER", "DURATION", "COMMENT"]) missing = [e.env_name for e in env if e.missing] if missing: raise BespinError("Missing environment variables", missing=missing) provided_env = dict(e.pair for e in env) author = provided_env["USER"] comment = provided_env["COMMENT"] duration = provided_env["DURATION"] downtimer = Downtimer(stack.downtimer_options, dry_run=collector.configuration["bespin"].dry_run) for system, options in stack.alerting_systems.items(): downtimer.register_system(system, options) getattr(downtimer, method)(duration, author, comment)
def normalise(self, meta, val): from harpoon.option_spec.harpoon_specs import HarpoonSpec formatted_string = sb.formatted(sb.string_spec(), formatter=MergedOptionStringFormatter) val = sb.apply_validators(meta, val, [validators.either_keys(["context"], ["content"], ["get"], ["formatted"])]) if "get" in val: val = sb.create_spec(CommandAddExtra , get = sb.required(sb.listof(formatted_string)) , prefix = sb.optional_spec(sb.string_spec()) ).normalise(meta, val) if "context" in val: val = sb.create_spec(CommandContextAdd , validators.deprecated_key("mtime", "Since docker 1.8, timestamps no longer invalidate the docker layer cache") , dest = sb.required(formatted_string) , context = sb.required(HarpoonSpec().context_spec) ).normalise(meta, val) if "formatted" in val: val = sb.create_spec(CommandContentAdd , validators.deprecated_key("mtime", "Since docker 1.8, timestamps no longer invalidate the docker layer cache") , dest = sb.required(formatted_string) , content = sb.overridden(sb.NotSpecified) , formatted = sb.container_spec(CommandContentAddString, formatted_string) ).normalise(meta, val) if "content" in val: val = sb.create_spec(CommandContentAdd , validators.deprecated_key("mtime", "Since docker 1.8, timestamps no longer invalidate the docker layer cache") , dest = sb.required(formatted_string) , content = sb.match_spec( (six.string_types, sb.container_spec(CommandContentAddString, sb.string_spec())) , fallback = complex_ADD_from_image_spec() ) ).normalise(meta, val) return list(val.commands(meta))
def normalise_filled(self, meta, val): val = sb.dictof(sb.string_choice_spec(["s3", "inline", "directory"]), sb.any_spec()).normalise(meta, val) if not val: raise BadSpecValue("Please specify s3, inline or directory for your code", meta=meta) if len(val) > 1: raise BadSpecValue("Please only specify one of s3, inline or directory for your code", got=list(val.keys()), meta=meta) formatted_string = sb.formatted(sb.string_spec(), formatter=MergedOptionStringFormatter) if "s3" in val: return sb.create_spec(S3Code , key = formatted_string , bucket = formatted_string , version = sb.defaulted(sb.string_spec(), NotSpecified) ).normalise(meta, val['s3']) elif "inline" in val: path = [p for p, _ in meta._path] path.pop() runtime = meta.everything['.'.join(path)].get("runtime", "python") runtime = sb.formatted(sb.string_spec(), formatter=MergedOptionStringFormatter).normalise(meta.at("runtime"), runtime) return sb.create_spec(InlineCode , code = sb.string_spec() , runtime = sb.overridden(runtime) ).normalise(meta, {"code": val['inline']}) else: directory = val['directory'] if isinstance(val['directory'], six.string_types): directory = {"directory": val['directory']} if 'directory' in directory: formatted_string = sb.formatted(sb.string_spec(), formatter=MergedOptionStringFormatter) directory['directory'] = formatted_string.normalise(meta.at("directory").at("directory"), directory['directory']) return sb.create_spec(DirectoryCode , directory = sb.directory_spec() , exclude = sb.listof(sb.string_spec()) ).normalise(meta, directory)
def setup_addon_register(self, harpoon): """Setup our addon register""" # Create the addon getter and register the crosshairs namespace self.addon_getter = AddonGetter() self.addon_getter.add_namespace("harpoon.crosshairs", Result.FieldSpec(), Addon.FieldSpec()) # Initiate the addons from our configuration register = Register(self.addon_getter, self) if "addons" in harpoon: addons = harpoon["addons"] if type(addons) in (MergedOptions, dict) or getattr(addons, "is_dict", False): spec = sb.dictof(sb.string_spec(), sb.listof(sb.string_spec())) meta = Meta(harpoon, []).at("addons") for namespace, adns in spec.normalise(meta, addons).items(): register.add_pairs(*[(namespace, adn) for adn in adns]) # Import our addons register.recursive_import_known() # Resolve our addons register.recursive_resolve_imported() return register
from bespin.formatter import MergedOptionStringFormatter from bespin.errors import BadNetScaler from input_algorithms.spec_base import Spec, dictof, listof, string_spec, container_spec, match_spec, overridden, formatted, set_options, any_spec, optional_spec from input_algorithms.spec_base import NotSpecified from input_algorithms.dictobj import dictobj import requests import logging import json import six import re log = logging.getLogger("bespin.option_spec.netscaler") netscaler_binding_spec = lambda: container_spec(NetscalerBinding, match_spec(((list, ) + six.string_types, listof(string_spec())), (dict, set_options(tagged=listof(string_spec()))))) class valid_environment_spec(Spec): def normalise_filled(self, meta, val): if "environments" not in meta.everything: raise BespinError("Please specify {environments}") val = string_spec().normalise(meta, val) available = list(meta.everything["environments"].keys()) if val not in available: raise BespinError("Please choose a valid environment", meta=meta, wanted=val, available=available) return val class netscaler_config_spec(Spec): def normalise_filled(self, meta, val): typ = formatted(overridden("{_key_name_1}"), formatter=MergedOptionStringFormatter).normalise(meta, val)