Ejemplo n.º 1
0
    def run(self, context, args, kwargs, opargs):
        if not args and not kwargs:
            raise CommandException(_("Create requires more arguments, see 'help create' for more information"))
        if len(args) > 1:
            raise CommandException(_("Wrong syntax for create, see 'help create' for more information"))

        if len(args) == 1:
            kwargs[self.parent.primary_key.name] = args.pop(0)

        if 'name' not in kwargs:
            raise CommandException(_('Please specify a name for your replication link'))
        else:
            name = kwargs.pop('name')

        master = kwargs.pop('master')
        slave = kwargs.pop('slave')
        partners = [master, slave]

        for ip in context.call_sync('network.config.get_my_ips'):
            if ip in partners:
                break
        else:
            raise CommandException(_(
                'None of provided replication link partners {0}, {1} match any of machine\'s IPs'.format(master, slave)
            ))

        datasets = kwargs.pop('datasets', [])
        if isinstance(datasets, six.string_types):
            datasets = [datasets]
        bidirectional = read_value(kwargs.pop('bidirectional', False), ValueType.BOOLEAN)
        recursive = read_value(kwargs.pop('recursive', False), ValueType.BOOLEAN)
        replicate_services = read_value(kwargs.pop('replicate_services', False), ValueType.BOOLEAN)

        if replicate_services and not bidirectional:
            raise CommandException(_(
                'Replication of services is available only when bi-directional replication is selected'
            ))

        ns = SingleItemNamespace(None, self.parent)
        ns.orig_entity = query.wrap(copy.deepcopy(self.parent.skeleton_entity))
        ns.entity = query.wrap(copy.deepcopy(self.parent.skeleton_entity))

        ns.entity['name'] = name
        ns.entity['master'] = master
        ns.entity['partners'] = partners
        ns.entity['datasets'] = datasets
        ns.entity['bidirectional'] = bidirectional
        ns.entity['recursive'] = recursive
        ns.entity['replicate_services'] = replicate_services

        context.submit_task(
            self.parent.create_task,
            ns.entity,
            callback=lambda s, t: post_save(ns, s, t)
        )
Ejemplo n.º 2
0
Archivo: disks.py Proyecto: jceel/cli
    def run(self, context, args, kwargs, opargs):
        if len(args) != 1:
            raise CommandException(
                'Specify whether to on or off identification light')

        on = read_value(args[0], ValueType.BOOLEAN)
        context.call_sync('disk.identify', self.parent.entity['id'], on)
Ejemplo n.º 3
0
    def do_set(self, obj, value):
        if self.condition and not self.condition(obj):
            raise ValueError(
                _("Property '{0}' is not settable for this entity".format(
                    self.name)))

        value = read_value(value, self.type)
        if self.enum:
            enum_val = self.enum() if callable(self.enum) else self.enum
            if (self.type == ValueType.SET
                    and isinstance(value, (list, tuple))):
                if bool(frozenset(value).symmetric_difference(enum_val)):
                    raise ValueError(
                        "Invalid value for property '{0}'. Should be one of: {1}"
                        .format(self.get_name, ', '.join(enum_val)))
            elif value not in enum_val:
                raise ValueError(
                    "Invalid value for property '{0}'. Should be one of: {1}".
                    format(self.get_name, ', '.join(enum_val)))

        if isinstance(self.set, collections.Callable):
            self.set(obj, value)
            return

        obj.set(self.set, value)
Ejemplo n.º 4
0
    def do_set(self, obj, value, check_entity=None):
        if not self.can_set(check_entity if check_entity else obj):
            raise ValueError(_("Property '{0}' is not settable for this entity".format(self.name)))

        value = read_value(value, self.type)

        if self.strict and self.enum:
            enum_val = self.enum(obj) if callable(self.enum) else self.enum
            if self.type == ValueType.SET:
                for e in value:
                    if e not in enum_val:
                        raise ValueError("Invalid value for property '{0}'. Should be one of: {1}".format(
                            self.get_name,
                            '; '.join(format_value(i) for i in enum_val))
                        )
            elif value not in enum_val:
                raise ValueError("Invalid value for property '{0}'. Should be one of: {1}".format(
                    self.get_name,
                    ', '.join(format_value(i) for i in enum_val))
                )

        if isinstance(self.set, collections.Callable):
            self.set(obj, value)
            return

        q.set(obj, self.set, value)
