This is an automated email from the ASF dual-hosted git repository.

micafer pushed a commit to branch improve_upload
in repository https://gitbox.apache.org/repos/asf/libcloud.git

commit cf74985387d859265ac8256a402679f7ac793846
Author: Miguel Caballer <[email protected]>
AuthorDate: Fri Jul 3 12:06:31 2026 +0200

    Add volume support and start stop operations
---
 libcloud/common/upcloud.py                         |  24 +-
 libcloud/compute/drivers/upcloud.py                | 283 ++++++++++++++++++++-
 ...orage_01d4fcd4-e446-433b-8a9c-551a1284952e.json |  29 +++
 .../fixtures/upcloud/api_1_2_storage_create.json   |  27 ++
 .../fixtures/upcloud/api_1_2_storage_normal.json   |  40 +++
 libcloud/test/compute/test_upcloud.py              | 173 ++++++++++++-
 6 files changed, 572 insertions(+), 4 deletions(-)

diff --git a/libcloud/common/upcloud.py b/libcloud/common/upcloud.py
index 5affb939a..632695335 100644
--- a/libcloud/common/upcloud.py
+++ b/libcloud/common/upcloud.py
@@ -52,6 +52,10 @@ class UpcloudCreateNodeRequestBody:
     :param ex_username: User's username, which is created.
                         Default is 'root'. (optional)
     :type ex_username: ``str``
+
+    :param ex_storage_devices: Additional UpCloud storage_device dictionaries.
+                               (optional)
+    :type ex_storage_devices: ``list`` of ``dict``
     """
 
     def __init__(
@@ -63,7 +67,12 @@ class UpcloudCreateNodeRequestBody:
         auth=None,
         ex_hostname="localhost",
         ex_username="root",
+        ex_storage_devices=None,
     ):
+        storage_devices = _StorageDevice(image, size).to_dict()
+        if ex_storage_devices:
+            storage_devices["storage_device"].extend(ex_storage_devices)
+
         self.body = {
             "server": {
                 "title": name,
@@ -71,7 +80,7 @@ class UpcloudCreateNodeRequestBody:
                 "plan": size.id,
                 "zone": location.id,
                 "login_user": _LoginUser(ex_username, auth).to_dict(),
-                "storage_devices": _StorageDevice(image, size).to_dict(),
+                "storage_devices": storage_devices,
             }
         }
 
@@ -172,6 +181,19 @@ class UpcloudNodeOperations:
             "1.2/server/{}/stop".format(node_id), method="POST", 
data=json.dumps(body)
         )
 
+    def start_node(self, node_id):
+        """
+        Starts the node
+
+        :param  node_id: Id of the Node
+        :type   node_id: ``int``
+        """
+        self.connection.request(
+            "1.2/server/{}/start".format(node_id),
+            method="POST",
+            data=json.dumps({"server": {}}),
+        )
+
     def get_node_state(self, node_id):
         """
         Get the state of the node.
diff --git a/libcloud/compute/drivers/upcloud.py 
b/libcloud/compute/drivers/upcloud.py
index 700c46501..1f781d19a 100644
--- a/libcloud/compute/drivers/upcloud.py
+++ b/libcloud/compute/drivers/upcloud.py
@@ -22,8 +22,16 @@ import base64
 from libcloud.utils.py3 import b, httplib
 from libcloud.common.base import JsonResponse, ConnectionUserAndKey
 from libcloud.common.types import InvalidCredsError
-from libcloud.compute.base import Node, NodeSize, NodeImage, NodeState, 
NodeDriver, NodeLocation
-from libcloud.compute.types import Provider
+from libcloud.compute.base import (
+    Node,
+    NodeSize,
+    NodeImage,
+    NodeState,
+    NodeDriver,
+    NodeLocation,
+    StorageVolume,
+)
+from libcloud.compute.types import Provider, StorageVolumeState
 from libcloud.common.upcloud import (
     PlanPrice,
     UpcloudNodeDestroyer,
@@ -95,6 +103,15 @@ class UpcloudDriver(NodeDriver):
         "error": NodeState.ERROR,
     }
 
