<commit_before>#!/usr/bin/python -u
#
# Copyright (C) Endpoints Server Proxy Authors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.

""" Fuzz tests for transcoding. Uses generated JSON, URL path and query parameters input
    to call ESP with the grpc echo backend.

    Usage:
       ./esp_fuzz_test.py \
           --address="<ESP HTTP/1.1 address>" \
           --status_address="<ESP status address>" \
           [--runs=<number of runs>]
"""

import argparse
import esp_utils
import httplib
import json
import sys

class C:
    pass
FLAGS = C

class Fuzzer(object):
    """ A fuzzer based on templates and tokens. Each template is a string with
        one or more placeholders ('FUZZ'). The placeholders are replaced with tokens
        from the given token set to generate fuzz inputs.
    """

    def __init__(self, templates, tokens):
      self._templates = templates
      self._tokens = tokens

    def _run(self, template, f):
      if 'FUZZ' in template:
        for token in self._tokens:
          # Replace the first placeholder with the current token and call _run() again
          self._run(template.replace('FUZZ', token, 1), f)
      else:
        # All placeholders are already replaced, call the function f()
        f(template)

    def run(self, f):
      """ Executes the given function f() on all the generated fuzz inputs. """
      for template in self._templates:
        self._run(template, f)

class JsonFuzzer(Fuzzer):
    """ JSON fuzzer that uses static and generated templates """

    def __init__(self, max_object_nest_level, max_list_nest_level):
      STATIC_JSON_TEMPLATES = ['', 'FUZZ', '{FUZZ}', '[FUZZ]', '{FUZZ: FUZZ}', '[FUZZ, FUZZ]' ]
      JSON_TOKEN_LIST = ['{', '}', '[', ']', '"message"', '"text"', 'true', 'false', '1234',
                          '-1234', '1.2345e-10', '-3.1415e+13', 'null']

      templates = STATIC_JSON_TEMPLATES
      for n in range(max_object_nest_level):
        templates += [ self._get_object_template(n) ]
      for n in range(max_list_nest_level):
        templates += [ self._get_list_template(n) ]

      Fuzzer.__init__(self, templates, JSON_TOKEN_LIST)

    def _get_object_template(self, nest_level):
        template = ""
        for i in range(nest_level):
            template += '{ "message": FUZZ'
            if i != nest_level - 1:
                template += ', '
        for i in range(nest_level):
            template += '}'
        return template

    def _get_list_template(self, nest_level):
        template = ""
        for i in range(nest_level):
            template += '[FUZZ'
            if i != nest_level - 1:
                template += ', '
        for i in range(nest_level):
            template += ']'
        return template

def url_path_fuzzer():
    """ URL Path fuzzer that uses static templates """
    URLPATH_TEMPLATES = ['/FUZZ', '/FUZZ/FUZZ', '/FUZZ/FUZZ/FUZZ']
    URLPATH_TOKEN_LIST = ['', '/', '#', '@#$%^& ', '%20%25', 'echo', 'echostream']
    return Fuzzer(URLPATH_TEMPLATES, URLPATH_TOKEN_LIST)

def query_param_fuzzer():
    """ URL Path fuzzer that uses static templates """
    QUERYPARAM_TEMPLATES = ['', '#', '#FUZZ', 'FUZZ', 'FUZZ=FUZZ', 'FUZZ&FUZZ']
    QUERYPARAM_TOKEN_LIST = ['', '/', '#', '=', '&', '?', '&?#', '@#$%^=', 'message',
                              'message=msg', '%2F%25%0A%20' ]
    return Fuzzer(QUERYPARAM_TEMPLATES, QUERYPARAM_TOKEN_LIST)

class EspTranscodingFuzzTest(object):
    """ ESP Transcoding Fuzz tests """

    def __init__(self):
        self._conn = esp_utils.http_connection(FLAGS.address, True)
        self._status_conn = esp_utils.http_connection(FLAGS.status_address, True)
        self._initial_status = self._get_status()
        self._total_requests = 0
        self._unexpected_errors = 0

    def _get_status(self):
        self._status_conn.request('GET', '/endpoints_status')
        response = esp_utils.Response(self._status_conn.getresponse())
        status = response.json()
        if len(status['processes']) == 0:
            sys.exit(esp_utils.red('Cloud not get ESP status'))
        return status

    def _check_for_crash(self):
        print "Checking for crashes..."
        current_status = self._get_status()
        initial_processes = self._initial_status['processes']
        current_processes = current_status['processes']
        if len(initial_processes) != len(current_processes):
            sys.exit(esp_utils.red(
                'ESP crashed. Initial & current process numbers do not match.'))
            return
        for i in range(len(initial_processes)):
            if initial_processes[i]['processId'] != current_processes[i]['processId']:
                sys.exit(esp_utils.red(
                    'ESP crashed. Initial & current pids do not match.'))
            if initial_processes[i]['startedAt'] != current_processes[i]['startedAt']:
                sys.exit(esp_utils.red(
                    'ESP crashed. Initial & current start times do not match.'))
        print esp_utils.green('No crashes detected.')

    def _request(self, url_path, query_params, json, expected_codes):
        # Construct the URL using url_path, query_params and the api key
        url = url_path
        if FLAGS.api_key:
            if query_params:
                url = '%s?key=%s&%s' % (url_path, FLAGS.api_key, query_params)
            else:
                url = '%s?key=%s' % (url_path, FLAGS.api_key)
        elif query_params:
            url = '%s?%s' % (url_path, query_params)

        # Prepare headers
        headers = {'Content-Type': 'application/json'}
        if FLAGS.auth_token:
            headers['Authorization'] = 'Bearer ' + FLAGS.auth_token

        self._conn.request('POST', url, json, headers)
        response = esp_utils.Response(self._conn.getresponse())

        # Make sure that the response status code is in 200s, 300s or 400s
        # and that the response payload is valid JSON
        if not response.status_code in expected_codes:
            print esp_utils.red('Invalid status code %d: url=%s, json=%s' % (
                                response.status_code, url, json) )
            self._unexpected_errors += 1
        elif not response.is_json():
            print esp_utils.red('Response is not json: url=%s, json=%s' % (url, json) )
            self._unexpected_errors += 1

        self._total_requests += 1

    def _print_results_so_far(self):
        print 'Fuzz test results so far: total - %d, unexpected errors - %d' % (
            self._total_requests, self._unexpected_errors)

    def _run_json_fuzz_tests(self, url, max_object_nest_level, max_list_nest_level):
        fuzzer = JsonFuzzer(max_object_nest_level, max_list_nest_level)
        fuzzer.run(lambda json: self._request(url, None, json, [200, 400]))

    def _run_query_param_fuzzer(self, url_path):
        fuzzer = query_param_fuzzer()
        fuzzer.run(
            lambda query_params: self._request(url_path, query_params, "{}", [200, 400]))

    def _run_url_path_fuzzer(self):
        fuzzer = url_path_fuzzer()
        # Url path fuzzer generated requests may return 404 Not Found in
        # addition to 200 OK and 400 Bad Request
        fuzzer.run(lambda url_path: self._request(url_path, None, "{}", [200, 400, 404]))

    def _run_fuzz_tests(self):
        print 'Running /echo JSON fuzz tests...'
        self._run_json_fuzz_tests('/echo', 4, 2)
        self._check_for_crash()
        self._print_results_so_far()

        print 'Running /echostream JSON fuzz tests...'
        self._run_json_fuzz_tests('/echostream', 2, 4)
        self._check_for_crash()
        self._print_results_so_far()

        print 'Running /echo query param fuzz tests...'
        self._run_query_param_fuzzer('/echo')
        self._check_for_crash()
        self._print_results_so_far()

        print 'Running URL path fuzz tests...'
        self._run_url_path_fuzzer()
        self._check_for_crash()
        self._print_results_so_far()

    def run_all_tests(self):
        for i in range(FLAGS.runs):
            self._run_fuzz_tests()
        if self._unexpected_errors > 0:
          sys.exit(esp_utils.red('Fuzz test failed.'))
        else:
          print esp_utils.green('Fuzz test passed.')

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--address', help='Deployed ESP HTTP/1.1 address.')
    parser.add_argument('--status_address',
                        help='Address for getting ESP status (/endpoints_status)')
    parser.add_argument('--api_key', help='Project api_key to access service.')
    parser.add_argument('--auth_token', help='Auth token.')
    parser.add_argument('--runs', type=int, default=1, help='Number of runs')
    flags = parser.parse_args(namespace=FLAGS)

    esp_test = EspTranscodingFuzzTest()
    esp_test.run_all_tests()
<commit_msg>Remove '#' from URL path fuzzing tokens<commit_after>#!/usr/bin/python -u
#
# Copyright (C) Endpoints Server Proxy Authors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.

""" Fuzz tests for transcoding. Uses generated JSON, URL path and query parameters input
    to call ESP with the grpc echo backend.

    Usage:
       ./esp_fuzz_test.py \
           --address="<ESP HTTP/1.1 address>" \
           --status_address="<ESP status address>" \
           [--runs=<number of runs>]
"""

import argparse
import esp_utils
import httplib
import json
import sys

class C:
    pass
FLAGS = C

class Fuzzer(object):
    """ A fuzzer based on templates and tokens. Each template is a string with
        one or more placeholders ('FUZZ'). The placeholders are replaced with tokens
        from the given token set to generate fuzz inputs.
    """

    def __init__(self, templates, tokens):
      self._templates = templates
      self._tokens = tokens

    def _run(self, template, f):
      if 'FUZZ' in template:
        for token in self._tokens:
          # Replace the first placeholder with the current token and call _run() again
          self._run(template.replace('FUZZ', token, 1), f)
      else:
        # All placeholders are already replaced, call the function f()
        f(template)

    def run(self, f):
      """ Executes the given function f() on all the generated fuzz inputs. """
      for template in self._templates:
        self._run(template, f)

class JsonFuzzer(Fuzzer):
    """ JSON fuzzer that uses static and generated templates """

    def __init__(self, max_object_nest_level, max_list_nest_level):
      STATIC_JSON_TEMPLATES = ['', 'FUZZ', '{FUZZ}', '[FUZZ]', '{FUZZ: FUZZ}', '[FUZZ, FUZZ]' ]
      JSON_TOKEN_LIST = ['{', '}', '[', ']', '"message"', '"text"', 'true', 'false', '1234',
                          '-1234', '1.2345e-10', '-3.1415e+13', 'null']

      templates = STATIC_JSON_TEMPLATES
      for n in range(max_object_nest_level):
        templates += [ self._get_object_template(n) ]
      for n in range(max_list_nest_level):
        templates += [ self._get_list_template(n) ]

      Fuzzer.__init__(self, templates, JSON_TOKEN_LIST)

    def _get_object_template(self, nest_level):
        template = ""
        for i in range(nest_level):
            template += '{ "message": FUZZ'
            if i != nest_level - 1:
                template += ', '
        for i in range(nest_level):
            template += '}'
        return template

    def _get_list_template(self, nest_level):
        template = ""
        for i in range(nest_level):
            template += '[FUZZ'
            if i != nest_level - 1:
                template += ', '
        for i in range(nest_level):
            template += ']'
        return template

