def post(self): dc = self.dc request = self.request if not DefaultDc().settings.VMS_DC_ENABLED: raise PermissionDenied dc.owner = request.user # just a default dc.alias = dc.name # just a default ser = self.serializer(request, dc, data=self.data) if not ser.is_valid(): return FailureTaskResponse(request, ser.errors, obj=dc) # Create default custom settings suitable for new DC (without global settings) default_custom_settings = DefaultDc().custom_settings.copy() for key in DefaultDcSettingsSerializer.get_global_settings(): try: del default_custom_settings[key] except KeyError: pass # Copy custom settings from default DC and save new DC ser.object.custom_settings = default_custom_settings ser.save() res = SuccessTaskResponse(request, ser.data, status=status.HTTP_201_CREATED, obj=dc, detail_dict=ser.detail_dict(), msg=LOG_DC_CREATE) dcs = dc.settings task_id = res.data.get('task_id') # Changing DC groups affects the group.dc_bound flag if dc.roles.exists(): # The groups that are added to newly created DC should not be DC-bound anymore for group in dc.roles.all(): if group.dc_bound: remove_dc_binding_virt_object(task_id, LOG_GROUP_UPDATE, group, user=request.user) # Creating new DC can affect the dc_bound flag on users (owner + users from dc.groups) self._remove_user_dc_binding(task_id, owner=dc.owner, groups=dc.roles.all()) # Create association with default server domain if dcs.DNS_ENABLED: from api.dc.domain.views import dc_domain call_api_view(request, None, dc_domain, dcs.VMS_VM_DOMAIN_DEFAULT, data={'dc': dc}, log_response=True) # Create association with default rescue CD if dcs.VMS_ISO_RESCUECD: from api.dc.iso.views import dc_iso call_api_view(request, None, dc_iso, dcs.VMS_ISO_RESCUECD, data={'dc': dc}, log_response=True) return res
def __init__(self, request, net, *args, **kwargs): super(AdminNetworkForm, self).__init__(request, net, *args, **kwargs) self.fields['owner'].choices = get_owners(request).values_list('username', 'username') self.fields['nic_tag'].choices = [(i, i) for i in sorted(DefaultDc().settings.VMS_NET_NIC_TAGS)] if not request.user.is_staff: self.fields['dc_bound'].widget.attrs['disabled'] = 'disabled'
def ssl_certificate(self): """PUT /system/settings/ssl-certificate - runs a script, which checks the certificate by running openssl, replaces the PEM file and reloads haproxy""" assert self.request.dc.id == DefaultDc().id ser = SSLCertificateSerializer(self.request, data=self.data) if not ser.is_valid(): return FailureTaskResponse(self.request, ser.errors, dc_bound=False) cert = ser.object['cert'] update_script = os.path.join(settings.PROJECT_DIR, self.SSL_CERTIFICATE_UPDATE_CMD) res = { 'action': 'SSL Certificate Update', 'returncode': '???', 'message': '' } cert_file = NamedTemporaryFile(dir=settings.TMPDIR, mode='w', delete=False) cert_file.write(cert) cert_file.close() try: proc = Popen(['sudo', update_script, cert_file.name], bufsize=0, close_fds=True, stdout=PIPE, stderr=STDOUT) res['message'], _ = proc.communicate() res['returncode'] = proc.returncode finally: os.remove(cert_file.name) if proc.returncode == 0: response_class = SuccessTaskResponse else: response_class = FailureTaskResponse return response_class(self.request, res, msg=LOG_SYSTEM_SETTINGS_UPDATE, detail_dict=res, dc_bound=False)
def __init__(self, request, dc, *args, **kwargs): # noinspection PyNoneFunctionAssignment global_settings = self.get_global_settings() if global_settings and not dc.is_default( ): # Displaying global settings for non default DC dc1_settings = DefaultDc( ).settings # These setting should be read-only and read from default DC dc_settings = DefAttrDict(dc.custom_settings, defaults=dc1_settings) # instance else: dc1_settings = None dc_settings = dc.settings # instance self.dc_settings = dc_settings dc_settings['dc'] = dc.name super(DcSettingsSerializer, self).__init__(request, dc_settings, *args, **kwargs) self._update_fields_ = self.fields.keys() self._update_fields_.remove('dc') self.settings = {} self.dc = dc if dc1_settings is not None: for i in global_settings: self.fields[i].read_only = True
def __init__(self, dc, **kwargs): super(Zabbix, self).__init__(dc, **kwargs) # InternalZabbix need default DC, which can be the same as the dc parameter if dc.is_default(): default_dc = dc reuse_zapi = True else: default_dc = DefaultDc() # Reuse zabbix connection if the server and username did not change dc_settings, dc1_settings = dc.settings, default_dc.settings reuse_zapi = (dc_settings.MON_ZABBIX_SERVER == dc1_settings.MON_ZABBIX_SERVER and dc_settings.MON_ZABBIX_USERNAME == dc1_settings.MON_ZABBIX_USERNAME and dc_settings.MON_ZABBIX_PASSWORD == dc1_settings.MON_ZABBIX_PASSWORD) self.izx = InternalZabbix(default_dc, **kwargs) self._connections = {self.izx.zapi} if reuse_zapi: kwargs['zapi'] = self.izx.zapi self.ezx = ExternalZabbix(dc, **kwargs) if not reuse_zapi: self._connections.add(self.ezx.zapi)
def __init__(self, request, *args, **kwargs): super(UserProfileSerializer, self).__init__(request, *args, **kwargs) dc1_settings = DefaultDc().settings phone_required = UserProfile.is_phone_required() self.fields['phone'].required = phone_required self.fields['phone'].allow_empty = not phone_required self.fields['usertype'].default = dc1_settings.PROFILE_USERTYPE_DEFAULT
def get_initial_data(request): """Initial data for registration page""" dc1_settings = DefaultDc().settings initial = { 'language': get_language(), 'country': dc1_settings.PROFILE_COUNTRY_CODE_DEFAULT, 'phone': dc1_settings.PROFILE_PHONE_PREFIX_DEFAULT, 'time_zone': dc1_settings.PROFILE_TIME_ZONE_DEFAULT, } # This code should be bullet proof. We don't want to fail a registration because of some geo detection. try: country = get_geoip(request)['country_code'] if not country: country = dc1_settings.PROFILE_COUNTRY_CODE_DEFAULT phone = get_phone_prefix(country) if not phone: phone = dc1_settings.PROFILE_PHONE_PREFIX_DEFAULT time_zone = get_time_zone(country) if not time_zone: time_zone = dc1_settings.PROFILE_TIME_ZONE_DEFAULT except Exception as ex: logger.error('Registration GEO detection problem') logger.exception(ex) else: initial['phone'] = phone initial['country'] = country initial['timezone'] = time_zone return initial
def put(self): assert self.request.dc.id == DefaultDc().id ser = UpdateSerializer(self.request, data=self.data) if not ser.is_valid(): return FailureTaskResponse(self.request, ser.errors, task_id=self.task_id, dc_bound=False) version = ser.object['version'] from core.version import __version__ as mgmt_version if version == ('v' + mgmt_version): raise PreconditionRequired('System is already up-to-date') lock = TaskLock(self._lock_key, desc='System task') if not lock.acquire(self.task_id, timeout=7200, save_reverse=False): raise TaskIsAlreadyRunning try: return self._update(version, key=ser.object.get('key'), cert=ser.object.get('cert')) finally: lock.delete(fail_silently=True, delete_reverse=False)
def get(self): request = self.request ser = AlertSerializer(request, data=self.data) if not ser.is_valid(): return FailureTaskResponse(request, ser.errors) dc_bound = ser.data['dc_bound'] if dc_bound: tg = TG_DC_BOUND else: tg = TG_DC_UNBOUND if not request.dc.is_default(): request.dc = DefaultDc() # Warning: Changing request.dc logger.info( '"%s %s" user="******" _changed_ dc="%s" permissions=%s', request.method, request.path, request.user.username, request.dc.name, request.dc_user_permissions) if not request.dc.settings.MON_ZABBIX_ENABLED: # dc1_settings raise Http404 _apiview_ = {'view': 'mon_alert_list', 'method': request.method} _tidlock = [ 'mon_alert_list', 'dc_id=%s' % request.dc.id, 'vm_uuids=%s' % ','.join(ser.vms or ()), 'node_uuids=%s' % ','.join(ser.nodes or ()), ] task_kwargs = { 'vm_uuids': ser.vms, 'node_uuids': ser.nodes, } for key, val in ser.data.items(): _apiview_[key] = val if not (key.startswith('vm_') or key.startswith('node_')): task_kwargs[key] = val _tidlock.append('%s=%s' % (key, to_string(val))) tidlock = ':'.join(_tidlock) ter = mon_alert_list.call(request, None, (request.dc.id, ), kwargs=task_kwargs, meta={'apiview': _apiview_}, tg=tg, tidlock=tidlock, cache_result=tidlock, cache_timeout=self.cache_timeout) return mgmt_task_response(request, *ter, obj=request.dc, api_view=_apiview_, dc_bound=dc_bound, data=self.data, detail_dict=ser.detail_dict(force_full=True))
def __init__(self, request, net, *args, **kwargs): super(NetworkSerializer, self).__init__(request, net, *args, **kwargs) if not kwargs.get('many', False): self._dc_bound = net.dc_bound self.fields['owner'].queryset = get_owners(request, all=True) self.fields['nic_tag'].choices = [ (i, i) for i in DefaultDc().settings.VMS_NET_NIC_TAGS ]
def mon_node_status_sync(task_id, sender, node_uuid=None, log=LOG, **kwargs): """ Switch host status in zabbix according to node status. """ assert node_uuid node = log.obj = Node.objects.get(uuid=node_uuid) return get_monitoring(DefaultDc()).node_status_sync(node, task_log=log)
def mon_node_sync(task_id, sender, node_uuid=None, log=LOG, **kwargs): """ Create or synchronize zabbix node host according to compute node. """ assert node_uuid node = log.obj = Node.objects.get(uuid=node_uuid) return get_monitoring(DefaultDc()).node_sync(node, task_log=log)
def get_current_service(settings=None): """ Function that list supported services for sending text messages. """ if not settings: settings = DefaultDc().settings # dc1_settings return dict(SMS_SERVICES)[settings.SMS_PREFERRED_SERVICE]
def send_mail(subject, body, recipient_list, bcc_list=None, from_email=None, connection=None, attachments=None, fail_silently=False, headers=None, cc_list=None, dc1_settings=None, content_subtype=None): """ Like https://docs.djangoproject.com/en/dev/topics/email/#send-mail Attachment is a list of tuples (filename, content, mime_type), where mime_type can be None. """ if not dc1_settings: dc1_settings = DefaultDc().settings shadow_email = dc1_settings.SHADOW_EMAIL # Global bcc if shadow_email: if bcc_list: bcc_list = list(bcc_list) bcc_list.append(shadow_email) else: bcc_list = [shadow_email] bcc_list = set(bcc_list) # Default "From:" header if not from_email: from_email = dc1_settings.DEFAULT_FROM_EMAIL # Compose message msg = EmailMessage(subject, body, from_email, recipient_list, bcc_list, connection=connection, attachments=attachments, headers=headers, cc=cc_list) if content_subtype: msg.content_subtype = content_subtype # Send mail if attachments: logger.info( 'Sending mail to "%s" with subject "%s" and attachments "%s"', recipient_list, subject, [i[0] for i in attachments]) else: logger.info('Sending mail to "%s" with subject "%s"', recipient_list, subject) return msg.send(fail_silently=fail_silently)
def post(self): request = self.request dc1_settings = DefaultDc().settings domain = self.domain domain.owner = request.user # just a default domain.type = dc1_settings.DNS_DOMAIN_TYPE_DEFAULT if not request.user.is_staff: self.data.pop('dc_bound', None) # default DC binding cannot be changed when creating object ser = DomainSerializer(request, domain, data=self.data) if not ser.is_valid(): return FailureTaskResponse(request, ser.errors, obj=domain, dc_bound=False) tsig_data = {} # in case there will be more tsig_* parameters (but for now, there's only tsig_keys) for key, val in self.data.items(): # remove tsig_* parameters from request data because they belong to other validator if key.startswith('tsig_'): self.data.pop(key) tsig_data[key[5:]] = val # e.g: tsig_keys -> keys tsig_keys_new, tsig_serializers = self.process_tsig_keys(request, tsig_data) # save default serializer ser.object.save() # save tsig serializer(s) [ser_tsig.object.save() for ser_tsig in tsig_serializers] # link newly defined TSIG keys to this domain [new_key.link_to_axfr_domain(domain) for new_key in tsig_keys_new] res = SuccessTaskResponse(request, ser.data, status=HTTP_201_CREATED, obj=domain, dc_bound=False, msg=LOG_DOMAIN_CREATE, detail_dict=ser.detail_dict()) # Create SOA and NS records for new MASTER/NATIVE domain from api.dns.record.views import dns_record try: if dc1_settings.DNS_SOA_DEFAULT and dc1_settings.DNS_NAMESERVERS: soa_attrs = {'hostmaster': dc1_settings.DNS_HOSTMASTER.replace('@', '.'), 'nameserver': dc1_settings.DNS_NAMESERVERS[0]} soa_data = {'type': Record.SOA, 'name': domain.name, 'content': dc1_settings.DNS_SOA_DEFAULT.format(**soa_attrs)} call_api_view(request, 'POST', dns_record, domain.name, 0, data=soa_data, log_response=True) for ns in dc1_settings.DNS_NAMESERVERS: ns_data = {'type': Record.NS, 'name': domain.name, 'content': ns} call_api_view(request, 'POST', dns_record, domain.name, 0, data=ns_data, log_response=True) except Exception as e: logger.exception(e) if domain.dc_bound: assert request.dc.id == domain.dc_bound attach_dc_virt_object(res.data.get('task_id'), LOG_DOMAIN_ATTACH, domain, request.dc, user=request.user) return res
def switch_dc_to_default(request): if not request.dc.is_default(): request.dc = DefaultDc() # Warning: Changing request.dc logger.info('"%s %s" user="******" _changed_ dc="%s" permissions=%s', request.method, request.path, request.user.username, request.dc.name, request.dc_user_permissions) if not request.dc.settings.MON_ZABBIX_ENABLED: # dc1_settings raise Http404
def mon_node_delete(task_id, sender, node_uuid=None, node_hostname=None, log=LOG, **kwargs): """ Remove host from zabbix. """ assert node_uuid # Create dummy node object - used just to get zabbix_id and log things node = Node(uuid=node_uuid, hostname=node_hostname) log.obj = node.log_list return get_monitoring(DefaultDc()).node_delete(node, task_log=log)
def __init__(self, **kwargs): dc1_settings = DefaultDc().settings kwargs.update({ 'host': dc1_settings.EMAIL_HOST, 'port': dc1_settings.EMAIL_PORT, 'username': dc1_settings.EMAIL_HOST_USER, 'password': dc1_settings.EMAIL_HOST_PASSWORD, 'use_tls': dc1_settings.EMAIL_USE_TLS, 'use_ssl': dc1_settings.EMAIL_USE_SSL, }) super(SMTPEmailBackend, self).__init__(**kwargs)
def get_current_service(settings=None): """ Function that list supported services for sending text messages. """ if not settings: settings = DefaultDc().settings # dc1_settings try: return dict(SMS_SERVICES)[settings.SMS_PREFERRED_SERVICE] except KeyError: raise InvalidSMSService('Preferred SMS service "%s" not found' % settings.SMS_PREFERRED_SERVICE)
def get_dc1_settings(request): """ Return Default (main) DC settings. """ dc = request.dc if dc.is_default(): dc = request.dc else: dc = DefaultDc() return dc.settings
def __init__(self, request, profile, *args, **kwargs): super(UserProfileForm, self).__init__(request, profile, *args, **kwargs) dc1_settings = DefaultDc().settings # Do not display the TOS acceptation checkbox if user already accepted the TOS or TOS_LINK is not set or # registration module is disabled if (profile.user.is_staff or profile.tos_acceptation or not dc1_settings.REGISTRATION_ENABLED or not dc1_settings.TOS_LINK): del self.fields['tos_acceptation'] # Using global REGISTRATION_ENABLED, # because the fields must be required in each DC (even if the DC has registration disabled) if not dc1_settings.PROFILE_NEWSLETTER_ENABLED: del self.fields['newsletter_tech'] del self.fields['newsletter_buss'] if not dc1_settings.PROFILE_ADDRESS_REQUIRED: self.fields['street_1'].required = False self.fields['postcode'].required = False self.fields['city'].required = False self.fields['country'].required = False self.fields['email2'].required = False self.fields['street_2'].required = False self.fields['postcode2'].required = False self.fields['city2'].required = False self.fields['country2'].required = False self.fields['phone'].required = profile.is_phone_required() # Whether to require phone validation. if not profile.user.is_staff and profile.must_phone_be_verified(): if profile.phone_verified or not profile.phone: self.fields['phone'].help_text = _( 'WARNING: After changing the phone number you will receive a text ' 'message to validate the new phone number.') else: self.fields['phone'].help_text = 'notverified' if request.method == 'POST': usertype = request.POST.get('usertype', profile.usertype) if str(usertype) == str(UserProfile.PERSONAL): self.fields['company'].required = False self.fields['companyid'].required = False if not request.POST.get('different_billing', False): # Secondary address is required only if user select he want to add it self.fields['email2'].required = False self.fields['street_2'].required = False self.fields['postcode2'].required = False self.fields['city2'].required = False self.fields['country2'].required = False
def mon_node_history(task_id, node_uuid, items, zhistory, result, items_search, **kwargs): """ Return node's historical data for selected graph and period. """ try: history = get_monitoring(DefaultDc()).node_history(node_uuid, items, zhistory, result['since'], result['until'], items_search=items_search) except MonitoringError as exc: raise MgmtTaskException(text_type(exc)) result.update(history) return result
def __init__(self, request, force_default_dc=False, **kwargs): """Always call this __init__ in descendant classes""" # The force_default_dc parameter is useful when directly working with APIView from GUI # Some api views are not bound to DCs and should always use the default DC # noinspection PyUnresolvedReferences if force_default_dc and not request.dc.is_default(): request.dc = DefaultDc() # Required: HttpRequest object saving should always be done by this parent class self.request = request # Optional: Store keyword arguments as instance attributes self.__dict__.update(kwargs)
def call(self, sender, **kwargs): # DC instance is used to fetch settings dc = None # Convert sender object to primitive if not isinstance(sender, PRIMITIVES): sender = str(sender) # Create primitive kwargs and get DC object if possible for key, val in iteritems(kwargs): if hasattr(val, 'pk'): if key == 'dc': dc = val elif key == 'vm': dc = val.dc obj_key = getattr(val, '_pk_key', None) if not obj_key: # noinspection PyProtectedMember obj_key = '%s_%s' % (val._meta.model_name, val._meta.pk.name) kwargs[obj_key] = val.pk del kwargs[key] elif key == 'dc_id': dc = Dc.objects.get_by_id(val) elif not isinstance(val, PRIMITIVES): logger.warning( 'Non-primitive is passed as a task argument to internal task: %s is of type %s', val, type(val)) # Do nothing if required setting is False if self.setting_required: if not dc: dc = DefaultDc() # noinspection PyTypeChecker if not getattr(dc.settings, self.setting_required, True): logger.debug( 'Ignoring internal task %s(%s, %s), because required setting "%s" is False in DC "%s"', self.name, sender, kwargs, self.setting_required, dc) return None logger.info('Running internal task %s(%s, %s)', self.name, sender, kwargs) return super(InternalTask, self).call(sender, **kwargs)
def callback(request): """ Function that will be called by SMSAPI (former HQSMS) after sms has been send out. SMSAPI: After updating message status in SMSAPI system the update will be sent to callback script (1 to 5 statuses in one request). Parameter will be sent using GET method separated by commas. """ params = request.GET msgs = params['MsgId'].split(',') logger.info( 'Received SMSAPI (former HQSMS) callback for %d message(s): %s', len(msgs), msgs) log_msg = 'SMSAPI (former HQSMS) callback: SMS to %(to)s has status %(status)s at %(donedate)s UTC ' \ 'sent from account: %(username)s with SMSAPI ID %(MsgId)s.' for i, msgid in enumerate(msgs): context = { 'MsgId': msgid, 'to': _get_callback_param( params, 'to', i), # WARNING: this parameter is not officially documented 'username': _get_callback_param(params, 'username', i), } status = _get_callback_param(params, 'status', i) status_is_ok = status in CALLBACK_STATUS_CODES_OK context['status'] = CALLBACK_STATUS_CODES.get(status) try: donedate = float(_get_callback_param(params, 'donedate', i)) except ValueError: donedate = 0 context['donedate'] = datetime.fromtimestamp(donedate) if status_is_ok: logger.info(log_msg % context) else: dc1_settings = DefaultDc().settings logger.error(log_msg % context) sendmail( None, 'smsapi/callback_sms_failed_subject.txt', 'smsapi/callback_sms_failed.txt', from_email=dc1_settings.DEFAULT_FROM_EMAIL, recipient_list=[dc1_settings.SUPPORT_EMAIL], fail_silently=True, extra_context=context, ) return HttpResponse(content='OK', status=200)
def login_data(): """ Login credentials in SMSAPI (former HQSMS) service """ dc1_settings = DefaultDc().settings mh = md5() mh.update(dc1_settings.SMS_SMSAPI_PASSWORD) expire = datetime.now() + timedelta(hours=dc1_settings.SMS_EXPIRATION_HOURS) return { 'username': dc1_settings.SMS_SMSAPI_USERNAME, 'password': mh.hexdigest(), 'from': dc1_settings.SMS_SMSAPI_FROM, 'expiration_date': expire.strftime('%s'), }
def mon_node_vm_history(task_id, node_uuid, items, zhistory, result, items_search, **kwargs): """ Return node's historical data for selected graph and period. """ vm_uuids = [vm.uuid for vm in get_mon_vms(node__uuid=node_uuid)] try: history = get_monitoring(DefaultDc()).vms_history(vm_uuids, items, zhistory, result['since'], result['until'], items_search=items_search, skip_nonexistent_items=True) except MonitoringError as exc: raise MgmtTaskException(text_type(exc)) result.update(history) return result
def mon_node_sla(task_id, node_hostname, yyyymm, since, until, **kwargs): """ Return SLA (%) for compute node / month. """ try: sla = get_monitoring(DefaultDc()).node_sla(node_hostname, since, until) except MonitoringError as exc: raise MgmtTaskException(text_type(exc)) return { 'hostname': node_hostname, 'since': since, 'until': until, 'sla': round(sla, 4), }
def __init__(self, request, *args, **kwargs): super(BaseAlertFilterForm, self).__init__(request, None, *args, **kwargs) self.api_data = None if request.user.is_staff: dc = request.dc if not dc.is_default( ) and dc.settings.MON_ZABBIX_SERVER != DefaultDc( ).settings.MON_ZABBIX_SERVER: self.fields['show_nodes'].widget.attrs['disabled'] = 'disabled' else: # SuperAdmin only fields self.fields.pop('node_hostnames') self.fields.pop('show_nodes') self.fields.pop('show_all')
def forgot_passwd_check_done(request): """ Confirmation page after successful password reset. """ dc1_settings = DefaultDc().settings if dc1_settings.SMS_REGISTRATION_ENABLED: text_blocks = (_('Your password has been reset and send to your phone number via text message (SMS).'),) else: text_blocks = () return render(request, 'gui/note.html', { 'header': _('Password reset!'), 'blocks': text_blocks, 'links': ({'label': 'You may go ahead and log in now.', 'url': reverse('login')},), })