Ejemplo n.º 5
0
    def do_set(self, obj, value):
        if self.condition and not self.condition(obj):
            raise ValueError(_("Property '{0}' is not settable for this entity".format(self.name)))

        value = read_value(value, self.type)
        if self.enum:
            enum_val = self.enum() if callable(self.enum) else self.enum
            if (self.type == ValueType.SET and isinstance(value, (list, tuple))):
                if bool(frozenset(value).symmetric_difference(enum_val)):
                    raise ValueError(
                        "Invalid value for property '{0}'. Should be one of: {1}".format(
                            self.get_name, ', '.join(enum_val)
                        )
                    )
            elif value not in enum_val:
                raise ValueError(
                    "Invalid value for property '{0}'. Should be one of: {1}".format(
                        self.get_name, ', '.join(enum_val))
                )

        if isinstance(self.set, collections.Callable):
            self.set(obj, value)
            return

        obj.set(self.set, value)
Ejemplo n.º 6
0
    def do_set(self, obj, value, check_entity=None):
        if not self.can_set(check_entity if check_entity else obj):
            raise ValueError(
                _("Property '{0}' is not settable for this entity".format(
                    self.name)))

        value = read_value(value, self.type)

        if self.strict and (self.enum or (self.complete and self.context)):
            enum_val = self.enum() if callable(
                self.enum) else self.enum or self.complete.choices(
                    self.context, None)
            if self.type == ValueType.SET:
                for e in value:
                    if e not in enum_val:
                        raise ValueError(
                            "Invalid value for property '{0}'. Should be one of: {1}"
                            .format(
                                self.get_name,
                                '; '.join(format_value(i) for i in enum_val)))
            elif value not in enum_val:
                raise ValueError(
                    "Invalid value for property '{0}'. Should be one of: {1}".
                    format(self.get_name,
                           ', '.join(format_value(i) for i in enum_val)))

        if isinstance(self.set, collections.Callable):
            self.set(obj, value)
            return

        q.set(obj, self.set, value)
Ejemplo n.º 7
0
 def run(self, context, args, kwargs, opargs):
     self.context = context
     self.reboot = read_value(kwargs.get('reboot', self.reboot), tv=ValueType.BOOLEAN)
     self.task_id = context.submit_task(
         'update.updatenow',
         self.reboot,
         callback=self.task_callback
     )
Ejemplo n.º 8
0
 def run(self, context, args, kwargs, opargs):
     ignore_volumes = read_value(kwargs.pop('ignore_volumes', False), tv=ValueType.BOOLEAN)
     if args or kwargs:
         raise CommandException(_(
             "Wrong syntax for {0}, see 'help {0}' for more information".format(
                 "migration_resume"
             )
         ))
     tid = context.submit_task('migration.mastermigrate', True, ignore_volumes)
     return TaskPromise(context, tid)
Ejemplo n.º 9
0
Archivo: backup.py Proyecto: zoot/cli
    def run(self, context, args, kwargs, opargs):
        incremental = read_value(kwargs.pop('incrementasl', 'yes'),
                                 ValueType.BOOLEAN)
        snapshot = read_value(kwargs.pop('snapshot', 'yes'), ValueType.BOOLEAN)
        dry_run = read_value(kwargs.pop('dry_run', 'no'), ValueType.BOOLEAN)

        if dry_run:

            def describe(row):
                if row['type'] == 'SEND_STREAM':
                    return '{localfs}@{snapshot} -> {remotefs}@{snapshot} ({incr})'.format(
                        incr='incremental'
                        if row.get('incremental') else 'full',
                        **row)

                if row['type'] == 'DELETE_SNAPSHOTS':
                    return 'reinitialize remote dataset {remotefs}'.format(
                        **row)

                if row['type'] == 'DELETE_DATASET':
                    return 'delete remote dataset {remotefs} (because it has been deleted locally)'.format(
                        **row)

            result = context.call_task_sync('backup.sync',
                                            self.parent.entity['id'], snapshot,
                                            True)
            if result['state'] != 'FINISHED':
                raise CommandException('Failed to query backup: {0}'.format(
                    q.get(result, 'error.message')))

            return Sequence(
                Table(result['result'], [
                    Table.Column('Action type', 'type', ValueType.STRING),
                    Table.Column('Description', describe, ValueType.STRING)
                ]), "Estimated backup stream size: {0}".format(
                    format_value(
                        sum(a.get('send_size', 0) for a in result['result']),
                        ValueType.SIZE)))
        else:
            tid = context.submit_task('backup.sync', self.parent.entity['id'],
                                      snapshot)
            return TaskPromise(context, tid)