def url_path_fuzzer():
    """ URL Path fuzzer that uses static templates """
    URLPATH_TEMPLATES = ['/FUZZ', '/FUZZ/FUZZ', '/FUZZ/FUZZ/FUZZ']
    URLPATH_TOKEN_LIST = ['', '/', '@$%^& ', '%20%25', 'echo', 'echostream']
    return Fuzzer(URLPATH_TEMPLATES, URLPATH_TOKEN_LIST)

def query_param_fuzzer():
    """ URL Path fuzzer that uses static templates """
    QUERYPARAM_TEMPLATES = ['', '#', '#FUZZ', 'FUZZ', 'FUZZ=FUZZ', 'FUZZ&FUZZ']
    QUERYPARAM_TOKEN_LIST = ['', '/', '#', '=', '&', '?', '&?#', '@#$%^=', 'message',
                              'message=msg', '%2F%25%0A%20' ]
    return Fuzzer(QUERYPARAM_TEMPLATES, QUERYPARAM_TOKEN_LIST)

class EspTranscodingFuzzTest(object):
    """ ESP Transcoding Fuzz tests """

    def __init__(self):
        self._conn = esp_utils.http_connection(FLAGS.address, True)
        self._status_conn = esp_utils.http_connection(FLAGS.status_address, True)
        self._initial_status = self._get_status()
        self._total_requests = 0
        self._unexpected_errors = 0

    def _get_status(self):
        self._status_conn.request('GET', '/endpoints_status')
        response = esp_utils.Response(self._status_conn.getresponse())
        status = response.json()
        if len(status['processes']) == 0:
            sys.exit(esp_utils.red('Cloud not get ESP status'))
        return status

    def _check_for_crash(self):
        print "Checking for crashes..."
        current_status = self._get_status()
        initial_processes = self._initial_status['processes']
        current_processes = current_status['processes']
        if len(initial_processes) != len(current_processes):
            sys.exit(esp_utils.red(
                'ESP crashed. Initial & current process numbers do not match.'))
            return
        for i in range(len(initial_processes)):
            if initial_processes[i]['processId'] != current_processes[i]['processId']:
                sys.exit(esp_utils.red(
                    'ESP crashed. Initial & current pids do not match.'))
            if initial_processes[i]['startedAt'] != current_processes[i]['startedAt']:
                sys.exit(esp_utils.red(
                    'ESP crashed. Initial & current start times do not match.'))
        print esp_utils.green('No crashes detected.')

    def _request(self, url_path, query_params, json, expected_codes):
        # Construct the URL using url_path, query_params and the api key
        url = url_path
        if FLAGS.api_key:
            if query_params:
                url = '%s?key=%s&%s' % (url_path, FLAGS.api_key, query_params)
            else:
                url = '%s?key=%s' % (url_path, FLAGS.api_key)
        elif query_params:
            url = '%s?%s' % (url_path, query_params)

        # Prepare headers
        headers = {'Content-Type': 'application/json'}
        if FLAGS.auth_token:
            headers['Authorization'] = 'Bearer ' + FLAGS.auth_token

        self._conn.request('POST', url, json, headers)
        response = esp_utils.Response(self._conn.getresponse())

        # Make sure that the response status code is in 200s, 300s or 400s
        # and that the response payload is valid JSON
        if not response.status_code in expected_codes:
            print esp_utils.red('Invalid status code %d: url=%s, json=%s' % (
                                response.status_code, url, json) )
            self._unexpected_errors += 1
        elif not response.is_json():
            print esp_utils.red('Response is not json: url=%s, json=%s' % (url, json) )
            self._unexpected_errors += 1

        self._total_requests += 1

    def _print_results_so_far(self):
        print 'Fuzz test results so far: total - %d, unexpected errors - %d' % (
            self._total_requests, self._unexpected_errors)

    def _run_json_fuzz_tests(self, url, max_object_nest_level, max_list_nest_level):
        fuzzer = JsonFuzzer(max_object_nest_level, max_list_nest_level)
        fuzzer.run(lambda json: self._request(url, None, json, [200, 400]))

    def _run_query_param_fuzzer(self, url_path):
        fuzzer = query_param_fuzzer()
        fuzzer.run(
            lambda query_params: self._request(url_path, query_params, "{}", [200, 400]))

    def _run_url_path_fuzzer(self):
        fuzzer = url_path_fuzzer()
        # Url path fuzzer generated requests may return 404 Not Found in
        # addition to 200 OK and 400 Bad Request
        fuzzer.run(lambda url_path: self._request(url_path, None, "{}", [200, 400, 404]))

    def _run_fuzz_tests(self):
        print 'Running /echo JSON fuzz tests...'
        self._run_json_fuzz_tests('/echo', 4, 2)
        self._check_for_crash()
        self._print_results_so_far()

        print 'Running /echostream JSON fuzz tests...'
        self._run_json_fuzz_tests('/echostream', 2, 4)
        self._check_for_crash()
        self._print_results_so_far()

        print 'Running /echo query param fuzz tests...'
        self._run_query_param_fuzzer('/echo')
        self._check_for_crash()
        self._print_results_so_far()

        print 'Running URL path fuzz tests...'
        self._run_url_path_fuzzer()
        self._check_for_crash()
        self._print_results_so_far()

    def run_all_tests(self):
        for i in range(FLAGS.runs):
            self._run_fuzz_tests()
        if self._unexpected_errors > 0:
          sys.exit(esp_utils.red('Fuzz test failed.'))
        else:
          print esp_utils.green('Fuzz test passed.')

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--address', help='Deployed ESP HTTP/1.1 address.')
    parser.add_argument('--status_address',
                        help='Address for getting ESP status (/endpoints_status)')
    parser.add_argument('--api_key', help='Project api_key to access service.')
    parser.add_argument('--auth_token', help='Auth token.')
    parser.add_argument('--runs', type=int, default=1, help='Number of runs')
    flags = parser.parse_args(namespace=FLAGS)

    esp_test = EspTranscodingFuzzTest()
    esp_test.run_all_tests()
<|endoftext|>


<commit_before>from django.shortcuts import render, redirect
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.contrib.auth.decorators import permission_required, login_required
from django.contrib.auth.forms import PasswordChangeForm
from django.utils.html import strip_tags

from UserInfo import utils
from UserInfo.models import UserInfo, EditUserInfoForm, PledgeClass

def users(request):
	"""
		Provides the collections of brothers in the house.
		Organizes them based on year and exec positions.
	"""

	# Find out what current year is the senior year grad date.
	senior_year = utils.get_senior_year()

	# Get the execs.  Use try/catch to avoid crashing the site if an exec is missing.
	try:
		sage = User.objects.get(groups__name='Sage')
	except:
		sage = None
	try:
		second = User.objects.get(groups__name='2nd Counselor')
	except:
		second = None
	try:
		third = User.objects.get(groups__name='3rd Counselor')
	except:
		third = None
	try:
		fourth = User.objects.get(groups__name='4th Counselor')
	except:
		fourth = None
	try:
		first = User.objects.get(groups__name='1st Counselor')
	except:
		first = None
	try:
		herald = User.objects.get(groups__name='Herald')
	except:
		herald = None

	# Get the rest of the users.  Exclude pledges or any execs.
	seniors = User.objects.filter(groups__name='Brothers')
	seniors = seniors.filter(userinfo__graduationYear__lte=senior_year).prefetch_related('userinfo').order_by("last_name")

	juniors = User.objects.filter(userinfo__graduationYear=(senior_year + 1)).prefetch_related('userinfo').order_by("last_name")
	juniors = juniors.exclude(groups__name='Pledges')
	juniors = juniors.exclude(groups__name='Alumni')

	sophomores = User.objects.filter(userinfo__graduationYear=(senior_year + 2)).prefetch_related('userinfo').order_by("last_name")
	sophomores = sophomores.exclude(groups__name='Pledges')
	sophomores = sophomores.exclude(groups__name='Alumni')

	freshmen = User.objects.filter(userinfo__graduationYear=(senior_year + 3)).prefetch_related('userinfo').order_by("last_name")
	freshmen = freshmen.exclude(groups__name='Pledges')
	freshmen = freshmen.exclude(groups__name='Alumni')

	# Exclude the execs, if applicable.
	if sage is not None:
		seniors = seniors.exclude(username=sage.username)
		juniors = juniors.exclude(username=sage.username)
		sophomores = sophomores.exclude(username=sage.username)
		freshmen = freshmen.exclude(username=sage.username)

	if second is not None:
		seniors = seniors.exclude(username=second.username)
		juniors = juniors.exclude(username=second.username)
		sophomores = sophomores.exclude(username=second.username)
		freshmen = freshmen.exclude(username=second.username)

	if third is not None:
		seniors = seniors.exclude(username=third.username)
		juniors = juniors.exclude(username=third.username)
		sophomores = sophomores.exclude(username=third.username)
		freshmen = freshmen.exclude(username=third.username)

	if fourth is not None:
		seniors = seniors.exclude(username=fourth.username)
		juniors = juniors.exclude(username=fourth.username)
		sophomores = sophomores.exclude(username=fourth.username)
		freshmen = freshmen.exclude(username=fourth.username)

	if first is not None:
		seniors = seniors.exclude(username=first.username)
		juniors = juniors.exclude(username=first.username)
		sophomores = sophomores.exclude(username=first.username)
		freshmen = freshmen.exclude(username=first.username)

	if herald is not None:
		seniors = seniors.exclude(username=herald.username)
		juniors = juniors.exclude(username=herald.username)
		sophomores = sophomores.exclude(username=herald.username)
		freshmen = freshmen.exclude(username=herald.username)

	context = {
		'sage': sage,
		'second': second,
		'third': third,
		'fourth': fourth,
		'first': first,
		'herald': herald,
		'seniors': seniors,
		'juniors': juniors,
		'sophomores': sophomores,
		'freshmen': freshmen
	}

	return render(request, 'users.html', context)

