Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release v5.15.0 #398

Merged
merged 7 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Integration Tests

on:
workflow_dispatch: null
push:
branches:
- main
- dev

jobs:
integration-tests:
runs-on: ubuntu-latest
env:
EXIT_STATUS: 0
steps:
- name: Clone Repository
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: 'recursive'

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.x'

- name: Install Python deps
run: pip install -U setuptools wheel boto3 certifi

- name: Install Python SDK
run: make dev-install
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Run Integration tests
run: |
timestamp=$(date +'%Y%m%d%H%M')
report_filename="${timestamp}_sdk_test_report.xml"
status=0
if ! python3 -m pytest test/integration/${INTEGRATION_TEST_PATH} --disable-warnings --junitxml="${report_filename}"; then
echo "EXIT_STATUS=1" >> $GITHUB_ENV
fi
env:
LINODE_TOKEN: ${{ secrets.LINODE_TOKEN }}

- name: Add additional information to XML report
run: |
filename=$(ls | grep -E '^[0-9]{12}_sdk_test_report\.xml$')
python tod_scripts/add_to_xml_test_report.py \
--branch_name "${GITHUB_REF#refs/*/}" \
--gha_run_id "$GITHUB_RUN_ID" \
--gha_run_number "$GITHUB_RUN_NUMBER" \
--xmlfile "${filename}"

- name: Upload test results
run: |
report_filename=$(ls | grep -E '^[0-9]{12}_sdk_test_report\.xml$')
python3 tod_scripts/test_report_upload_script.py "${report_filename}"
env:
LINODE_CLI_OBJ_ACCESS_KEY: ${{ secrets.LINODE_CLI_OBJ_ACCESS_KEY }}
LINODE_CLI_OBJ_SECRET_KEY: ${{ secrets.LINODE_CLI_OBJ_SECRET_KEY }}

- name: Test Execution Status Handler
run: |
if [[ "$EXIT_STATUS" != 0 ]]; then
echo "Test execution contains failure(s)"
exit $EXIT_STATUS
else
echo "Tests passed!"
fi
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,4 @@ testunit:

.PHONY: smoketest
smoketest:
$(PYTHON) -m pytest -m smoke test/integration --disable-warnings
$(PYTHON) -m pytest -m smoke test/integration
4 changes: 2 additions & 2 deletions linode_api4/groups/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,10 +487,10 @@ def join_beta_program(self, beta: Union[str, BetaProgram]):

def availabilities(self, *filters):
"""
Returns a list of all available regions and the resources which are NOT available
Returns a list of all available regions and the resource types which are available
to the account.

API doc: TBD
API doc: https://www.linode.com/docs/api/account/#region-service-availability

:returns: a list of region availability information.
:rtype: PaginatedList of AccountAvailability
Expand Down
10 changes: 6 additions & 4 deletions linode_api4/objects/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class Account(Base):
"zip": Property(mutable=True),
"address_2": Property(mutable=True),
"tax_id": Property(mutable=True),
"capabilities": Property(),
"capabilities": Property(unordered=True),
"credit_card": Property(),
"active_promotions": Property(),
"active_since": Property(),
Expand Down Expand Up @@ -660,15 +660,17 @@ class AccountBetaProgram(Base):

class AccountAvailability(Base):
"""
The resources information in a region which are NOT available to an account.
Contains information about the resources available for a region under the
current account.

