Example #1
0
class Resource(models.Resource):
    cli_help = 'Manage job templates.'
    endpoint = '/job_templates/'

    name = models.Field(unique=True)
    description = models.Field(required=False, display=False)
    job_type = models.Field(
        default='run',
        display=False,
        show_default=True,
        type=click.Choice(['run', 'check']),
    )
    inventory = models.Field(type=types.Related('inventory'))
    project = models.Field(type=types.Related('project'))
    playbook = models.Field()
    machine_credential = models.Field('credential',
        display=False,
        type=types.Related('credential'),
    )
    cloud_credential = models.Field(type=types.Related('credential'),
                                    required=False, display=False)
    forks = models.Field(type=int, required=False, display=False)
    limit = models.Field(required=False, display=False)
    verbosity = models.Field(
        display=False,
        type=types.MappedChoice([
            (0, 'default'),
            (1, 'verbose'),
            (2, 'debug'),
        ]),
    )
    job_tags = models.Field(required=False, display=False)
    extra_vars = models.Field(type=models.File('r'), required=False,
                              display=False)
Example #2
0
class Resource(models.Resource):
    cli_help = 'Manage inventory within Ansible Tower.'
    endpoint = '/inventories/'
    identity = ('organization', 'name')

    name = models.Field(unique=True)
    description = models.Field(required=False, display=False)
    organization = models.Field(type=types.Related('organization'))
    variables = models.Field(type=models.File('r'), required=False,
                             display=False)
Example #3
0
class Resource(models.Resource):
    cli_help = 'Manage credentials within Ansible Tower.'
    endpoint = '/credentials/'
    identity = ('user', 'team', 'kind', 'name')

    name = models.Field(unique=True)
    description = models.Field(required=False, display=False)

    # Who owns this credential?
    user = models.Field(
        display=False,
        type=types.Related('user'),
        required=False,
    )
    team = models.Field(
        display=False,
        type=types.Related('team'),
        required=False,
    )

    # What type of credential is this (machine, SCM, etc.)?
    kind = models.Field(
        help_text='The type of credential being added. '
        'Valid options are: ssh, scm, aws, rax, gce, azure.',
        type=click.Choice(['ssh', 'scm', 'aws', 'rax', 'gce', 'azure']),
    )

    # SSH and SCM fields.
    username = models.Field(
        help_text='The username. For AWS credentials, the access key.',
        required=False,
    )
    password = models.Field(
        help_text='The password. For AWS credentials, the secret key. '
        'For Rackspace credentials, the API key.',
        password=True,
        required=False,
    )
    private_key = models.Field(
        'ssh_key_data',
        display=False,
        help_text="The full path to the SSH private key to store. "
        "(Don't worry; it's encrypted.)",
        required=False,
        type=models.File('r'),
    )
    private_key_password = models.Field('ssh_key_unlock',
                                        password=True,
                                        required=False)

    # SSH specific fields.
    sudo_username = models.Field(required=False, display=False)
    sudo_password = models.Field(password=True, required=False)
    vault_password = models.Field(password=True, required=False)
Example #4
0
class Resource(models.Resource):
    cli_help = 'Manage credentials within Ansible Tower.'
    endpoint = '/credentials/'
    identity = ('user', 'team', 'kind', 'name')

    name = models.Field(unique=True)
    description = models.Field(required=False, display=False)

    # Who owns this credential?
    user = models.Field(
        display=False,
        type=types.Related('user'),
        required=False,
    )
    team = models.Field(
        display=True,
        type=types.Related('team'),
        required=False,
    )

    # What type of credential is this (machine, SCM, etc.)?
    kind = models.Field(
        display=True,
        help_text='The type of credential being added. '
        'Valid options are: ssh, scm, aws, rax, vmware,'
        ' gce, azure, openstack.',
        type=click.Choice([
            'ssh', 'scm', 'aws', 'rax', 'vmware', 'gce', 'azure', 'openstack'
        ]),
    )

    # need host in order to use VMware
    host = models.Field(help_text='The hostname or IP address to use.',
                        required=False,
                        display=False)
    # need project to use openstack
    project = models.Field(help_text='The identifier for the project.',
                           required=False,
                           display=False)

    # SSH and SCM fields.
    username = models.Field(
        help_text='The username. For AWS credentials, the access key.',
        required=False,
    )
    password = models.Field(
        help_text='The password. For AWS credentials, the secret key. '
        'For Rackspace credentials, the API key.',
        password=True,
        required=False,
    )
    ssh_key_data = models.Field(
        'ssh_key_data',
        display=False,
        help_text="The full path to the SSH private key to store. "
        "(Don't worry; it's encrypted.)",
        required=False,
        type=models.File('r'),
    )
    ssh_key_unlock = models.Field('ssh_key_unlock',
                                  password=True,
                                  required=False)

    # Method with which to esclate
    become_method = models.Field(
        help_text='Privledge escalation method. ',
        type=types.MappedChoice([
            ('', 'None'),
            ('sudo', 'sudo'),
            ('su', 'su'),
            ('pbrun', 'pbrun'),
            ('pfexec', 'pfexec'),
        ]),
        required=False,
    )

    # SSH specific fields.
    become_username = models.Field(required=False, display=False)
    become_password = models.Field(password=True, required=False)
    vault_password = models.Field(password=True, required=False)
