예제 #1
0
def delete_account(request):
    """
    A user requests his account to be deleted. In order to verify the request
    the user's password should be included as a parameter.
    """
    email = request.matchdict['email']
    params = params_from_request(request)
    plaintext_password = params.get('password', None)
    if not email:
        raise ValueError('No email provided')

    if config.SSO_TEST_EMAIL == "":
        raise MethodNotAllowedError("Configuration error")

    # SEC only allow test user to self delete
    if email != config.SSO_TEST_EMAIL:
        raise MethodNotAllowedError("This method is only for the test user")

    try:
        user = User.objects.get(email=email)
    except UserNotFoundError:
        return OK
    if not user.check_password(password=plaintext_password):
        raise MethodNotAllowedError("Password is wrong!!")
    user.delete()
    return OK
예제 #2
0
def register_user(email,
                  first_name,
                  last_name,
                  registration_method,
                  selected_plan=None,
                  promo_code=None,
                  token=None,
                  status='pending',
                  create_organization=True,
                  request=None):
    # User does not exist so we have to add him/her to the database
    # First make sure that email is not banned
    # Then create the User objects and the Organization
    if email.split('@')[1] in config.BANNED_EMAIL_PROVIDERS:
        raise MethodNotAllowedError("Email provider is banned.")

    user = User()
    user.email = email
    user.first_name = first_name
    user.last_name = last_name
    user.registration_method = registration_method
    user.registration_date = time()
    user.status = status
    user.activation_key = get_secure_rand_token()
    user.can_create_org = True
    user.save()

    # For some users registering through sso it might not be necessary to
    # create an organization, hence the flag
    org = create_org_for_user(user, '', promo_code, token, selected_plan) \
        if create_organization else None

    log_event_args = {
        'owner_id': org and org.id or '',
        'user_id': user.id,
        'first_name': user.first_name,
        'last_name': user.last_name,
        'company': user.feedback.company_name,
        'event_type': 'request',
        'action': 'register',
        'authentication_provider': registration_method
    }

    if request:
        log_event_args.update({
            'request_method': request.method,
            'request_path': request.path,
            'request_ip': ip_from_request(request),
            'user_agent': request.user_agent,
        })

    if org:
        log_event_args.update({'org_id': org.id, 'org_name': org.name})

    # Create log for the registration of a user and if an org has been created
    # add the id and name of the org
    from mist.api.logs.methods import log_event
    log_event(**log_event_args)

    return user, org
예제 #3
0
def get_stats(request):
    """
    Tags: monitoring
    ---
    Request monitoring data for a machine
    ---
    machine:
      in: path
      type: string
      required: true
    start:
      in: query
      type: string
      default: now
      required: false
      description: time (eg. '10s') since when to fetch stats
    stop:
      in: query
      type: string
      required: false
      description: time until when to fetch stats
    step:
      in: query
      type: string
      required: false
      description: step to fetch stats, used in aggregations
    metrics:
      in: query
      type: string
      required: false
    request_id:
      in: query
      type: string
      required: false

    """
    machine = _machine_from_matchdict(request)
    if not machine.monitoring.hasmonitoring:
        raise MethodNotAllowedError("Machine doesn't have monitoring enabled")

    # SEC require permission READ on machine
    auth_context = auth_context_from_request(request)
    auth_context.check_perm('machine', 'read', machine.id)

    params = params_from_request(request)
    start = params.get('start', '')
    stop = params.get('stop', '')
    step = params.get('step', '')
    try:
        metrics = params.getall('metrics')
    except:
        metrics = params.get('metrics')

    data = mist.api.monitoring.methods.get_stats(machine,
                                                 start=start,
                                                 stop=stop,
                                                 step=step,
                                                 metrics=metrics)
    data['request_id'] = params.get('request_id')
    return data
예제 #4
0
def associate_metric(machine, metric_id, name='', unit=''):
    """Associate a new metric to a machine."""
    if not machine.monitoring.hasmonitoring:
        raise MethodNotAllowedError("Machine doesn't have monitoring enabled")
    metric = update_metric(machine.owner, metric_id, name, unit)
    if metric_id not in machine.monitoring.metrics:
        machine.monitoring.metrics.append(metric_id)
        machine.save()
    trigger_session_update(machine.owner, ['monitoring'])
    return metric