@permission_required('UserInfo.manage_users', login_url='Secure.views.index')
def add_users(request):
	"""
		Provides a view for adding a user
	"""
	context = {
		'message': []
	}

	if request.method == 'POST':
		add_type = request.POST['type']

		if add_type == "SINGLE":
			to_add = strip_tags(request.POST['username'])
			first_name = strip_tags(request.POST['firstname'])
			last_name = strip_tags(request.POST['lastname'])
			major = strip_tags(request.POST['major'])
			year = strip_tags(request.POST['class'])

			exists = User.objects.filter(username=to_add).count()
			if exists:
				context['message'].append("Username " + to_add + " is taken.")
			else:
				try:
					utils.create_user(to_add, first_name, last_name, major, year)
					context['message'].append("User " + to_add + " successfully added.")
				except:
					context['message'].append("Error adding " + to_add + ".")
	return render(request, 'secure/add_users.html', context)

@permission_required('UserInfo.manage_users', login_url='Secure.views.index')
def manage_users(request):
	"""
		Provides a view to manage all of the users in the system.
	"""

	all_users = User.objects.all().order_by("last_name")

	context = {
		'all_users': all_users
	}

	return render(request, 'secure/manage_users.html', context)

@permission_required('UserInfo.manage_users', login_url='Secure.views.index')
def reset_password(request, user):
	"""
		Resets a single user's password.
	"""

	# TODO: This should be changed over to being a POST request in the future.
	requested_user = User.objects.get(username__exact=user)

	utils.reset_password(requested_user)

	return redirect("UserInfo.views.manage_users")

@login_required
def edit_user(request, user):
	"""
		Provides a view to edit a single user.
	"""
	requested_user = User.objects.get(username__exact=user)
	if (not requested_user == request.user) and not request.user.is_staff:
		return redirect('PubSite.views.permission_denied')
	message = ""
	if request.method == 'POST':
		try:
			form = EditUserInfoForm(request.POST, instance=requested_user.userinfo)
			if form.is_valid():
				form.save()
				message = "Profile successfully updated"
		except UserInfo.DoesNotExist:
			form = EditUserInfoForm(request.POST)
			UserInfo.objects.get_or_create(user=request.user,
			                               pledgeClass=PledgeClass.objects.get(id=request.POST["pledgeClass"]),
			                               phoneNumber=request.POST["phoneNumber"],
			                               major=request.POST["major"],
			                               hometown=request.POST["hometown"],
			                               activities=request.POST["activities"],
			                               interests=request.POST["interests"],
			                               favoriteMemory=request.POST["favoriteMemory"])
			message = "Profile successfully updated"
	else:
		try:
			form = EditUserInfoForm(instance=requested_user.userinfo)
		except UserInfo.DoesNotExist as e:
			form = EditUserInfoForm()

	context = {
		'requested_user': requested_user,
		'form': form,
		'error': form.errors
	}
	if message is not "":
		context['message'] = [message]

	return render(request, 'secure/edit_user.html', context)

@login_required
def change_password(request):
	"""
		Provides a view where a user can change their change_password
	"""

	context = {
		'message': []
	}

	if request.method == 'POST':
		form = PasswordChangeForm(user=request.user, data=request.POST)
		if form.is_valid():
			form.save()
			context['message'].append("Password successfully changed.")
		else:
			context['message'].append("Error changing password.  Check that your passwords match and that your old password is correct.")

	context['form'] = PasswordChangeForm(user=request.user)

	return render(request, 'secure/reset_password.html', context)
<commit_msg>Fixed issue where any staff editing another account's user info from the website view would either: (1) create the staff member's user_info instead if the staff member did not have a user_info yet; or (2) produce an IntegrityError if the staff member already had a user_info;  if the target user did not already have a user_info<commit_after>from django.shortcuts import render, redirect
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.contrib.auth.decorators import permission_required, login_required
from django.contrib.auth.forms import PasswordChangeForm
from django.utils.html import strip_tags

from UserInfo import utils
from UserInfo.models import UserInfo, EditUserInfoForm, PledgeClass

def users(request):
	"""
		Provides the collections of brothers in the house.
		Organizes them based on year and exec positions.
	"""

	# Find out what current year is the senior year grad date.
	senior_year = utils.get_senior_year()

	# Get the execs.  Use try/catch to avoid crashing the site if an exec is missing.
	try:
		sage = User.objects.get(groups__name='Sage')
	except:
		sage = None
	try:
		second = User.objects.get(groups__name='2nd Counselor')
	except:
		second = None
	try:
		third = User.objects.get(groups__name='3rd Counselor')
	except:
		third = None
	try:
		fourth = User.objects.get(groups__name='4th Counselor')
	except:
		fourth = None
	try:
		first = User.objects.get(groups__name='1st Counselor')
	except:
		first = None
	try:
		herald = User.objects.get(groups__name='Herald')
	except:
		herald = None

	# Get the rest of the users.  Exclude pledges or any execs.
	seniors = User.objects.filter(groups__name='Brothers')
	seniors = seniors.filter(userinfo__graduationYear__lte=senior_year).prefetch_related('userinfo').order_by("last_name")

	juniors = User.objects.filter(userinfo__graduationYear=(senior_year + 1)).prefetch_related('userinfo').order_by("last_name")
	juniors = juniors.exclude(groups__name='Pledges')
	juniors = juniors.exclude(groups__name='Alumni')

	sophomores = User.objects.filter(userinfo__graduationYear=(senior_year + 2)).prefetch_related('userinfo').order_by("last_name")
	sophomores = sophomores.exclude(groups__name='Pledges')
	sophomores = sophomores.exclude(groups__name='Alumni')

	freshmen = User.objects.filter(userinfo__graduationYear=(senior_year + 3)).prefetch_related('userinfo').order_by("last_name")
	freshmen = freshmen.exclude(groups__name='Pledges')
	freshmen = freshmen.exclude(groups__name='Alumni')

	# Exclude the execs, if applicable.
	if sage is not None:
		seniors = seniors.exclude(username=sage.username)
		juniors = juniors.exclude(username=sage.username)
		sophomores = sophomores.exclude(username=sage.username)
		freshmen = freshmen.exclude(username=sage.username)

	if second is not None:
		seniors = seniors.exclude(username=second.username)
		juniors = juniors.exclude(username=second.username)
		sophomores = sophomores.exclude(username=second.username)
		freshmen = freshmen.exclude(username=second.username)

	if third is not None:
		seniors = seniors.exclude(username=third.username)
		juniors = juniors.exclude(username=third.username)
		sophomores = sophomores.exclude(username=third.username)
		freshmen = freshmen.exclude(username=third.username)

	if fourth is not None:
		seniors = seniors.exclude(username=fourth.username)
		juniors = juniors.exclude(username=fourth.username)
		sophomores = sophomores.exclude(username=fourth.username)
		freshmen = freshmen.exclude(username=fourth.username)

	if first is not None:
		seniors = seniors.exclude(username=first.username)
		juniors = juniors.exclude(username=first.username)
		sophomores = sophomores.exclude(username=first.username)
		freshmen = freshmen.exclude(username=first.username)

	if herald is not None:
		seniors = seniors.exclude(username=herald.username)
		juniors = juniors.exclude(username=herald.username)
		sophomores = sophomores.exclude(username=herald.username)
		freshmen = freshmen.exclude(username=herald.username)

	context = {
		'sage': sage,
		'second': second,
		'third': third,
		'fourth': fourth,
		'first': first,
		'herald': herald,
		'seniors': seniors,
		'juniors': juniors,
		'sophomores': sophomores,
		'freshmen': freshmen
	}

	return render(request, 'users.html', context)

@permission_required('UserInfo.manage_users', login_url='Secure.views.index')
def add_users(request):
	"""
		Provides a view for adding a user
	"""
	context = {
		'message': []
	}

	if request.method == 'POST':
		add_type = request.POST['type']

		if add_type == "SINGLE":
			to_add = strip_tags(request.POST['username'])
			first_name = strip_tags(request.POST['firstname'])
			last_name = strip_tags(request.POST['lastname'])
			major = strip_tags(request.POST['major'])
			year = strip_tags(request.POST['class'])

			exists = User.objects.filter(username=to_add).count()
			if exists:
				context['message'].append("Username " + to_add + " is taken.")
			else:
				try:
					utils.create_user(to_add, first_name, last_name, major, year)
					context['message'].append("User " + to_add + " successfully added.")
				except:
					context['message'].append("Error adding " + to_add + ".")
	return render(request, 'secure/add_users.html', context)

@permission_required('UserInfo.manage_users', login_url='Secure.views.index')
def manage_users(request):
	"""
		Provides a view to manage all of the users in the system.
	"""

	all_users = User.objects.all().order_by("last_name")

	context = {
		'all_users': all_users
	}

	return render(request, 'secure/manage_users.html', context)

@permission_required('UserInfo.manage_users', login_url='Secure.views.index')
def reset_password(request, user):
	"""
		Resets a single user's password.
	"""

	# TODO: This should be changed over to being a POST request in the future.
	requested_user = User.objects.get(username__exact=user)

	utils.reset_password(requested_user)

	return redirect("UserInfo.views.manage_users")

@login_required
def edit_user(request, user):
	"""
		Provides a view to edit a single user.
	"""
	requested_user = User.objects.get(username__exact=user)
	if (not requested_user == request.user) and not request.user.is_staff:
		return redirect('PubSite.views.permission_denied')
	message = ""
	if request.method == 'POST':
		try:
			form = EditUserInfoForm(request.POST, instance=requested_user.userinfo)
			if form.is_valid():
				form.save()
				message = "Profile successfully updated"
		except UserInfo.DoesNotExist:
			if request.user.is_staff:
				user_to_update = User.objects.get(username=request.META["HTTP_REFERER"].split("/")[-2])
			else:
				user_to_update = request.user
			form = EditUserInfoForm(request.POST)
			UserInfo.objects.get_or_create(user=user_to_update,
			                               pledgeClass=PledgeClass.objects.get(id=request.POST["pledgeClass"]),
			                               phoneNumber=request.POST["phoneNumber"],
			                               major=request.POST["major"],
			                               hometown=request.POST["hometown"],
			                               activities=request.POST["activities"],
			                               interests=request.POST["interests"],
			                               favoriteMemory=request.POST["favoriteMemory"])
			message = "Profile successfully updated"
	else:
		try:
			form = EditUserInfoForm(instance=requested_user.userinfo)
		except UserInfo.DoesNotExist as e:
			form = EditUserInfoForm()

	context = {
		'requested_user': requested_user,
		'form': form,
		'error': form.errors
	}
	if message is not "":
		context['message'] = [message]

	return render(request, 'secure/edit_user.html', context)