Ejemplo n.º 10
0
 def run(self, context, args, kwargs, opargs):
     if (args or len(kwargs) > 1 or ('reboot' not in kwargs and len(kwargs) == 1)):
         raise CommandException(_(
             "Incorrect syntax {0} {1}\n{2}".format(args, kwargs, inspect.getdoc(self))
         ))
     self.context = context
     self.reboot = read_value(kwargs.get('reboot', self.reboot), tv=ValueType.BOOLEAN)
     self.task_id = context.submit_task(
         'update.updatenow',
         self.reboot,
         callback=self.task_callback
     )
Ejemplo n.º 11
0
Archivo: backup.py Proyecto: erinix/cli
    def run(self, context, args, kwargs, opargs):
        incremental = read_value(kwargs.pop('incrementasl', 'yes'), ValueType.BOOLEAN)
        snapshot = read_value(kwargs.pop('snapshot', 'yes'), ValueType.BOOLEAN)
        dry_run = read_value(kwargs.pop('dry_run', 'no'), ValueType.BOOLEAN)

        if dry_run:
            def describe(row):
                if row['type'] == 'SEND_STREAM':
                    return '{localfs}@{snapshot} -> {remotefs}@{snapshot} ({incr})'.format(
                        incr='incremental' if row.get('incremental') else 'full',
                        **row
                    )

                if row['type'] == 'DELETE_SNAPSHOTS':
                    return 'reinitialize remote dataset {remotefs}'.format(**row)

                if row['type'] == 'DELETE_DATASET':
                    return 'delete remote dataset {remotefs} (because it has been deleted locally)'.format(**row)

            result = context.call_task_sync('backup.sync', self.parent.entity['id'], snapshot, True)
            if result['state'] != 'FINISHED':
                raise CommandException('Failed to query backup: {0}'.format(q.get(result, 'error.message')))

            return Sequence(
                Table(
                    result['result'], [
                        Table.Column('Action type', 'type', ValueType.STRING),
                        Table.Column('Description', describe, ValueType.STRING)
                    ]
                ),
                "Estimated backup stream size: {0}".format(format_value(
                    sum(a.get('send_size', 0) for a in result['result']),
                    ValueType.SIZE)
                )
            )
        else:
            tid = context.submit_task('backup.sync', self.parent.entity['id'], snapshot)
            return TaskPromise(context, tid)
Ejemplo n.º 12
0
def map_opargs(opargs, context):
    ns = context.pipe_cwd
    mapped_opargs = []
    for k, o, v in opargs:
        if ns.has_property(k):
            mapping = ns.get_mapping(k)
            mapped_opargs.append((mapping.name, o, read_value(v,
                                                              mapping.type)))
        else:
            raise CommandException(
                _('Property {0} not found, valid properties are: {1}'.format(
                    k,
                    ','.join([x.name for x in ns.property_mappings
                              if x.list]))))
    return mapped_opargs
Ejemplo n.º 13
0
def map_opargs(opargs, context):
    ns = context.pipe_cwd
    mapped_opargs = []
    for k, o, v in opargs:
        if ns.has_property(k):
            mapping = ns.get_mapping(k)
            mapped_opargs.append((mapping.name, o, read_value(v, mapping.type)))
        else:
            raise CommandException(_(
                'Property {0} not found, valid properties are: {1}'.format(
                    k,
                    ','.join([x.name for x in ns.property_mappings if x.list])
                )
            ))
    return mapped_opargs