예제 #5
0
def disassociate_metric(machine, metric_id):
    """Disassociate a metric from a machine."""
    if not machine.monitoring.hasmonitoring:
        raise MethodNotAllowedError("Machine doesn't have monitoring enabled")
    try:
        Metric.objects.get(owner=machine.owner, metric_id=metric_id)
    except Metric.DoesNotExist:
        raise NotFoundError("Invalid metric_id")
    if metric_id not in machine.monitoring.metrics:
        raise NotFoundError("Metric isn't associated with this Machine")
    machine.monitoring.metrics.remove(metric_id)
    machine.save()
    trigger_session_update(machine.owner, ['monitoring'])
예제 #6
0
def find_metrics(machine):
    """Return the metrics associated with the specified machine."""
    if not machine.monitoring.hasmonitoring:
        raise MethodNotAllowedError("Machine doesn't have monitoring enabled")

    if machine.monitoring.method in ('telegraf-graphite'):
        return graphite_find_metrics(machine)
    elif machine.monitoring.method == 'telegraf-influxdb':
        metrics = {}
        for metric in show_fields(show_measurements(machine.id)):
            metrics[metric['id']] = metric
        return metrics
    else:
        raise Exception("Invalid monitoring method")
예제 #7
0
def machine_dashboard(request):
    """
    Tags: monitoring
    ---
    Return monitoring dashboard for a machine.
    READ permission required on cloud.
    READ permission required on machine.
    """
    machine = _machine_from_matchdict(request)
    if not machine.monitoring.hasmonitoring:
        raise MethodNotAllowedError("Machine doesn't have monitoring enabled")

    if machine.monitoring.method in ('telegraf-graphite'):
        if machine.os_type == "windows":
            ret = copy.deepcopy(config.WINDOWS_MACHINE_DASHBOARD_DEFAULT)
        else:
            ret = copy.deepcopy(config.GRAPHITE_MACHINE_DASHBOARD_DEFAULT)
    elif machine.monitoring.method in ('telegraf-tsfdb'):
        ret = copy.deepcopy(config.FDB_MACHINE_DASHBOARD_DEFAULT)
    else:
        ret = copy.deepcopy(config.INFLUXDB_MACHINE_DASHBOARD_DEFAULT)
    dashboard = ret['dashboard']
    for m in machine.monitoring.metrics:
        panels = dashboard['rows'][-1]['panels']
        panels.append({
            "id": len(panels),
            "title": m.replace('mist.python', '').replace('.', ' '),
            "type": "graph",
            "span": 6,
            "stack": False,
            "removable": True,
            "datasource": "mist.monitor",
            "targets": [{
                "refId": "m",
                "target": m
            }],
            "x-axis": True,
            "y-axis": True
        })
    for i in range(0, len(dashboard['rows'])):
        for j in range(0, len(dashboard['rows'][i]['panels'])):
            dashboard['rows'][i]['panels'][j]['machine'] = [
                machine.cloud.id, machine.machine_id
            ]
    return ret
예제 #8
0
def get_stats(machine, start='', stop='', step='', metrics=None):
    """Get all monitoring data for the specified machine.

    If a list of `metrics` is provided, each metric needs to comply with the
    following template:

        <measurement>.<tags>.<column>

    where <tags> (optional) must be in "key=value" format and delimited by ".".

    Regular expressions may also be specified, but they need to be inside `/`,
    as defined by InfluxQL. The usage of "." should be avoided when using
    regular expressions, since dots are also used to delimit the metrics' path.

    Arguments:
        - machine: Machine model instance to get stats for
        - start: the time since when to query for stats, eg. 10s, 2m, etc
        - stop: the time until which to query for stats
        - step: the step at which to return stats
        - metrics: the metrics to query for, if explicitly specified

    """
    if not machine.monitoring.hasmonitoring:
        raise MethodNotAllowedError('Machine does not have monitoring enabled')
    if metrics is None:
        metrics = []
    elif not isinstance(metrics, list):
        metrics = [metrics]

    if machine.monitoring.method in ('telegraf-graphite'):
        return graphite_get_stats(
            machine,
            start=start,
            stop=stop,
            step=step,
            metrics=metrics,
        )
    elif machine.monitoring.method == 'telegraf-influxdb':
        if not metrics:
            metrics = (config.INFLUXDB_BUILTIN_METRICS.keys() +
                       machine.monitoring.metrics)

        # NOTE: For backwards compatibility.
        # Transform "min" and "sec" to "m" and "s", respectively.
        start, stop, step = map(lambda x: re.sub('in|ec', repl='', string=x),
                                (start.strip('-'), stop.strip('-'), step))

        # Fetch series.
        results = {}
        for metric in metrics:
            regex = r'^(?:\w+)\((.+)\)$'
            match = re.match(regex, metric)
            if not match:
                groups = (metric, )
            while match:
                groups = match.groups()
                match = re.match(regex, groups[0])
            measurement, _ = groups[0].split('.', 1)
            handler = INFLUXDB_HANDLERS.get(measurement,
                                            InfluxMainStatsHandler)(machine)
            data = handler.get_stats(metric=metric,
                                     start=start,
                                     stop=stop,
                                     step=step)
            if data:
                results.update(data)
        return results
    else:
        raise Exception("Invalid monitoring method")
