Skip to content

Commit

Permalink
Merge pull request #449 from linode/dev
Browse files Browse the repository at this point in the history
v5.20.0
  • Loading branch information
zliang-akamai authored Aug 12, 2024
2 parents bc9f123 + cea7eb2 commit 7359942
Show file tree
Hide file tree
Showing 27 changed files with 439 additions and 89 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/e2e-test-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,13 @@ jobs:
if: always()
run: |
filename=$(ls | grep -E '^[0-9]{12}_sdk_test_report\.xml$')
python tod_scripts/add_to_xml_test_report.py \
python3 e2e_scripts/tod_scripts/xml_to_obj_storage/scripts/add_gha_info_to_xml.py \
--branch_name "${GITHUB_REF#refs/*/}" \
--gha_run_id "$GITHUB_RUN_ID" \
--gha_run_number "$GITHUB_RUN_NUMBER" \
--xmlfile "${filename}"
sync
python3 tod_scripts/test_report_upload_script.py "${filename}"
python3 e2e_scripts/tod_scripts/xml_to_obj_storage/scripts/xml_to_obj.py "${filename}"
env:
LINODE_CLI_OBJ_ACCESS_KEY: ${{ secrets.LINODE_CLI_OBJ_ACCESS_KEY }}
LINODE_CLI_OBJ_SECRET_KEY: ${{ secrets.LINODE_CLI_OBJ_SECRET_KEY }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,13 @@ jobs:
if: always()
run: |
filename=$(ls | grep -E '^[0-9]{12}_sdk_test_report\.xml$')
python tod_scripts/add_to_xml_test_report.py \
python3 e2e_scripts/tod_scripts/xml_to_obj_storage/scripts/add_gha_info_to_xml.py \
--branch_name "${GITHUB_REF#refs/*/}" \
--gha_run_id "$GITHUB_RUN_ID" \
--gha_run_number "$GITHUB_RUN_NUMBER" \
--xmlfile "${filename}"
sync
python3 tod_scripts/test_report_upload_script.py "${filename}"
python3 e2e_scripts/tod_scripts/xml_to_obj_storage/scripts/xml_to_obj.py "${filename}"
env:
LINODE_CLI_OBJ_ACCESS_KEY: ${{ secrets.LINODE_CLI_OBJ_ACCESS_KEY }}
LINODE_CLI_OBJ_SECRET_KEY: ${{ secrets.LINODE_CLI_OBJ_SECRET_KEY }}
6 changes: 3 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "tod_scripts"]
path = tod_scripts
url = https://github.com/linode/TOD-test-report-uploader.git
[submodule "e2e_scripts"]
path = e2e_scripts
url = https://github.com/linode/dx-e2e-test-scripts
1 change: 1 addition & 0 deletions e2e_scripts
Submodule e2e_scripts added at b56178
2 changes: 1 addition & 1 deletion linode_api4/groups/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ def child_accounts(self, *filters):
NOTE: Parent/Child related features may not be generally available.
API doc: TBD
API Documentation: https://techdocs.akamai.com/linode-api/reference/get-child-accounts
:returns: a list of all child accounts.
:rtype: PaginatedList of ChildAccount
Expand Down
51 changes: 37 additions & 14 deletions linode_api4/groups/image.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from typing import BinaryIO, Tuple
from typing import BinaryIO, List, Optional, Tuple, Union

import requests

from linode_api4.errors import UnexpectedResponseError
from linode_api4.groups import Group
from linode_api4.objects import Base, Image
from linode_api4.objects import Base, Disk, Image
from linode_api4.util import drop_null_keys


