Exemplo n.º 1
0
 def test_request_from_http(self):
     # We can't just call self.make_file because HTTPServerFixture will only
     # serve content from the current WD. And we don't want to create random
     # content in the original WD.
     self.useFixture(TempWDFixture())
     name = factory.getRandomString()
     content = factory.getRandomString().encode('ascii')
     factory.make_file(location='.', name=name, contents=content)
     with HTTPServerFixture() as httpd:
         url = urljoin(httpd.url, name)
         response = MAASDispatcher().dispatch_query(url, {})
         self.assertEqual(200, response.code)
         self.assertEqual(content, response.read())
Exemplo n.º 2
0
 def test_request_from_http(self):
     # We can't just call self.make_file because HTTPServerFixture will only
     # serve content from the current WD. And we don't want to create random
     # content in the original WD.
     self.useFixture(TempWDFixture())
     name = factory.getRandomString()
     content = factory.getRandomString().encode('ascii')
     factory.make_file(location='.', name=name, contents=content)
     with HTTPServerFixture() as httpd:
         url = urljoin(httpd.url, name)
         response = MAASDispatcher().dispatch_query(url, {})
         self.assertEqual(200, response.code)
         self.assertEqual(content, response.read())
Exemplo n.º 3
0
 def test_no_autodetects_proxies(self):
     self.open_func = lambda *args: MagicMock()
     url = factory.make_url()
     proxy_variables = {
         "http_proxy": "http://proxy.example.com",
         "https_proxy": "https://proxy.example.com",
         "no_proxy": "noproxy.example.com",
     }
     with patch.dict(os.environ, proxy_variables):
         dispatcher = MAASDispatcher(autodetect_proxies=False)
         dispatcher.dispatch_query(url, {}, method="GET")
     for handler in self.opener.handle_open["http"]:
         if isinstance(handler, urllib.request.ProxyHandler):
             raise AssertionError("ProxyHandler shouldn't be there")
Exemplo n.º 4
0
def evaluate_tag(
    system_id,
    nodes,
    tag_name,
    tag_definition,
    tag_nsmap,
    credentials,
    maas_url,
):
    """Evaluate `tag_definition` against this cluster's nodes' details.

    :param system_id: System ID for the rack controller.
    :param nodes: List of nodes to evaluate.
    :param tag_name: The name of the tag, used for logging.
    :param tag_definition: The XPath expression of the tag.
    :param tag_nsmap: The namespace map as used by LXML's ETree library.
    :param credentials: A 3-tuple of OAuth credentials.
    :param maas_url: URL of the MAAS API.
    """
    # Turn off proxy detection, since the rack should talk directly to
    # the region, even if a system-wide proxy is configured.
    client = MAASClient(
        auth=MAASOAuth(*credentials),
        dispatcher=MAASDispatcher(autodetect_proxies=False),
        base_url=maas_url,
    )
    process_node_tags(
        rack_id=system_id,
        nodes=nodes,
        tag_name=tag_name,
        tag_definition=tag_definition,
        tag_nsmap=tag_nsmap,
        client=client,
    )
Exemplo n.º 5
0
def evaluate_tag(
    system_id,
    nodes,
    tag_name,
    tag_definition,
    tag_nsmap,
    credentials,
    maas_url,
):
    """Evaluate `tag_definition` against this cluster's nodes' details.

    :param system_id: System ID for the rack controller.
    :param nodes: List of nodes to evaluate.
    :param tag_name: The name of the tag, used for logging.
    :param tag_definition: The XPath expression of the tag.
    :param tag_nsmap: The namespace map as used by LXML's ETree library.
    :param credentials: A 3-tuple of OAuth credentials.
    :param maas_url: URL of the MAAS API.
    """
    client = MAASClient(
        auth=MAASOAuth(*credentials),
        dispatcher=MAASDispatcher(),
        base_url=maas_url,
    )
    process_node_tags(
        rack_id=system_id,
        nodes=nodes,
        tag_name=tag_name,
        tag_definition=tag_definition,
        tag_nsmap=tag_nsmap,
        client=client,
    )