@login_required
def change_password(request):
	"""
		Provides a view where a user can change their change_password
	"""

	context = {
		'message': []
	}

	if request.method == 'POST':
		form = PasswordChangeForm(user=request.user, data=request.POST)
		if form.is_valid():
			form.save()
			context['message'].append("Password successfully changed.")
		else:
			context['message'].append("Error changing password.  Check that your passwords match and that your old password is correct.")

	context['form'] = PasswordChangeForm(user=request.user)

	return render(request, 'secure/reset_password.html', context)
<|endoftext|>


<commit_before>from __future__ import print_function
from scipy.constants import mu_0
from SimPEG import *
from SimPEG import Utils
from SimPEG import Mesh
import numpy as np
from SimPEG.Utils import kron3, speye, sdiag
import matplotlib.pyplot as plt

def spheremodel(mesh, x0, y0, z0, r):
    """
        Generate model indicies for sphere
        - (x0, y0, z0 ): is the center location of sphere
        - r: is the radius of the sphere
        - it returns logical indicies of cell-center model
    """
    ind = np.sqrt( (mesh.gridCC[:, 0]-x0)**2+(mesh.gridCC[:, 1]-y0)**2+(mesh.gridCC[:, 2]-z0)**2 ) < r
    return ind

def MagSphereAnaFun(x, y, z, R, x0, y0, z0, mu1, mu2, H0, flag='total'):
    """
        test
        Analytic function for Magnetics problem. The set up here is
        magnetic sphere in whole-space assuming that the inducing field is oriented in the x-direction.

        * (x0, y0, z0)
        * (x0, y0, z0 ): is the center location of sphere
        * r: is the radius of the sphere

    .. math::

        \mathbf{H}_0 = H_0\hat{x}

    """

    if (~np.size(x)==np.size(y)==np.size(z)):
        print("Specify same size of x, y, z")
        return
    dim = x.shape
    x = Utils.mkvc(x)
    y = Utils.mkvc(y)
    z = Utils.mkvc(z)

    ind = np.sqrt((x-x0)**2+(y-y0)**2+(z-z0)**2) < R
    r = Utils.mkvc(np.sqrt((x-x0)**2+(y-y0)**2+(z-z0)**2))
    Bx = np.zeros(x.size)
    By = np.zeros(x.size)
    Bz = np.zeros(x.size)

    # Inside of the sphere
    rf2 = 3*mu1/(mu2+2*mu1)
    if flag is 'total' and any(ind):
        Bx[ind] = mu2*H0*(rf2)
    elif (flag == 'secondary'):
        Bx[ind] = mu2*H0*(rf2)-mu1*H0

    By[ind] = 0.
    Bz[ind] = 0.
    # Outside of the sphere
    rf1 = (mu2-mu1)/(mu2+2*mu1)
    if (flag == 'total'):
        Bx[~ind] = mu1*(H0+H0/r[~ind]**5*(R**3)*rf1*(2*(x[~ind]-x0)**2-(y[~ind]-y0)**2-(z[~ind]-z0)**2))
    elif (flag == 'secondary'):
        Bx[~ind] = mu1*(H0/r[~ind]**5*(R**3)*rf1*(2*(x[~ind]-x0)**2-(y[~ind]-y0)**2-(z[~ind]-z0)**2))

    By[~ind] = mu1*(H0/r[~ind]**5*(R**3)*rf1*(3*(x[~ind]-x0)*(y[~ind]-y0)))
    Bz[~ind] = mu1*(H0/r[~ind]**5*(R**3)*rf1*(3*(x[~ind]-x0)*(z[~ind]-z0)))
    return np.reshape(Bx, x.shape, order='F'), np.reshape(By, x.shape, order='F'), np.reshape(Bz, x.shape, order='F')

def CongruousMagBC(mesh, Bo, chi):
    """Computing boundary condition using Congrous sphere method.
    This is designed for secondary field formulation.

    >> Input

    * mesh:   Mesh class
    * Bo:     np.array([Box, Boy, Boz]): Primary magnetic flux
    * chi:    susceptibility at cell volume

    .. math::

        \\vec{B}(r) = \\frac{\mu_0}{4\pi} \\frac{m}{ \| \\vec{r} - \\vec{r}_0\|^3}[3\hat{m}\cdot\hat{r}-\hat{m}]

    """

    ind = chi > 0.
    V = mesh.vol[ind].sum()

    gamma = 1/V*(chi*mesh.vol).sum()  # like a mass!

    Bot = np.sqrt(sum(Bo**2))
    mx = Bo[0]/Bot
    my = Bo[1]/Bot
    mz = Bo[2]/Bot

    mom = 1/mu_0*Bot*gamma*V/(1+gamma/3)
    xc = sum(chi[ind]*mesh.gridCC[:, 0][ind])/sum(chi[ind])
    yc = sum(chi[ind]*mesh.gridCC[:, 1][ind])/sum(chi[ind])
    zc = sum(chi[ind]*mesh.gridCC[:, 2][ind])/sum(chi[ind])

    indxd, indxu, indyd, indyu, indzd, indzu =  mesh.faceBoundaryInd

    const = mu_0/(4*np.pi)*mom
    rfun = lambda x: np.sqrt((x[:, 0]-xc)**2 + (x[:, 1]-yc)**2 + (x[:, 2]-zc)**2)

    mdotrx = (mx*(mesh.gridFx[(indxd|indxu), 0]-xc)/rfun(mesh.gridFx[(indxd|indxu), :]) +
              my*(mesh.gridFx[(indxd|indxu), 1]-yc)/rfun(mesh.gridFx[(indxd|indxu), :]) +
              mz*(mesh.gridFx[(indxd|indxu), 2]-zc)/rfun(mesh.gridFx[(indxd|indxu), :]))

    Bbcx = const/(rfun(mesh.gridFx[(indxd|indxu), :])**3)*(3*mdotrx*(mesh.gridFx[(indxd|indxu), 0]-xc)/rfun(mesh.gridFx[(indxd|indxu), :])-mx)

    mdotry = (mx*(mesh.gridFy[(indyd|indyu), 0]-xc)/rfun(mesh.gridFy[(indyd|indyu), :]) +
              my*(mesh.gridFy[(indyd|indyu), 1]-yc)/rfun(mesh.gridFy[(indyd|indyu), :]) +
              mz*(mesh.gridFy[(indyd|indyu), 2]-zc)/rfun(mesh.gridFy[(indyd|indyu), :]))

    Bbcy = const/(rfun(mesh.gridFy[(indyd|indyu), :])**3)*(3*mdotry*(mesh.gridFy[(indyd|indyu), 1]-yc)/rfun(mesh.gridFy[(indyd|indyu), :])-my)

    mdotrz = (mx*(mesh.gridFz[(indzd|indzu), 0]-xc)/rfun(mesh.gridFz[(indzd|indzu), :])  +
              my*(mesh.gridFz[(indzd|indzu), 1]-yc)/rfun(mesh.gridFz[(indzd|indzu), :]) +
              mz*(mesh.gridFz[(indzd|indzu), 2]-zc)/rfun(mesh.gridFz[(indzd|indzu), :]))

    Bbcz = const/(rfun(mesh.gridFz[(indzd|indzu), :])**3)*(3*mdotrz*(mesh.gridFz[(indzd|indzu), 2]-zc)/rfun(mesh.gridFz[(indzd|indzu), :])-mz)

    return np.r_[Bbcx, Bbcy, Bbcz], (1/gamma-1/(3+gamma))*1/V

def MagSphereAnaFunA(x, y, z, R, xc, yc, zc, chi, Bo, flag):
    """Computing boundary condition using Congrous sphere method.
    This is designed for secondary field formulation.
    >> Input
    mesh:   Mesh class
    Bo:     np.array([Box, Boy, Boz]): Primary magnetic flux
    Chi:    susceptibility at cell volume

    .. math::

        \\vec{B}(r) = \\frac{\mu_0}{4\pi}\\frac{m}{\| \\vec{r}-\\vec{r}_0\|^3}[3\hat{m}\cdot\hat{r}-\hat{m}]

    """
    if (~np.size(x)==np.size(y)==np.size(z)):
        print("Specify same size of x, y, z")
        return
    dim = x.shape
    x = Utils.mkvc(x)
    y = Utils.mkvc(y)
    z = Utils.mkvc(z)

    Bot = np.sqrt(sum(Bo**2))
    mx = Bo[0]/Bot
    my = Bo[1]/Bot
    mz = Bo[2]/Bot

    ind = np.sqrt((x-xc)**2+(y-yc)**2+(z-zc)**2 ) < R

    Bx = np.zeros(x.size)
    By = np.zeros(x.size)
    Bz = np.zeros(x.size)

    # Inside of the sphere
    rf2 = 3/(chi+3)*(1+chi)
    if (flag == 'total'):
        Bx[ind] = Bo[0]*(rf2)
        By[ind] = Bo[1]*(rf2)
        Bz[ind] = Bo[2]*(rf2)
    elif (flag == 'secondary'):
        Bx[ind] = Bo[0]*(rf2)-Bo[0]
        By[ind] = Bo[1]*(rf2)-Bo[1]
        Bz[ind] = Bo[2]*(rf2)-Bo[2]

    r = Utils.mkvc(np.sqrt((x-xc)**2+(y-yc)**2+(z-zc)**2 ))
    V = 4*np.pi*R**3/3
    mom = Bot/mu_0*chi/(1+chi/3)*V
    const = mu_0/(4*np.pi)*mom
    mdotr = (mx*(x[~ind]-xc)/r[~ind] + my*(y[~ind]-yc)/r[~ind] + mz*(z[~ind]-zc)/r[~ind])
    Bx[~ind] = const/(r[~ind]**3)*(3*mdotr*(x[~ind]-xc)/r[~ind]-mx)
    By[~ind] = const/(r[~ind]**3)*(3*mdotr*(y[~ind]-yc)/r[~ind]-my)
    Bz[~ind] = const/(r[~ind]**3)*(3*mdotr*(z[~ind]-zc)/r[~ind]-mz)

    return Bx, By, Bz

def IDTtoxyz(Inc, Dec, Btot):
    """Convert from Inclination, Declination,
    Total intensity of earth field to x, y, z
    """
    Bx = Btot*np.cos(Inc/180.*np.pi)*np.sin(Dec/180.*np.pi)
    By = Btot*np.cos(Inc/180.*np.pi)*np.cos(Dec/180.*np.pi)
    Bz = -Btot*np.sin(Inc/180.*np.pi)

    return np.r_[Bx, By, Bz]

