def validate(self, value): # check for valid hostname_template variables formatter = string.Formatter() template_vars = [x[1] for x in formatter.parse(value) if x[1]] invalid_vars = [] for var in template_vars: if var not in VALID_TEMPLATE_VARS: invalid_vars.append(var) errors = [] if invalid_vars: errors.append('Invalid variables: {0}'.format(', '.join(invalid_vars))) raw_str = '' for parse in formatter.parse(value): raw_str += parse[0] if parse[1] is not None: raw_str += 'placeholder' errors.extend(validate_hostname(raw_str)) if errors: raise ValidationError({ 'hostname_template': errors })
def validate(self, attrs): errors = {} # make sure the user has a public key or they won't be able to SSH # later request = self.context['request'] if 'create_users' in attrs: create_users = attrs['create_users'] else: create_users = self.instance.create_users if create_users and not request.user.settings.public_key: errors.setdefault('public_key', []).append( 'You have not added a public key to your user ' 'profile and will not be able to SSH in to any ' 'machines. Please update your user profile ' 'before continuing.' ) # Check to see if the launching user has permission to launch from the blueprint user = request.user blueprint = self.instance.blueprint if self.instance else attrs['blueprint'] if not user.has_perm('blueprints.view_blueprint', blueprint): err_msg = 'You do not have permission to launch a stack from this blueprint.' errors.setdefault('blueprint', []).append(err_msg) # Check to make sure we don't have security group creation turned off without default # security groups accounts = set() for host_definition in blueprint.host_definitions.all(): accounts.add(host_definition.cloud_image.account) for account in accounts: if ( not account.create_security_groups and account.security_groups.filter(is_default=True).count() < 1 ): errors.setdefault('security_groups', []).append( 'Account `{0}` has per-stack security groups disabled, but doesn\'t define any ' 'default security groups. You must define at least 1 default security group ' 'on this account before launching stacks.'.format(account.title) ) # check for hostname collisions if namespace is provided namespace = attrs.get('namespace') if namespace: # This all has to be here vs. in its own validator b/c it needs the blueprint hostname_errors = validate_hostname(namespace) if hostname_errors: errors.setdefault('namespace', []).extend(hostname_errors) # This is all only necessary if a namespace was provided # (It may not be provided on a PATCH request) host_definitions = blueprint.host_definitions.all() hostnames = models.get_hostnames_from_hostdefs( host_definitions, namespace=namespace ) # query for existing host names # Leave this in so that we catch errors faster if they are local, # Only hit up salt cloud if there are no duplicates locally hosts = models.Host.objects.filter(hostname__in=hostnames) if hosts.count() > 0: err_msg = 'Duplicate hostnames: {0}'.format(', '.join([h.hostname for h in hosts])) errors.setdefault('namespace', []).append(err_msg) if errors: # Go ahead and raise an error here so that we don't check the provider if # we don't need to raise serializers.ValidationError(errors) salt_cloud = salt.cloud.CloudClient(os.path.join( settings.STACKDIO_CONFIG.salt_config_root, 'cloud' )) query = salt_cloud.query() # Since a blueprint can have multiple accounts accounts = set() for bhd in host_definitions: accounts.add(bhd.cloud_image.account) # Check to find duplicates dups = [] for account in accounts: provider = account.provider.name for instance, details in query.get(account.slug, {}).get(provider, {}).items(): if instance in hostnames: if details['state'] not in ('shutting-down', 'terminated'): dups.append(instance) if dups: err_msg = 'Duplicate hostnames: {0}'.format(', '.join(dups)) errors.setdefault('namespace', []).append(err_msg) if errors: raise serializers.ValidationError(errors) return attrs
def validate(self, attrs): errors = {} # make sure the user has a public key or they won't be able to SSH # later request = self.context['request'] blueprint = self.instance.blueprint if self.instance else attrs[ 'blueprint'] if 'create_users' in attrs: create_users = attrs['create_users'] else: if self.instance: create_users = self.instance.create_users else: attrs['create_users'] = blueprint.create_users create_users = attrs['create_users'] if create_users and not request.user.settings.public_key: errors.setdefault('public_key', []).append( 'You have not added a public key to your user ' 'profile and will not be able to SSH in to any ' 'machines. Please update your user profile ' 'before continuing.') # Check to see if the launching user has permission to launch from the blueprint user = request.user if not user.has_perm('blueprints.view_blueprint', blueprint): err_msg = 'You do not have permission to launch a stack from this blueprint.' errors.setdefault('blueprint', []).append(err_msg) # Check to make sure we don't have security group creation turned off without default # security groups accounts = set() for host_definition in blueprint.host_definitions.all(): accounts.add(host_definition.cloud_image.account) for account in accounts: if (not account.create_security_groups and account.security_groups.filter( is_default=True).count() < 1): errors.setdefault('security_groups', []).append( 'Account `{0}` has per-stack security groups disabled, but doesn\'t define any ' 'default security groups. You must define at least 1 default security group ' 'on this account before launching stacks.'.format( account.title)) # check for hostname collisions if namespace is provided namespace = attrs.get('namespace') if namespace: # This all has to be here vs. in its own validator b/c it needs the blueprint hostname_errors = validate_hostname(namespace) if hostname_errors: errors.setdefault('namespace', []).extend(hostname_errors) # This is all only necessary if a namespace was provided # (It may not be provided on a PATCH request) host_definitions = blueprint.host_definitions.all() hostnames = models.get_hostnames_from_hostdefs(host_definitions, namespace=namespace) # query for existing host names # Leave this in so that we catch errors faster if they are local, # Only hit up salt cloud if there are no duplicates locally hosts = models.Host.objects.filter(hostname__in=hostnames) if hosts.count() > 0: err_msg = 'Duplicate hostnames: {0}'.format(', '.join( [h.hostname for h in hosts])) errors.setdefault('namespace', []).append(err_msg) if errors: # Go ahead and raise an error here so that we don't check the provider if # we don't need to raise serializers.ValidationError(errors) salt_cloud = salt.cloud.CloudClient( os.path.join(settings.STACKDIO_CONFIG.salt_config_root, 'cloud')) query = salt_cloud.query() # Since a blueprint can have multiple accounts accounts = set() for bhd in host_definitions: accounts.add(bhd.cloud_image.account) # Check to find duplicates dups = [] for account in accounts: provider = account.provider.name for instance, details in query.get(account.slug, {}).get(provider, {}).items(): if instance in hostnames: if details['state'] not in ('shutting-down', 'terminated'): dups.append(instance) if dups: err_msg = 'Duplicate hostnames: {0}'.format(', '.join(dups)) errors.setdefault('namespace', []).append(err_msg) if errors: raise serializers.ValidationError(errors) return attrs