Ejemplo n.º 14
0
    def do_append(self, obj, value):
        if self.type not in (ValueType.SET, ValueType.ARRAY):
            raise ValueError('Property is not a set or array')

        value = read_value(value, self.type)
        oldvalues = q.get(obj, self.set)
        if oldvalues is not None:
            newvalues = oldvalues + list(value)
        else:
            newvalues = value

        if isinstance(self.set, collections.Callable):
            self.set(obj, newvalues)
            return

        q.set(obj, self.set, newvalues)
Ejemplo n.º 15
0
    def do_append(self, obj, value):
        if self.type != ValueType.SET:
            raise ValueError('Property is not a set')

        value = read_value(value, self.type)
        oldvalues = obj.get(self.set)
        if oldvalues is not None:
            newvalues = oldvalues + value
        else:
            newvalues = value

        if isinstance(self.set, collections.Callable):
            self.set(obj, newvalues)
            return

        obj.set(self.set, newvalues)
Ejemplo n.º 16
0
    def do_append(self, obj, value):
        if self.type not in (ValueType.SET, ValueType.ARRAY):
            raise ValueError('Property is not a set or array')

        value = read_value(value, self.type)
        oldvalues = q.get(obj, self.set)
        if oldvalues is not None:
            newvalues = oldvalues + value
        else:
            newvalues = value

        if isinstance(self.set, collections.Callable):
            self.set(obj, newvalues)
            return

        q.set(obj, self.set, newvalues)
Ejemplo n.º 17
0
    def do_append(self, obj, value):
        if self.type != ValueType.SET:
            raise ValueError('Property is not a set')

        value = read_value(value, self.type)
        oldvalues = obj.get(self.set)
        if oldvalues is not None:
            newvalues = oldvalues + value
        else:
            newvalues = value

        if isinstance(self.set, collections.Callable):
            self.set(obj, newvalues)
            return

        obj.set(self.set, newvalues)
Ejemplo n.º 18
0
    def do_set(self, obj, value):
        if self.condition and not self.condition(obj):
            raise ValueError(_("Property '{0}' is not settable for this entity".format(self.name)))

        if self.enum:
            if str(value) not in self.enum:
                raise ValueError(
                    "Invalid value for property '{0}'. Should be one of: {1}".format(
                        self.get_name, ', '.join(self.enum))
                )

        value = read_value(value, self.type)
        if isinstance(self.set, collections.Callable):
            self.set(obj, value)
            return

        obj.set(self.set, value)
Ejemplo n.º 19
0
    def do_remove(self, obj, value):
        if self.type not in (ValueType.SET, ValueType.ARRAY):
            raise ValueError('Property is not a set or array')

        value = read_value(value, self.type)
        oldvalues = q.get(obj, self.set)
        newvalues = oldvalues
        for v in value:
            if v in newvalues:
                newvalues.remove(v)
            else:
                raise CommandException(_('{0} is not a value in {1}'.format(v, self.set)))

        if isinstance(self.set, collections.Callable):
            self.set(obj, newvalues)
            return

        q.set(obj, self.set, newvalues)
Ejemplo n.º 20
0
    def do_remove(self, obj, value):
        if self.type not in (ValueType.SET, ValueType.ARRAY):
            raise ValueError('Property is not a set or array')

        value = read_value(value, self.type)
        oldvalues = q.get(obj, self.set)
        newvalues = oldvalues
        for v in value:
            if v in newvalues:
                newvalues.remove(v)
            else:
                raise CommandException(
                    _('{0} is not a value in {1}'.format(v, self.set)))

        if isinstance(self.set, collections.Callable):
            self.set(obj, newvalues)
            return

        q.set(obj, self.set, newvalues)
Ejemplo n.º 21
0
Archivo: disks.py Proyecto: freenas/cli
    def run(self, context, args, kwargs, opargs):
        if len(args) != 1:
            raise CommandException('Specify whether to on or off identification light')

        on = read_value(args[0], ValueType.BOOLEAN)
        context.call_sync('disk.identify', self.parent.entity['id'], on)