def MagSphereFreeSpace(x, y, z, R, xc, yc, zc, chi, Bo):
    """Computing the induced response of magnetic sphere in free-space.

    >> Input
    x, y, z:   Observation locations
    R:     radius of the sphere
    xc, yc, zc: Location of the sphere
    chi: Susceptibility of sphere
    Bo: Inducing field components [bx, by, bz]*|H0|
    """
    if (~np.size(x) == np.size(y) == np.size(z)):
        print("Specify same size of x, y, z")
        return

    x = Utils.mkvc(x)
    y = Utils.mkvc(y)
    z = Utils.mkvc(z)

    nobs = len(x)

    Bot = np.sqrt(sum(Bo**2))

    mx = np.ones([nobs]) * Bo[0] * R**3 / 3. * chi
    my = np.ones([nobs]) * Bo[1] * R**3 / 3. * chi
    mz = np.ones([nobs]) * Bo[2] * R**3 / 3. * chi

    M = np.c_[mx, my, mz]

    rx = (x - xc)
    ry = (y - yc)
    rz = (zc - z)

    rvec = np.c_[rx, ry, rz]
    r = np.sqrt((rx)**2+(ry)**2+(rz)**2)

    B = -Utils.sdiag(1./r**3)*M + \
        Utils.sdiag((3 * np.sum(M*rvec, axis=1))/r**5)*rvec

    Bx = B[:, 0]
    By = B[:, 1]
    Bz = B[:, 2]

    return Bx, By, Bz
<commit_msg>Fix test for convention change<commit_after>from __future__ import print_function
from scipy.constants import mu_0
from SimPEG import *
from SimPEG import Utils
from SimPEG import Mesh
import numpy as np
from SimPEG.Utils import kron3, speye, sdiag
import matplotlib.pyplot as plt

def spheremodel(mesh, x0, y0, z0, r):
    """
        Generate model indicies for sphere
        - (x0, y0, z0 ): is the center location of sphere
        - r: is the radius of the sphere
        - it returns logical indicies of cell-center model
    """
    ind = np.sqrt( (mesh.gridCC[:, 0]-x0)**2+(mesh.gridCC[:, 1]-y0)**2+(mesh.gridCC[:, 2]-z0)**2 ) < r
    return ind

def MagSphereAnaFun(x, y, z, R, x0, y0, z0, mu1, mu2, H0, flag='total'):
    """
        test
        Analytic function for Magnetics problem. The set up here is
        magnetic sphere in whole-space assuming that the inducing field is oriented in the x-direction.

        * (x0, y0, z0)
        * (x0, y0, z0 ): is the center location of sphere
        * r: is the radius of the sphere

    .. math::

        \mathbf{H}_0 = H_0\hat{x}

    """

    if (~np.size(x)==np.size(y)==np.size(z)):
        print("Specify same size of x, y, z")
        return
    dim = x.shape
    x = Utils.mkvc(x)
    y = Utils.mkvc(y)
    z = Utils.mkvc(z)

    ind = np.sqrt((x-x0)**2+(y-y0)**2+(z-z0)**2) < R
    r = Utils.mkvc(np.sqrt((x-x0)**2+(y-y0)**2+(z-z0)**2))
    Bx = np.zeros(x.size)
    By = np.zeros(x.size)
    Bz = np.zeros(x.size)

    # Inside of the sphere
    rf2 = 3*mu1/(mu2+2*mu1)
    if flag is 'total' and any(ind):
        Bx[ind] = mu2*H0*(rf2)
    elif (flag == 'secondary'):
        Bx[ind] = mu2*H0*(rf2)-mu1*H0

    By[ind] = 0.
    Bz[ind] = 0.
    # Outside of the sphere
    rf1 = (mu2-mu1)/(mu2+2*mu1)
    if (flag == 'total'):
        Bx[~ind] = mu1*(H0+H0/r[~ind]**5*(R**3)*rf1*(2*(x[~ind]-x0)**2-(y[~ind]-y0)**2-(z[~ind]-z0)**2))
    elif (flag == 'secondary'):
        Bx[~ind] = mu1*(H0/r[~ind]**5*(R**3)*rf1*(2*(x[~ind]-x0)**2-(y[~ind]-y0)**2-(z[~ind]-z0)**2))

    By[~ind] = mu1*(H0/r[~ind]**5*(R**3)*rf1*(3*(x[~ind]-x0)*(y[~ind]-y0)))
    Bz[~ind] = mu1*(H0/r[~ind]**5*(R**3)*rf1*(3*(x[~ind]-x0)*(z[~ind]-z0)))
    return np.reshape(Bx, x.shape, order='F'), np.reshape(By, x.shape, order='F'), np.reshape(Bz, x.shape, order='F')

def CongruousMagBC(mesh, Bo, chi):
    """Computing boundary condition using Congrous sphere method.
    This is designed for secondary field formulation.

    >> Input

    * mesh:   Mesh class
    * Bo:     np.array([Box, Boy, Boz]): Primary magnetic flux
    * chi:    susceptibility at cell volume

    .. math::

        \\vec{B}(r) = \\frac{\mu_0}{4\pi} \\frac{m}{ \| \\vec{r} - \\vec{r}_0\|^3}[3\hat{m}\cdot\hat{r}-\hat{m}]

    """

    ind = chi > 0.
    V = mesh.vol[ind].sum()

    gamma = 1/V*(chi*mesh.vol).sum()  # like a mass!

    Bot = np.sqrt(sum(Bo**2))
    mx = Bo[0]/Bot
    my = Bo[1]/Bot
    mz = Bo[2]/Bot

    mom = 1/mu_0*Bot*gamma*V/(1+gamma/3)
    xc = sum(chi[ind]*mesh.gridCC[:, 0][ind])/sum(chi[ind])
    yc = sum(chi[ind]*mesh.gridCC[:, 1][ind])/sum(chi[ind])
    zc = sum(chi[ind]*mesh.gridCC[:, 2][ind])/sum(chi[ind])

    indxd, indxu, indyd, indyu, indzd, indzu =  mesh.faceBoundaryInd

    const = mu_0/(4*np.pi)*mom
    rfun = lambda x: np.sqrt((x[:, 0]-xc)**2 + (x[:, 1]-yc)**2 + (x[:, 2]-zc)**2)

    mdotrx = (mx*(mesh.gridFx[(indxd|indxu), 0]-xc)/rfun(mesh.gridFx[(indxd|indxu), :]) +
              my*(mesh.gridFx[(indxd|indxu), 1]-yc)/rfun(mesh.gridFx[(indxd|indxu), :]) +
              mz*(mesh.gridFx[(indxd|indxu), 2]-zc)/rfun(mesh.gridFx[(indxd|indxu), :]))

    Bbcx = const/(rfun(mesh.gridFx[(indxd|indxu), :])**3)*(3*mdotrx*(mesh.gridFx[(indxd|indxu), 0]-xc)/rfun(mesh.gridFx[(indxd|indxu), :])-mx)

    mdotry = (mx*(mesh.gridFy[(indyd|indyu), 0]-xc)/rfun(mesh.gridFy[(indyd|indyu), :]) +
              my*(mesh.gridFy[(indyd|indyu), 1]-yc)/rfun(mesh.gridFy[(indyd|indyu), :]) +
              mz*(mesh.gridFy[(indyd|indyu), 2]-zc)/rfun(mesh.gridFy[(indyd|indyu), :]))

    Bbcy = const/(rfun(mesh.gridFy[(indyd|indyu), :])**3)*(3*mdotry*(mesh.gridFy[(indyd|indyu), 1]-yc)/rfun(mesh.gridFy[(indyd|indyu), :])-my)

    mdotrz = (mx*(mesh.gridFz[(indzd|indzu), 0]-xc)/rfun(mesh.gridFz[(indzd|indzu), :])  +
              my*(mesh.gridFz[(indzd|indzu), 1]-yc)/rfun(mesh.gridFz[(indzd|indzu), :]) +
              mz*(mesh.gridFz[(indzd|indzu), 2]-zc)/rfun(mesh.gridFz[(indzd|indzu), :]))

    Bbcz = const/(rfun(mesh.gridFz[(indzd|indzu), :])**3)*(3*mdotrz*(mesh.gridFz[(indzd|indzu), 2]-zc)/rfun(mesh.gridFz[(indzd|indzu), :])-mz)

    return np.r_[Bbcx, Bbcy, Bbcz], (1/gamma-1/(3+gamma))*1/V

def MagSphereAnaFunA(x, y, z, R, xc, yc, zc, chi, Bo, flag):
    """Computing boundary condition using Congrous sphere method.
    This is designed for secondary field formulation.
    >> Input
    mesh:   Mesh class
    Bo:     np.array([Box, Boy, Boz]): Primary magnetic flux
    Chi:    susceptibility at cell volume

    .. math::

        \\vec{B}(r) = \\frac{\mu_0}{4\pi}\\frac{m}{\| \\vec{r}-\\vec{r}_0\|^3}[3\hat{m}\cdot\hat{r}-\hat{m}]

    """
    if (~np.size(x)==np.size(y)==np.size(z)):
        print("Specify same size of x, y, z")
        return
    dim = x.shape
    x = Utils.mkvc(x)
    y = Utils.mkvc(y)
    z = Utils.mkvc(z)

    Bot = np.sqrt(sum(Bo**2))
    mx = Bo[0]/Bot
    my = Bo[1]/Bot
    mz = Bo[2]/Bot

    ind = np.sqrt((x-xc)**2+(y-yc)**2+(z-zc)**2 ) < R

    Bx = np.zeros(x.size)
    By = np.zeros(x.size)
    Bz = np.zeros(x.size)

    # Inside of the sphere
    rf2 = 3/(chi+3)*(1+chi)
    if (flag == 'total'):
        Bx[ind] = Bo[0]*(rf2)
        By[ind] = Bo[1]*(rf2)
        Bz[ind] = Bo[2]*(rf2)
    elif (flag == 'secondary'):
        Bx[ind] = Bo[0]*(rf2)-Bo[0]
        By[ind] = Bo[1]*(rf2)-Bo[1]
        Bz[ind] = Bo[2]*(rf2)-Bo[2]

    r = Utils.mkvc(np.sqrt((x-xc)**2+(y-yc)**2+(z-zc)**2 ))
    V = 4*np.pi*R**3/3
    mom = Bot/mu_0*chi/(1+chi/3)*V
    const = mu_0/(4*np.pi)*mom
    mdotr = (mx*(x[~ind]-xc)/r[~ind] + my*(y[~ind]-yc)/r[~ind] + mz*(z[~ind]-zc)/r[~ind])
    Bx[~ind] = const/(r[~ind]**3)*(3*mdotr*(x[~ind]-xc)/r[~ind]-mx)
    By[~ind] = const/(r[~ind]**3)*(3*mdotr*(y[~ind]-yc)/r[~ind]-my)
    Bz[~ind] = const/(r[~ind]**3)*(3*mdotr*(z[~ind]-zc)/r[~ind]-mz)

    return Bx, By, Bz