Exemplo n.º 6
0
def submit(maas_url, api_credentials, images):
    """Submit images to server."""
    MAASClient(MAASOAuth(*api_credentials), MAASDispatcher(),
               maas_url).post('api/1.0/boot-images/',
                              'report_boot_images',
                              nodegroup=get_cluster_uuid(),
                              images=json.dumps(images))
Exemplo n.º 7
0
 def test_doesnt_override_accept_encoding_headers(self):
     # If someone passes their own Accept-Encoding header, then dispatch
     # just passes it through.
     self.useFixture(TempWDFixture())
     name = factory.getRandomString()
     content = factory.getRandomString(300).encode('ascii')
     factory.make_file(location='.', name=name, contents=content)
     with HTTPServerFixture() as httpd:
         url = urljoin(httpd.url, name)
         headers = {'Accept-encoding': 'gzip'}
         res = MAASDispatcher().dispatch_query(url, headers)
         self.assertEqual(200, res.code)
         self.assertEqual('gzip', res.info().get('Content-Encoding'))
         raw_content = res.read()
     read_content = gzip.GzipFile(
         mode='rb', fileobj=BytesIO(raw_content)).read()
     self.assertEqual(content, read_content)
Exemplo n.º 8
0
 def __init__(self, api_key=None, url=maas_url):
     if api_key == None:
         self.api_key = self.get_api_key()
     else:
         self.api_key = api_key
     self.auth = MAASOAuth(*self.api_key.split(':'))
     self.url = url
     self.client = MAASClient(self.auth, MAASDispatcher(), self.url)
Exemplo n.º 9
0
 def test_doesnt_override_accept_encoding_headers(self):
     # If someone passes their own Accept-Encoding header, then dispatch
     # just passes it through.
     self.useFixture(TempWDFixture())
     name = factory.getRandomString()
     content = factory.getRandomString(300).encode('ascii')
     factory.make_file(location='.', name=name, contents=content)
     with HTTPServerFixture() as httpd:
         url = urljoin(httpd.url, name)
         headers = {'Accept-encoding': 'gzip'}
         res = MAASDispatcher().dispatch_query(url, headers)
         self.assertEqual(200, res.code)
         self.assertEqual('gzip', res.info().get('Content-Encoding'))
         raw_content = res.read()
     read_content = gzip.GzipFile(mode='rb',
                                  fileobj=BytesIO(raw_content)).read()
     self.assertEqual(content, read_content)
Exemplo n.º 10
0
 def test_dispatch_query_encodes_string_data(self):
     # urllib, used by MAASDispatcher, requires data encoded into bytes. We
     # encode into utf-8 in dispatch_query if necessary.
     request = self.patch(urllib.request.Request, "__init__")
     self.patch_urllib()
     self.open_func = lambda *args: MagicMock()
     url = factory.make_url()
     data = factory.make_string(300, spaces=True)
     MAASDispatcher().dispatch_query(url, {}, method="POST", data=data)
     request.assert_called_once_with(ANY, url, bytes(data, "utf-8"), ANY)
Exemplo n.º 11
0
    def test_retries_three_times_on_503_service_unavailable(self):
        self.useFixture(TempWDFixture())
        name = factory.make_string()
        content = factory.make_string().encode("ascii")
        factory.make_file(location=".", name=name, contents=content)
        with HTTPServerFixture() as httpd:
            url = urljoin(httpd.url, name)

            counter = {"count": 0}

            def _wrap_open(*args, **kwargs):
                if counter["count"] < 2:
                    counter["count"] += 1
                    raise urllib.error.HTTPError(url, 503,
                                                 "service unavailable", {},
                                                 None)
                else:
                    return self.orig_open_func(*args, **kwargs)

            self.open_func = _wrap_open
            response = MAASDispatcher().dispatch_query(url, {})
            self.assertEqual(200, response.code)
            self.assertEqual(content, response.read())