Ejemplo n.º 22
0
    def run(self, context, args, kwargs, opargs):
        if not args and not kwargs:
            raise CommandException(_("create requires more arguments, see 'help create' for more information"))
        if len(args) > 1:
            raise CommandException(_("Wrong syntax for create, see 'help create' for more information"))

        # This magic below make either `create foo` or `create name=foo` work
        if len(args) == 1:
            # However, do not allow user to specify name as both implicit and explicit parameter as this suggests a mistake
            if 'name' in kwargs:
                raise CommandException(_("Both implicit and explicit 'name' parameters are specified."))
            else:
                kwargs[self.parent.primary_key.name] = args.pop(0)

        if 'name' not in kwargs:
            raise CommandException(_('Please specify a name for your pool'))
        else:
            name = kwargs.pop('name')

        volume_type = kwargs.pop('type', 'auto')
        if volume_type not in VDEV_TYPES:
            raise CommandException(_(
                "Invalid volume type {0}.  Should be one of: {1}".format(volume_type, VDEV_TYPES)
            ))

        if 'disks' not in kwargs:
            raise CommandException(_("Please specify one or more disks using the disks property"))
        else:
            disks = kwargs.pop('disks')
            if isinstance(disks, six.string_types):
                disks = [disks]

        if read_value(kwargs.pop('encryption', False), ValueType.BOOLEAN) is True:
            encryption = True
            password = kwargs.get('password', None)
        else:
            encryption = False
            password = None

        cache_disks = kwargs.pop('cache', [])
        log_disks = kwargs.pop('log', [])
        if cache_disks is None:
            cache_disks = []
        if log_disks is None:
            log_disks = []
        if isinstance(cache_disks, six.string_types):
            cache_disks = [cache_disks]
        if isinstance(log_disks, six.string_types):
            log_disks = [log_disks]

        ns = SingleItemNamespace(None, self.parent)
        ns.orig_entity = query.wrap(copy.deepcopy(self.parent.skeleton_entity))
        ns.entity = query.wrap(copy.deepcopy(self.parent.skeleton_entity))

        disks, cache_disks, log_disks = check_disks(context, disks, cache_disks, log_disks)

        if disks != 'auto':
            if len(disks) < DISKS_PER_TYPE[volume_type]:
                raise CommandException(_("Volume type {0} requires at least {1} disks".format(
                    volume_type,
                    DISKS_PER_TYPE[volume_type]
                )))
            if len(disks) > 1 and volume_type == 'disk':
                raise CommandException(_("Cannot create a volume of type disk with multiple disks"))

        if volume_type == 'auto':
            layout = kwargs.pop('layout', 'auto')
            if layout not in VOLUME_LAYOUTS:
                raise CommandException(_(
                    "Invalid layout {0}.  Should be one of: {1}".format(layout, list(VOLUME_LAYOUTS.keys()))
                ))
            else:
                if disks != 'auto' and len(disks) < DISKS_PER_TYPE[VOLUME_LAYOUTS[layout]]:
                    raise CommandException(_("Volume layout {0} requires at least {1} disks".format(layout, DISKS_PER_TYPE[VOLUME_LAYOUTS[layout]])))

            context.submit_task('volume.create_auto', name, 'zfs', layout, disks, cache_disks, log_disks, encryption, password)
        else:
            ns.entity['id'] = name
            ns.entity['topology'] = {}
            ns.entity['topology']['data'] = []
            if volume_type == 'disk':
                ns.entity['topology']['data'].append(
                    {'type': 'disk', 'path': correct_disk_path(disks[0])})
            else:
                ns.entity['topology']['data'].append({
                    'type': volume_type,
                    'children': [{'type': 'disk', 'path': correct_disk_path(disk)} for disk in disks]
                })
            ns.entity['encrypted'] = encryption
            if len(cache_disks) > 0:
                if 'cache' not in ns.entity:
                    ns.entity['topology']['cache'] = []

                for disk in cache_disks:
                    ns.entity['topology']['cache'].append({
                        'type': 'disk',
                        'path': correct_disk_path(disk)
                    })

            if len(log_disks) > 0:
                if 'log' not in ns.entity:
                    ns.entity['topology']['log'] = []

                if len(log_disks) > 1:
                    ns.entity['topology']['log'].append({
                        'type': 'mirror',
                        'children': [{'type': 'disk', 'path': correct_disk_path(disk)} for disk in log_disks]
                    })
                else:
                    ns.entity['topology']['log'].append({
                        'type': 'disk',
                        'path': correct_disk_path(log_disks[0])
                    })

            context.submit_task(
                self.parent.create_task,
                ns.entity,
                password,
                callback=lambda s, t: post_save(ns, s, t))