Example #5
0
class Resource(models.Resource):
    cli_help = 'Manage notification templates within Ansible Tower.'
    endpoint = '/notification_templates/'

    # Actual fields
    name = models.Field(unique=True)
    description = models.Field(required=False, display=False)
    organization = models.Field(type=types.Related('organization'),
                                required=False,
                                display=False)
    notification_type = models.Field(type=click.Choice([
        'email', 'slack', 'twilio', 'pagerduty', 'hipchat', 'webhook', 'irc'
    ]))
    notification_configuration = models.Field(
        type=models.File('r', lazy=True),
        required=False,
        display=False,
        help_text='The notification configuration field. Note providing this'
        ' field would disable all notification-configuration-related'
        ' fields.')

    # Fields that are part of notification_configuration
    config_fields = [
        'notification_configuration', 'channels', 'token', 'username',
        'sender', 'recipients', 'use_tls', 'host', 'use_ssl', 'password',
        'port', 'account_token', 'from_number', 'to_numbers', 'account_sid',
        'subdomain', 'service_key', 'client_name', 'message_from', 'api_url',
        'color', 'notify', 'rooms', 'url', 'headers', 'server', 'nickname',
        'targets'
    ]
    # Fields that are part of notification_configuration which are categorized
    # according to notification_type
    configuration = {
        'slack': ['channels', 'token'],
        'email': [
            'username', 'sender', 'recipients', 'use_tls', 'host', 'use_ssl',
            'password', 'port'
        ],
        'twilio':
        ['account_token', 'from_number', 'to_numbers', 'account_sid'],
        'pagerduty': ['token', 'subdomain', 'service_key', 'client_name'],
        'hipchat':
        ['message_from', 'api_url', 'color', 'token', 'notify', 'rooms'],
        'webhook': ['url', 'headers'],
        'irc':
        ['server', 'port', 'use_ssl', 'password', 'nickname', 'targets']
    }

    # Fields which are expected to be json files.
    json_fields = ['notification_configuration', 'headers']
    encrypted_fields = ['password', 'token', 'account_token']

    # notification_configuration-related fields. fields with default values
    # are optional.
    username = models.Field(required=False,
                            display=False,
                            help_text='[{0}]The username.'.format('email'))
    sender = models.Field(required=False,
                          display=False,
                          help_text='[{0}]The sender.'.format('email'))
    recipients = models.Field(required=False,
                              display=False,
                              multiple=True,
                              help_text='[{0}]The recipients.'.format('email'))
    use_tls = models.Field(required=False,
                           display=False,
                           type=click.BOOL,
                           default=False,
                           help_text='[{0}]The tls trigger.'.format('email'))
    host = models.Field(required=False,
                        display=False,
                        help_text='[{0}]The host.'.format('email'))
    use_ssl = models.Field(
        required=False,
        display=False,
        type=click.BOOL,
        default=False,
        help_text='[{0}]The ssl trigger.'.format('email/irc'))
    password = models.Field(required=False,
                            display=False,
                            password=True,
                            help_text='[{0}]The password.'.format('email/irc'))
    port = models.Field(required=False,
                        display=False,
                        type=click.INT,
                        help_text='[{0}]The email port.'.format('email/irc'))
    channels = models.Field(required=False,
                            display=False,
                            multiple=True,
                            help_text='[{0}]The channel.'.format('slack'))
    token = models.Field(
        required=False,
        display=False,
        password=True,
        help_text='[{0}]The token.'.format('slack/pagerduty/hipchat'))
    account_token = models.Field(
        required=False,
        display=False,
        password=True,
        help_text='[{0}]The account token.'.format('twilio'))
    from_number = models.Field(
        required=False,
        display=False,
        help_text='[{0}]The source phone number.'.format('twilio'))
    to_numbers = models.Field(
        required=False,
        display=False,
        multiple=True,
        help_text='[{0}]The destination SMS numbers.'.format('twilio'))
    account_sid = models.Field(
        required=False,
        display=False,
        help_text='[{0}The account sid.'.format('twilio'))
    subdomain = models.Field(
        required=False,
        display=False,
        help_text='[{0}]The subdomain.'.format('pagerduty'))
    service_key = models.Field(required=False,
                               display=False,
                               help_text='[{0}]The API service/integration'
                               ' key.'.format('pagerduty'))
    client_name = models.Field(
        required=False,
        display=False,
        help_text='[{0}]The client identifier.'.format('pagerduty'))
    message_from = models.Field(required=False,
                                display=False,
                                help_text='[{0}]The label to be shown with '
                                'notification.'.format('hipchat'))
    api_url = models.Field(required=False,
                           display=False,
                           help_text='[{0}]The api url.'.format('hipchat'))
    color = models.Field(
        required=False,
        display=False,
        type=click.Choice(
            ['yellow', 'green', 'red', 'purple', 'gray', 'random']),
        help_text='[{0}]The notification color.'.format('hipchat'))
    notify = models.Field(
        required=False,
        display=False,
        default=False,
        help_text='[{0}]The notify channel trigger.'.format('hipchat'))
    url = models.Field(required=False,
                       display=False,
                       help_text='[{0}]The target URL.'.format('webhook'))
    headers = models.Field(
        required=False,
        display=False,
        type=models.File('r', lazy=True),
        help_text='[{0}]The http headers.'.format('webhook'))
    server = models.Field(required=False,
                          display=False,
                          help_text='[{0}]Server address.'.format('irc'))
    nickname = models.Field(required=False,
                            display=False,
                            help_text='[{0}]The irc nick.'.format('irc'))
    target = models.Field(
        required=False,
        display=False,
        help_text='[{0}]The distination channels or users.'.format('irc'))

    def _separate(self, kwargs):
        """Remove None-valued and configuration-related keyworded arguments
        """
        self._pop_none(kwargs)
        result = {}
        for field in Resource.config_fields:
            if field in kwargs:
                result[field] = kwargs.pop(field)
                if field in Resource.json_fields:
                    try:
                        data = json.loads(result[field])
                        result[field] = data
                    except ValueError:
                        raise exc.TowerCLIError('Provided json file format '
                                                'invalid. Please recheck.')
        return result

    def _configuration(self, kwargs, config_item):
        """Combine configuration-related keyworded arguments into
        notification_configuration.
        """
        if 'notification_configuration' not in config_item:
            if 'notification_type' not in kwargs:
                return
            nc = kwargs['notification_configuration'] = {}
            for field in Resource.configuration[kwargs['notification_type']]:
                if field not in config_item:
                    raise exc.TowerCLIError('Required config field %s not'
                                            ' provided.' % field)
                else:
                    nc[field] = config_item[field]
        else:
            kwargs['notification_configuration'] = \
                    config_item['notification_configuration']

    @resources.command
    @click.option('--job-template',
                  type=types.Related('job_template'),
                  required=False,
                  help='The job template to relate to.')
    @click.option('--status',
                  type=click.Choice(['error', 'success']),
                  required=False,
                  help='Specify job run status of job '
                  'template to relate to.')
    def create(self, fail_on_found=False, force_on_exists=False, **kwargs):
        """Create a notification template.

        All required configuration-related fields (required according to
        notification_type) must be provided.

        There are two types of notification template creation: isolatedly
        creating a new notification template and creating a new notification
        template under a job template. Here the two types are discriminated by
        whether to provide --job-template option. --status option controls
        more specific, job-run-status-related association.

        Fields in the resource's `identity` tuple are used for a lookup;
        if a match is found, then no-op (unless `force_on_exists` is set) but
        do not fail (unless `fail_on_found` is set).
        """
        config_item = self._separate(kwargs)
        jt_id = kwargs.pop('job_template', None)
        status = kwargs.pop('status', 'any')
        old_endpoint = self.endpoint
        if jt_id is not None:
            jt = get_resource('job_template')
            jt.get(pk=jt_id)
            try:
                nt_id = self.get(**copy.deepcopy(kwargs))['id']
            except exc.NotFound:
                pass
            else:
                if fail_on_found:
                    raise exc.TowerCLIError('Notification template already '
                                            'exists and fail-on-found is '
                                            'switched on. Please use'
                                            ' "associate_notification" method'
                                            ' of job_template instead.')
                else:
                    debug.log(
                        'Notification template already exists, '
                        'associating with job template.',
                        header='details')
                    return jt.associate_notification(jt_id,
                                                     nt_id,
                                                     status=status)
            self.endpoint = '/job_templates/%d/notification_templates_%s/' %\
                            (jt_id, status)
        self._configuration(kwargs, config_item)
        result = super(Resource, self).create(**kwargs)
        self.endpoint = old_endpoint
        return result

    @resources.command
    def modify(self, pk=None, create_on_missing=False, **kwargs):
        """Modify an existing notification template.

        Not all required configuration-related fields (required according to
        notification_type) should be provided.

        Fields in the resource's `identity` tuple can be used in lieu of a
        primary key for a lookup; in such a case, only other fields are
        written.

        To modify unique fields, you must use the primary key for the lookup.
        """
        # Create the resource if needed.
        if pk is None and create_on_missing:
            try:
                self.get(**copy.deepcopy(kwargs))
            except exc.NotFound:
                return self.create(**kwargs)

        # Modify everything except notification type and configuration
        config_item = self._separate(kwargs)
        notification_type = kwargs.pop('notification_type', None)
        debug.log(
            'Modify everything except notification type and'
            ' configuration',
            header='details')
        part_result = super(Resource, self).\
            modify(pk=pk, create_on_missing=create_on_missing, **kwargs)

        # Modify notification type and configuration
        if notification_type is None or \
           notification_type == part_result['notification_type']:
            for item in part_result['notification_configuration']:
                if item not in config_item or not config_item[item]:
                    to_add = part_result['notification_configuration'][item]
                    if not (to_add == '$encrypted$'
                            and item in Resource.encrypted_fields):
                        config_item[item] = to_add
        if notification_type is None:
            kwargs['notification_type'] = part_result['notification_type']
        else:
            kwargs['notification_type'] = notification_type
        self._configuration(kwargs, config_item)
        debug.log('Modify notification type and configuration',
                  header='details')
        result = super(Resource, self).\
            modify(pk=pk, create_on_missing=create_on_missing, **kwargs)

        # Update 'changed' field to give general changed info
        if 'changed' in result and 'changed' in part_result:
            result['changed'] = result['changed'] or part_result['changed']
        return result

    @resources.command
    def delete(self, pk=None, fail_on_missing=False, **kwargs):
        """Remove the given notification template.

        Note here configuration-related fields like
        'notification_configuration' and 'channels' will not be
        used even provided.

        If `fail_on_missing` is True, then the object's not being found is
        considered a failure; otherwise, a success with no change is reported.
        """
        self._separate(kwargs)
        return super(Resource, self).\
            delete(pk=pk, fail_on_missing=fail_on_missing, **kwargs)

    @resources.command
    def list(self, all_pages=False, **kwargs):
        """Return a list of notification templates.

        Note here configuration-related fields like
        'notification_configuration' and 'channels' will not be
        used even provided.

        If one or more filters are provided through keyword arguments,
        filter the results accordingly.

        If no filters are provided, return all results.
        """
        self._separate(kwargs)
        return super(Resource, self).list(all_pages=all_pages, **kwargs)

    @resources.command
    def get(self, pk=None, **kwargs):
        """Return one and exactly one notification template.

        Note here configuration-related fields like
        'notification_configuration' and 'channels' will not be
        used even provided.

        Lookups may be through a primary key, specified as a positional
        argument, and/or through filters specified through keyword arguments.

        If the number of results does not equal one, raise an exception.
        """
        self._separate(kwargs)
        return super(Resource, self).get(pk=pk, **kwargs)