Exemplo n.º 12
0
    def test_supports_content_encoding_gzip(self):
        # The client will set the Accept-Encoding: gzip header, and it will
        # also decompress the response if it comes back with Content-Encoding:
        # gzip.
        self.useFixture(TempWDFixture())
        name = factory.make_string()
        content = factory.make_string(300).encode('ascii')
        factory.make_file(location='.', name=name, contents=content)
        called = []
        orig_urllib = urllib2.urlopen

        def logging_urlopen(*args, **kwargs):
            called.append((args, kwargs))
            return orig_urllib(*args, **kwargs)
        self.patch(urllib2, 'urlopen', logging_urlopen)
        with HTTPServerFixture() as httpd:
            url = urljoin(httpd.url, name)
            res = MAASDispatcher().dispatch_query(url, {})
            self.assertEqual(200, res.code)
            self.assertEqual(content, res.read())
        request = called[0][0][0]
        self.assertEqual([((request,), {})], called)
        self.assertEqual('gzip', request.headers.get('Accept-encoding'))
Exemplo n.º 13
0
def update_region_controller(knowledge, interface, server):
    """Update the region controller with the status of the probe.

    :param knowledge: dictionary of server info
    :param interface: name of interface, e.g. eth0
    :param server: IP address of detected DHCP server, or None
    """
    api_path = 'api/1.0/nodegroups/%s/interfaces/%s/' % (
        knowledge['nodegroup_uuid'], interface)
    oauth = MAASOAuth(*knowledge['api_credentials'])
    client = MAASClient(oauth, MAASDispatcher(), knowledge['maas_url'])
    if server is None:
        server = ''
    process_request(client.put, api_path, foreign_dhcp_ip=server)
Exemplo n.º 14
0
    def test_supports_content_encoding_gzip(self):
        # The client will set the Accept-Encoding: gzip header, and it will
        # also decompress the response if it comes back with Content-Encoding:
        # gzip.
        self.useFixture(TempWDFixture())
        name = factory.getRandomString()
        content = factory.getRandomString(300).encode('ascii')
        factory.make_file(location='.', name=name, contents=content)
        called = []
        orig_urllib = urllib2.urlopen

        def logging_urlopen(*args, **kwargs):
            called.append((args, kwargs))
            return orig_urllib(*args, **kwargs)
        self.patch(urllib2, 'urlopen', logging_urlopen)
        with HTTPServerFixture() as httpd:
            url = urljoin(httpd.url, name)
            res = MAASDispatcher().dispatch_query(url, {})
            self.assertEqual(200, res.code)
            self.assertEqual(content, res.read())
        request = called[0][0][0]
        self.assertEqual([((request,), {})], called)
        self.assertEqual('gzip', request.headers.get('Accept-encoding'))
Exemplo n.º 15
0
    def test_retries_three_times_on_503_service_unavailable(self):
        self.useFixture(TempWDFixture())
        name = factory.make_string()
        content = factory.make_string().encode('ascii')
        factory.make_file(location='.', name=name, contents=content)
        with HTTPServerFixture() as httpd:
            url = urljoin(httpd.url, name)
            original_urlopen = urllib.request.urlopen

            counter = {'count': 0}

            def _wrap_urlopen(*args, **kwargs):
                if counter['count'] < 2:
                    counter['count'] += 1
                    raise urllib.error.HTTPError(url, 503,
                                                 "service unavailable", {},
                                                 None)
                else:
                    return original_urlopen(*args, **kwargs)

            self.patch(urllib.request, "urlopen").side_effect = _wrap_urlopen
            response = MAASDispatcher().dispatch_query(url, {})
            self.assertEqual(200, response.code)
            self.assertEqual(content, response.read())