Ejemplo n.º 23
0
    def run(self, context, args, kwargs, opargs):
        if not args and not kwargs:
            raise CommandException(_("create requires more arguments, see 'help create' for more information"))
        if len(args) > 1:
            raise CommandException(_("Wrong syntax for create, see 'help create' for more information"))

        # This magic below make either `create foo` or `create name=foo` work
        if len(args) == 1:
            # However, do not allow user to specify name as both implicit and explicit parameter as this suggests a mistake
            if 'name' in kwargs:
                raise CommandException(_("Both implicit and explicit 'name' parameters are specified."))
            else:
                kwargs[self.parent.primary_key.name] = args.pop(0)

        if 'name' not in kwargs:
            raise CommandException(_('Please specify a name for your pool'))
        else:
            name = kwargs.pop('name')

        volume_type = kwargs.pop('type', 'auto')
        if volume_type not in VDEV_TYPES:
            raise CommandException(_(
                "Invalid volume type {0}.  Should be one of: {1}".format(volume_type, VDEV_TYPES)
            ))

        if 'disks' not in kwargs:
            raise CommandException(_("Please specify one or more disks using the disks property"))
        else:
            disks = kwargs.pop('disks')
            if isinstance(disks, six.string_types):
                disks = [disks]

        if read_value(kwargs.pop('encryption', False), ValueType.BOOLEAN) is True:
            encryption = True
            password = kwargs.get('password', None)
        else:
            encryption = False
            password = None

        cache_disks = kwargs.pop('cache', [])
        log_disks = kwargs.pop('log', [])
        if cache_disks is None:
            cache_disks = []
        if log_disks is None:
            log_disks = []
        if isinstance(cache_disks, six.string_types):
            cache_disks = [cache_disks]
        if isinstance(log_disks, six.string_types):
            log_disks = [log_disks]

        ns = SingleItemNamespace(None, self.parent)
        ns.orig_entity = query.wrap(copy.deepcopy(self.parent.skeleton_entity))
        ns.entity = query.wrap(copy.deepcopy(self.parent.skeleton_entity))

        disks, cache_disks, log_disks = check_disks(context, disks, cache_disks, log_disks)

        if len(disks) < DISKS_PER_TYPE[volume_type]:
            raise CommandException(_("Volume type {0} requires at least {1} disks".format(volume_type,
                                                                                          DISKS_PER_TYPE[volume_type])))
        if len(disks) > 1 and volume_type == 'disk':
            raise CommandException(_("Cannot create a volume of type disk with multiple disks"))

        if volume_type == 'auto':
            layout = kwargs.pop('layout', 'auto')
            if layout not in VOLUME_LAYOUTS:
                raise CommandException(_(
                    "Invalid layout {0}.  Should be one of: {1}".format(layout, list(VOLUME_LAYOUTS.keys()))
                ))
            else:
                if len(disks) < DISKS_PER_TYPE[VOLUME_LAYOUTS[layout]]:
                    raise CommandException(_("Volume layout {0} requires at least {1} disks".format(layout, DISKS_PER_TYPE[VOLUME_LAYOUTS[layout]])))

            context.submit_task('volume.create_auto', name, 'zfs', layout, disks, cache_disks, log_disks, encryption, password)
        else:
            ns.entity['id'] = name
            ns.entity['topology'] = {}
            ns.entity['topology']['data'] = []
            if volume_type == 'disk':
                ns.entity['topology']['data'].append(
                    {'type': 'disk', 'path': correct_disk_path(disks[0])})
            else:
                ns.entity['topology']['data'].append({
                    'type': volume_type,
                    'children': [{'type': 'disk', 'path': correct_disk_path(disk)} for disk in disks]
                })
            ns.entity['encrypted'] = encryption
            if len(cache_disks) > 0:
                if 'cache' not in ns.entity:
                    ns.entity['topology']['cache'] = []

                for disk in cache_disks:
                    ns.entity['topology']['cache'].append({
                        'type': 'disk',
                        'path': correct_disk_path(disk)
                    })

            if len(log_disks) > 0:
                if 'log' not in ns.entity:
                    ns.entity['topology']['log'] = []

                if len(log_disks) > 1:
                    ns.entity['topology']['log'].append({
                        'type': 'mirror',
                        'children': [{'type': 'disk', 'path': correct_disk_path(disk)} for disk in log_disks]
                    })
                else:
                    ns.entity['topology']['log'].append({
                        'type': 'disk',
                        'path': correct_disk_path(log_disks[0])
                    })

            context.submit_task(
                self.parent.create_task,
                ns.entity,
                password,
                callback=lambda s, t: post_save(ns, s, t))
