def __post_init__(self): ASSERT.in_(self.kind, ('range', 'values')) if self.kind == 'range': ASSERT.equal(len(self.args), 2) ASSERT.all(self.args, lambda arg: isinstance(arg, int)) ASSERT.less_or_equal(self.args[0], self.args[1]) else: ASSERT.equal(self.kind, 'values') ASSERT.all(self.args, lambda arg: isinstance(arg, str))
def build(parameters): ASSERT.is_(parameters['inside-builder-pod'], True) ASSERT.all(parameters['roots'], _is_root_dir) with scripts.using_sudo(): # We should run `apt-get update` even when we are not upgrading # the full system because some packages may be removed from the # distro repo while our local package index still has it. scripts.apt_get_update() scripts.mkdir(parameters['drydock'])
def __post_init__(self): validate_pod_label(self.label) ctr_models.validate_pod_version(self.version) # Only allow specifying image for pods by name for now. ASSERT.all(self.images, lambda image: image.name and image.version) # The current implementation does not resolve any unit name # conflicts (note that because we include pod id in the unit # name, they could only conflict within the same group). ASSERT.unique(self.systemd_unit_configs, lambda config: config.unit_name)
def raising(*exc_types): """Annotate a class or a method about what exceptions it raises.""" ASSERT.all(exc_types, lambda type_: issubclass(type_, Exception)) def decorate(cls_or_func): md = get_interface_metadata(cls_or_func) if md: md = Metadata(raising=md.raising + exc_types) else: md = Metadata(raising=exc_types) set_interface_metadata(cls_or_func, md) return cls_or_func return decorate
def columnar_arguments(columns, default_columns): return functionals.compose( argparses.argument( '--format', action=argparses.StoreEnumAction, default=Formats.TEXT, help='set output format (default: %(default_string)s)', ), argparses.argument( '--header', action=argparses.StoreBoolAction, default=True, help='enable/disable header output (default: %(default_string)s)', ), argparses.begin_argument( '--columns', type=lambda columns_str: ASSERT.all( list(filter(None, columns_str.split(','))), columns.__contains__, ), default=','.join(default_columns), help=('set output columns that are comma separated ' 'from available columns: %(columns)s ' '(default: %(default)s)'), ), argparses.apply(lambda action: setattr(action, 'columns', ', '.join( sorted(columns)))), argparses.end, )
def validate_assigned_values(self, assigned_values): """Validate assigned values. * No duplicated assignments. * Assigned values are a subset of defined values. """ ASSERT.all(assigned_values, lambda value: isinstance(value, str)) if self.kind == 'range': ASSERT.unique(assigned_values) ASSERT.all( assigned_values, lambda value: self.args[0] <= int(value) < self.args[1], ) else: ASSERT.equal(self.kind, 'values') ASSERT.issubset( g1_collections.Multiset(assigned_values), g1_collections.Multiset(self.args), ) return assigned_values
def __post_init__(self): validate_pod_label(self.label) ASSERT.equal( _get_label_name(_POD_LABEL_PATTERN, self.label), self.pod_config_template.name, ) # Only allow specifying image for pods by name for now. ASSERT.all(self.images, lambda image: image.name and image.version) # Due to bundle directory layout, image names and volume names # are expected to be unique. (This layout restriction should be # not too restrictive in practice.) ASSERT.unique(self.images, lambda image: image.name) ASSERT.unique(self.volumes, lambda volume: volume.name) # We use the same format on local alias as on token name. ASSERT.all(self.token_names.keys(), validate_token_name) ASSERT.all(self.token_names.values(), validate_token_name)
def post_init(self): ASSERT.predicate(self.path, Path.is_dir) ASSERT.predicate(self.deploy_instruction_path, Path.is_file) ASSERT.all((path for _, path in self.iter_images()), Path.is_file) ASSERT.all((path for _, path in self.iter_volumes()), Path.is_file)
def define_pod( *, name: str, apps: typing.List[App] = (), images: typing.List[str] = (), mounts: typing.List[Mount] = (), volumes: typing.List[Volume] = (), systemd_unit_groups: typing.List[SystemdUnitGroup] = (), token_names: typing.Mapping[str, str] = None, ): """Define a pod. This defines: * Parameter: name/version. * Rule: name/build. NOTE: This rule is generally run in the host system, not inside a builder pod. """ ASSERT(len(images) <= 1, 'expect at most one image per pod for now: {}') # Let's require absolute release labels (because it is quite hard to # derive label path for images and volumes from pod label). ASSERT.all(images, lambda label: label.startswith('//')) ASSERT.all(volumes, lambda volume: volume.label.startswith('//')) ASSERT.unique(map(_get_label_name, images)) ASSERT.unique(_get_label_name(volume.label) for volume in volumes) name_prefix = shipyard2.rules.canonicalize_name_prefix(name) parameter_version = name_prefix + 'version' rule_build = name_prefix + 'build' (foreman.define_parameter(parameter_version)\ .with_doc('pod version')) images = list(map(foreman.Label.parse, images)) @foreman.rule(rule_build) @foreman.rule.depend('//pods/bases:build') @foreman.rule.depend('//releases:build') def build(parameters): version = ASSERT.not_none(parameters[parameter_version]) pod_dir_path = releases.get_output_dir_path(parameters, name, version) if ( pod_dir_path / \ shipyard2.POD_DIR_RELEASE_METADATA_FILENAME ).exists(): LOG.info('skip: build pod: %s %s', name, version) return LOG.info('build pod: %s %s', name, version) try: scripts.mkdir(pod_dir_path) releases.generate_release_metadata( parameters, pod_dir_path / shipyard2.POD_DIR_RELEASE_METADATA_FILENAME, ) _generate_deploy_instruction( parameters=parameters, pod_dir_path=pod_dir_path, name=name, version=version, apps=apps, images=images, mounts=mounts, volumes=volumes, systemd_unit_groups=systemd_unit_groups, token_names=token_names, ) _link_images(parameters, pod_dir_path, images) _link_volumes(parameters, pod_dir_path, volumes) except Exception: # Roll back on error. scripts.rm(pod_dir_path, recursive=True) raise for label in images: build.depend(str(_images.derive_rule(label))) return PodRules(build=build)
def cleanup(parameters): ASSERT.is_(parameters['inside-builder-pod'], True) ASSERT.all(parameters['roots'], _is_root_dir) with scripts.using_sudo(): scripts.apt_get_clean()
def test_assert_collection_mapper(self): self.assertEqual(ASSERT.all([2, 4, 6], is_even), [2, 4, 6]) pattern = r'expect all .*is_even.*, not \[2, 4, 6, 7\]' with self.assertRaisesRegex(AssertionError, pattern): ASSERT.all([2, 4, 6, 7], is_even)
def check_invariants(self): ASSERT.all(self.definitions, models.validate_token_name) for token_name, assignments in self.assignments.items(): models.validate_token_name(token_name) ASSERT.getitem(self.definitions, token_name)\ .validate_assigned_values([a.value for a in assignments])