API doc: TBD
API doc: https://www.linode.com/docs/api/account/#region-service-availability
"""

api_endpoint = "/account/availability/{region}"
id_attribute = "region"

properties = {
"region": Property(identifier=True),
"unavailable": Property(),
"unavailable": Property(unordered=True),
"available": Property(unordered=True),
}
16 changes: 14 additions & 2 deletions linode_api4/objects/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def __init__(
id_relationship=False,
slug_relationship=False,
nullable=False,
unordered=False,
json_object=None,
):
"""
Expand All @@ -50,6 +51,10 @@ def __init__(
(This should be used on fields ending with '_id' only)
slug_relationship - This property is a slug related for a given type.
nullable - This property can be explicitly null on PUT requests.
unordered - The order of this property is not significant.
NOTE: This field is currently only for annotations purposes
and does not influence any update or decoding/encoding logic.
json_object - The JSONObject class this property should be decoded into.
"""
self.mutable = mutable
self.identifier = identifier
Expand All @@ -60,6 +65,7 @@ def __init__(
self.id_relationship = id_relationship
self.slug_relationship = slug_relationship
self.nullable = nullable
self.unordered = unordered
self.json_class = json_object


Expand Down Expand Up @@ -103,9 +109,15 @@ def dict(self):
result[k] = v.dict
elif isinstance(v, list):
result[k] = [
item.dict if isinstance(item, cls) else item for item in v
(
item.dict
if isinstance(item, cls)
else item._raw_json if isinstance(item, Base) else item
)
for item in v
]

elif isinstance(v, Base):
result[k] = v._raw_json
return result


Expand Down
6 changes: 3 additions & 3 deletions linode_api4/objects/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ class MySQLDatabase(Base):
properties = {
"id": Property(identifier=True),
"label": Property(mutable=True),
"allow_list": Property(mutable=True),
"allow_list": Property(mutable=True, unordered=True),
"backups": Property(derived_class=MySQLDatabaseBackup),
"cluster_size": Property(),
"created": Property(is_datetime=True),
Expand Down Expand Up @@ -262,7 +262,7 @@ class PostgreSQLDatabase(Base):
properties = {
"id": Property(identifier=True),
"label": Property(mutable=True),
"allow_list": Property(mutable=True),
"allow_list": Property(mutable=True, unordered=True),
"backups": Property(derived_class=PostgreSQLDatabaseBackup),
"cluster_size": Property(),
"created": Property(is_datetime=True),
Expand Down Expand Up @@ -404,7 +404,7 @@ class Database(Base):
properties = {
"id": Property(),
"label": Property(),
"allow_list": Property(),
"allow_list": Property(unordered=True),
"cluster_size": Property(),
"created": Property(),
"encrypted": Property(),
Expand Down
6 changes: 3 additions & 3 deletions linode_api4/objects/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ class Domain(Base):
"status": Property(mutable=True),
"soa_email": Property(mutable=True),
"retry_sec": Property(mutable=True),
"master_ips": Property(mutable=True),
"axfr_ips": Property(mutable=True),
"master_ips": Property(mutable=True, unordered=True),
"axfr_ips": Property(mutable=True, unordered=True),
"expire_sec": Property(mutable=True),
"refresh_sec": Property(mutable=True),
"ttl_sec": Property(mutable=True),
"records": Property(derived_class=DomainRecord),
"type": Property(mutable=True),
"tags": Property(mutable=True),
"tags": Property(mutable=True, unordered=True),
}

def record_create(self, record_type, **kwargs):
Expand Down
4 changes: 3 additions & 1 deletion linode_api4/objects/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,7 @@ class Image(Base):
"vendor": Property(),
"size": Property(),
"deprecated": Property(),
"capabilities": Property(),
"capabilities": Property(
unordered=True,
),
}
8 changes: 5 additions & 3 deletions linode_api4/objects/linode.py
Original file line number Diff line number Diff line change
Expand Up @@ -642,11 +642,11 @@ class Instance(Base):
"configs": Property(derived_class=Config),
"type": Property(slug_relationship=Type),
"backups": Property(mutable=True),
"ipv4": Property(),
"ipv4": Property(unordered=True),
"ipv6": Property(),
"hypervisor": Property(),
"specs": Property(),
"tags": Property(mutable=True),
"tags": Property(mutable=True, unordered=True),
"host_uuid": Property(),
"watchdog_enabled": Property(mutable=True),
"has_user_data": Property(),
Expand Down Expand Up @@ -1745,7 +1745,9 @@ class StackScript(Base):
"created": Property(is_datetime=True),
"deployments_active": Property(),
"script": Property(mutable=True),
"images": Property(mutable=True), # TODO make slug_relationship
"images": Property(
mutable=True, unordered=True
), # TODO make slug_relationship
"deployments_total": Property(),
"description": Property(mutable=True),
"updated": Property(is_datetime=True),
Expand Down
4 changes: 2 additions & 2 deletions linode_api4/objects/lke.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class LKENodePool(DerivedBase):
volatile=True
), # this is formatted in _populate below
"autoscaler": Property(mutable=True),
"tags": Property(mutable=True),
"tags": Property(mutable=True, unordered=True),
}

def _populate(self, json):
Expand Down Expand Up @@ -121,7 +121,7 @@ class LKECluster(Base):
"id": Property(identifier=True),
"created": Property(is_datetime=True),
"label": Property(mutable=True),
"tags": Property(mutable=True),
"tags": Property(mutable=True, unordered=True),
"updated": Property(is_datetime=True),
"region": Property(slug_relationship=Region),
"k8s_version": Property(slug_relationship=KubeVersion, mutable=True),
Expand Down
8 changes: 5 additions & 3 deletions linode_api4/objects/networking.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ class IPv6Range(Base):
"region": Property(slug_relationship=Region),
"prefix": Property(),
"route_target": Property(),
"linodes": Property(),
"linodes": Property(
unordered=True,
),
"is_bgp": Property(),
}

Expand Down Expand Up @@ -151,7 +153,7 @@ class VLAN(Base):
properties = {
"label": Property(identifier=True),
"created": Property(is_datetime=True),
"linodes": Property(),
"linodes": Property(unordered=True),
"region": Property(slug_relationship=Region),
}

Expand Down Expand Up @@ -189,7 +191,7 @@ class Firewall(Base):
properties = {
"id": Property(identifier=True),
"label": Property(mutable=True),
"tags": Property(mutable=True),
"tags": Property(mutable=True, unordered=True),
"status": Property(mutable=True),
"created": Property(is_datetime=True),
"updated": Property(is_datetime=True),
Expand Down
4 changes: 2 additions & 2 deletions linode_api4/objects/nodebalancer.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class NodeBalancerNode(DerivedBase):
"weight": Property(mutable=True),
"mode": Property(mutable=True),
"status": Property(),
"tags": Property(mutable=True),
"tags": Property(mutable=True, unordered=True),
}

def __init__(self, client, id, parent_id, nodebalancer_id=None, json=None):
Expand Down Expand Up @@ -217,7 +217,7 @@ class NodeBalancer(Base):
"region": Property(slug_relationship=Region),
"configs": Property(derived_class=NodeBalancerConfig),
"transfer": Property(),
"tags": Property(mutable=True),
"tags": Property(mutable=True, unordered=True),
}

# create derived objects
Expand Down
2 changes: 1 addition & 1 deletion linode_api4/objects/region.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Region(Base):
properties = {
"id": Property(identifier=True),
"country": Property(),
"capabilities": Property(),
"capabilities": Property(unordered=True),
"status": Property(),
"resolvers": Property(),
"label": Property(),
Expand Down
2 changes: 1 addition & 1 deletion linode_api4/objects/volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class Volume(Base):
"size": Property(),
"status": Property(),
"region": Property(slug_relationship=Region),
"tags": Property(mutable=True),
"tags": Property(mutable=True, unordered=True),
"filesystem_path": Property(),
"hardware_type": Property(),
"linode_label": Property(),
Expand Down
23 changes: 22 additions & 1 deletion linode_api4/objects/vpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from linode_api4.errors import UnexpectedResponseError
from linode_api4.objects import Base, DerivedBase, Property, Region
from linode_api4.objects.serializable import JSONObject
from linode_api4.paginated_list import PaginatedList


@dataclass
Expand Down Expand Up @@ -33,7 +34,7 @@ class VPCSubnet(DerivedBase):
"id": Property(identifier=True),
"label": Property(mutable=True),
"ipv4": Property(),
"linodes": Property(json_object=VPCSubnetLinode),
"linodes": Property(json_object=VPCSubnetLinode, unordered=True),
"created": Property(is_datetime=True),
"updated": Property(is_datetime=True),
}
Expand Down Expand Up @@ -97,3 +98,23 @@ def subnet_create(

d = VPCSubnet(self._client, result["id"], self.id, result)
return d

@property
def ips(self, *filters) -> PaginatedList:
"""
Get all the IP addresses under this VPC.

API Documentation: TODO

:returns: A list of VPCIPAddresses the acting user can access.
:rtype: PaginatedList of VPCIPAddress
"""

# need to avoid circular import
from linode_api4.objects import ( # pylint: disable=import-outside-toplevel
VPCIPAddress,
)

return self._client._get_and_filter(
VPCIPAddress, *filters, endpoint="/vpcs/{}/ips".format(self.id)
)
Loading
Loading