Exemplo n.º 16
0
def create_node(mac, arch, power_type, power_parameters):
    api_credentials = get_recorded_api_credentials()
    if api_credentials is None:
        raise Exception('Not creating node: no API key yet.')
    client = MAASClient(MAASOAuth(*api_credentials), MAASDispatcher(),
                        get_maas_url())

    data = {
        'op': 'new',
        'architecture': arch,
        'power_type': power_type,
        'power_parameters': power_parameters,
        'mac_addresses': mac
    }
    return client.post('/api/1.0/nodes/', data)
Exemplo n.º 17
0
def get_cached_knowledge():
    """Get all the information that we need to know, or raise an error.

    :return: (client, nodegroup_uuid)
    """
    api_credentials = get_recorded_api_credentials()
    if api_credentials is None:
        logger.error("Not updating tags: don't have API key yet.")
        return None, None
    nodegroup_uuid = get_recorded_nodegroup_uuid()
    if nodegroup_uuid is None:
        logger.error("Not updating tags: don't have UUID yet.")
        return None, None
    client = MAASClient(MAASOAuth(*api_credentials), MAASDispatcher(),
                        get_maas_url())
    return client, nodegroup_uuid
Exemplo n.º 18
0
    def test_retries_three_times_raises_503_service_unavailable(self):
        self.useFixture(TempWDFixture())
        name = factory.make_string()
        content = factory.make_string().encode('ascii')
        factory.make_file(location='.', name=name, contents=content)
        with HTTPServerFixture() as httpd:
            url = urljoin(httpd.url, name)

            def _wrap_urlopen(*args, **kwargs):
                raise urllib.error.HTTPError(url, 503, "service unavailable",
                                             {}, None)

            self.patch(urllib.request, "urlopen").side_effect = _wrap_urlopen
            err = self.assertRaises(urllib.error.HTTPError,
                                    MAASDispatcher().dispatch_query, url, {})
            self.assertEqual(503, err.code)
Exemplo n.º 19
0
    def test_supports_any_method(self):
        # urllib2, which MAASDispatcher uses, only supports POST and
        # GET. There is some extra code that makes sure the passed
        # method is honoured which is tested here.
        self.useFixture(TempWDFixture())
        name = factory.make_string()
        content = factory.make_string(300).encode('ascii')
        factory.make_file(location='.', name=name, contents=content)

        method = "PUT"
        # The test httpd doesn't like PUT, so we'll look for it bitching
        # about that for the purposes of this test.
        with HTTPServerFixture() as httpd:
            url = urljoin(httpd.url, name)
            e = self.assertRaises(
                urllib2.HTTPError, MAASDispatcher().dispatch_query, url, {},
                method=method)
            self.assertIn("Unsupported method ('PUT')", e.reason)
Exemplo n.º 20
0
def _getclient(url=u'http://localhost/MAAS/api/1.0/'):
    '''
  Use the MAAS apiclient to aquire a session with the Maas API
  :param url:
    How to connect to the Maas server. As we require the Maas tools
    installed on the executing machine, this can be the localhost by default.

  :return:
    A MAASClient object
  '''
    global _mclient
    if _mclient is None:
        consumer_key, token, secret = key('root').split(':', 3)
        auth = MAASOAuth(consumer_key, token, secret)
        dispatch = MAASDispatcher()
        _mclient = MAASClient(auth, dispatch, url)

    return _mclient
Exemplo n.º 21
0
def determine_cluster_interfaces(knowledge):
    """Given server knowledge, determine network interfaces on this cluster.

    :return: a list of tuples of (interface name, ip) for all interfaces.

    :note: this uses an API call and not local probing because the
        region controller has the definitive and final say in what does and
        doesn't exist.
    """
    api_path = 'api/1.0/nodegroups/%s/interfaces' % knowledge['nodegroup_uuid']
    oauth = MAASOAuth(*knowledge['api_credentials'])
    client = MAASClient(oauth, MAASDispatcher(), knowledge['maas_url'])
    interfaces = process_request(client.get, api_path, 'list')
    if interfaces is None:
        return None

    interface_names = sorted((interface['interface'], interface['ip'])
                             for interface in interfaces
                             if interface['interface'] != '')
    return interface_names