def IDTtoxyz(Inc, Dec, Btot):
    """Convert from Inclination, Declination,
    Total intensity of earth field to x, y, z
    """
    Bx = Btot*np.cos(Inc/180.*np.pi)*np.sin(Dec/180.*np.pi)
    By = Btot*np.cos(Inc/180.*np.pi)*np.cos(Dec/180.*np.pi)
    Bz = Btot*np.sin(Inc/180.*np.pi)

    return np.r_[Bx, By, Bz]

def MagSphereFreeSpace(x, y, z, R, xc, yc, zc, chi, Bo):
    """Computing the induced response of magnetic sphere in free-space.

    >> Input
    x, y, z:   Observation locations
    R:     radius of the sphere
    xc, yc, zc: Location of the sphere
    chi: Susceptibility of sphere
    Bo: Inducing field components [bx, by, bz]*|H0|
    """
    if (~np.size(x) == np.size(y) == np.size(z)):
        print("Specify same size of x, y, z")
        return

    x = Utils.mkvc(x)
    y = Utils.mkvc(y)
    z = Utils.mkvc(z)

    nobs = len(x)

    Bot = np.sqrt(sum(Bo**2))

    mx = np.ones([nobs]) * Bo[0] * R**3 / 3. * chi
    my = np.ones([nobs]) * Bo[1] * R**3 / 3. * chi
    mz = np.ones([nobs]) * Bo[2] * R**3 / 3. * chi

    M = np.c_[mx, my, mz]

    rx = (x - xc)
    ry = (y - yc)
    rz = (z - zc)

    rvec = np.c_[rx, ry, rz]
    r = np.sqrt((rx)**2+(ry)**2+(rz)**2)

    B = -Utils.sdiag(1./r**3)*M + \
        Utils.sdiag((3 * np.sum(M*rvec, axis=1))/r**5)*rvec

    Bx = B[:, 0]
    By = B[:, 1]
    Bz = B[:, 2]

    return Bx, By, Bz
<|endoftext|>


<commit_before>"""
    SoftLayer.cci
    ~~~~~~~~~~~~~
    CCI Manager/helpers

    :copyright: (c) 2013, SoftLayer Technologies, Inc. All rights reserved.
    :license: MIT, see LICENSE for more details.
"""
import socket
from time import sleep
from itertools import repeat

from SoftLayer.utils import NestedDict, query_filter, IdentifierMixin, lookup

class CCIManager(IdentifierMixin, object):
    """ Manage CCIs """
    def __init__(self, client):
        #: A valid `SoftLayer.API.Client` object that will be used for all
        #: actions.
        self.client = client
        #: Reference to the SoftLayer_Account API object.
        self.account = client['Account']
        #: Reference to the SoftLayer_Virtual_Guest API object.
        self.guest = client['Virtual_Guest']
        #: A list of resolver functions. Used primarily by the CLI to provide
        #: a variety of methods for uniquely identifying an object such as
        #: hostname and IP address.
        self.resolvers = [self._get_ids_from_ip, self._get_ids_from_hostname]

    def list_instances(self, hourly=True, monthly=True, tags=None, cpus=None,
                       memory=None, hostname=None, domain=None,
                       local_disk=None, datacenter=None, nic_speed=None,
                       public_ip=None, private_ip=None, **kwargs):
        """ Retrieve a list of all CCIs on the account.

        :param boolean hourly: include hourly instances
        :param boolean monthly: include monthly instances
        :param list tags: filter based on tags
        :param integer cpus: filter based on number of CPUS
        :param integer memory: filter based on amount of memory
        :param string hostname: filter based on hostname
        :param string domain: filter based on domain
        :param string local_disk: filter based on local_disk
        :param string datacenter: filter based on datacenter
        :param integer nic_speed: filter based on network speed (in MBPS)
        :param string public_ip: filter based on public ip address
        :param string private_ip: filter based on private ip address
        :param dict \*\*kwargs: response-level arguments (limit, offset, etc.)
        :returns: Returns a list of dictionaries representing the matching CCIs

        ::

           # Print out a list of all hourly CCIs in the DAL05 data center.
           # env variables
           # SL_USERNAME = YOUR_USERNAME
           # SL_API_KEY = YOUR_API_KEY
           import SoftLayer
           client = SoftLayer.Client()

           mgr = SoftLayer.CCIManager(client)
           for cci in mgr.list_instances(hourly=True, datacenter='dal05'):
               print cci['fullyQualifiedDomainName'], cci['primaryIpAddress']

        """
        if 'mask' not in kwargs:
            items = set([
                'id',
                'globalIdentifier',
                'hostname',
                'domain',
                'fullyQualifiedDomainName',
                'primaryBackendIpAddress',
                'primaryIpAddress',
                'lastKnownPowerState.name',
                'powerState',
                'maxCpu',
                'maxMemory',
                'datacenter',
                'activeTransaction.transactionStatus[friendlyName,name]',
                'status',
            ])
            kwargs['mask'] = "mask[%s]" % ','.join(items)

        call = 'getVirtualGuests'
        if not all([hourly, monthly]):
            if hourly:
                call = 'getHourlyVirtualGuests'
            elif monthly:
                call = 'getMonthlyVirtualGuests'

        _filter = NestedDict(kwargs.get('filter') or {})
        if tags:
            _filter['virtualGuests']['tagReferences']['tag']['name'] = {
                'operation': 'in',
                'options': [{'name': 'data', 'value': tags}],
            }

        if cpus:
            _filter['virtualGuests']['maxCpu'] = query_filter(cpus)

        if memory:
            _filter['virtualGuests']['maxMemory'] = query_filter(memory)

        if hostname:
            _filter['virtualGuests']['hostname'] = query_filter(hostname)

        if domain:
            _filter['virtualGuests']['domain'] = query_filter(domain)

        if local_disk is not None:
            _filter['virtualGuests']['localDiskFlag'] = \
                query_filter(bool(local_disk))

        if datacenter:
            _filter['virtualGuests']['datacenter']['name'] = \
                query_filter(datacenter)

        if nic_speed:
            _filter['virtualGuests']['networkComponents']['maxSpeed'] = \
                query_filter(nic_speed)

        if public_ip:
            _filter['virtualGuests']['primaryIpAddress'] = \
                query_filter(public_ip)

        if private_ip:
            _filter['virtualGuests']['primaryBackendIpAddress'] = \
                query_filter(private_ip)

        kwargs['filter'] = _filter.to_dict()
        func = getattr(self.account, call)
        return func(**kwargs)

    def get_instance(self, instance_id, **kwargs):
        """ Get details about a CCI instance

        :param integer instance_id: the instance ID
        :returns: A dictionary containing a large amount of information about
                  the specified instance.

        """

        if 'mask' not in kwargs:
            items = set([
                'id',
                'globalIdentifier',
                'fullyQualifiedDomainName',
                'hostname',
                'domain',
                'createDate',
                'modifyDate',
                'provisionDate',
                'notes',
                'dedicatedAccountHostOnlyFlag',
                'privateNetworkOnlyFlag',
                'primaryBackendIpAddress',
                'primaryIpAddress',
                'networkComponents[id, status, speed, maxSpeed, name,'
                'macAddress, primaryIpAddress, port, primarySubnet]',
                'lastKnownPowerState.name',
                'powerState',
                'status',
                'maxCpu',
                'maxMemory',
                'datacenter',
                'activeTransaction[id, transactionStatus[friendlyName,name]]',
                'lastOperatingSystemReload.id',
                'blockDevices',
                'blockDeviceTemplateGroup[id, name, globalIdentifier]',
                'postInstallScriptUri',
                'userData',
                'operatingSystem.softwareLicense.'
                'softwareDescription[manufacturer,name,version,referenceCode]',
                'operatingSystem.passwords[username,password]',
                'hourlyBillingFlag',
                'billingItem.recurringFee',
                'tagReferences[id,tag[name,id]]',
                'networkVlans[id,vlanNumber,networkSpace]',
            ])
            kwargs['mask'] = "mask[%s]" % ','.join(items)

        return self.guest.getObject(id=instance_id, **kwargs)

    def get_create_options(self):
        """ Retrieves the available options for creating a CCI.

        :returns: A dictionary of creation options.

        """
        return self.guest.getCreateObjectOptions()

    def cancel_instance(self, instance_id):
        """ Cancel an instance immediately, deleting all its data.

        :param integer instance_id: the instance ID to cancel

        """
        return self.guest.deleteObject(id=instance_id)

    def reload_instance(self, instance_id, post_uri=None, ssh_keys=None):
        """ Perform an OS reload of an instance with its current configuration.

        :param integer instance_id: the instance ID to reload
        :param string post_url: The URI of the post-install script to run
                                after reload
        :param list ssh_keys: The SSH keys to add to the root user
        """
        payload = {
            'token': 'FORCE',
            'config': {},
        }

        if post_uri:
            payload['config']['customProvisionScriptUri'] = post_uri

        if ssh_keys:
            payload['config']['sshKeyIds'] = [key_id for key_id in ssh_keys]

        return self.guest.reloadOperatingSystem('FORCE', payload['config'],
                                                id=instance_id)

    def _generate_create_dict(
            self, cpus=None, memory=None, hourly=True,
            hostname=None, domain=None, local_disk=True,
            datacenter=None, os_code=None, image_id=None,
            dedicated=False, public_vlan=None, private_vlan=None,
            userdata=None, nic_speed=None, disks=None, post_uri=None,
            private=False, ssh_keys=None):
        """
        Translates a list of arguments into a dictionary necessary for creating
        a CCI.

        :param int cpus: The number of virtual CPUs to include in the instance.
        :param int memory: The amount of RAM to order.
        :param bool hourly: Flag to indicate if this server should be billed
                            hourly (default) or monthly.
        :param string hostname: The hostname to use for the new server.
        :param string domain: The domain to use for the new server.
        :param bool local_disk: Flag to indicate if this should be a local disk
                                (default) or a SAN disk.
        :param string datacenter: The short name of the data center in which
                                  the CCI should reside.
        :param string os_code: The operating system to use. Cannot be specified
                               if image_id is specified.
        :param int image_id: The ID of the image to load onto the server.
                             Cannot be specified if os_code is specified.
        :param bool dedicated: Flag to indicate if this should be housed on a
                               dedicated or shared host (default). This will
                               incur a fee on your account.
        :param int public_vlan: The ID of the public VLAN on which you want
                                this CCI placed.
        :param int private_vlan: The ID of the public VLAN on which you want
                                 this CCI placed.
        :param bool bare_metal: Flag to indicate if this is a bare metal server
                                or a dedicated server (default).
        :param list disks: A list of disk capacities for this server.
        :param string post_url: The URI of the post-install script to run
                                after reload
        :param bool private: If true, the CCI will be provisioned only with
                             access to the private network. Defaults to false
        :param list ssh_keys: The SSH keys to add to the root user
        """

        required = [cpus, memory, hostname, domain]

        mutually_exclusive = [
            {'os_code': os_code, "image_id": image_id},
        ]

        if not all(required):
            raise ValueError("cpu, memory, hostname, and domain are required")

        for me in mutually_exclusive:
            if all(me.values()):
                raise ValueError(
                    'Can only specify one of: %s' % (','.join(me.keys())))

        data = {
            "startCpus": int(cpus),
            "maxMemory": int(memory),
            "hostname": hostname,
            "domain": domain,
            "localDiskFlag": local_disk,
        }

        data["hourlyBillingFlag"] = hourly

        if dedicated:
            data["dedicatedAccountHostOnlyFlag"] = dedicated

        if private:
            data['privateNetworkOnlyFlag'] = private

        if image_id:
            data["blockDeviceTemplateGroup"] = {"globalIdentifier": image_id}
        elif os_code:
            data["operatingSystemReferenceCode"] = os_code

        if datacenter:
            data["datacenter"] = {"name": datacenter}

        if public_vlan:
            data.update({
                'primaryNetworkComponent': {
                    "networkVlan": {"id": int(public_vlan)}}})
        if private_vlan:
            data.update({
                "primaryBackendNetworkComponent": {
                    "networkVlan": {"id": int(private_vlan)}}})

        if userdata:
            data['userData'] = [{'value': userdata}]

        if nic_speed:
            data['networkComponents'] = [{'maxSpeed': nic_speed}]

        if disks and isinstance(disks, list):
            data['blockDevices'] = [
                {"device": "0", "diskImage": {"capacity": disks[0]}}
            ]

            for dev_id, disk in enumerate(disks[1:], start=2):
                data['blockDevices'].append(
                    {
                        "device": str(dev_id),
                        "diskImage": {"capacity": disk}
                    }
                )

        if post_uri:
            data['postInstallScriptUri'] = post_uri

        if ssh_keys:
            data['sshKeys'] = [{'id': key_id} for key_id in ssh_keys]

        return data

    def wait_for_transaction(self, instance_id, limit, delay=1):
        """ Waits on a CCI transaction for the specified amount of time.
        is really just a wrapper for wait_for_ready(pending=True).
        Provided for backwards compatibility.

        :param int instance_id: The instance ID with the pending transaction
        :param int limit: The maximum amount of time to wait.
        :param int delay: The number of seconds to sleep before checks.
                          Defaults to 1.
        """

        return self.wait_for_ready(instance_id, limit, delay=delay,
                                   pending=True)

    def wait_for_ready(self, instance_id, limit, delay=1, pending=False):
        """ Determine if a CCI is ready and available.  In some cases
        though, that can mean that no transactions are running.

        :param int instance_id: The instance ID with the pending transaction
        :param int limit: The maximum amount of time to wait.
        :param int delay: The number of seconds to sleep before checks.
                          Defaults to 1.
        :param bool pending: Wait for pending transactions not related to
                             provisioning or reloads such as monitoring.
        """
        for count, new_instance in enumerate(repeat(instance_id)):
            instance = self.get_instance(new_instance)
            last_reload = lookup(instance, 'lastOperatingSystemReload', 'id')
            active_transaction = lookup(instance, 'activeTransaction', 'id')

            reloading = all((
                active_transaction,
                last_reload,
                last_reload == active_transaction
            ))

            # only check for outstanding transactions if requested
            outstanding = False
            if pending:
                outstanding = active_transaction

            # return True if the instance has only if the instance has
            # finished provisioning and isn't currently reloading the OS.
            if instance.get('provisionDate') \
                    and not reloading and not outstanding:
                return True

            if count >= limit:
                return False

            sleep(delay)

    def verify_create_instance(self, **kwargs):
        """ Verifies an instance creation command without actually placing an
        order. See :func:`_generate_create_dict` for a list of available
        options. """
        create_options = self._generate_create_dict(**kwargs)
        return self.guest.generateOrderTemplate(create_options)

    def create_instance(self, **kwargs):
        """ Orders a new instance. See :func:`_generate_create_dict` for
        a list of available options. """
        create_options = self._generate_create_dict(**kwargs)
        return self.guest.createObject(create_options)

    def change_port_speed(self, instance_id, public, speed):
        """ Allows you to change the port speed of a CCI's NICs.

        :param int instance_id: The ID of the CCI
        :param bool public: Flag to indicate which interface to change.
                            True (default) means the public interface.
                            False indicates the private interface.
        :param int speed: The port speed to set.
        """
        if public:
            func = self.guest.setPublicNetworkInterfaceSpeed
        else:
            func = self.guest.setPrivateNetworkInterfaceSpeed

        return func(speed, id=instance_id)

    def _get_ids_from_hostname(self, hostname):
        results = self.list_instances(hostname=hostname, mask="id")
        return [result['id'] for result in results]

    def _get_ids_from_ip(self, ip):
        try:
            # Does it look like an ip address?
            socket.inet_aton(ip)
        except socket.error:
            return []

        # Find the CCI via ip address. First try public ip, then private
        results = self.list_instances(public_ip=ip, mask="id")
        if results:
            return [result['id'] for result in results]

        results = self.list_instances(private_ip=ip, mask="id")
        if results:
            return [result['id'] for result in results]

    def edit(self, instance_id, userdata=None, hostname=None, domain=None,
             notes=None):
        """ Edit hostname, domain name, notes, and/or the user data of a CCI

        Parameters set to None will be ignored and not attempted to be updated.

        :param integer instance_id: the instance ID to edit
        :param string userdata: user data on CCI to edit.
                                If none exist it will be created
        :param string hostname: valid hostname
        :param string domain: valid domain namem
        :param string notes: notes about this particular CCI

        """

        obj = {}
        if userdata:
            self.guest.setUserMetadata([userdata], id=instance_id)

        if hostname:
            obj['hostname'] = hostname

        if domain:
            obj['domain'] = domain

        if notes:
            obj['notes'] = notes

        if not obj:
            return True

        return self.guest.editObject(obj, id=instance_id)