Ejemplo n.º 24
0
    def run(self, context, args, kwargs, opargs):
        if not kwargs.get('name') and not args:
            raise CommandException('name is a required property')

        if not kwargs.get('image'):
            raise CommandException('image is a required property')

        name = kwargs.get('name') or args[0]
        image = context.entity_subscribers['docker.image'].query(('names', 'in', kwargs['image']), single=True)
        if not image:
            image = q.query(DockerImageNamespace.default_images, ('name', '=', kwargs['image']), single=True)

        command = kwargs.get('command', [])
        command = command if isinstance(command, (list, tuple)) else [command]
        env = ['{0}={1}'.format(k, v) for k, v in kwargs.items() if k.isupper()]
        presets = image.get('presets') or {} if image else {}
        ports = presets.get('ports', [])
        volumes = presets.get('static_volumes', [])

        for k, v in kwargs.items():
            if k.startswith('volume:'):
                _, container_path = k.split(':', maxsplit=1)
                volumes.append({
                    'container_path': container_path,
                    'host_path': v,
                    'readonly': False
                })

            if k.startswith('port:'):
                _, portspec = k.split(':', maxsplit=1)
                port, protocol = portspec.split('/', maxsplit=1)
                protocol = protocol.upper()
                try:
                    port = int(port)
                except ValueError:
                    continue

                if protocol not in ('TCP', 'UDP'):
                    continue

                mapping = first_or_default(lambda m: m['container_port'] == port and m['protocol'] == protocol, ports)
                if mapping:
                    mapping['host_port'] = v
                    continue

                ports.append({
                    'container_port': port,
                    'host_port': v,
                    'protocol': protocol
                })

        if presets and len(presets.get('volumes', [])) != len(volumes):
            presets_volumes = set(i['container_path'] for i in presets['volumes'])
            entered_volumes = set(i['container_path'] for i in volumes)
            raise CommandException('Required volumes missing: {0}'.format(', '.join(presets_volumes - entered_volumes)))

        create_args = {
            'names': [name],
            'image': kwargs['image'],
            'host': kwargs.get('host'),
            'hostname': kwargs.get('hostname'),
            'command': command,
            'environment': env,
            'volumes': volumes,
            'ports': ports,
            'autostart': read_value(kwargs.get('autostart', 'no'), ValueType.BOOLEAN),
            'expose_ports': read_value(
                kwargs.get('expose_ports', q.get(presets, 'expose_ports', False)),
                ValueType.BOOLEAN
            ),
            'interactive': read_value(
                kwargs.get('interactive', q.get(presets, 'interactive', False)),
                ValueType.BOOLEAN
            )
        }

        ns = get_item_stub(context, self.parent, name)

        tid = context.submit_task(self.parent.create_task, create_args, callback=lambda s, t: post_save(ns, s, t))
        return EntityPromise(context, tid, ns)