示例#1
0
文件: test_pods.py 项目: sfeole/maas
 def test__get_requested_machine_handles_no_tags_in_storage(self):
     request = MagicMock()
     pod = make_pod_with_hints()
     disk_1 = random.randint(8, 16) * (1000 ** 3)
     disk_2 = random.randint(8, 16) * (1000 ** 3)
     storage = 'root:%d,extra:%d' % (
         disk_1 // (1000 ** 3),
         disk_2 // (1000 ** 3))
     form = ComposeMachineForm(data={
         'storage': storage,
     }, request=request, pod=pod)
     self.assertTrue(form.is_valid(), form.errors)
     request_machine = form.get_requested_machine()
     self.assertThat(request_machine, MatchesAll(
         IsInstance(RequestedMachine),
         MatchesStructure(
             block_devices=MatchesListwise([
                 MatchesAll(
                     IsInstance(RequestedMachineBlockDevice),
                     MatchesStructure(
                         size=Equals(disk_1), tags=Equals([]))),
                 MatchesAll(
                     IsInstance(RequestedMachineBlockDevice),
                     MatchesStructure(
                         size=Equals(disk_2), tags=Equals([]))),
                 ]))))
示例#2
0
文件: pod.py 项目: uraniid/maas
 def get_form(obj, params):
     request = HttpRequest()
     request.user = self.user
     form = ComposeMachineForm(pod=obj, data=params, request=request)
     if not form.is_valid():
         raise HandlerValidationError(form.errors)
     return form, obj
示例#3
0
文件: test_pods.py 项目: sfeole/maas
    def test__compose_with_skip_commissioning_passed(self):
        request = MagicMock()
        pod = make_pod_with_hints()

        # Mock the RPC client.
        client = MagicMock()
        mock_getClient = self.patch(pods_module, "getClientFromIdentifiers")
        mock_getClient.return_value = succeed(client)

        # Mock the result of the composed machine.
        composed_machine, pod_hints = self.make_compose_machine_result(pod)
        mock_compose_machine = self.patch(pods_module, "compose_machine")
        mock_compose_machine.return_value = succeed(
            (composed_machine, pod_hints))

        # Mock start_commissioning so it doesn't use post commit hooks.
        mock_commissioning = self.patch(Machine, "start_commissioning")

        form = ComposeMachineForm(data={}, request=request, pod=pod)
        self.assertTrue(form.is_valid())
        created_machine = form.compose(skip_commissioning=True)
        self.assertThat(created_machine, MatchesAll(
            IsInstance(Machine),
            MatchesStructure(
                cpu_count=Equals(1),
                memory=Equals(1024),
                cpu_speed=Equals(300))))
        self.assertThat(mock_commissioning, MockNotCalled())
示例#4
0
文件: test_pods.py 项目: sfeole/maas
    def test__compose_sets_domain_and_zone(self):
        request = MagicMock()
        pod = make_pod_with_hints()

        # Mock the RPC client.
        client = MagicMock()
        mock_getClient = self.patch(pods_module, "getClientFromIdentifiers")
        mock_getClient.return_value = succeed(client)

        # Mock the result of the composed machine.
        composed_machine, pod_hints = self.make_compose_machine_result(pod)
        mock_compose_machine = self.patch(pods_module, "compose_machine")
        mock_compose_machine.return_value = succeed(
            (composed_machine, pod_hints))

        domain = factory.make_Domain()
        zone = factory.make_Zone()
        form = ComposeMachineForm(data={
            "domain": domain.id,
            "zone": zone.id,
            "skip_commissioning": 'true',
        }, request=request, pod=pod)
        self.assertTrue(form.is_valid())
        created_machine = form.compose()
        self.assertThat(created_machine, MatchesAll(
            IsInstance(Machine),
            MatchesStructure(
                domain=Equals(domain),
                zone=Equals(zone))))
示例#5
0
文件: test_pods.py 项目: sfeole/maas
    def test__compose_duplicated_hostname(self):
        factory.make_Node(hostname='test')

        request = MagicMock()
        pod = make_pod_with_hints()

        form = ComposeMachineForm(
            data={'hostname': 'test'}, request=request, pod=pod)
        self.assertFalse(form.is_valid())
        self.assertEqual(
            {'hostname': ['Node with hostname "test" already exists']},
            form.errors)
示例#6
0
文件: test_pods.py 项目: sfeole/maas
 def test__get_requested_machine_uses_passed_values(self):
     request = MagicMock()
     pod = make_pod_with_hints()
     architecture = random.choice(pod.architectures)
     cores = random.randint(1, pod.hints.cores)
     memory = random.randint(1024, pod.hints.memory)
     cpu_speed = random.randint(300, pod.hints.cpu_speed)
     disk_1 = random.randint(8, 16) * (1000 ** 3)
     disk_1_tags = [
         factory.make_name('tag')
         for _ in range(3)
     ]
     disk_2 = random.randint(8, 16) * (1000 ** 3)
     disk_2_tags = [
         factory.make_name('tag')
         for _ in range(3)
     ]
     storage = 'root:%d(%s),extra:%d(%s)' % (
         disk_1 // (1000 ** 3), ','.join(disk_1_tags),
         disk_2 // (1000 ** 3), ','.join(disk_2_tags))
     form = ComposeMachineForm(data={
         'architecture': architecture,
         'cores': cores,
         'memory': memory,
         'cpu_speed': cpu_speed,
         'storage': storage,
     }, request=request, pod=pod)
     self.assertTrue(form.is_valid(), form.errors)
     request_machine = form.get_requested_machine()
     self.assertThat(request_machine, MatchesAll(
         IsInstance(RequestedMachine),
         MatchesStructure(
             architecture=Equals(architecture),
             cores=Equals(cores),
             memory=Equals(memory),
             cpu_speed=Equals(cpu_speed),
             block_devices=MatchesListwise([
                 MatchesAll(
                     IsInstance(RequestedMachineBlockDevice),
                     MatchesStructure(
                         size=Equals(disk_1), tags=Equals(disk_1_tags))),
                 MatchesAll(
                     IsInstance(RequestedMachineBlockDevice),
                     MatchesStructure(
                         size=Equals(disk_2), tags=Equals(disk_2_tags))),
                 ]),
             interfaces=MatchesListwise([
                 IsInstance(RequestedMachineInterface)]))))
示例#7
0
文件: test_pods.py 项目: sfeole/maas
    def test__compose_handles_timeout_error(self):
        request = MagicMock()
        pod = make_pod_with_hints()

        # Mock the RPC client.
        client = MagicMock()
        client.side_effect = crochet.TimeoutError()
        mock_getClient = self.patch(pods_module, "getClientFromIdentifiers")
        mock_getClient.return_value = succeed(client)

        form = ComposeMachineForm(data={}, request=request, pod=pod)
        self.assertTrue(form.is_valid())
        error = self.assertRaises(PodProblem, form.compose)
        self.assertEquals(
            "Unable to compose a machine because '%s' driver timed out "
            "after 120 seconds." % pod.power_type, str(error))
示例#8
0
文件: test_pods.py 项目: sfeole/maas
 def test__sets_up_pool_default(self):
     request = MagicMock()
     pod = make_pod_with_hints()
     pool = factory.make_ResourcePool()
     pod.pool = pool
     pod.save()
     form = ComposeMachineForm(request=request, pod=pod)
     self.assertEqual(pool, form.initial['pool'])
示例#9
0
文件: pods.py 项目: zeronewb/maas
    def compose(self, request, id):
        """Compose a machine from Pod.

        All fields below are optional:

        :param cores: Minimum number of CPU cores.
        :type cores: unicode
        :param memory: Minimum amount of memory (MiB).
        :type memory: unicode
        :param cpu_speed: Minimum amount of CPU speed (MHz).
        :type cpu_speed: unicode
        :param architecture: Architecture for the machine. Must be an
            architecture that the pod supports.
        :param architecture: unicode
        :param storage: A list of storage constraint identifiers, in the form:
            <label>:<size>(<tag>[,<tag>[,...])][,<label>:...]
        :type storage: unicode
        :param hostname: Hostname for the newly composed machine.
        :type hostname: unicode
        :param domain: ID of domain to place the newly composed machine in.
        :type domain: unicode
        :param zone: ID of zone place the newly composed machine in.
        :type zone: unicode
        :param pool: ID of resource pool to place the newly composed machine
            in.
        :type pool: unicode

        Returns 404 if the pod is not found.
        Returns 403 if the user does not have permission to compose machine.
        """
        pod = get_object_or_404(Pod, id=id)
        if Capabilities.COMPOSABLE not in pod.capabilities:
            raise MAASAPIValidationError("Pod does not support composability.")
        form = ComposeMachineForm(data=request.data, pod=pod, request=request)
        if form.is_valid():
            machine = form.compose()
            return {
                'system_id':
                machine.system_id,
                'resource_uri':
                reverse('machine_handler',
                        kwargs={'system_id': machine.system_id})
            }
        else:
            raise MAASAPIValidationError(form.errors)
示例#10
0
文件: test_pods.py 项目: sfeole/maas
    def test__compose_check_over_commit_ratios_raises_error_for_memory(self):
        request = MagicMock()
        pod = make_pod_with_hints()
        pod.memory = 0
        pod.save()

        # Mock the RPC client.
        client = MagicMock()
        mock_getClient = self.patch(pods_module, "getClientFromIdentifiers")
        mock_getClient.return_value = succeed(client)

        form = ComposeMachineForm(data={}, request=request, pod=pod)
        self.assertTrue(form.is_valid())
        error = self.assertRaises(PodProblem, form.compose)
        self.assertEqual(
            "Memory over commit ratio is %s and there are %s "
            "available resources." %
            (pod.memory_over_commit_ratio, pod.memory), str(error))
示例#11
0
文件: test_pods.py 项目: sfeole/maas
 def test__get_requested_machine_uses_all_initial_values(self):
     request = MagicMock()
     pod = make_pod_with_hints()
     form = ComposeMachineForm(data={}, request=request, pod=pod)
     self.assertTrue(form.is_valid())
     request_machine = form.get_requested_machine()
     self.assertThat(request_machine, MatchesAll(
         IsInstance(RequestedMachine),
         MatchesStructure(
             architecture=Equals(pod.architectures[0]),
             cores=Equals(1),
             memory=Equals(1024),
             cpu_speed=Is(None),
             block_devices=MatchesListwise([
                 MatchesAll(
                     IsInstance(RequestedMachineBlockDevice),
                     MatchesStructure(size=Equals(8 * (1000 ** 3))))]),
             interfaces=MatchesListwise([
                 IsInstance(RequestedMachineInterface)]))))
示例#12
0
文件: test_pods.py 项目: sfeole/maas
 def test__sets_up_fields_based_on_pod_no_max_cpu_speed(self):
     request = MagicMock()
     pod = make_pod_with_hints()
     pod.hints.cpu_speed = 0
     pod.save()
     form = ComposeMachineForm(request=request, pod=pod)
     self.assertThat(form.fields['cpu_speed'], MatchesStructure(
         required=Equals(False),
         validators=MatchesSetwise(
             MatchesAll(
                 IsInstance(MinValueValidator),
                 MatchesStructure(limit_value=Equals(300))))))
示例#13
0
文件: test_pods.py 项目: sfeole/maas
    def test__compose_sends_default_storage_pool_id(self):
        request = MagicMock()
        pod = make_pod_with_hints()

        # Mock the RPC client.
        client = MagicMock()
        mock_getClient = self.patch(pods_module, "getClientFromIdentifiers")
        mock_getClient.return_value = succeed(client)

        # Mock the result of the composed machine.
        composed_machine, pod_hints = self.make_compose_machine_result(pod)
        mock_compose_machine = self.patch(pods_module, "compose_machine")
        mock_compose_machine.return_value = succeed(
            (composed_machine, pod_hints))

        # Mock start_commissioning so it doesn't use post commit hooks.
        self.patch(Machine, "start_commissioning")

        form = ComposeMachineForm(data={}, request=request, pod=pod)
        self.assertTrue(form.is_valid())
        form.compose()
        self.assertThat(mock_compose_machine, MockCalledOnceWith(
            ANY, pod.power_type, {
                'default_storage_pool_id': pod.default_storage_pool.pool_id,
            },
            form.get_requested_machine(), pod_id=pod.id, name=pod.name))
示例#14
0
文件: test_pods.py 项目: sfeole/maas
    def test__compose_uses_pod_pool(self):
        request = MagicMock()
        pod = make_pod_with_hints()
        pod.pool = factory.make_ResourcePool()
        pod.save()

        # Mock the RPC client.
        client = MagicMock()
        mock_getClient = self.patch(pods_module, "getClientFromIdentifiers")
        mock_getClient.return_value = succeed(client)

        # Mock the result of the composed machine.
        composed_machine, pod_hints = self.make_compose_machine_result(pod)
        mock_compose_machine = self.patch(pods_module, "compose_machine")
        mock_compose_machine.return_value = succeed(
            (composed_machine, pod_hints))

        form = ComposeMachineForm(data={
            "skip_commissioning": 'true',
        }, request=request, pod=pod)
        self.assertTrue(form.is_valid())
        created_machine = form.compose()
        self.assertEqual(pod.pool, created_machine.pool)
示例#15
0
 def test__sets_up_fields_based_on_pod(self):
     request = MagicMock()
     pod = make_pod_with_hints()
     form = ComposeMachineForm(request=request, pod=pod)
     self.assertThat(
         form.fields['cores'],
         MatchesStructure(
             required=Equals(False),
             validators=MatchesSetwise(
                 MatchesAll(
                     IsInstance(MaxValueValidator),
                     MatchesStructure(limit_value=Equals(pod.hints.cores))),
                 MatchesAll(IsInstance(MinValueValidator),
                            MatchesStructure(limit_value=Equals(1))))))
     self.assertThat(
         form.fields['memory'],
         MatchesStructure(
             required=Equals(False),
             validators=MatchesSetwise(
                 MatchesAll(
                     IsInstance(MaxValueValidator),
                     MatchesStructure(
                         limit_value=Equals(pod.hints.memory))),
                 MatchesAll(IsInstance(MinValueValidator),
                            MatchesStructure(limit_value=Equals(1024))))))
     self.assertThat(
         form.fields['architecture'],
         MatchesStructure(required=Equals(False),
                          choices=MatchesSetwise(*[
                              Equals((architecture, architecture))
                              for architecture in pod.architectures
                          ])))
     self.assertThat(
         form.fields['cpu_speed'],
         MatchesStructure(
             required=Equals(False),
             validators=MatchesSetwise(
                 MatchesAll(
                     IsInstance(MaxValueValidator),
                     MatchesStructure(
                         limit_value=Equals(pod.hints.cpu_speed))),
                 MatchesAll(IsInstance(MinValueValidator),
                            MatchesStructure(limit_value=Equals(300))))))
示例#16
0
    def compose(self, request, id):
        """Compose a machine from Pod.

        All fields below are optional:

        :param cores: Minimum number of CPU cores.
        :type cores: unicode
        :param memory: Minimum amount of memory (MiB).
        :type memory: unicode
        :param cpu_speed: Minimum amount of CPU speed (MHz).
        :type cpu_speed: unicode
        :param architecture: Architecture for the machine. Must be an
            architecture that the pod supports.
        :param architecture: unicode
        :param storage: A list of storage constraint identifiers, in the form:
            <label>:<size>(<tag>[,<tag>[,...])][,<label>:...]
        :type storage: unicode
        :param interfaces: A labeled constraint map associating constraint
            labels with interface properties that should be matched. Returned
            nodes must have one or more interface matching the specified
            constraints. The labeled constraint map must be in the format:
            ``<label>:<key>=<value>[,<key2>=<value2>[,...]]``

            Each key can be one of the following:

            - id: Matches an interface with the specific id
            - fabric: Matches an interface attached to the specified fabric.
            - fabric_class: Matches an interface attached to a fabric
              with the specified class.
            - ip: Matches an interface whose VLAN is on the subnet implied by
              the given IP address, and allocates the specified IP address for
              the machine on that interface (if it is available).
            - mode: Matches an interface with the specified mode. (Currently,
              the only supported mode is "unconfigured".)
            - name: Matches an interface with the specified name.
              (For example, "eth0".)
            - hostname: Matches an interface attached to the node with
              the specified hostname.
            - subnet: Matches an interface attached to the specified subnet.
            - space: Matches an interface attached to the specified space.
            - subnet_cidr: Matches an interface attached to the specified
              subnet CIDR. (For example, "192.168.0.0/24".)
            - type: Matches an interface of the specified type. (Valid
              types: "physical", "vlan", "bond", "bridge", or "unknown".)
            - vlan: Matches an interface on the specified VLAN.
            - vid: Matches an interface on a VLAN with the specified VID.
            - tag: Matches an interface tagged with the specified tag.
        :type interfaces: unicode
        :param hostname: Hostname for the newly composed machine.
        :type hostname: unicode
        :param domain: ID of domain to place the newly composed machine in.
        :type domain: unicode
        :param zone: ID of zone place the newly composed machine in.
        :type zone: unicode
        :param pool: ID of resource pool to place the newly composed machine
            in.
        :type pool: unicode

        Returns 404 if the pod is not found.
        Returns 403 if the user does not have permission to compose machine.
        """
        pod = get_object_or_404(Pod, id=id)
        if Capabilities.COMPOSABLE not in pod.capabilities:
            raise MAASAPIValidationError("Pod does not support composability.")
        form = ComposeMachineForm(data=request.data, pod=pod, request=request)
        if form.is_valid():
            machine = form.compose()
            return {
                'system_id':
                machine.system_id,
                'resource_uri':
                reverse('machine_handler',
                        kwargs={'system_id': machine.system_id})
            }
        else:
            raise MAASAPIValidationError(form.errors)
示例#17
0
文件: pods.py 项目: pingli-study/maas
    def compose(self, request, id):
        """@description-title Compose a pod machine
        @description Compose a new machine from a pod.

        @param (int) "cores" [required=false] The minimum number of CPU cores.
        @param (int) "memory" [required=false] The minimum amount of memory,
        specified in MiB (e.g. 2 MiB == 2*1024*1024).
        @param (int) "cores" [required=false] The minimum number of CPU cores.
        @param (int) "cpu_speed" [required=false] The minimum CPU speed,
        specified in MHz.
        @param (string) "architecture" [required=false] The architecture of
        the new machine (e.g. amd64). This must be an architecture the pod
        supports.
        @param (string) "storage" [required=false] A list of storage
        constraint identifiers in the form ``label:size(tag,tag,...),
        label:size(tag,tag,...)``. For more information please see the CLI
        pod management page of the official MAAS documentation.
        @param (string) "interfaces" [required=false,formatting=true] A
        labeled constraint map associating constraint labels with desired
        interface properties. MAAS will assign interfaces that match the
        given interface properties.

        Format: ``label:key=value,key=value,...``

        Keys:

        - ``id``: Matches an interface with the specific id
        - ``fabric``: Matches an interface attached to the specified fabric.
        - ``fabric_class``: Matches an interface attached to a fabric
          with the specified class.
        - ``ip``: Matches an interface whose VLAN is on the subnet implied by
          the given IP address, and allocates the specified IP address for
          the machine on that interface (if it is available).
        - ``mode``: Matches an interface with the specified mode. (Currently,
          the only supported mode is "unconfigured".)
        - ``name``: Matches an interface with the specified name.
          (For example, "eth0".)
        - ``hostname``: Matches an interface attached to the node with
          the specified hostname.
        - ``subnet``: Matches an interface attached to the specified subnet.
        - ``space``: Matches an interface attached to the specified space.
        - ``subnet_cidr``: Matches an interface attached to the specified
          subnet CIDR. (For example, "192.168.0.0/24".)
        - ``type``: Matches an interface of the specified type. (Valid
          types: "physical", "vlan", "bond", "bridge", or "unknown".)
        - ``vlan``: Matches an interface on the specified VLAN.
        - ``vid``: Matches an interface on a VLAN with the specified VID.
        - ``tag``: Matches an interface tagged with the specified tag.
        @param (string) "hostname" [required=false] The hostname of the newly
        composed machine.
        @param (int) "domain" [required=false] The ID of the domain in which
        to put the newly composed machine.
        @param (int) "zone" [required=false] The ID of the zone in which to
        put the newly composed machine.
        @param (int) "pool" [required=false] The ID of the pool in which to
        put the newly composed machine.

        @success (http-status-code) "200" 200
        @success (json) "success-json" A JSON object containing the new
        machine ID and resource URI.
        @success-example (json) "success-json" [exkey=compose] placeholder
        text

        @error (http-status-code) "404" 404
        @error (content) "not-found" No pod with that ID can be found.
        @error-example "not-found"
            Not Found

        @error (http-status-code) "403" 403
        @error (content) "no-perms" The user does not have the permissions
        to delete the pod.
        @error-example (content) "no-perms"
            This method is reserved for admin users.
        """
        pod = Pod.objects.get_pod_or_404(id, request.user,
                                         PodPermission.compose)
        if Capabilities.COMPOSABLE not in pod.capabilities:
            raise MAASAPIValidationError("Pod does not support composability.")
        form = ComposeMachineForm(data=request.data, pod=pod, request=request)
        if form.is_valid():
            machine = form.compose()
            return {
                "system_id":
                machine.system_id,
                "resource_uri":
                reverse("machine_handler",
                        kwargs={"system_id": machine.system_id}),
            }
        else:
            raise MAASAPIValidationError(form.errors)
示例#18
0
文件: test_pods.py 项目: sfeole/maas
 def test__save_raises_AttributeError(self):
     request = MagicMock()
     pod = make_pod_with_hints()
     form = ComposeMachineForm(data={}, request=request, pod=pod)
     self.assertTrue(form.is_valid())
     self.assertRaises(AttributeError, form.save)