Exemplo n.º 22
0
 def test_autodetects_proxies(self):
     self.open_func = lambda *args: MagicMock()
     url = factory.make_url()
     proxy_variables = {
         "http_proxy": "http://proxy.example.com",
         "https_proxy": "https://proxy.example.com",
         "no_proxy": "noproxy.example.com",
     }
     with patch.dict(os.environ, proxy_variables):
         MAASDispatcher().dispatch_query(url, {}, method="GET")
     for handler in self.opener.handle_open["http"]:
         if isinstance(handler, urllib.request.ProxyHandler):
             break
     else:
         raise AssertionError("No ProxyHandler installed")
     expected = {
         "http": proxy_variables["http_proxy"],
         "https": proxy_variables["https_proxy"],
         "no": proxy_variables["no_proxy"],
     }
     for key, value in expected.items():
         self.assertEqual(value, handler.proxies[key])
Exemplo n.º 23
0
def send_leases(leases):
    """Send lease updates to the server API."""
    # Items that the server must have sent us before we can do this.
    knowledge = {
        'maas_url': get_maas_url(),
        'api_credentials': get_recorded_api_credentials(),
        'nodegroup_uuid': get_recorded_nodegroup_uuid(),
    }
    if None in knowledge.values():
        # The MAAS server hasn't sent us enough information for us to do
        # this yet.  Leave it for another time.
        logger.info(
            "Not sending DHCP leases to server: not all required knowledge "
            "received from server yet.  "
            "Missing: %s" % ', '.join(list_missing_items(knowledge)))
        return

    api_path = 'api/1.0/nodegroups/%s/' % knowledge['nodegroup_uuid']
    oauth = MAASOAuth(*knowledge['api_credentials'])
    MAASClient(oauth, MAASDispatcher(),
               knowledge['maas_url']).post(api_path,
                                           'update_leases',
                                           leases=json.dumps(leases))
Exemplo n.º 24
0
def _auth(**connection_args):
    '''
    Set up maas credentials

    Only intended to be used within maas-enabled modules
    '''

    prefix = "maas."

    # look in connection_args first, then default to config file
    def get(key, default=None):
        return connection_args.get(
            'connection_' + key, __salt__['config.get'](prefix + key, default))

    api_token = get('token')
    api_url = get('url', 'https://localhost/')

    LOG.debug("MAAS url: " + api_url)
    LOG.debug("MAAS token: " + api_token)
    auth = MAASOAuth(*api_token.split(":"))
    dispatcher = MAASDispatcher()
    client = MAASClient(auth, dispatcher, api_url)

    return client
Exemplo n.º 25
0
 def test_dispatch_query_makes_direct_call(self):
     contents = factory.getRandomString()
     url = "file://%s" % self.make_file(contents=contents)
     self.assertEqual(contents,
                      MAASDispatcher().dispatch_query(url, {}).read())
Exemplo n.º 26
0
 def _connect(self):
     if not self.conn:
         auth = MAASOAuth(*self.maas_api_key.split(':'))
         dispatcher = MAASDispatcher()
         self.maas_client = MAASClient(auth, dispatcher, self.maas_url)
         self.conn = True
Exemplo n.º 27
0
def get_client(url, creds):
    [consumer_key, token, secret] = creds.split(':')
    auth = MAASOAuth(consumer_key=consumer_key,
                     resource_token=token,
                     resource_secret=secret)
    return MAASClient(auth, MAASDispatcher(), url)
Exemplo n.º 28
0
def _getclient(url=u'http://localhost/MAAS/api/1.0/'):
    consumer_key, token, secret = key('root').split(':', 3)
    auth = MAASOAuth(consumer_key, token, secret)
    dispatch = MAASDispatcher()
    client = MAASClient(auth, dispatch, url)
    return client
Exemplo n.º 29
0
def make_anonymous_api_client(server_url):
    """Create an unauthenticated API client."""
    return MAASClient(NoAuth(), MAASDispatcher(), server_url)