+    STORAGE_VOLUME_STATE_MAP = {
+        "online": StorageVolumeState.AVAILABLE,
+        "maintenance": StorageVolumeState.UPDATING,
+        "cloning": StorageVolumeState.CREATING,
+        "backuping": StorageVolumeState.BACKUP,
+        "syncing": StorageVolumeState.MIGRATING,
+        "error": StorageVolumeState.ERROR,
+    }
+
     def __init__(self, username, password, **kwargs):
         super().__init__(key=username, secret=password, **kwargs)
 
@@ -148,6 +165,7 @@ class UpcloudDriver(NodeDriver):
         auth=None,
         ex_hostname="localhost",
         ex_username="root",
+        ex_storage_devices=None,
     ):
         """
         Creates instance to upcloud.
@@ -179,6 +197,14 @@ class UpcloudDriver(NodeDriver):
                             Default is 'root'. (optional)
         :type ex_username: ``str``
 
+        :param ex_storage_devices: Additional UpCloud storage_device
+                                   dictionaries to include in the server
+                                   creation request. For example, an
+                                   ``attach`` action can attach an existing
+                                   storage and a ``create`` action can create
+                                   an extra data disk. (optional)
+        :type ex_storage_devices: ``list`` of ``dict``
+
         :return: The newly created node.
         :rtype: :class:`.Node`
         """
@@ -190,6 +216,7 @@ class UpcloudDriver(NodeDriver):
             auth=auth,
             ex_hostname=ex_hostname,
             ex_username=ex_username,
+            ex_storage_devices=ex_storage_devices,
         )
         response = self.connection.request("1.2/server", method="POST", 
data=body.to_json())
         server = response.object["server"]
@@ -197,6 +224,153 @@ class UpcloudDriver(NodeDriver):
         # from state to other, it is safe to assume STARTING state
         return self._to_node(server, state=NodeState.STARTING)
 