Expand All @@ -29,39 +29,45 @@ def __call__(self, *filters):
"""
return self.client._get_and_filter(Image, *filters)

def create(self, disk, label=None, description=None, cloud_init=False):
def create(
self,
disk: Union[Disk, int],
label: str = None,
description: str = None,
cloud_init: bool = False,
tags: Optional[List[str]] = None,
):
"""
Creates a new Image from a disk you own.
API Documentation: https://techdocs.akamai.com/linode-api/reference/post-image
:param disk: The Disk to imagize.
:type disk: Disk or int
:type disk: Union[Disk, int]
:param label: The label for the resulting Image (defaults to the disk's
label.
:type label: str
:param description: The description for the new Image.
:type description: str
:param cloud_init: Whether this Image supports cloud-init.
:type cloud_init: bool
:param tags: A list of customized tags of this new Image.
:type tags: Optional[List[str]]
:returns: The new Image.
:rtype: Image
"""
params = {
"disk_id": disk.id if issubclass(type(disk), Base) else disk,
"label": label,
"description": description,
"tags": tags,
}

if label is not None:
params["label"] = label

if description is not None:
params["description"] = description

if cloud_init:
params["cloud_init"] = cloud_init

result = self.client.post("/images", data=params)
result = self.client.post("/images", data=drop_null_keys(params))

if not "id" in result:
raise UnexpectedResponseError(
Expand All @@ -78,6 +84,7 @@ def create_upload(
region: str,
description: str = None,
cloud_init: bool = False,
tags: Optional[List[str]] = None,
) -> Tuple[Image, str]:
"""
Creates a new Image and returns the corresponding upload URL.
Expand All @@ -92,11 +99,18 @@ def create_upload(
:type description: str
:param cloud_init: Whether this Image supports cloud-init.
:type cloud_init: bool
:param tags: A list of customized tags of this Image.
:type tags: Optional[List[str]]
:returns: A tuple containing the new image and the image upload URL.
:rtype: (Image, str)
"""
params = {"label": label, "region": region, "description": description}
params = {
"label": label,
"region": region,
"description": description,
"tags": tags,
}

if cloud_init:
params["cloud_init"] = cloud_init
Expand All @@ -114,7 +128,12 @@ def create_upload(
return Image(self.client, result_image["id"], result_image), result_url

def upload(
self, label: str, region: str, file: BinaryIO, description: str = None
self,
label: str,
region: str,
file: BinaryIO,
description: str = None,
tags: Optional[List[str]] = None,
) -> Image:
"""
Creates and uploads a new image.
Expand All @@ -128,12 +147,16 @@ def upload(
:param file: The BinaryIO object to upload to the image. This is generally obtained from open("myfile", "rb").
:param description: The description for the new Image.
:type description: str
:param tags: A list of customized tags of this Image.
:type tags: Optional[List[str]]
:returns: The resulting image.
:rtype: Image
"""

image, url = self.create_upload(label, region, description=description)
image, url = self.create_upload(
label, region, description=description, tags=tags
)

requests.put(
url,
Expand Down
2 changes: 1 addition & 1 deletion linode_api4/groups/placement.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def groups(self, *filters):
groups = client.placement.groups(PlacementGroup.label == "test")
API Documentation: TODO
API Documentation: https://techdocs.akamai.com/linode-api/reference/get-placement-groups
:param filters: Any number of filters to apply to this query.
See :doc:`Filtering Collections</linode_api4/objects/filtering>`
Expand Down
6 changes: 3 additions & 3 deletions linode_api4/groups/vpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def __call__(self, *filters) -> PaginatedList:
vpcs = client.vpcs()
API Documentation: TODO
API Documentation: https://techdocs.akamai.com/linode-api/reference/get-vpcs
:param filters: Any number of filters to apply to this query.
See :doc:`Filtering Collections</linode_api4/objects/filtering>`
Expand All @@ -38,7 +38,7 @@ def create(
"""
Creates a new VPC under your Linode account.
API Documentation: TODO
API Documentation: https://techdocs.akamai.com/linode-api/reference/post-vpc
:param label: The label of the newly created VPC.
:type label: str
Expand Down Expand Up @@ -90,7 +90,7 @@ def ips(self, *filters) -> PaginatedList:
vpc_ips = client.vpcs.ips()
API Documentation: TODO
API Documentation: https://techdocs.akamai.com/linode-api/reference/get-vpcs-ips
:param filters: Any number of filters to apply to this query.
See :doc:`Filtering Collections</linode_api4/objects/filtering>`
Expand Down
29 changes: 22 additions & 7 deletions linode_api4/linode_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import json
import logging
from importlib.metadata import version
from typing import BinaryIO, Tuple
from typing import BinaryIO, List, Tuple
from urllib import parse

import requests
Expand Down Expand Up @@ -378,32 +378,47 @@ def __setattr__(self, key, value):

super().__setattr__(key, value)

def image_create(self, disk, label=None, description=None):
def image_create(self, disk, label=None, description=None, tags=None):
"""
.. note:: This method is an alias to maintain backwards compatibility.
Please use :meth:`LinodeClient.images.create(...) <.ImageGroup.create>` for all new projects.
"""
return self.images.create(disk, label=label, description=description)
return self.images.create(
disk, label=label, description=description, tags=tags
)

def image_create_upload(
self, label: str, region: str, description: str = None
self,
label: str,
region: str,
description: str = None,
tags: List[str] = None,
) -> Tuple[Image, str]:
"""
.. note:: This method is an alias to maintain backwards compatibility.
Please use :meth:`LinodeClient.images.create_upload(...) <.ImageGroup.create_upload>`
for all new projects.
"""

return self.images.create_upload(label, region, description=description)
return self.images.create_upload(
label, region, description=description, tags=tags
)

def image_upload(
self, label: str, region: str, file: BinaryIO, description: str = None
self,
label: str,
region: str,
file: BinaryIO,
description: str = None,
tags: List[str] = None,
) -> Image:
"""
.. note:: This method is an alias to maintain backwards compatibility.
Please use :meth:`LinodeClient.images.upload(...) <.ImageGroup.upload>` for all new projects.
"""
return self.images.upload(label, region, file, description=description)
return self.images.upload(
label, region, file, description=description, tags=tags
)

def nodebalancer_create(self, region, **kwargs):
"""
Expand Down
6 changes: 3 additions & 3 deletions linode_api4/objects/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,17 @@ class ChildAccount(Account):
NOTE: Parent/Child related features may not be generally available.
API Documentation: TBD
API Documentation: https://techdocs.akamai.com/linode-api/reference/get-child-account
"""

api_endpoint = "/account/child-accounts/{euuid}"
id_attribute = "euuid"

def create_token(self, **kwargs):
"""
Create a ephemeral token for accessing the child account.
Create an ephemeral token for accessing the child account.
API Documentation: TBD
API Documentation: https://techdocs.akamai.com/linode-api/reference/post-child-account-token
"""
resp = self._client.post(
"{}/token".format(self.api_endpoint),
Expand Down
60 changes: 59 additions & 1 deletion linode_api4/objects/image.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,31 @@
from linode_api4.objects import Base, Property
from dataclasses import dataclass
from typing import List, Union

from linode_api4.objects import Base, Property, Region
from linode_api4.objects.serializable import JSONObject, StrEnum


class ReplicationStatus(StrEnum):
"""
The Enum class represents image replication status.
"""

pending_replication = "pending replication"
pending_deletion = "pending deletion"
available = "available"
creating = "creating"
pending = "pending"
replicating = "replicating"


@dataclass
class ImageRegion(JSONObject):
"""
The region and status of an image replica.
"""

region: str = ""
status: ReplicationStatus = None


class Image(Base):
Expand Down Expand Up @@ -28,4 +55,35 @@ class Image(Base):
"capabilities": Property(
unordered=True,
),
"tags": Property(mutable=True, unordered=True),
"total_size": Property(),
"regions": Property(json_object=ImageRegion, unordered=True),
}

def replicate(self, regions: Union[List[str], List[Region]]):
"""
Replicate the image to other regions.
Note: Image replication may not currently be available to all users.
API Documentation: https://techdocs.akamai.com/linode-api/reference/post-replicate-image
:param regions: A list of regions that the customer wants to replicate this image in.
At least one valid region is required and only core regions allowed.
Existing images in the regions not passed will be removed.
:type regions: List[str]
"""
params = {
"regions": [
region.id if isinstance(region, Region) else region
for region in regions
]
}

result = self._client.post(
"{}/regions".format(self.api_endpoint), model=self, data=params
)

# The replicate endpoint returns the updated Image, so we can use this
# as an opportunity to refresh the object
self._populate(result)
Loading

0 comments on commit 7359942

Please sign in to comment.