UpCloudLtd / upcloud-python-api

Python client for UpCloud's API
MIT License
53 stars 21 forks source link

AttributeError: 'Server' object has no attribute 'cloud_manager' #159

Open helioloureiro opened 1 week ago

helioloureiro commented 1 week ago

Hi,

I've tried to apply what is describe on the project page to have a server up and running.

My Server builder is like this:

class CloudServer:
   [...]
    def buildServerData(self):
        ## check again if it exists from existent servers
        for server in self.manager.get_servers():
            if server.hostname == self.args.hostname:
                doesExist = True
                self.uuid = server.uuid
                break

        server_networking = []
        for network_type in NETWORK_TYPES.split(","):
            server_networking.append(
                ServerNetworkInterface(
                    {
                        'type': network_type
                        , 'ip_addresses': [
                            {
                                'family': 'IPv4'
                            }
                        ]
                    }
                )
            )

        self.server = Server(
            plan=self.args.plan,
            hostname=self.args.hostname,
            zone=self.args.zone,
            storage_devices=[
                Storage(
                    os=self.args.os, 
                    size=self.args.storage_size,
                    encryption=self.args.storage_encryption
                )
            ],
            login_user=self.login_user,
            metadata=self.args.metadata,
            title=f"{self.args.hostname} created by python",
            networking=server_networking,
            simple_backup=self.args.simple_backup,
            uuid=self.uuid
        )
        try:
            print("server:", self.server)
        except TypeError:
            print("server returned a null string")

and it works to create the server.

    def createServer(self):
        if self.uuid is None:
            self.manager.create_server(self.server)
        else:
            print("Server already created and using uuid:", self.uuid)

but it is crashing during shutdown and destroy. The code is this below:

    def destroyServer(self):
        self.server.stop_and_destroy()
        for disk in self.server.storage_devices:
            disk.destroy()

And I get the following error:

Traceback (most recent call last):
  File "/home/helio/upcloud-testing/python/./server1.py", line 154, in <module>
    server.takeAction()
  File "/home/helio/upcloud-testing/python/./server1.py", line 112, in takeAction
    self.destroyServer()
  File "/home/helio/upcloud-testing/python/./server1.py", line 129, in destroyServer
    self.server.stop_and_destroy()
  File "/home/helio/upcloud-testing/python/venv/lib/python3.12/site-packages/upcloud_api/server.py", line 609, in stop_and_destroy
    self.populate()
  File "/home/helio/upcloud-testing/python/venv/lib/python3.12/site-packages/upcloud_api/server.py", line 174, in populate
    server, IPAddresses, storages = self.cloud_manager.get_server_data(self.uuid)
                                    ^^^^^^^^^^^^^^^^^^
AttributeError: 'Server' object has no attribute 'cloud_manager'

So I'm not sure whether I did something wrong, but it complains about this missing attribute.

helioloureiro commented 1 week ago

I got what I did wrong. I forced to create, even if created, and that worked.

    def destroyServer(self):
        self.manager.create_server(self.server)
        self.server.stop_and_destroy()
        for disk in self.server.storage_devices:
            disk.destroy()
helioloureiro commented 1 week ago

Ok... that wasn ´t a good idea. I ended up creating an extra server every time I tried to destroy the other.

So problem remains.

Darep commented 1 week ago

The creation of the Server object on the server = Server(-line manually seems to create the problem. It seems that the same object is later used in destroyServer(). The Server() objects should really be only sent to the create_server() method provided by the SDK.

Here are a couple of ideas that came to my mind to try and fix this:

  1. Change the line for self.manager.create_server(self.server) to self.server = self.manager.create_server(self.server)
    • the create_server() method returns a Server-object with the cloud_manager correctly populated
  2. Change deletion to accept UUID and get the Server-object using the get_server(uuid) method provided by the SDK
  3. Use self.server = Server._create_server_obj(Server(...your fields here...), cloud_manager=self.manager) to create the Server object
  4. Try to inject the manager to the Server()-object after the server = Server(-call like so: server.cloud_manager = self.manager or server['cloud_manager'] = self.manager
    • I'm not sure if this works 😅

Hope this helps!