+    def list_volumes(self):
+        """
+        List normal storage volumes.
+
+        :rtype: ``list`` of :class:`StorageVolume`
+        """
+        response = self.connection.request("1.2/storage/normal")
+        return self._to_volumes(response.object["storages"]["storage"])
+
+    def create_volume(
+        self,
+        size,
+        name,
+        location=None,
+        snapshot=None,
+        ex_tier="maxiops",
+        ex_encrypted=False,
+        ex_labels=None,
+        ex_backup_rule=None,
+    ):
+        """
+        Create a new storage volume.
+
+        :param size: Size of volume in gigabytes. (required)
+        :type size: ``int``
+
+        :param name: Name of the volume to be created. (required)
+        :type name: ``str``
+
+        :param location: Which data center to create a volume in. (required)
+        :type location: :class:`.NodeLocation`
+
+        :param ex_tier: UpCloud storage tier: ``maxiops``, ``standard``, or
+                        ``hdd``. Default is ``maxiops``. (optional)
+        :type ex_tier: ``str``
+
+        :param ex_encrypted: Create the volume encrypted at rest. Default is
+                             False. (optional)
+        :type ex_encrypted: ``bool``
+
+        :param ex_labels: Labels for the volume. (optional)
+        :type ex_labels: ``list`` of ``dict``
+
+        :param ex_backup_rule: Backup rule block for automatic backups.
+                               (optional)
+        :type ex_backup_rule: ``dict``
+
+        :rtype: :class:`StorageVolume`
+        """
+        if location is None:
+            raise ValueError("Must provide `location` value.")
+
+        if snapshot is not None:
+            raise NotImplementedError("Creating a volume from snapshot is not 
supported.")
+
+        storage = {
+            "size": size,
+            "title": name,
+            "zone": location.id,
+            "tier": ex_tier,
+            "encrypted": "yes" if ex_encrypted else "no",
+        }
+        if ex_labels is not None:
+            storage["labels"] = ex_labels
+        if ex_backup_rule is not None:
+            storage["backup_rule"] = ex_backup_rule
+
+        response = self.connection.request(
+            "1.2/storage",
+            method="POST",
+            data=json.dumps({"storage": storage}),
+        )
+        return self._to_volume(response.object["storage"])
+
+    def attach_volume(
+        self,
+        node,
+        volume,
+        device=None,
+        ex_type="disk",
+        ex_boot_disk=False,
+    ):
+        """
+        Attach a storage volume to a node.
+
+        :param node: Node to attach volume to.
+        :type node: :class:`Node`
+
+        :param volume: Volume to attach.
+        :type volume: :class:`StorageVolume`
+
+        :param device: UpCloud device address or bus, for example
+                       ``virtio``, ``scsi`` or ``scsi:0:0``. (optional)
+        :type device: ``str``
+
+        :param ex_type: Attached device type, ``disk`` or ``cdrom``.
+                        Default is ``disk``. (optional)
+        :type ex_type: ``str``
+
+        :param ex_boot_disk: Whether the storage should be a boot disk.
+                             Default is False. (optional)
+        :type ex_boot_disk: ``bool``
+
+        :rtype: :class:`StorageVolume`
+        """
+        storage_device = {
+            "type": ex_type,
+            "server": node.id,
+            "boot_disk": "1" if ex_boot_disk else "0",
+        }
+        if device is not None:
+            storage_device["address"] = device
+
+        response = self.connection.request(
+            "1.2/storage/{}/attach".format(volume.id),
+            method="POST",
+            data=json.dumps({"storage_device": storage_device}),
+        )
+        return self._to_volume(response.object["storage"])
+
+    def detach_volume(self, volume):
+        """
+        Detach a storage volume from its server.
+
+        :param volume: Volume to detach.
+        :type volume: :class:`StorageVolume`
+
+        :rtype: ``bool``
+        """
+        self.connection.request(
+            "1.2/storage/{}/detach".format(volume.id),
+            method="POST",
+        )
+        return True
+
+    def destroy_volume(self, volume):
+        """
+        Destroy a storage volume.
+
+        :param volume: Volume to destroy.
+        :type volume: :class:`StorageVolume`
+
+        :rtype: ``bool``
+        """
+        self.connection.request("1.2/storage/{}".format(volume.id), 
method="DELETE")
+        return True
+
     def list_nodes(self):
         """
         List nodes
@@ -227,6 +401,76 @@ class UpcloudDriver(NodeDriver):
         )
         return True
 
+    def start_node(
+        self,
+        node,
+        ex_host=None,
+        ex_avoid_host=None,
+        ex_start_type=None,
+    ):
+        """
+        Start the given node.
+
+        :param node: the node to start
+        :type node: :class:`Node`
+
+        :param ex_host: Host id to start the node on. Only available for
+                        private cloud hosts. (optional)
+        :type ex_host: ``int``
+
+        :param ex_avoid_host: Host id to avoid when starting the node.
+                              (optional)
+        :type ex_avoid_host: ``int``
+
+        :param ex_start_type: Start type, ``sync`` or ``async``. (optional)
+        :type ex_start_type: ``str``
+
+        :rtype: ``bool``
+        """
+        server = {}
+        if ex_host is not None:
+            server["host"] = ex_host
+        if ex_avoid_host is not None:
+            server["avoid_host"] = ex_avoid_host
+        if ex_start_type is not None:
+            server["start_type"] = ex_start_type
+
+        self.connection.request(
+            "1.2/server/{}/start".format(node.id),
+            method="POST",
+            data=json.dumps({"server": server}),
+        )
+        return True
+
+    def stop_node(self, node, ex_stop_type="hard", ex_timeout=None):
+        """
+        Stop the given node.
+
+        :param node: the node to stop
+        :type node: :class:`Node`
+
+        :param ex_stop_type: Stop type, ``hard`` or ``soft``. Default is
+                             ``hard`` to match the destroy helper behavior.
+                             (optional)
+        :type ex_stop_type: ``str``
+
+        :param ex_timeout: Stop timeout in seconds when using a soft stop.
+                           (optional)
+        :type ex_timeout: ``int``
+
+        :rtype: ``bool``
+        """
+        stop_server = {"stop_type": ex_stop_type}
+        if ex_timeout is not None:
+            stop_server["timeout"] = ex_timeout
+
+        self.connection.request(
+            "1.2/server/{}/stop".format(node.id),
+            method="POST",
+            data=json.dumps({"stop_server": stop_server}),
+        )
+        return True
+
     def destroy_node(self, node):
         """
         Destroy the given node
@@ -312,6 +556,41 @@ class UpcloudDriver(NodeDriver):
         extra = self._copy_dict(("access", "license", "size", "state", 
"type"), image)
         return NodeImage(id=image["uuid"], name=image["title"], driver=self, 
extra=extra)
 
+    def _to_volumes(self, volumes):
+        return [self._to_volume(volume) for volume in volumes]
+
+    def _to_volume(self, volume):
+        extra_keys = (
+            "access",
+            "backup_rule",
+            "backups",
+            "encrypted",
+            "labels",
+            "license",
+            "origin",
+            "part_of_plan",
+            "progress",
+            "servers",
+            "tier",
+            "type",
+            "zone",
+        )
+        extra = {}
+        for key in extra_keys:
+            if key in volume:
+                extra[key] = volume[key]
+
+        return StorageVolume(
+            id=volume["uuid"],
+            name=volume["title"],
+            size=int(volume["size"]),
+            driver=self,
+            state=self.STORAGE_VOLUME_STATE_MAP.get(
+                volume["state"], StorageVolumeState.UNKNOWN
+            ),
+            extra=extra,
+        )
+
     def _copy_dict(self, keys, d):
         extra = {}
         for key in keys:
diff --git 
a/libcloud/test/compute/fixtures/upcloud/api_1_2_storage_01d4fcd4-e446-433b-8a9c-551a1284952e.json
 
b/libcloud/test/compute/fixtures/upcloud/api_1_2_storage_01d4fcd4-e446-433b-8a9c-551a1284952e.json
new file mode 100644
index 000000000..2269ac415
--- /dev/null
+++ 
b/libcloud/test/compute/fixtures/upcloud/api_1_2_storage_01d4fcd4-e446-433b-8a9c-551a1284952e.json
@@ -0,0 +1,29 @@
+{
+  "storage": {
+    "access": "private",
+    "encrypted": "yes",
+    "backup_rule": "",
+    "backups": {
+      "backup": []
+    },
+    "labels": [
+      {
+        "key": "env",
+        "value": "test"
+      }
+    ],
+    "license": 0,
+    "servers": {
+      "server": [
+        "00f8c525-7e62-4108-8115-3958df5b43dc"
+      ]
+    },
+    "size": 50,
+    "state": "online",
+    "tier": "standard",
+    "title": "data",
+    "type": "normal",
+    "uuid": "01d4fcd4-e446-433b-8a9c-551a1284952e",
+    "zone": "fi-hel1"
+  }
+}
diff --git a/libcloud/test/compute/fixtures/upcloud/api_1_2_storage_create.json 
b/libcloud/test/compute/fixtures/upcloud/api_1_2_storage_create.json
new file mode 100644
index 000000000..aa16983f1
--- /dev/null
+++ b/libcloud/test/compute/fixtures/upcloud/api_1_2_storage_create.json
@@ -0,0 +1,27 @@
+{
+  "storage": {
+    "access": "private",
+    "encrypted": "yes",
+    "backup_rule": "",
+    "backups": {
+      "backup": []
+    },
+    "labels": [
+      {
+        "key": "env",
+        "value": "test"
+      }
+    ],
+    "license": 0,
+    "servers": {
+      "server": []
+    },
+    "size": 50,
+    "state": "online",
+    "tier": "standard",
+    "title": "data",
+    "type": "normal",
+    "uuid": "01d4fcd4-e446-433b-8a9c-551a1284952e",
+    "zone": "fi-hel1"
+  }
+}
diff --git a/libcloud/test/compute/fixtures/upcloud/api_1_2_storage_normal.json 
b/libcloud/test/compute/fixtures/upcloud/api_1_2_storage_normal.json
new file mode 100644
index 000000000..2c274c5d2
--- /dev/null
+++ b/libcloud/test/compute/fixtures/upcloud/api_1_2_storage_normal.json
@@ -0,0 +1,40 @@
+{
+  "storages": {
+    "storage": [
+      {
+        "access": "private",
+        "encrypted": "no",
+        "labels": [],
+        "license": 0,
+        "size": 10,
+        "state": "online",
+        "tier": "hdd",
+        "title": "Operating system disk",
+        "type": "normal",
+        "uuid": "01eff7ad-168e-413e-83b0-054f6a28fa23",
+        "zone": "uk-lon1"
+      },
+      {
+        "access": "private",
+        "encrypted": "yes",
+        "labels": [
+          {
+            "key": "env",
+            "value": "test"
+          }
+        ],
+        "license": 0,
+        "servers": {
+          "server": []
+        },
+        "size": 50,
+        "state": "online",
+        "tier": "standard",
+        "title": "data",
+        "type": "normal",
+        "uuid": "01d4fcd4-e446-433b-8a9c-551a1284952e",
+        "zone": "fi-hel1"
+      }
+    ]
+  }
+}
diff --git a/libcloud/test/compute/test_upcloud.py 
b/libcloud/test/compute/test_upcloud.py
index d6f86890b..06d5a7c6b 100644
--- a/libcloud/test/compute/test_upcloud.py
+++ b/libcloud/test/compute/test_upcloud.py
@@ -23,7 +23,14 @@ from libcloud.test import MockHttp, LibcloudTestCase, 
unittest
 from libcloud.compute import providers
 from libcloud.utils.py3 import httplib, ensure_string
 from libcloud.common.types import InvalidCredsError
-from libcloud.compute.base import Node, NodeSize, NodeImage, NodeLocation, 
NodeAuthSSHKey
+from libcloud.compute.base import (
+    Node,
+    NodeSize,
+    NodeImage,
+    NodeLocation,
+    NodeAuthSSHKey,
+    StorageVolume,
+)
 from libcloud.test.secrets import UPCLOUD_PARAMS
 from libcloud.compute.types import Provider, NodeState
 from libcloud.test.file_fixtures import ComputeFileFixtures
@@ -192,6 +199,102 @@ class UpcloudDriverTests(LibcloudTestCase):
         self.assertTrue(len(node.private_ips) > 0)
         self.assertEqual(node.driver, self.driver)
 
+    def test_create_node_with_extra_storage_devices(self):
+        image = NodeImage(
+            id="01000000-0000-4000-8000-000030060200",
+            name="Ubuntu Server 16.04 LTS (Xenial Xerus)",
+            extra={"type": "template"},
+            driver=self.driver,
+        )
+        location = NodeLocation(id="fi-hel1", name="Helsinki #1", 
country="FI", driver=self.driver)
+        size = NodeSize(
+            id="1xCPU-1GB",
+            name="1xCPU-1GB",
+            ram=1024,
+            disk=30,
+            bandwidth=2048,
+            extra={"storage_tier": "maxiops"},
+            price=None,
+            driver=self.driver,
+        )
+        extra_storage = {
+            "action": "create",
+            "title": "data",
+            "size": 25,
+            "tier": "standard",
+        }
+
+        self.driver.create_node(
+            name="test_server",
+            size=size,
+            image=image,
+            location=location,
+            ex_storage_devices=[extra_storage],
+        )
+
+        storage_devices = 
UpcloudMockHttp.last_request_body["server"]["storage_devices"][
+            "storage_device"
+        ]
+        self.assertEqual(len(storage_devices), 2)
+        self.assertEqual(storage_devices[1], extra_storage)
+
+    def test_list_volumes(self):
+        volumes = self.driver.list_volumes()
+        self.assertEqual(len(volumes), 2)
+
+        volume = volumes[0]
+        self.assertIsInstance(volume, StorageVolume)
+        self.assertEqual(volume.id, "01eff7ad-168e-413e-83b0-054f6a28fa23")
+        self.assertEqual(volume.name, "Operating system disk")
+        self.assertEqual(volume.size, 10)
+        self.assertEqual(volume.extra["tier"], "hdd")
+        self.assertEqual(volume.extra["zone"], "uk-lon1")
+
+    def test_create_volume(self):
+        location = NodeLocation(id="fi-hel1", name="Helsinki #1", 
country="FI", driver=self.driver)
+        volume = self.driver.create_volume(
+            size=50,
+            name="data",
+            location=location,
+            ex_tier="standard",
+            ex_encrypted=True,
+            ex_labels=[{"key": "env", "value": "test"}],
+        )
+
+        self.assertEqual(volume.id, "01d4fcd4-e446-433b-8a9c-551a1284952e")
+        self.assertEqual(volume.name, "data")
+        self.assertEqual(volume.size, 50)
+        self.assertEqual(volume.extra["encrypted"], "yes")
+        request_storage = UpcloudMockHttp.last_request_body["storage"]
+        self.assertEqual(request_storage["tier"], "standard")
+        self.assertEqual(request_storage["encrypted"], "yes")
+        self.assertEqual(request_storage["labels"], [{"key": "env", "value": 
"test"}])
+
+    def test_create_volume_requires_location(self):
+        with self.assertRaises(ValueError):
+            self.driver.create_volume(size=50, name="data")
+
+    def test_attach_volume(self):
+        node = self.driver.list_nodes()[0]
+        volume = self.driver.list_volumes()[1]
+
+        attached_volume = self.driver.attach_volume(node, volume, 
device="scsi")
+
+        self.assertIsInstance(attached_volume, StorageVolume)
+        self.assertEqual(attached_volume.id, volume.id)
+        request_device = UpcloudMockHttp.last_request_body["storage_device"]
+        self.assertEqual(request_device["server"], node.id)
+        self.assertEqual(request_device["address"], "scsi")
+        self.assertEqual(request_device["boot_disk"], "0")
+
+    def test_detach_volume(self):
+        volume = self.driver.list_volumes()[1]
+        self.assertTrue(self.driver.detach_volume(volume))
+
+    def test_destroy_volume(self):
+        volume = self.driver.list_volumes()[1]
+        self.assertTrue(self.driver.destroy_volume(volume))
+
     def test_list_nodes(self):
         nodes = self.driver.list_nodes()
 
@@ -208,6 +311,37 @@ class UpcloudDriverTests(LibcloudTestCase):
         success = self.driver.reboot_node(nodes[0])
         self.assertTrue(success)
 
+    def test_start_node(self):
+        nodes = self.driver.list_nodes()
+        success = self.driver.start_node(
+            nodes[0],
+            ex_host=8055964291,
+            ex_avoid_host=7653311107,
+            ex_start_type="async",
+        )
+
+        self.assertTrue(success)
+        self.assertEqual(
+            UpcloudMockHttp.last_request_body,
+            {
+                "server": {
+                    "host": 8055964291,
+                    "avoid_host": 7653311107,
+                    "start_type": "async",
+                }
+            },
+        )
+
+    def test_stop_node(self):
+        nodes = self.driver.list_nodes()
+        success = self.driver.stop_node(nodes[0], ex_stop_type="soft", 
ex_timeout=60)
+
+        self.assertTrue(success)
+        self.assertEqual(
+            UpcloudMockHttp.last_request_body,
+            {"stop_server": {"stop_type": "soft", "timeout": 60}},
+        )
+
     def test_destroy_node(self):
         if UpcloudDriver.connectionCls.conn_class == UpcloudMockHttp:
             nodes = [
@@ -258,6 +392,7 @@ class UpcloudDriverTests(LibcloudTestCase):
 
 class UpcloudMockHttp(MockHttp):
     fixtures = ComputeFileFixtures("upcloud")
+    last_request_body = None
 
     def _1_2_zone(self, method, url, body, headers):
         auth = headers["Authorization"].split(" ")[1]
@@ -289,6 +424,7 @@ class UpcloudMockHttp(MockHttp):
     def _1_2_server(self, method, url, body, headers):
         if method == "POST":
             dbody = json.loads(body)
+            self.__class__.last_request_body = dbody
             storages = dbody["server"]["storage_devices"]["storage_device"]
             if any(["type" in storage and storage["type"] == "cdrom" for 
storage in storages]):
                 body = self.fixtures.load("api_1_2_server_from_cdrom.json")
@@ -298,6 +434,31 @@ class UpcloudMockHttp(MockHttp):
             body = self.fixtures.load("api_1_2_server.json")
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
 
+    def _1_2_storage_normal(self, method, url, body, headers):
+        body = self.fixtures.load("api_1_2_storage_normal.json")
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _1_2_storage(self, method, url, body, headers):
+        self.__class__.last_request_body = json.loads(body)
+        body = self.fixtures.load("api_1_2_storage_create.json")
+        return (httplib.CREATED, body, {}, httplib.responses[httplib.CREATED])
+
+    def _1_2_storage_01d4fcd4_e446_433b_8a9c_551a1284952e_attach(
+        self, method, url, body, headers
+    ):
+        self.__class__.last_request_body = json.loads(body)
+        body = 
self.fixtures.load("api_1_2_storage_01d4fcd4-e446-433b-8a9c-551a1284952e.json")
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _1_2_storage_01d4fcd4_e446_433b_8a9c_551a1284952e_detach(
+        self, method, url, body, headers
+    ):
+        body = 
self.fixtures.load("api_1_2_storage_01d4fcd4-e446-433b-8a9c-551a1284952e.json")
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _1_2_storage_01d4fcd4_e446_433b_8a9c_551a1284952e(self, method, url, 
body, headers):
+        return (httplib.NO_CONTENT, "", {}, 
httplib.responses[httplib.NO_CONTENT])
+
     def _1_2_server_00f8c525_7e62_4108_8115_3958df5b43dc(self, method, url, 
body, headers):
         body = 
self.fixtures.load("api_1_2_server_00f8c525-7e62-4108-8115-3958df5b43dc.json")
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
@@ -308,6 +469,16 @@ class UpcloudMockHttp(MockHttp):
         )
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
 
+    def _1_2_server_00f8c525_7e62_4108_8115_3958df5b43dc_start(self, method, 
url, body, headers):
+        self.__class__.last_request_body = json.loads(body)
+        body = 
self.fixtures.load("api_1_2_server_00f8c525-7e62-4108-8115-3958df5b43dc.json")
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _1_2_server_00f8c525_7e62_4108_8115_3958df5b43dc_stop(self, method, 
url, body, headers):
+        self.__class__.last_request_body = json.loads(body)
+        body = 
self.fixtures.load("api_1_2_server_00f8c525-7e62-4108-8115-3958df5b43dc.json")
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
     def _1_2_server_00893c98_5d5a_4363_b177_88df518a2b60(self, method, url, 
body, headers):
         body = 
self.fixtures.load("api_1_2_server_00893c98-5d5a-4363-b177-88df518a2b60.json")
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])

Reply via email to