Example #6
0
class Resource(models.Resource):
    cli_help = 'Manage credentials within Ansible Tower.'
    endpoint = '/credentials/'
    identity = ('organization', 'user', 'team', 'kind', 'name')

    name = models.Field(unique=True)
    description = models.Field(required=False, display=False)

    # Who owns this credential?
    user = models.Field(
        display=False,
        type=types.Related('user'),
        required=False,
    )
    team = models.Field(
        display=False,
        type=types.Related('team'),
        required=False,
    )
    organization = models.Field(
        display=False,
        type=types.Related('organization'),
        required=False,
    )

    # What type of credential is this (machine, SCM, etc.)?
    kind = models.Field(
        display=True,
        help_text='The type of credential being added. '
        'Valid options are: ssh, net, scm, aws, rax, vmware,'
        ' satellite6, cloudforms, gce, azure, azure_rm, openstack.',
        type=click.Choice([
            'ssh', 'net', 'scm', 'aws', 'rax', 'vmware', 'satellite6',
            'cloudforms', 'gce', 'azure', 'azure_rm', 'openstack'
        ]),
    )

    # need host in order to use VMware
    host = models.Field(help_text='The hostname or IP address to use.',
                        required=False,
                        display=False)
    # need project to use openstack
    project = models.Field(help_text='The identifier for the project.',
                           required=False,
                           display=False)

    # SSH and SCM fields.
    username = models.Field(
        help_text='The username. For AWS credentials, the access key.',
        required=False,
    )
    password = models.Field(
        help_text='%sThe password. For AWS credentials, the secret key. '
        'For Rackspace credentials, the API key.' % PROMPT,
        password=True,
        required=False,
    )
    ssh_key_data = models.Field(
        'ssh_key_data',
        display=False,
        help_text="The full path to the SSH private key to store. "
        "(Don't worry; it's encrypted.)",
        required=False,
        type=models.File('r'),
    )
    ssh_key_unlock = models.Field(help_text='%sssh_key_unlock' % PROMPT,
                                  password=True,
                                  required=False)

    # Extra fields in 3.0
    authorize = models.Field(
        help_text='Whether to use the authorize mechanism when type is "net".',
        required=False,
        display=False,
        type=click.BOOL,
    )
    authorize_password = models.Field(
        help_text='Password used by the authorize mechanism when type is '
        '"net".',
        password=True,
        required=False,
        display=False,
    )
    client = models.Field(
        help_text='Client Id or Application Id for the credential when type '
        'is "azure_rm".',
        required=False,
        display=False,
    )
    secret = models.Field(
        help_text='Secret Token for this credential when type is "azure_rm".',
        required=False,
        display=False)
    subscription = models.Field(
        help_text='Subscription identifier for this credential when type is '
        '"azure_rm".',
        required=False,
        display=False,
    )
    tenant = models.Field(
        help_text='Tenant identifier for this credential when type is '
        '"azure_rm"',
        required=False,
        display=False,
    )
    domain = models.Field(
        help_text='Domain name for this credential when type is "openstack".',
        required=False,
        display=False,
    )

    # Method with which to esclate
    become_method = models.Field(
        display=False,
        help_text='Privledge escalation method. ',
        type=types.MappedChoice([
            ('', 'None'),
            ('sudo', 'sudo'),
            ('su', 'su'),
            ('pbrun', 'pbrun'),
            ('pfexec', 'pfexec'),
        ]),
        required=False,
    )

    # SSH specific fields.
    become_username = models.Field(required=False, display=False)
    become_password = models.Field(password=True,
                                   required=False,
                                   help_text='%sThe become_password field' %
                                   PROMPT)
    vault_password = models.Field(password=True,
                                  required=False,
                                  help_text='%sThe vault_password field' %
                                  PROMPT)

    @resources.command
    def create(self, **kwargs):
        """Create a credential.
        """
        if (kwargs.get('user', False) or kwargs.get('team', False)
                or kwargs.get('organization', False)):
            debug.log('Checking Project API Details.', header='details')
            r = client.options('/credentials/')
            if 'organization' in r.json()['actions']['POST']:
                for i in range(len(self.fields)):
                    if self.fields[i].name in ('user', 'team'):
                        self.fields[i].no_lookup = True
        return super(Resource, self).create(**kwargs)