def authLogLogin(request, authenticator, userName, logStr=''): ''' Logs authentication ''' if logStr == '': logStr = 'Logged in' authLogger.info('|'.join([ authenticator.name, userName, request.ip, request.os['OS'], logStr, request.META.get('HTTP_USER_AGENT', 'Undefined') ])) level = (logStr == 'Logged in') and log.INFO or log.ERROR log.doLog( authenticator, level, 'user {0} has {1} from {2} where os is {3}'.format( userName, logStr, request.ip, request.os['OS']), log.WEB) try: user = authenticator.users.get(name=userName) log.doLog( user, level, '{0} from {1} where os is {3}'.format(logStr, request.ip, request.os['OS']), log.WEB) except Exception: pass
def cancel(self, publication: ServicePoolPublication): # pylint: disable=no-self-use """ Invoked to cancel a publication. Double invokation (i.e. invokation over a "cancelling" item) will lead to a "forced" cancellation (unclean) :param servicePoolPub: Service pool publication (db object for a publication) """ publication = ServicePoolPublication.objects.get( pk=publication.id) # Reloads publication from db if publication.state not in State.PUBLISH_STATES: if publication.state == State.CANCELING: # Double cancel logger.info('Double cancel invoked for a publication') log.doLog( publication.deployed_service, log.WARN, 'Forced cancel on publication, you must check uncleaned resources manually', log.ADMIN) publication.setState(State.CANCELED) publication.save() return publication raise PublishException(_('Can\'t cancel non running publication')) if publication.state == State.LAUNCHING: publication.state = State.CANCELED publication.deployed_service.storeValue('toBeReplacedIn', None) publication.save() return publication try: pubInstance = publication.getInstance() state = pubInstance.cancel() publication.setState(State.CANCELING) PublicationFinishChecker.checkAndUpdateState( publication, pubInstance, state) return publication except Exception as e: raise PublishException(str(e))
def deleteItem(self, parent: MetaPool, item: str): member = parent.members.get(uuid=processUuid(self._args[0])) logStr = "Removed meta pool member {} by {}".format(member.pool.name, self._user.pretty_name) member.delete() log.doLog(parent, log.INFO, logStr, log.ADMIN)
def run(self): since_state: datetime = getSqlDatetime() - timedelta( seconds=MAX_STUCK_TIME) # Filter for locating machine stuck on removing, cancelling, etc.. # Locate service pools with pending assigned service in use servicePoolswithStucks = ServicePool.objects.annotate(stuckCount=Count( 'userServices', filter=Q(userServices__state_date__lt=since_state) & (Q(userServices__state=State.PREPARING, userServices__properties__name='destroy_after') | ~Q(userServices__state__in=State.INFO_STATES + State.VALID_STATES)))).filter( service__provider__maintenance_mode=False, state=State.ACTIVE).exclude(stuckCount=0) # Info states are removed on UserServiceCleaner and VALID_STATES are ok, or if "hanged", checked on "HangedCleaner" def stuckUserServices( servicePool: ServicePool) -> typing.Iterable[UserService]: q = servicePool.userServices.filter(state_date__lt=since_state) yield from q.exclude(state__in=State.INFO_STATES + State.VALID_STATES) yield from q.filter(state=State.PREPARING, properties__name='destroy_after') for servicePool in servicePoolswithStucks: # logger.debug('Searching for stuck states for %s', servicePool.name) for stuck in stuckUserServices(servicePool): logger.debug('Found stuck user service %s', stuck) log.doLog( servicePool, log.ERROR, 'User service {} has been hard removed because it\'s stuck' .format(stuck.name)) # stuck.setState(State.ERROR) stuck.delete()
def saveItem(self, parent: 'ServicePool', item: typing.Optional[str]) -> None: # If already exists uuid = processUuid(item) if item is not None else None calendar = Calendar.objects.get(uuid=processUuid(self._params['calendarId'])) action = self._params['action'].upper() if action not in CALENDAR_ACTION_DICT: raise self.invalidRequestException() eventsOffset = int(self._params['eventsOffset']) atStart = self._params['atStart'] not in ('false', False, '0', 0) params = json.dumps(self._params['params']) # logger.debug('Got parameters: {} {} {} {} ----> {}'.format(calendar, action, eventsOffset, atStart, params)) logStr = "Added scheduled action \"{},{},{},{},{}\" by {}".format( calendar.name, action, eventsOffset, atStart and 'Start' or 'End', params, self._user.pretty_name ) if uuid is not None: calAction = CalendarAction.objects.get(uuid=uuid) calAction.calendar = calendar calAction.service_pool = parent calAction.action = action calAction.at_start = atStart calAction.events_offset = eventsOffset calAction.params = params calAction.save() else: CalendarAction.objects.create(calendar=calendar, service_pool=parent, action=action, at_start=atStart, events_offset=eventsOffset, params=params) log.doLog(parent, log.INFO, logStr, log.ADMIN)
def saveItem(self, parent, item): # If already exists uuid = processUuid(item) if item is not None else None try: calendar = Calendar.objects.get(uuid=processUuid(self._params['calendarId'])) access = self._params['access'].upper() if access not in ('ALLOW', 'DENY'): raise Exception() except Exception: self.invalidRequestException(_('Invalid parameters on request')) priority = int(self._params['priority']) if uuid is not None: calAccess = parent.calendarAccess.get(uuid=uuid) calAccess.calendar = calendar calAccess.service_pool = parent calAccess.access = access calAccess.priority = priority calAccess.save() else: parent.calendarAccess.create(calendar=calendar, access=access, priority=priority) log.doLog(parent, log.INFO, "Added access calendar {}/{} by {}".format(calendar.name, access, self._user.pretty_name), log.ADMIN) return self.success()
def checkAndUpdateState(userService, userServiceInstance, state): """ Checks the value returned from invocation to publish or checkPublishingState, updating the servicePoolPub database object Return True if it has to continue checking, False if finished """ try: # Fills up basic data userService.unique_id = userServiceInstance.getUniqueId() # Updates uniqueId userService.friendly_name = userServiceInstance.getName() # And name, both methods can modify serviceInstance, so we save it later userService.save(update_fields=['unique_id', 'friendly_name']) updater = { State.PREPARING: UpdateFromPreparing, State.REMOVING: UpdateFromRemoving, State.CANCELING: UpdateFromCanceling }.get(userService.state, UpdateFromOther) logger.debug('Updating from {} with updater {} and state {}'.format(State.toString(userService.state), updater, state)) updater(userService, userServiceInstance).run(state) except Exception as e: logger.exception('Checking service state') log.doLog(userService, log.ERROR, 'Exception: {0}'.format(e), log.INTERNAL) userService.setState(State.ERROR) userService.save(update_fields=['data'])
def cancel(self, servicePoolPub): # pylint: disable=no-self-use ''' Invoked to cancel a publication. Double invokation (i.e. invokation over a "cancelling" item) will lead to a "forced" cancellation (unclean) :param servicePoolPub: Service pool publication (db object for a publication) ''' servicePoolPub = DeployedServicePublication.objects.get(pk=servicePoolPub.id) if servicePoolPub.state not in State.PUBLISH_STATES: if servicePoolPub.state == State.CANCELING: # Double cancel logger.info('Double cancel invoked for a publication') log.doLog(servicePoolPub.deployed_service, log.WARN, 'Forced cancel on publication, you must check uncleaned resources manually', log.ADMIN) servicePoolPub.setState(State.CANCELED) servicePoolPub.save() return else: raise PublishException(_('Can\'t cancel non running publication')) if servicePoolPub.state == State.LAUNCHING: servicePoolPub.state = State.CANCELED servicePoolPub.save() return servicePoolPub try: pubInstance = servicePoolPub.getInstance() state = pubInstance.cancel() servicePoolPub.setState(State.CANCELING) PublicationFinishChecker.checkAndUpdateState(servicePoolPub, pubInstance, state) return servicePoolPub except Exception as e: raise PublishException(str(e))
def run(self): logger.debug('Checking user service finished {0}'.format(self._svrId)) uService = None try: uService = UserService.objects.get(pk=self._svrId) if uService.state != self._state: logger.debug('Task overrided by another task (state of item changed)') # This item is no longer valid, returning will not check it again (no checkLater called) return ci = uService.getInstance() logger.debug("uService instance class: {0}".format(ci.__class__)) state = ci.checkState() UserServiceOpChecker.checkAndUpdateState(uService, ci, state) except UserService.DoesNotExist as e: logger.error('User service not found (erased from database?) {0} : {1}'.format(e.__class__, e)) except Exception as e: # Exception caught, mark service as errored logger.exception("Error {0}, {1} :".format(e.__class__, e)) if uService is not None: log.doLog(uService, log.ERROR, 'Exception: {0}'.format(e), log.INTERNAL) try: uService.setState(State.ERROR) uService.save(update_fields=['data', 'state', 'state_date']) except Exception: logger.error('Can\'t update state of uService object')
def release(self, service): ''' service is a db user service object ''' super(WinDomainOsManager, self).release(service) if not '.' in self._domain: logger.info('Releasing from a not FQDN domain is not supported') return try: l = self.__connectLdap() except dns.resolver.NXDOMAIN: # No domain found, log it and pass logger.warn('Could not find _ldap._tcp.' + self._domain) log.doLog(service, log.WARN, "Could not remove machine from domain (_ldap._tcp.{0} not found)".format(self._domain), log.OSMANAGER) return except ldap.LDAPError: logger.exception('Ldap Exception caught') log.doLog(service, log.WARN, "Could not remove machine from domain (invalid credentials for {0})".format(self._account), log.OSMANAGER) return except Exception: logger.exception('Exception caught') return try: res = self.__getMachine(l, service.friendly_name) if res is None: raise Exception('Machine {} not found on AD (permissions?)'.format(service.friendly_name)) l.delete_s(res) # Remove by DN, SYNC except IndexError: logger.error('Error deleting {} from BASE {}'.format(service.friendly_name, self._ou)) except Exception: logger.exception('Deleting from AD: ')
def authLogLogin(request: HttpRequest, authenticator: Authenticator, userName: str, logStr: str = '') -> None: """ Logs authentication """ if logStr == '': logStr = 'Logged in' authLogger.info('|'.join([ authenticator.name, userName, request.ip, request.os['OS'], logStr, request.META.get('HTTP_USER_AGENT', 'Undefined') ])) level = log.INFO if logStr == 'Logged in' else log.ERROR log.doLog( authenticator, level, 'user {} has {} from {} where os is {}'.format(userName, logStr, request.ip, request.os['OS']), log.WEB) try: user = authenticator.users.get(name=userName) log.doLog( user, level, '{} from {} where OS is {}'.format(logStr, request.ip, request.os['OS']), log.WEB) except Exception: pass
def readyReceived(self, userService, data): # No group to add if self._group == '': return if not '.' in self._domain: logger.info('Adding to a group for a non FQDN domain is not supported') return try: l = self.__connectLdap() except dns.resolver.NXDOMAIN: # No domain found, log it and pass logger.warn('Could not find _ldap._tcp.' + self._domain) log.doLog(service, log.WARN, "Could not remove machine from domain (_ldap._tcp.{0} not found)".format(self._domain), log.OSMANAGER) except ldap.LDAPError: logger.exception('Ldap Exception caught') log.doLog(service, log.WARN, "Could not remove machine from domain (invalid credentials for {0})".format(self._account), log.OSMANAGER) try: machine = self.__getMachine(l, userService.friendly_name) group = self.__getGroup(l) l.modify_s(group, ((ldap.MOD_ADD, 'member', machine),)) except ldap.ALREADY_EXISTS: # Already added this machine to this group, pass pass except Exception: logger.error('Got exception trying to add machine to group')
def run(self): since_state = getSqlDatetime() - timedelta( seconds=GlobalConfig.MAX_INITIALIZING_TIME.getInt()) # Filter for locating machine not ready flt = Q(state_date__lt=since_state, state=State.PREPARING) | Q( state_date__lt=since_state, state=State.USABLE, os_state=State.PREPARING) | Q(state_date__lt=since_state, state=State.REMOVING) for ds in DeployedService.objects.exclude( osmanager=None, state__in=State.VALID_STATES, service__provider__maintenance_mode=True): logger.debug('Searching for hanged services for {0}'.format(ds)) for us in ds.userServices.filter(flt): logger.debug('Found hanged service {0}'.format(us)) log.doLog(us, log.ERROR, 'User Service seems to be hanged. Removing it.', log.INTERNAL) log.doLog( ds, log.ERROR, 'Removing user service {0} because it seems to be hanged'. format(us.friendly_name)) if us.state in (State.REMOVING, ): us.setState(State.ERROR) else: us.removeOrCancel()
def checkAndUpdateState(userService, userServiceInstance, state): ''' Checks the value returned from invocation to publish or checkPublishingState, updating the servicePoolPub database object Return True if it has to continue checking, False if finished ''' try: # Fills up basic data userService.unique_id = userServiceInstance.getUniqueId( ) # Updates uniqueId userService.friendly_name = userServiceInstance.getName( ) # And name, both methods can modify serviceInstance, so we save it later updater = { State.PREPARING: UpdateFromPreparing, State.REMOVING: UpdateFromRemoving, State.CANCELING: UpdateFromCanceling }.get(userService.state, UpdateFromOther) logger.debug( 'Updating from {} with updater {} and state {}'.format( State.toString(userService.state), updater, state)) updater(userService, userServiceInstance).run(state) except Exception as e: logger.exception('Checking service state') log.doLog(userService, log.ERROR, 'Exception: {0}'.format(e), log.INTERNAL) userService.setState(State.ERROR) userService.save()
def action(self) -> typing.MutableMapping[str, typing.Any]: logger.debug('Args: %s, Params: %s', self._args, self._params) userService = self.getUserService() log.doLog(userService, int(self._params['level']), self._params['message'], log.ACTOR) return ActorV3Action.actorResult('ok')
def readyReceived(self, userService, data): # No group to add if self._group == '': return if not '.' in self._domain: logger.info( 'Adding to a group for a non FQDN domain is not supported') return try: l = self.__connectLdap() except dns.resolver.NXDOMAIN: # No domain found, log it and pass logger.warn('Could not find _ldap._tcp.' + self._domain) log.doLog( service, log.WARN, "Could not remove machine from domain (_ldap._tcp.{0} not found)" .format(self._domain), log.OSMANAGER) except ldap.LDAPError: logger.exception('Ldap Exception caught') log.doLog( service, log.WARN, "Could not remove machine from domain (invalid credentials for {0})" .format(self._account), log.OSMANAGER) try: machine = self.__getMachine(l, userService.friendly_name) group = self.__getGroup(l) l.modify_s(group, ((ldap.MOD_ADD, 'member', machine), )) except ldap.ALREADY_EXISTS: # Already added this machine to this group, pass pass except Exception: logger.error('Got exception trying to add machine to group')
def authLogLogout(request): log.doLog( request.user.manager, log.INFO, 'user {0} has logged out from {1}'.format(request.user.name, request.ip), log.WEB) log.doLog(request.user, log.INFO, 'has logged out from {0}'.format(request.ip), log.WEB)
def release(self, service): ''' service is a db user service object ''' super(WinDomainOsManager, self).release(service) if not '.' in self._domain: logger.info('Releasing from a not FQDN domain is not supported') return try: l = self.__connectLdap() except dns.resolver.NXDOMAIN: # No domain found, log it and pass logger.warn('Could not find _ldap._tcp.' + self._domain) log.doLog(service, log.WARN, "Could not remove machine from domain (_ldap._tcp.{0} not found)".format(self._domain), log.OSMANAGER) except ldap.LDAPError: logger.exception('Ldap Exception caught') log.doLog(service, log.WARN, "Could not remove machine from domain (invalid credentials for {0})".format(self._account), log.OSMANAGER) try: res = self.__getMachine(l, service.friendly_name) if res is None: raise Exception('Machine {} not found on AD (permissions?)'.format(service.friendly_name)) l.delete_s(res) # Remove by DN, SYNC except IndexError: logger.error('Error deleting {} from BASE {}'.format(service.friendly_name, ou)) except Exception: logger.exception('Deleting from AD: ')
def growL1Cache(self, sp, cacheL1, cacheL2, assigned): ''' This method tries to enlarge L1 cache. If for some reason the number of deployed services (Counting all, ACTIVE and PREPARING, assigned, L1 and L2) is over max allowed service deployments, this method will not grow the L1 cache ''' logger.debug("Growing L1 cache creating a new service for {0}".format(sp)) # First, we try to assign from L2 cache if cacheL2 > 0: valid = None with transaction.atomic(): for n in sp.cachedUserServices().select_for_update().filter(UserServiceManager.getCacheStateFilter(services.UserDeployment.L2_CACHE)).order_by('creation_date'): if n.needsOsManager(): if State.isUsable(n.state) is False or State.isUsable(n.os_state): valid = n break else: valid = n break if valid is not None: valid.moveToLevel(services.UserDeployment.L1_CACHE) return try: UserServiceManager.manager().createCacheFor(sp.activePublication(), services.UserDeployment.L1_CACHE) except MaxServicesReachedException as e: log.doLog(sp, log.ERROR, 'Max number of services reached for this service', log.INTERNAL) logger.error(str(e)) except: logger.exception('Exception')
def checkAndUpdateState(userService, userServiceInstance, state): """ Checks the value returned from invocation to publish or checkPublishingState, updating the servicePoolPub database object Return True if it has to continue checking, False if finished """ try: if State.isFinished(state): checkLater = False userServiceInstance.finish() userService.updateData(userServiceInstance) userService.setState(State.USABLE) # Wi will only migrate fully functional services elif State.isErrored(state): checkLater = False userService.updateData(userServiceInstance) userService.setState(State.ERROR) else: checkLater = True # The task is running userService.updateData(userServiceInstance) userService.save() if checkLater: ClusterMigrationTask.checkLater(userService, userServiceInstance) except Exception as e: logger.exception('Migrating service') log.doLog(userService, log.ERROR, 'Exception: {0}'.format(e), log.INTERNAL) userService.setState(State.ERROR) userService.save()
def sernotify(request, idUserService, notification): try: if notification == 'hostname': hostname = request.GET.get('hostname', None)[:64] # Cuts host name to 64 chars ip = request.ip if GlobalConfig.HONOR_CLIENT_IP_NOTIFY.getBool(True) is True: ip = request.GET.get('ip', ip) if ip is not None and hostname is not None: us = UserService.objects.get(uuid=idUserService) us.setConnectionSource(ip, hostname) else: return HttpResponse('Invalid request!', 'text/plain') elif notification == "log": message = request.GET.get('message', None) level = request.GET.get('level', None) if message is not None and level is not None: us = UserService.objects.get(uuid=idUserService) log.doLog(us, level, message, log.TRANSPORT) else: return HttpResponse('Invalid request!', 'text/plain') except Exception as e: logger.exception("Exception") return errors.errorView(request, e) return HttpResponse('ok', content_type='text/plain')
def deleteItem(self, parent, item): # This is also used by CachedService, so we use "userServices" directly and is valid for both service = None try: service = parent.userServices.get(uuid=processUuid(item)) except Exception: logger.exception('deleteItem') self.invalidItemException() if service.user: logStr = 'Deleted assigned service {} to user {} by {}'.format(service.friendly_name, service.user.pretty_name, self._user.pretty_name) else: logStr = 'Deleted cached service {} by {}'.format(service.friendly_name, self._user.pretty_name) if service.state in (State.USABLE, State.REMOVING): service.remove() elif service.state == State.PREPARING: service.cancel() elif service.state == State.REMOVABLE: self.invalidItemException(_('Item already being removed')) else: self.invalidItemException(_('Item is not removable')) log.doLog(parent, log.INFO, logStr, log.ADMIN) return self.success()
def saveItem(self, parent: 'ServicePool', item: typing.Optional[str]) -> None: # If already exists uuid = processUuid(item) if item is not None else None try: calendar: Calendar = Calendar.objects.get( uuid=processUuid(self._params['calendarId'])) access: str = self._params['access'].upper() if access not in (ALLOW, DENY): raise Exception() except Exception: raise self.invalidRequestException( _('Invalid parameters on request')) priority = int(self._params['priority']) if uuid is not None: calAccess: 'CalendarAccess' = parent.calendarAccess.get(uuid=uuid) calAccess.calendar = calendar # type: ignore calAccess.service_pool = parent # type: ignore calAccess.access = access calAccess.priority = priority calAccess.save() else: parent.calendarAccess.create(calendar=calendar, access=access, priority=priority) log.doLog( parent, log.INFO, "Added access calendar {}/{} by {}".format(calendar.name, access, self._user.pretty_name), log.ADMIN)
def migrate(serviceId, toNode): try: with transaction.atomic(): service = UserService.objects.select_for_update().get( pk=serviceId) service.setState(State.BALANCING) service.save() serviceInstance = service.getInstance() # Now we will start a new task, similar to those of deploying state = serviceInstance.startMigration(toNode) ClusterMigrationTask.checkAndUpdateState(service, serviceInstance, state) except Exception as e: logger.exception('Initializing migration') if service is not None: log.doLog(service, log.ERROR, 'At migration init: {0}'.format(e), log.INTERNAL) try: service.setState(State.ERROR) service.save() except: logger.exception('Setting error state at migration init')
def run(self): logger.debug('Checking user service finished %s', self._svrId) uService = None try: uService = UserService.objects.get(pk=self._svrId) if uService.state != self._state: logger.debug( 'Task overrided by another task (state of item changed)') # This item is no longer valid, returning will not check it again (no checkLater called) return ci = uService.getInstance() logger.debug("uService instance class: %s", ci.__class__) state = ci.checkState() UserServiceOpChecker.checkAndUpdateState(uService, ci, state) except UserService.DoesNotExist as e: logger.error( 'User service not found (erased from database?) %s : %s', e.__class__, e) except Exception as e: # Exception caught, mark service as errored logger.exception("Error %s, %s :", e.__class__, e) if uService is not None: log.doLog(uService, log.ERROR, 'Exception: {}'.format(e), log.INTERNAL) try: uService.setState(State.ERROR) uService.save(update_fields=['data', 'state', 'state_date']) except Exception: logger.error('Can\'t update state of uService object')
def authLogLogout(request: HttpRequest) -> None: log.doLog( request.user.manager, log.INFO, 'user {} has logged out from {}'.format(request.user.name, request.ip), log.WEB) log.doLog(request.user, log.INFO, 'has logged out from {}'.format(request.ip), log.WEB)
def run(self): logger.debug('Checking user service finished migrating {0}'.format(self._serviceId)) uService = None try: uService = UserService.objects.get(pk=self._serviceId) if uService.state != self._state: logger.debug('Task overrided by another task (state of item changed)') # This item is no longer valid, returning will not check it again (no checkLater called) return ci = uService.getInstance() logger.debug("uService instance class: {0}".format(ci.__class__)) state = ci.checkState() ClusterMigrationTask.checkAndUpdateState(uService, ci, state) except UserService.DoesNotExist as e: logger.error('User service not found (erased from database?) {0} : {1}'.format(e.__class__, e)) except Exception as e: # Exception caught, mark service as errored logger.exception("Error {0}, {1} :".format(e.__class__, e)) if uService is not None: log.doLog(uService, log.ERROR, 'Exception: {0}'.format(e), log.INTERNAL) try: uService.setState(State.ERROR) uService.save() except Exception: logger.error('Can\'t update state of uService object')
def growL1Cache(self, servicePool: ServicePool, cacheL1: int, cacheL2: int, assigned: int) -> None: """ This method tries to enlarge L1 cache. If for some reason the number of deployed services (Counting all, ACTIVE and PREPARING, assigned, L1 and L2) is over max allowed service deployments, this method will not grow the L1 cache """ logger.debug('Growing L1 cache creating a new service for %s', servicePool.name) # First, we try to assign from L2 cache if cacheL2 > 0: valid = None with transaction.atomic(): for n in servicePool.cachedUserServices().select_for_update().filter(userServiceManager().getCacheStateFilter(services.UserDeployment.L2_CACHE)).order_by('creation_date'): if n.needsOsManager(): if State.isUsable(n.state) is False or State.isUsable(n.os_state): valid = n break else: valid = n break if valid is not None: valid.moveToLevel(services.UserDeployment.L1_CACHE) return try: # This has a velid publication, or it will not be here userServiceManager().createCacheFor( typing.cast(ServicePoolPublication, servicePool.activePublication()), services.UserDeployment.L1_CACHE ) except MaxServicesReachedError: log.doLog(servicePool, log.ERROR, 'Max number of services reached for this service', log.INTERNAL) logger.warning('Max user services reached for %s: %s. Cache not created', servicePool.name, servicePool.max_srvs) except Exception: logger.exception('Exception')
def saveItem(self, parent, item): # If already exists uuid = processUuid(item) if item is not None else None calendar = Calendar.objects.get(uuid=processUuid(self._params['calendarId'])) action = self._params['action'].upper() if action not in CALENDAR_ACTION_DICT: self.invalidRequestException() eventsOffset = int(self._params['eventsOffset']) atStart = self._params['atStart'] not in ('false', False, '0', 0) params = json.dumps(self._params['params']) # logger.debug('Got parameters: {} {} {} {} ----> {}'.format(calendar, action, eventsOffset, atStart, params)) logStr = "Added scheduled action \"{},{},{},{},{}\" by {}".format( calendar.name, action, eventsOffset, atStart and 'Start' or 'End', params, self._user.pretty_name ) if uuid is not None: calAction = CalendarAction.objects.get(uuid=uuid) calAction.calendar = calendar calAction.service_pool = parent calAction.action = action calAction.at_start = atStart calAction.events_offset = eventsOffset calAction.params = params calAction.save() else: CalendarAction.objects.create(calendar=calendar, service_pool=parent, action=action, at_start=atStart, events_offset=eventsOffset, params=params) log.doLog(parent, log.INFO, logStr, log.ADMIN) return self.success()
def action(self) -> typing.MutableMapping[str, typing.Any]: logger.debug('Args: %s, Params: %s', self._args, self._params) userService = self.getUserService() # Adjust loglevel to own, we start on 10000 for OTHER, and received is 0 for OTHER log.doLog(userService, int(self._params['level']) + 10000, self._params['message'], log.ACTOR) return ActorV3Action.actorResult('ok')
def saveItem(self, parent: models.ServicePool, item: typing.Optional[str]) -> None: if not item: raise self.invalidItemException('Only modify is allowed') fields = self.readFieldsFromParams(['auth_id', 'user_id']) userService = parent.userServices.get(uuid=processUuid(item)) user = models.User.objects.get(uuid=processUuid(fields['user_id'])) logStr = 'Changing ownership of service from {} to {} by {}'.format( userService.user.pretty_name, user.pretty_name, self._user.pretty_name) # If there is another service that has this same owner, raise an exception if (parent.userServices.filter(user=user).exclude( uuid=userService.uuid).exclude( state__in=State.INFO_STATES).count() > 0): raise self.invalidResponseException( 'There is already another user service assigned to {}'.format( user.pretty_name)) userService.user = user userService.save() # Log change log.doLog(parent, log.INFO, logStr, log.ADMIN)
def deleteItem(self, parent: 'ServicePool', item: str) -> None: calendarAccess = parent.calendarAccess.get(uuid=processUuid(self._args[0])) logStr = "Removed access calendar {} by {}".format(calendarAccess.calendar.name, self._user.pretty_name) calendarAccess.delete() log.doLog(parent, log.INFO, logStr, log.ADMIN)
def saveItem(self, parent: MetaPool, item): # If already exists uuid = processUuid(item) if item is not None else None pool = ServicePool.objects.get( uuid=processUuid(self._params['pool_id'])) enabled = self._params['enabled'] not in ('false', False, '0', 0) priority = int(self._params['priority']) if uuid is not None: member = parent.members.get(uuid=uuid) member.pool = pool member.enabled = enabled member.priority = priority member.save() else: parent.members.create(pool=pool, priority=priority, enabled=enabled) log.doLog(parent, log.INFO, (uuid is None and "Added" or "Modified") + " meta pool member {}/{}/{} by {}".format( pool.name, priority, enabled, self._user.pretty_name), log.ADMIN) return self.success()
def saveItem(self, parent, item): # If already exists uuid = processUuid(item) if item is not None else None calendar = Calendar.objects.get( uuid=processUuid(self._params['calendarId'])) access = self._params['access'].upper() priority = int(self._params['priority']) if uuid is not None: calAccess = parent.calendarAccess.get(uuid=uuid) calAccess.calendar = calendar calAccess.service_pool = parent calAccess.access = access calAccess.priority = priority calAccess.save() else: parent.calendarAccess.create(calendar=calendar, access=access, priority=priority) log.doLog( parent, log.INFO, "Added access calendar {}/{} by {}".format(calendar.name, access, self._user.pretty_name), log.ADMIN) return self.success()
def loggedOut(self, userService, userName=None, save=True): ''' This method: - Add log in event to stats - Sets service in use - Invokes userLoggedIn for user service instance ''' uniqueId = userService.unique_id userService.setInUse(False) si = userService.getInstance() si.userLoggedOut(userName) userService.updateData(si) serviceIp = si.getIp() fullUserName = '******' if userService.user is not None: fullUserName = userService.user.manager.name + '\\' + userService.user.name knownUserIP = userService.src_ip + ':' + userService.src_hostname knownUserIP = knownUserIP if knownUserIP != ':' else 'unknown' addEvent(userService.deployed_service, ET_LOGOUT, fld1=userName, fld2=knownUserIP, fld3=serviceIp, fld4=fullUserName) log.doLog(userService, log.INFO, "User {0} has logged out", log.OSMANAGER) log.useLog('logout', uniqueId, serviceIp, userName, knownUserIP, fullUserName) if save: userService.save()
def loggedIn(self, userService, userName=None): """ This method: - Add log in event to stats - Sets service in use - Invokes userLoggedIn for user service instance """ uniqueId = userService.unique_id userService.setInUse(True) si = userService.getInstance() si.userLoggedIn(userName) userService.updateData(si) serviceIp = si.getIp() fullUserName = '******' if userService.user is not None: fullUserName = userService.user.manager.name + '\\' + userService.user.name knownUserIP = userService.src_ip + ':' + userService.src_hostname knownUserIP = knownUserIP if knownUserIP != ':' else 'unknown' if userName is None: userName = '******' addEvent(userService.deployed_service, ET_LOGIN, fld1=userName, fld2=knownUserIP, fld3=serviceIp, fld4=fullUserName) log.doLog(userService, log.INFO, "User {0} has logged in".format(userName), log.OSMANAGER) log.useLog('login', uniqueId, serviceIp, userName, knownUserIP, fullUserName, userService.friendly_name, userService.deployed_service.name) counter = int(userService.getProperty('loginsCounter', '0')) + 1 userService.setProperty('loginsCounter', six.text_type(counter))
def cancel(self, servicePoolPub): # pylint: disable=no-self-use ''' Invoked to cancel a publication. Double invokation (i.e. invokation over a "cancelling" item) will lead to a "forced" cancellation (unclean) :param servicePoolPub: Service pool publication (db object for a publication) ''' servicePoolPub = DeployedServicePublication.objects.get(pk=servicePoolPub.id) if servicePoolPub.state not in State.PUBLISH_STATES: if servicePoolPub.state == State.CANCELING: # Double cancel logger.info('Double cancel invoked for a publication') log.doLog(servicePoolPub.deployed_service, log.WARN, 'Forced cancel on publication, you must check uncleaned resources manually', log.ADMIN) servicePoolPub.setState(State.CANCELED) servicePoolPub.save() return else: raise PublishException(_('Can\'t cancel non running publication')) if servicePoolPub.state == State.LAUNCHING: servicePoolPub.state = State.CANCELED servicePoolPub.save() return servicePoolPub try: pubInstance = servicePoolPub.getInstance() state = pubInstance.cancel() servicePoolPub.setState(State.CANCELING) PublicationFinishChecker.checkAndUpdateState(servicePoolPub, pubInstance, state) return servicePoolPub except Exception, e: raise PublishException(str(e))
def cancel(self, parent, uuid): """ Invoked to cancel a running publication Double invocation (this means, invoking cancel twice) will mean that is a "forced cancelation" :param parent: Parent service pool :param uuid: uuid of the publication """ if permissions.checkPermissions( self._user, parent, permissions.PERMISSION_MANAGEMENT) is False: logger.debug('Management Permission failed for user {}'.format( self._user)) self.accessDenied() try: ds = DeployedServicePublication.objects.get(uuid=processUuid(uuid)) ds.cancel() except Exception as e: raise ResponseError("{}".format(e)) log.doLog( parent, log.INFO, "Canceled publication v{} by {}".format( parent.current_pub_revision, self._user.pretty_name), log.ADMIN) return self.success()
def publish(self, parent): """ Custom method "publish", provided to initiate a publication of a deployed service :param parent: Parent service pool """ changeLog = self._params[ 'changelog'] if 'changelog' in self._params else None if permissions.checkPermissions( self._user, parent, permissions.PERMISSION_MANAGEMENT) is False: logger.debug('Management Permission failed for user {}'.format( self._user)) self.accessDenied() logger.debug('Custom "publish" invoked for {}'.format(parent)) parent.publish( changeLog ) # Can raise exceptions that will be processed on response log.doLog( parent, log.INFO, "Initated publication v{} by {}".format( parent.current_pub_revision, self._user.pretty_name), log.ADMIN) return self.success()
def deleteItem( self, parent, item ): # This is also used by CachedService, so we use "userServices" directly and is valid for both service = None try: service = parent.userServices.get(uuid=processUuid(item)) except Exception: logger.exception('deleteItem') self.invalidItemException() if service.user: logStr = 'Deleted assigned service {} to user {} by {}'.format( service.friendly_name, service.user.pretty_name, self._user.pretty_name) else: logStr = 'Deleted cached service {} by {}'.format( service.friendly_name, self._user.pretty_name) if service.state in (State.USABLE, State.REMOVING): service.remove() elif service.state == State.PREPARING: service.cancel() elif service.state == State.REMOVABLE: self.invalidItemException(_('Item already being removed')) else: self.invalidItemException(_('Item is not removable')) log.doLog(parent, log.INFO, logStr, log.ADMIN) return self.success()
def deleteItem(self, parent: models.ServicePool, item: str) -> None: try: userService: models.UserService = parent.userServices.get( uuid=processUuid(item)) except Exception: logger.exception('deleteItem') raise self.invalidItemException() if userService.user: logStr = 'Deleted assigned service {} to user {} by {}'.format( userService.friendly_name, userService.user.pretty_name, self._user.pretty_name) else: logStr = 'Deleted cached service {} by {}'.format( userService.friendly_name, self._user.pretty_name) if userService.state in (State.USABLE, State.REMOVING): userService.remove() elif userService.state == State.PREPARING: userService.cancel() elif userService.state == State.REMOVABLE: raise self.invalidItemException(_('Item already being removed')) else: raise self.invalidItemException(_('Item is not removable')) log.doLog(parent, log.INFO, logStr, log.ADMIN)
def deleteItem(self, parent: MetaPool, item: str): member = parent.members.get(uuid=processUuid(self._args[0])) logStr = "Removed meta pool member {} by {}".format(member.pool.name, self._user.pretty_name) member.delete() log.doLog(parent, log.INFO, logStr, log.ADMIN) return self.success()
def genPassword(self, service): import random import string randomPass = service.recoverValue('winOsRandomPass') if randomPass is None: randomPass = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(16)) service.storeValue('winOsRandomPass', randomPass) log.doLog(service, log.INFO, "Password set to \"{}\"".format(randomPass), log.OSMANAGER) return randomPass
def deleteItem(self, parent, item): calendarAccess = parent.calendarAccess.get(uuid=processUuid(self._args[0])) logStr = "Removed access calendar {} by {}".format(calendarAccess.calendar.name, self._user.pretty_name) calendarAccess.delete() log.doLog(parent, log.INFO, logStr, log.ADMIN) return self.success()
def checkAndUpdateState(userService, userServiceInstance, state): ''' Checks the value returned from invocation to publish or checkPublishingState, updating the servicePoolPub database object Return True if it has to continue checking, False if finished ''' try: prevState = userService.state userService.unique_id = userServiceInstance.getUniqueId() # Updates uniqueId userService.friendly_name = userServiceInstance.getName() # And name, both methods can modify serviceInstance, so we save it later if State.isFinished(state): checkLater = False userServiceInstance.finish() if State.isPreparing(prevState): if userServiceInstance.service().publicationType is None or userService.publication == userService.deployed_service.activePublication(): userService.setState(State.USABLE) # and make this usable if os manager says that it is usable, else it pass to configuring state if userServiceInstance.osmanager() is not None and userService.os_state == State.PREPARING: # If state is already "Usable", do not recheck it stateOs = userServiceInstance.osmanager().checkState(userService) # If state is finish, we need to notify the userService again that os has finished if State.isFinished(stateOs): state = userServiceInstance.notifyReadyFromOsManager('') userService.updateData(userServiceInstance) else: stateOs = State.FINISHED if State.isRuning(stateOs): userService.setOsState(State.PREPARING) else: userService.setOsState(State.USABLE) else: # We ignore OsManager info and if userService don't belong to "current" publication, mark it as removable userService.setState(State.REMOVABLE) elif State.isRemoving(prevState): if userServiceInstance.osmanager() is not None: userServiceInstance.osmanager().release(userService) userService.setState(State.REMOVED) else: # Canceled, logger.debug("Canceled us {2}: {0}, {1}".format(prevState, State.toString(state), State.toString(userService))) userService.setState(State.CANCELED) userServiceInstance.osmanager().release(userService) userService.updateData(userServiceInstance) elif State.isErrored(state): checkLater = False userService.updateData(userServiceInstance) userService.setState(State.ERROR) else: checkLater = True # The task is running userService.updateData(userServiceInstance) userService.save() if checkLater: UserServiceOpChecker.checkLater(userService, userServiceInstance) except Exception as e: logger.exception('Checking service state') log.doLog(userService, log.ERROR, 'Exception: {0}'.format(e), log.INTERNAL) userService.setState(State.ERROR) userService.save()
def run(self): since_state = getSqlDatetime() - timedelta(seconds=MAX_STUCK_TIME) # Filter for locating machine not ready for ds in DeployedService.objects.filter(service__provider__maintenance_mode=False): logger.debug('Searching for stuck states for {0}'.format(ds)) # Info states are removed on UserServiceCleaner and VALID_STATES are ok, or if "hanged", checked on "HangedCleaner" for us in ds.userServices.filter(state_date__lt=since_state).exclude(state__in=State.INFO_STATES + State.VALID_STATES): logger.debug('Found stuck user service {0}'.format(us)) log.doLog(ds, log.ERROR, 'User service {0} has been hard removed because it\'s stuck'.format(us.friendly_name)) us.delete()
def run(self): since_state = getSqlDatetime() - timedelta(seconds=GlobalConfig.MAX_INITIALIZING_TIME.getInt()) # Filter for locating machine not ready flt = Q(state_date__lt=since_state, state=State.PREPARING) | Q(state_date__lt=since_state, state=State.USABLE, os_state=State.PREPARING) for ds in DeployedService.objects.exclude(osmanager=None, state__in=State.VALID_STATES, service__provider__maintenance_mode=True): logger.debug('Searching for hanged services for {0}'.format(ds)) for us in ds.userServices.filter(flt): logger.debug('Found hanged service {0}'.format(us)) log.doLog(us, log.ERROR, 'User Service seems to be hanged. Removing it.', log.INTERNAL) log.doLog(ds, log.ERROR, 'Removing user service {0} because it seems to be hanged'.format(us.friendly_name)) us.removeOrCancel()
def doLog(self, service, data, origin=log.OSMANAGER): # Stores a log associated with this service try: msg, level = data.split('\t') try: level = int(level) except Exception: logger.debug('Do not understand level {}'.format(level)) level = log.INFO log.doLog(service, level, msg, origin) except Exception: log.doLog(service, log.ERROR, "do not understand {0}".format(data), origin)
def deleteItem(self, parent, item): calendarAction = CalendarAction.objects.get(uuid=processUuid(self._args[0])) logStr = "Removed scheduled action \"{},{},{},{},{}\" by {}".format( calendarAction.calendar.name, calendarAction.action, calendarAction.events_offset, calendarAction.at_start and 'Start' or 'End', calendarAction.params, self._user.pretty_name ) calendarAction.delete() log.doLog(parent, log.INFO, logStr, log.ADMIN) return self.success()
def release(request, idService): logger.debug('ID Service: {}'.format(idService)) userService = userServiceManager().locateUserService(request.user, idService, create=False) logger.debug('UserSrvice: >{}<'.format(userService)) if userService is not None and userService.deployed_service.allow_users_remove: log.doLog( userService.deployed_service, log.INFO, "Removing User Service {} as requested by {} from {}".format(userService.friendly_name, request.user.pretty_name, request.ip), log.WEB ) userServiceManager().requestLogoff(userService) userService.release() return HttpResponseRedirect(reverse('Index'))
def execute(self, parent, item): self.ensureAccess(item, permissions.PERMISSION_MANAGEMENT) logger.debug('Launching action') uuid = processUuid(item) calendarAction = CalendarAction.objects.get(uuid=uuid) logStr = "Launched scheduled action \"{},{},{},{},{}\" by {}".format( calendarAction.calendar.name, calendarAction.action, calendarAction.events_offset, calendarAction.at_start and 'Start' or 'End', calendarAction.params, self._user.pretty_name ) calendarAction.execute() log.doLog(parent, log.INFO, logStr, log.ADMIN) return self.success()
def publish(self, parent): """ Custom method "publish", provided to initiate a publication of a deployed service :param parent: Parent service pool """ changeLog = self._params['changelog'] if 'changelog' in self._params else None if permissions.checkPermissions(self._user, parent, permissions.PERMISSION_MANAGEMENT) is False: logger.debug('Management Permission failed for user {}'.format(self._user)) self.accessDenied() logger.debug('Custom "publish" invoked for {}'.format(parent)) parent.publish(changeLog) # Can raise exceptions that will be processed on response log.doLog(parent, log.INFO, "Initated publication v{} by {}".format(parent.current_pub_revision, self._user.pretty_name), log.ADMIN) return self.success()
def getService(request, idService, idTransport, doTest=True): kind, idService = idService[0], idService[1:] logger.debug('Kind of service: {0}, idService: {1}'.format(kind, idService)) if kind == 'A': # This is an assigned service logger.debug('Getting A service {}'.format(idService)) ads = UserService.objects.get(uuid=idService) ads.deployed_service.validateUser(request.user) else: ds = DeployedService.objects.get(uuid=idService) # We first do a sanity check for this, if the user has access to this service # If it fails, will raise an exception ds.validateUser(request.user) # Now we have to locate an instance of the service, so we can assign it to user. ads = UserServiceManager.manager().getAssignationForUser(ds, request.user) if ads.isInMaintenance() is True: raise ServiceInMaintenanceMode() logger.debug('Found service: {0}'.format(ads)) trans = Transport.objects.get(uuid=idTransport) # Ensures that the transport is allowed for this service if trans not in ads.deployed_service.transports.all(): raise InvalidServiceException() # If transport is not available for the request IP... if trans.validForIp(request.ip) is False: raise InvalidServiceException() if doTest is False: return (None, ads, None, trans, None) # Test if the service is ready if ads.isReady(): log.doLog(ads, log.INFO, "User {0} from {1} has initiated access".format(request.user.name, request.ip), log.WEB) # If ready, show transport for this service, if also ready ofc iads = ads.getInstance() ip = iads.getIp() events.addEvent(ads.deployed_service, events.ET_ACCESS, username=request.user.name, srcip=request.ip, dstip=ip, uniqueid=ads.unique_id) if ip is not None: itrans = trans.getInstance() if itrans.isAvailableFor(ip): ads.setConnectionSource(request.ip, 'unknown') log.doLog(ads, log.INFO, "User service ready", log.WEB) UserServiceManager.manager().notifyPreconnect(ads, itrans.processedUser(ads, request.user), itrans.protocol) return (ip, ads, iads, trans, itrans) else: log.doLog(ads, log.WARN, "User service is not accessible (ip {0})".format(ip), log.TRANSPORT) logger.debug('Transport is not ready for user service {0}'.format(ads)) else: logger.debug('Ip not available from user service {0}'.format(ads)) else: log.doLog(ads, log.WARN, "User {0} from {1} tried to access, but machine was not ready".format(request.user.name, request.ip), log.WEB) return None
def saveItem(self, parent, item): fields = self.readFieldsFromParams(['auth_id', 'user_id']) service = parent.userServices.get(uuid=processUuid(item)) user = User.objects.get(uuid=processUuid(fields['user_id'])) logStr = 'Changing ownership of service from {} to {} by {}'.format(service.user.pretty_name, user.pretty_name, self._user.pretty_name) # If there is another service that has this same owner, raise an exception if parent.userServices.filter(user=user).exclude(uuid=service.uuid).exclude(state__in=State.INFO_STATES).count() > 0: raise self.invalidResponseException('There is already another user service assigned to {}'.format(user.pretty_name)) service.user = user service.save() # Log change log.doLog(parent, log.INFO, logStr, log.ADMIN) return self.success()
def authLogLogin(request, authenticator, userName, logStr=''): """ Logs authentication """ if logStr == '': logStr = 'Logged in' authLogger.info('|'.join([authenticator.name, userName, request.ip, request.os['OS'], logStr, request.META.get('HTTP_USER_AGENT', 'Undefined')])) level = (logStr == 'Logged in') and log.INFO or log.ERROR log.doLog(authenticator, level, 'user {0} has {1} from {2} where os is {3}'.format(userName, logStr, request.ip, request.os['OS']), log.WEB) try: user = authenticator.users.get(name=userName) log.doLog(user, level, '{} from {} where OS is {}'.format(logStr, request.ip, request.os['OS']), log.WEB ) except Exception: pass
def loggedOut(self, userService, userName=None, save=True): """ This method: - Add log in event to stats - Sets service in use - Invokes userLoggedIn for user service instance """ counter = int(userService.getProperty('loginsCounter', '0')) if counter > 0: counter -= 1 userService.setProperty('loginsCounter', six.text_type(counter)) if GlobalConfig.EXCLUSIVE_LOGOUT.getBool(True) is True: if counter > 0: return uniqueId = userService.unique_id userService.setInUse(False) si = userService.getInstance() si.userLoggedOut(userName) userService.updateData(si) serviceIp = si.getIp() fullUserName = '******' if userService.user is not None: fullUserName = userService.user.manager.name + '\\' + userService.user.name knownUserIP = userService.src_ip + ':' + userService.src_hostname knownUserIP = knownUserIP if knownUserIP != ':' else 'unknown' if userName is None: userName = '******' addEvent(userService.deployed_service, ET_LOGOUT, fld1=userName, fld2=knownUserIP, fld3=serviceIp, fld4=fullUserName) log.doLog(userService, log.INFO, "User {0} has logged out".format(userName), log.OSMANAGER) log.useLog('logout', uniqueId, serviceIp, userName, knownUserIP, fullUserName, userService.friendly_name, userService.deployed_service.name) if save: userService.save()
def readyReceived(self, userService, data): # No group to add if self._group == '': return if not '.' in self._domain: logger.info('Adding to a group for a non FQDN domain is not supported') return # The machine is on a AD for sure, and maybe they are not already sync servers = list(self.__getServerList()) error = None for s in servers: try: l = self.__connectLdap(servers=(s,)) machine = self.__getMachine(l, userService.friendly_name) group = self.__getGroup(l) # # # Direct LDAP operation "modify", maybe this need to be added to ldaputil? :) # # l.modify_s(group, ((ldap.MOD_ADD, 'member', machine),)) error = None break except dns.resolver.NXDOMAIN: # No domain found, log it and pass logger.warn('Could not find _ldap._tcp.' + self._domain) log.doLog(userService, log.WARN, "Could not remove machine from domain (_ldap._tcp.{0} not found)".format(self._domain), log.OSMANAGER) except ldap.ALREADY_EXISTS: # Already added this machine to this group, pass error = None break except ldaputil.LDAPError: logger.exception('Ldap Exception caught') error = "Could not remove machine from domain (invalid credentials for {0})".format(self._account) except Exception as e: error = "Could not add machine {} to group {}: {}".format(userService.friendly_name, self._group, e) # logger.exception('Ldap Exception caught') if error is not None: log.doLog(userService, log.WARN, error, log.OSMANAGER) logger.error(error)
def cancel(self, parent, uuid): """ Invoked to cancel a running publication Double invocation (this means, invoking cancel twice) will mean that is a "forced cancelation" :param parent: Parent service pool :param uuid: uuid of the publication """ if permissions.checkPermissions(self._user, parent, permissions.PERMISSION_MANAGEMENT) is False: logger.debug('Management Permission failed for user {}'.format(self._user)) self.accessDenied() try: ds = DeployedServicePublication.objects.get(uuid=processUuid(uuid)) ds.cancel() except Exception as e: raise ResponseError("{}".format(e)) log.doLog(parent, log.INFO, "Canceled publication v{} by {}".format(parent.current_pub_revision, self._user.pretty_name), log.ADMIN) return self.success()