예제 #9
0
def machine_console(request):
    """
    Tags: machines
    ---
    Open VNC console.
    Generate and return an URI to open a VNC console to target machine
    READ permission required on cloud.
    READ permission required on machine.
    ---
    cloud:
      in: path
      required: true
      type: string
    machine:
      in: path
      required: true
      type: string
    rdp_port:
      default: 3389
      in: query
      required: true
      type: integer
    host:
      in: query
      required: true
      type: string
    """
    cloud_id = request.matchdict.get('cloud')

    auth_context = auth_context_from_request(request)

    if cloud_id:
        machine_id = request.matchdict['machine']
        auth_context.check_perm("cloud", "read", cloud_id)
        try:
            machine = Machine.objects.get(cloud=cloud_id,
                                          machine_id=machine_id,
                                          state__ne='terminated')
            # used by logging_view_decorator
            request.environ['machine_uuid'] = machine.id
        except Machine.DoesNotExist:
            raise NotFoundError("Machine %s doesn't exist" % machine_id)
    else:
        machine_uuid = request.matchdict['machine_uuid']
        try:
            machine = Machine.objects.get(id=machine_uuid,
                                          state__ne='terminated')
            # used by logging_view_decorator
            request.environ['machine_id'] = machine.machine_id
            request.environ['cloud_id'] = machine.cloud.id
        except Machine.DoesNotExist:
            raise NotFoundError("Machine %s doesn't exist" % machine_uuid)

        cloud_id = machine.cloud.id
        auth_context.check_perm("cloud", "read", cloud_id)

    auth_context.check_perm("machine", "read", machine.id)

    if machine.cloud.ctl.provider not in ['vsphere', 'openstack', 'libvirt']:
        raise MistNotImplementedError(
            "VNC console only supported for vSphere, OpenStack or KVM")

    if machine.cloud.ctl.provider == 'libvirt':
        import xml.etree.ElementTree as ET
        from html import unescape
        from datetime import datetime
        import hmac
        import hashlib
        xml_desc = unescape(machine.extra.get('xml_description', ''))
        root = ET.fromstring(xml_desc)
        vnc_element = root.find('devices').find('graphics[@type="vnc"]')
        if not vnc_element:
            raise MethodNotAllowedError(
                "VNC console not supported by this KVM domain")
        vnc_port = vnc_element.attrib.get('port')
        vnc_host = vnc_element.attrib.get('listen')
        from mongoengine import Q
        # Get key associations, prefer root or sudoer ones
        key_associations = KeyMachineAssociation.objects(
            Q(machine=machine.parent) & (Q(ssh_user='******') | Q(sudo=True))) \
            or KeyMachineAssociation.objects(machine=machine.parent)
        if not key_associations:
            raise ForbiddenError()
        key_id = key_associations[0].key.id
        host = '%s@%s:%d' % (key_associations[0].ssh_user,
                             machine.parent.hostname, key_associations[0].port)
        expiry = int(datetime.now().timestamp()) + 100
        msg = '%s,%s,%s,%s,%s' % (host, key_id, vnc_host, vnc_port, expiry)
        mac = hmac.new(config.SECRET.encode(),
                       msg=msg.encode(),
                       digestmod=hashlib.sha256).hexdigest()
        base_ws_uri = config.CORE_URI.replace('http', 'ws')
        proxy_uri = '%s/proxy/%s/%s/%s/%s/%s/%s' % (
            base_ws_uri, host, key_id, vnc_host, vnc_port, expiry, mac)
        return render_to_response('../templates/novnc.pt', {'url': proxy_uri})
    if machine.cloud.ctl.provider == 'vsphere':
        console_uri = machine.cloud.ctl.compute.connection.ex_open_console(
            machine.machine_id)
        protocol, host = config.CORE_URI.split('://')
        protocol = protocol.replace('http', 'ws')
        params = urllib.parse.urlencode({'url': console_uri})
        proxy_uri = f"{protocol}://{host}/wsproxy/?{params}"
        return render_to_response('../templates/novnc.pt', {'url': proxy_uri})
    else:
        console_url = machine.cloud.ctl.compute.connection.ex_open_console(
            machine.machine_id)
    raise RedirectError(console_url)