<commit_msg>Adds more clarify on the pending flag<commit_after>"""
    SoftLayer.cci
    ~~~~~~~~~~~~~
    CCI Manager/helpers

    :copyright: (c) 2013, SoftLayer Technologies, Inc. All rights reserved.
    :license: MIT, see LICENSE for more details.
"""
import socket
from time import sleep
from itertools import repeat

from SoftLayer.utils import NestedDict, query_filter, IdentifierMixin, lookup

class CCIManager(IdentifierMixin, object):
    """ Manage CCIs """
    def __init__(self, client):
        #: A valid `SoftLayer.API.Client` object that will be used for all
        #: actions.
        self.client = client
        #: Reference to the SoftLayer_Account API object.
        self.account = client['Account']
        #: Reference to the SoftLayer_Virtual_Guest API object.
        self.guest = client['Virtual_Guest']
        #: A list of resolver functions. Used primarily by the CLI to provide
        #: a variety of methods for uniquely identifying an object such as
        #: hostname and IP address.
        self.resolvers = [self._get_ids_from_ip, self._get_ids_from_hostname]

    def list_instances(self, hourly=True, monthly=True, tags=None, cpus=None,
                       memory=None, hostname=None, domain=None,
                       local_disk=None, datacenter=None, nic_speed=None,
                       public_ip=None, private_ip=None, **kwargs):
        """ Retrieve a list of all CCIs on the account.

        :param boolean hourly: include hourly instances
        :param boolean monthly: include monthly instances
        :param list tags: filter based on tags
        :param integer cpus: filter based on number of CPUS
        :param integer memory: filter based on amount of memory
        :param string hostname: filter based on hostname
        :param string domain: filter based on domain
        :param string local_disk: filter based on local_disk
        :param string datacenter: filter based on datacenter
        :param integer nic_speed: filter based on network speed (in MBPS)
        :param string public_ip: filter based on public ip address
        :param string private_ip: filter based on private ip address
        :param dict \*\*kwargs: response-level arguments (limit, offset, etc.)
        :returns: Returns a list of dictionaries representing the matching CCIs

        ::

           # Print out a list of all hourly CCIs in the DAL05 data center.
           # env variables
           # SL_USERNAME = YOUR_USERNAME
           # SL_API_KEY = YOUR_API_KEY
           import SoftLayer
           client = SoftLayer.Client()

           mgr = SoftLayer.CCIManager(client)
           for cci in mgr.list_instances(hourly=True, datacenter='dal05'):
               print cci['fullyQualifiedDomainName'], cci['primaryIpAddress']

        """
        if 'mask' not in kwargs:
            items = set([
                'id',
                'globalIdentifier',
                'hostname',
                'domain',
                'fullyQualifiedDomainName',
                'primaryBackendIpAddress',
                'primaryIpAddress',
                'lastKnownPowerState.name',
                'powerState',
                'maxCpu',
                'maxMemory',
                'datacenter',
                'activeTransaction.transactionStatus[friendlyName,name]',
                'status',
            ])
            kwargs['mask'] = "mask[%s]" % ','.join(items)

        call = 'getVirtualGuests'
        if not all([hourly, monthly]):
            if hourly:
                call = 'getHourlyVirtualGuests'
            elif monthly:
                call = 'getMonthlyVirtualGuests'

        _filter = NestedDict(kwargs.get('filter') or {})
        if tags:
            _filter['virtualGuests']['tagReferences']['tag']['name'] = {
                'operation': 'in',
                'options': [{'name': 'data', 'value': tags}],
            }

        if cpus:
            _filter['virtualGuests']['maxCpu'] = query_filter(cpus)

        if memory:
            _filter['virtualGuests']['maxMemory'] = query_filter(memory)

        if hostname:
            _filter['virtualGuests']['hostname'] = query_filter(hostname)

        if domain:
            _filter['virtualGuests']['domain'] = query_filter(domain)

        if local_disk is not None:
            _filter['virtualGuests']['localDiskFlag'] = \
                query_filter(bool(local_disk))

        if datacenter:
            _filter['virtualGuests']['datacenter']['name'] = \
                query_filter(datacenter)

        if nic_speed:
            _filter['virtualGuests']['networkComponents']['maxSpeed'] = \
                query_filter(nic_speed)

        if public_ip:
            _filter['virtualGuests']['primaryIpAddress'] = \
                query_filter(public_ip)

        if private_ip:
            _filter['virtualGuests']['primaryBackendIpAddress'] = \
                query_filter(private_ip)

        kwargs['filter'] = _filter.to_dict()
        func = getattr(self.account, call)
        return func(**kwargs)

    def get_instance(self, instance_id, **kwargs):
        """ Get details about a CCI instance

        :param integer instance_id: the instance ID
        :returns: A dictionary containing a large amount of information about
                  the specified instance.

        """

        if 'mask' not in kwargs:
            items = set([
                'id',
                'globalIdentifier',
                'fullyQualifiedDomainName',
                'hostname',
                'domain',
                'createDate',
                'modifyDate',
                'provisionDate',
                'notes',
                'dedicatedAccountHostOnlyFlag',
                'privateNetworkOnlyFlag',
                'primaryBackendIpAddress',
                'primaryIpAddress',
                'networkComponents[id, status, speed, maxSpeed, name,'
                'macAddress, primaryIpAddress, port, primarySubnet]',
                'lastKnownPowerState.name',
                'powerState',
                'status',
                'maxCpu',
                'maxMemory',
                'datacenter',
                'activeTransaction[id, transactionStatus[friendlyName,name]]',
                'lastOperatingSystemReload.id',
                'blockDevices',
                'blockDeviceTemplateGroup[id, name, globalIdentifier]',
                'postInstallScriptUri',
                'userData',
                'operatingSystem.softwareLicense.'
                'softwareDescription[manufacturer,name,version,referenceCode]',
                'operatingSystem.passwords[username,password]',
                'hourlyBillingFlag',
                'billingItem.recurringFee',
                'tagReferences[id,tag[name,id]]',
                'networkVlans[id,vlanNumber,networkSpace]',
            ])
            kwargs['mask'] = "mask[%s]" % ','.join(items)

        return self.guest.getObject(id=instance_id, **kwargs)

    def get_create_options(self):
        """ Retrieves the available options for creating a CCI.

        :returns: A dictionary of creation options.

        """
        return self.guest.getCreateObjectOptions()

    def cancel_instance(self, instance_id):
        """ Cancel an instance immediately, deleting all its data.

        :param integer instance_id: the instance ID to cancel

        """
        return self.guest.deleteObject(id=instance_id)

    def reload_instance(self, instance_id, post_uri=None, ssh_keys=None):
        """ Perform an OS reload of an instance with its current configuration.

        :param integer instance_id: the instance ID to reload
        :param string post_url: The URI of the post-install script to run
                                after reload
        :param list ssh_keys: The SSH keys to add to the root user
        """
        payload = {
            'token': 'FORCE',
            'config': {},
        }

        if post_uri:
            payload['config']['customProvisionScriptUri'] = post_uri

        if ssh_keys:
            payload['config']['sshKeyIds'] = [key_id for key_id in ssh_keys]

        return self.guest.reloadOperatingSystem('FORCE', payload['config'],
                                                id=instance_id)

    def _generate_create_dict(
            self, cpus=None, memory=None, hourly=True,
            hostname=None, domain=None, local_disk=True,
            datacenter=None, os_code=None, image_id=None,
            dedicated=False, public_vlan=None, private_vlan=None,
            userdata=None, nic_speed=None, disks=None, post_uri=None,
            private=False, ssh_keys=None):
        """
        Translates a list of arguments into a dictionary necessary for creating
        a CCI.

        :param int cpus: The number of virtual CPUs to include in the instance.
        :param int memory: The amount of RAM to order.
        :param bool hourly: Flag to indicate if this server should be billed
                            hourly (default) or monthly.
        :param string hostname: The hostname to use for the new server.
        :param string domain: The domain to use for the new server.
        :param bool local_disk: Flag to indicate if this should be a local disk
                                (default) or a SAN disk.
        :param string datacenter: The short name of the data center in which
                                  the CCI should reside.
        :param string os_code: The operating system to use. Cannot be specified
                               if image_id is specified.
        :param int image_id: The ID of the image to load onto the server.
                             Cannot be specified if os_code is specified.
        :param bool dedicated: Flag to indicate if this should be housed on a
                               dedicated or shared host (default). This will
                               incur a fee on your account.
        :param int public_vlan: The ID of the public VLAN on which you want
                                this CCI placed.
        :param int private_vlan: The ID of the public VLAN on which you want
                                 this CCI placed.
        :param bool bare_metal: Flag to indicate if this is a bare metal server
                                or a dedicated server (default).
        :param list disks: A list of disk capacities for this server.
        :param string post_url: The URI of the post-install script to run
                                after reload
        :param bool private: If true, the CCI will be provisioned only with
                             access to the private network. Defaults to false
        :param list ssh_keys: The SSH keys to add to the root user
        """

        required = [cpus, memory, hostname, domain]

        mutually_exclusive = [
            {'os_code': os_code, "image_id": image_id},
        ]

        if not all(required):
            raise ValueError("cpu, memory, hostname, and domain are required")

        for me in mutually_exclusive:
            if all(me.values()):
                raise ValueError(
                    'Can only specify one of: %s' % (','.join(me.keys())))

        data = {
            "startCpus": int(cpus),
            "maxMemory": int(memory),
            "hostname": hostname,
            "domain": domain,
            "localDiskFlag": local_disk,
        }

        data["hourlyBillingFlag"] = hourly

        if dedicated:
            data["dedicatedAccountHostOnlyFlag"] = dedicated

        if private:
            data['privateNetworkOnlyFlag'] = private

        if image_id:
            data["blockDeviceTemplateGroup"] = {"globalIdentifier": image_id}
        elif os_code:
            data["operatingSystemReferenceCode"] = os_code

        if datacenter:
            data["datacenter"] = {"name": datacenter}

        if public_vlan:
            data.update({
                'primaryNetworkComponent': {
                    "networkVlan": {"id": int(public_vlan)}}})
        if private_vlan:
            data.update({
                "primaryBackendNetworkComponent": {
                    "networkVlan": {"id": int(private_vlan)}}})

        if userdata:
            data['userData'] = [{'value': userdata}]

        if nic_speed:
            data['networkComponents'] = [{'maxSpeed': nic_speed}]

        if disks and isinstance(disks, list):
            data['blockDevices'] = [
                {"device": "0", "diskImage": {"capacity": disks[0]}}
            ]

            for dev_id, disk in enumerate(disks[1:], start=2):
                data['blockDevices'].append(
                    {
                        "device": str(dev_id),
                        "diskImage": {"capacity": disk}
                    }
                )

        if post_uri:
            data['postInstallScriptUri'] = post_uri

        if ssh_keys:
            data['sshKeys'] = [{'id': key_id} for key_id in ssh_keys]

        return data

    def wait_for_transaction(self, instance_id, limit, delay=1):
        """ Waits on a CCI transaction for the specified amount of time.
        is really just a wrapper for wait_for_ready(pending=True).
        Provided for backwards compatibility.

        :param int instance_id: The instance ID with the pending transaction
        :param int limit: The maximum amount of time to wait.
        :param int delay: The number of seconds to sleep before checks.
                          Defaults to 1.
        """

        return self.wait_for_ready(instance_id, limit, delay=delay,
                                   pending=True)

    def wait_for_ready(self, instance_id, limit, delay=1, pending=False):
        """ Determine if a CCI is ready and available.  In some cases
        though, that can mean that no transactions are running. The default
        arguments imply a CCI is usable from an operational and
        ready for use: having network connectivity and remote access is
        available.  Setting ``pending=True`` will ensure future API calls
        against this instance will not error out due to pending
        transactions such as OS Reloads and cancellations.

        :param int instance_id: The instance ID with the pending transaction
        :param int limit: The maximum amount of time to wait.
        :param int delay: The number of seconds to sleep before checks.
                          Defaults to 1.
        :param bool pending: Wait for pending transactions not related to
                             provisioning or reloads such as monitoring.
        """
        for count, new_instance in enumerate(repeat(instance_id)):
            instance = self.get_instance(new_instance)
            last_reload = lookup(instance, 'lastOperatingSystemReload', 'id')
            active_transaction = lookup(instance, 'activeTransaction', 'id')

            reloading = all((
                active_transaction,
                last_reload,
                last_reload == active_transaction
            ))

            # only check for outstanding transactions if requested
            outstanding = False
            if pending:
                outstanding = active_transaction

            # return True if the instance has only if the instance has
            # finished provisioning and isn't currently reloading the OS.
            if instance.get('provisionDate') \
                    and not reloading and not outstanding:
                return True

            if count >= limit:
                return False

            sleep(delay)

    def verify_create_instance(self, **kwargs):
        """ Verifies an instance creation command without actually placing an
        order. See :func:`_generate_create_dict` for a list of available
        options. """
        create_options = self._generate_create_dict(**kwargs)
        return self.guest.generateOrderTemplate(create_options)

    def create_instance(self, **kwargs):
        """ Orders a new instance. See :func:`_generate_create_dict` for
        a list of available options. """
        create_options = self._generate_create_dict(**kwargs)
        return self.guest.createObject(create_options)

    def change_port_speed(self, instance_id, public, speed):
        """ Allows you to change the port speed of a CCI's NICs.

        :param int instance_id: The ID of the CCI
        :param bool public: Flag to indicate which interface to change.
                            True (default) means the public interface.
                            False indicates the private interface.
        :param int speed: The port speed to set.
        """
        if public:
            func = self.guest.setPublicNetworkInterfaceSpeed
        else:
            func = self.guest.setPrivateNetworkInterfaceSpeed

        return func(speed, id=instance_id)

    def _get_ids_from_hostname(self, hostname):
        results = self.list_instances(hostname=hostname, mask="id")
        return [result['id'] for result in results]

    def _get_ids_from_ip(self, ip):
        try:
            # Does it look like an ip address?
            socket.inet_aton(ip)
        except socket.error:
            return []

        # Find the CCI via ip address. First try public ip, then private
        results = self.list_instances(public_ip=ip, mask="id")
        if results:
            return [result['id'] for result in results]

        results = self.list_instances(private_ip=ip, mask="id")
        if results:
            return [result['id'] for result in results]

    def edit(self, instance_id, userdata=None, hostname=None, domain=None,
             notes=None):
        """ Edit hostname, domain name, notes, and/or the user data of a CCI

        Parameters set to None will be ignored and not attempted to be updated.

        :param integer instance_id: the instance ID to edit
        :param string userdata: user data on CCI to edit.
                                If none exist it will be created
        :param string hostname: valid hostname
        :param string domain: valid domain namem
        :param string notes: notes about this particular CCI

        """

        obj = {}
        if userdata:
            self.guest.setUserMetadata([userdata], id=instance_id)

        if hostname:
            obj['hostname'] = hostname

        if domain:
            obj['domain'] = domain

        if notes:
            obj['notes'] = notes

        if not obj:
            return True

        return self.guest.editObject(obj, id=instance_id)
<|endoftext|>