From 88e61076c9c63926000a6c5ea83fb6efe1cf5c28 Mon Sep 17 00:00:00 2001 From: Zhiwei Liang <121905282+zliang-akamai@users.noreply.github.com> Date: Thu, 12 Dec 2024 17:03:01 -0500 Subject: [PATCH 1/3] Update OBJ tests and examples (#633) * Update version of the AWS Collection * Update obj tests --- .github/workflows/integration-tests-pr.yml | 9 +-------- .github/workflows/integration-tests.yml | 2 +- .github/workflows/nightly-smoke-tests.yml | 2 +- .github/workflows/release.yml | 2 +- .../obj_static_site/roles/static_site/tasks/main.yml | 7 ++++--- tests/integration/targets/object_basic/tasks/main.yaml | 10 +++++++--- .../targets/object_keys_basic/tasks/main.yaml | 10 +++++++--- 7 files changed, 22 insertions(+), 20 deletions(-) diff --git a/.github/workflows/integration-tests-pr.yml b/.github/workflows/integration-tests-pr.yml index e10b9145..19743f0f 100644 --- a/.github/workflows/integration-tests-pr.yml +++ b/.github/workflows/integration-tests-pr.yml @@ -39,13 +39,6 @@ jobs: fetch-depth: 0 submodules: 'recursive' - # Install deps - - name: update packages - run: sudo apt-get update -y - - - name: install make - run: sudo apt-get install -y build-essential - - name: setup python 3 uses: actions/setup-python@v5 with: @@ -55,7 +48,7 @@ jobs: run: make deps - name: install ansible dependencies - run: ansible-galaxy collection install amazon.aws:==6.0.1 + run: ansible-galaxy collection install amazon.aws:==9.1.0 - name: install collection run: make install diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 49fbfb0b..051ea283 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -52,7 +52,7 @@ jobs: run: make deps - name: Install ansible dependencies - run: ansible-galaxy collection install amazon.aws:==6.0.1 + run: ansible-galaxy collection install amazon.aws:==9.1.0 - name: Install Collection run: make install diff --git a/.github/workflows/nightly-smoke-tests.yml b/.github/workflows/nightly-smoke-tests.yml index da150285..888aae95 100644 --- a/.github/workflows/nightly-smoke-tests.yml +++ b/.github/workflows/nightly-smoke-tests.yml @@ -40,7 +40,7 @@ jobs: run: make deps - name: Install ansible dependencies - run: ansible-galaxy collection install amazon.aws:==6.0.1 + run: ansible-galaxy collection install amazon.aws:==9.1.0 - name: Install Collection run: make install diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 785c5993..f5cd811b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,7 +33,7 @@ jobs: run: make deps - name: install ansible dependencies - run: ansible-galaxy collection install amazon.aws:==6.0.1 + run: ansible-galaxy collection install amazon.aws:==9.1.0 - name: inject docs using specdoc run: make inject diff --git a/examples/obj_static_site/roles/static_site/tasks/main.yml b/examples/obj_static_site/roles/static_site/tasks/main.yml index 6e0b2c7d..68a62ee0 100644 --- a/examples/obj_static_site/roles/static_site/tasks/main.yml +++ b/examples/obj_static_site/roles/static_site/tasks/main.yml @@ -12,15 +12,15 @@ - name: Create an Object Storage bucket amazon.aws.s3_bucket: name: "{{ bucket_name }}" - s3_url: "https://{{ cluster_info.clusters[0].domain }}/" + endpoint_url: "https://{{ cluster_info.clusters[0].domain }}/" aws_access_key: "{{ obj_key.key.access_key }}" aws_secret_key: "{{ obj_key.key.secret_key }}" state: present - name: Upload the static site files - amazon.aws.aws_s3: - s3_url: "https://{{ cluster_info.clusters[0].domain }}/" + amazon.aws.s3_object: + endpoint_url: "https://{{ cluster_info.clusters[0].domain }}/" aws_access_key: "{{ obj_key.key.access_key }}" aws_secret_key: "{{ obj_key.key.secret_key }}" @@ -29,6 +29,7 @@ src: "{{ item }}" mode: put permission: public-read + ceph: true with_fileglob: 'roles/static_site/files/public/*.html' - name: Configure the Object Storage Bucket as a website with index and error pages diff --git a/tests/integration/targets/object_basic/tasks/main.yaml b/tests/integration/targets/object_basic/tasks/main.yaml index 9cf48616..b4e3f052 100644 --- a/tests/integration/targets/object_basic/tasks/main.yaml +++ b/tests/integration/targets/object_basic/tasks/main.yaml @@ -39,10 +39,12 @@ - name: Create an S3 bucket amazon.aws.s3_bucket: - s3_url: 'http://{{ info_by_id.clusters[0].domain }}/' + endpoint_url: 'https://{{ info_by_id.clusters[0].domain }}/' aws_access_key: '{{ create_key.key.access_key }}' aws_secret_key: '{{ create_key.key.secret_key }}' name: 'test-ansible-bucket-{{ r }}' + ceph: true + region: "default" state: present register: create_bucket @@ -77,14 +79,16 @@ - create_access.key.bucket_access[1].permissions == 'read_only' always: - - ignore_errors: yes + - ignore_errors: true block: - name: Delete the S3 bucket amazon.aws.s3_bucket: - s3_url: 'http://{{ info_by_id.clusters[0].domain }}/' + endpoint_url: 'https://{{ info_by_id.clusters[0].domain }}/' aws_access_key: '{{ create_key.key.access_key }}' aws_secret_key: '{{ create_key.key.secret_key }}' name: '{{ create_bucket.name }}' + ceph: true + region: "default" state: absent register: delete_bucket diff --git a/tests/integration/targets/object_keys_basic/tasks/main.yaml b/tests/integration/targets/object_keys_basic/tasks/main.yaml index b40fd7c7..fabff4e9 100644 --- a/tests/integration/targets/object_keys_basic/tasks/main.yaml +++ b/tests/integration/targets/object_keys_basic/tasks/main.yaml @@ -58,11 +58,13 @@ - name: Create an S3 bucket using the key amazon.aws.s3_bucket: - s3_url: "https://{{ update.key.regions[0].s3_endpoint }}/" + endpoint_url: "https://{{ update.key.regions[0].s3_endpoint }}/" aws_access_key: "{{ create.key.access_key }}" aws_secret_key: "{{ create.key.secret_key }}" name: "test-ansible-bucket-{{ r }}" state: present + ceph: true + region: "default" register: create_bucket - name: Assert bucket was created @@ -137,14 +139,16 @@ failed_when: "'`access` is not an updatable field' not in update_scoped.msg" always: - - ignore_errors: yes + - ignore_errors: true block: - name: Delete the OBJ bucket amazon.aws.s3_bucket: - s3_url: "https://{{ update.key.regions[0].s3_endpoint }}//" + endpoint_url: "https://{{ update.key.regions[0].s3_endpoint }}//" aws_access_key: "{{ create.key.access_key }}" aws_secret_key: "{{ create.key.secret_key }}" name: "{{ create_bucket.name }}" + ceph: true + region: "default" state: absent register: delete_bucket From 997487070633aac016532ccbb7f5241062705039 Mon Sep 17 00:00:00 2001 From: Zhiwei Liang <121905282+zliang-akamai@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:11:15 -0500 Subject: [PATCH 2/3] Add security workflows (#634) * Add security workflows * Remove apt install steps in all workflows --- .github/workflows/codeql.yml | 39 +++++++++++++++++++++++ .github/workflows/dependency-review.yml | 19 +++++++++++ .github/workflows/docs.yml | 12 ------- .github/workflows/integration-tests.yml | 3 -- .github/workflows/nightly-smoke-tests.yml | 3 -- 5 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/dependency-review.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..de49ed0c --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,39 @@ +name: "CodeQL Advanced" + +on: + push: + branches: [ "dev", "main", "proj/*" ] + pull_request: + branches: [ "dev", "main", "proj/*" ] + schedule: + - cron: '0 13 * * 5' + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + runs-on: ubuntu-latest + permissions: + security-events: write + + strategy: + fail-fast: false + matrix: + include: + - language: python + build-mode: none + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + queries: security-and-quality + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 00000000..bf9f46d8 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,19 @@ +name: 'Dependency review' +on: + pull_request: + branches: [ "dev", "main", "proj/*" ] + +permissions: + contents: read + pull-requests: write + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout repository' + uses: actions/checkout@v4 + - name: 'Dependency Review' + uses: actions/dependency-review-action@v4 + with: + comment-summary-in-pr: on-failure diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 754d0506..1df2f9d5 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -17,12 +17,6 @@ jobs: with: path: .ansible/collections/ansible_collections/linode/cloud - - name: update packages - run: sudo apt-get update -y - - - name: install packages - run: sudo apt-get install -y make - - name: setup python 3 uses: actions/setup-python@v5 with: @@ -60,12 +54,6 @@ jobs: with: path: .ansible/collections/ansible_collections/linode/cloud - - name: update packages - run: sudo apt-get update -y - - - name: install packages - run: sudo apt-get install -y make - - name: setup python 3 uses: actions/setup-python@v5 with: diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 051ea283..64f6a45d 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -40,9 +40,6 @@ jobs: fetch-depth: 0 submodules: 'recursive' - - name: Update packages - run: sudo apt-get update -y - - name: Setup Python 3 uses: actions/setup-python@v5 with: diff --git a/.github/workflows/nightly-smoke-tests.yml b/.github/workflows/nightly-smoke-tests.yml index 888aae95..9e503542 100644 --- a/.github/workflows/nightly-smoke-tests.yml +++ b/.github/workflows/nightly-smoke-tests.yml @@ -28,9 +28,6 @@ jobs: fetch-depth: 0 submodules: 'recursive' - - name: Update packages - run: sudo apt-get update -y - - name: Setup Python 3 uses: actions/setup-python@v5 with: From 4da84f0c09e7606293939e0955ed531317315ad8 Mon Sep 17 00:00:00 2001 From: Ye Chen <127243817+yec-akamai@users.noreply.github.com> Date: Tue, 7 Jan 2025 11:04:51 -0500 Subject: [PATCH 3/3] new: Support IP module to allocate a new IP (#628) * ip module * simplify test * address comments * fix lint&doc * handle absent --- README.md | 1 + docs/modules/ip.md | 38 +++++ plugins/module_utils/doc_fragments/ip.py | 25 ++++ plugins/modules/ip.py | 137 ++++++++++++++++++ .../targets/ip_basic/tasks/main.yaml | 53 +++++++ 5 files changed, 254 insertions(+) create mode 100644 docs/modules/ip.md create mode 100644 plugins/module_utils/doc_fragments/ip.py create mode 100644 plugins/modules/ip.py create mode 100644 tests/integration/targets/ip_basic/tasks/main.yaml diff --git a/README.md b/README.md index 49e15ab1..15a1da13 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Name | Description | [linode.cloud.firewall_device](./docs/modules/firewall_device.md)|Manage Linode Firewall Devices.| [linode.cloud.image](./docs/modules/image.md)|Manage a Linode Image.| [linode.cloud.instance](./docs/modules/instance.md)|Manage Linode Instances, Configs, and Disks.| +[linode.cloud.ip](./docs/modules/ip.md)|Allocates a new IPv4 Address on your Account. The Linode must be configured to support additional addresses - please Open a support ticket requesting additional addresses before attempting allocation.| [linode.cloud.ip_assign](./docs/modules/ip_assign.md)|Assign IPs to Linodes in a given Region.| [linode.cloud.ip_rdns](./docs/modules/ip_rdns.md)|Manage a Linode IP address's rDNS.| [linode.cloud.ip_share](./docs/modules/ip_share.md)|Manage the Linode shared IPs.| diff --git a/docs/modules/ip.md b/docs/modules/ip.md new file mode 100644 index 00000000..f9175fce --- /dev/null +++ b/docs/modules/ip.md @@ -0,0 +1,38 @@ +# ip + +Allocates a new IPv4 Address on your Account. The Linode must be configured to support additional addresses - please Open a support ticket requesting additional addresses before attempting allocation. + +- [Minimum Required Fields](#minimum-required-fields) +- [Examples](#examples) +- [Parameters](#parameters) +- [Return Values](#return-values) + +## Minimum Required Fields +| Field | Type | Required | Description | +|-------------|-------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `api_token` | `str` | **Required** | The Linode account personal access token. It is necessary to run the module.
It can be exposed by the environment variable `LINODE_API_TOKEN` instead.
See details in [Usage](https://github.com/linode/ansible_linode?tab=readme-ov-file#usage). | + +## Examples + +```yaml +- name: Allocate IP to Linode + linode.cloud.ip: + linode_id: 123 + public: true + type: ipv4 + state: present +``` + + +## Parameters + +| Field | Type | Required | Description | +|-----------|------|----------|------------------------------------------------------------------------------| +| `state` |
`str`
|
**Required**
| The state of this IP. **(Choices: `present`, `absent`)** | +| `linode_id` |
`int`
|
Optional
| The ID of a Linode you have access to that this address will be allocated to. | +| `public` |
`bool`
|
Optional
| Whether to create a public or private IPv4 address. | +| `type` |
`str`
|
Optional
| The type of address you are requesting. Only IPv4 addresses may be allocated through this operation. **(Choices: `ipv4`)** | +| `address` |
`str`
|
Optional
| The IP address to delete. **(Conflicts With: `linode_id`,`public`,`type`)** | + +## Return Values + diff --git a/plugins/module_utils/doc_fragments/ip.py b/plugins/module_utils/doc_fragments/ip.py new file mode 100644 index 00000000..aefaed91 --- /dev/null +++ b/plugins/module_utils/doc_fragments/ip.py @@ -0,0 +1,25 @@ +"""Documentation fragments for the ip module""" +specdoc_examples = [''' +- name: Allocate IP to Linode + linode.cloud.ip: + linode_id: 123 + public: true + type: ipv4 + state: present'''] + +result_ip_samples = ['''{ + "address": "97.107.143.141", + "gateway": "97.107.143.1", + "linode_id": 123, + "prefix": 24, + "public": true, + "rdns": "test.example.org", + "region": "us-east", + "subnet_mask": "255.255.255.0", + "type": "ipv4", + "vpc_nat_1_1": { + "vpc_id": 242, + "subnet_id": 194, + "address": "139.144.244.36" + } +}'''] diff --git a/plugins/modules/ip.py b/plugins/modules/ip.py new file mode 100644 index 00000000..073d437d --- /dev/null +++ b/plugins/modules/ip.py @@ -0,0 +1,137 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +"""This module allows users to allocate a new IPv4 Address on their accounts.""" + +from __future__ import absolute_import, division, print_function + +from typing import Any, Optional + +import ansible_collections.linode.cloud.plugins.module_utils.doc_fragments.ip as docs +from ansible_collections.linode.cloud.plugins.module_utils.linode_common import ( + LinodeModuleBase, +) +from ansible_collections.linode.cloud.plugins.module_utils.linode_docs import ( + global_authors, + global_requirements, +) +from ansible_collections.linode.cloud.plugins.module_utils.linode_helper import ( + filter_null_values, +) +from ansible_specdoc.objects import FieldType, SpecDocMeta, SpecField + +spec: dict = { + "linode_id": SpecField( + type=FieldType.integer, + description=[ + "The ID of a Linode you have access to " + "that this address will be allocated to." + ], + ), + "public": SpecField( + type=FieldType.bool, + description=["Whether to create a public or private IPv4 address."], + ), + "type": SpecField( + type=FieldType.string, + choices=["ipv4"], + description=[ + "The type of address you are requesting. " + "Only IPv4 addresses may be allocated through this operation." + ], + ), + "address": SpecField( + type=FieldType.string, + description=["The IP address to delete."], + conflicts_with=["linode_id", "public", "type"], + ), + "state": SpecField( + type=FieldType.string, + choices=["present", "absent"], + required=True, + description=["The state of this IP."], + ), +} + +SPECDOC_META = SpecDocMeta( + description=[ + "Allocates a new IPv4 Address on your Account. " + "The Linode must be configured to support " + "additional addresses - " + "please Open a support ticket " + "requesting additional addresses before attempting allocation.", + ], + requirements=global_requirements, + author=global_authors, + options=spec, + examples=docs.specdoc_examples, + return_values={}, +) + +DOCUMENTATION = r""" +""" +EXAMPLES = r""" +""" +RETURN = r""" +""" + + +class Module(LinodeModuleBase): + """Module for allocating a new IP""" + + def __init__(self) -> None: + self.module_arg_spec = SPECDOC_META.ansible_spec + self.results = { + "changed": False, + "actions": [], + "ip": None, + } + super().__init__( + module_arg_spec=self.module_arg_spec, + required_together=[ + ("linode_id", "public", "type"), + ], + ) + + def _handle_present(self) -> None: + params = filter_null_values(self.module.params) + linode_id = params.get("linode_id") + public = params.get("public") + + try: + ip = self.client.networking.ip_allocate(linode_id, public) + self.register_action( + f"IP allocation to Linode {linode_id} completed." + ) + except Exception as exc: + self.fail(msg=f"failed to allocate IP to Linode {linode_id}: {exc}") + + self.results["ip"] = ip._raw_json + + def _handle_absent(self) -> None: + # TODO: Implement deleting IP once it's available in python-sdk. + # Raise an error for now when user reaches deleting IP. + self.fail( + msg="failed to delete IP: IP deleting is currently not supported." + ) + + def exec_module(self, **kwargs: Any) -> Optional[dict]: + """Entrypoint for IP module""" + + state = kwargs.get("state") + + if state == "absent": + self._handle_absent() + return self.results + + self._handle_present() + + return self.results + + +def main() -> None: + """Constructs and calls the module""" + Module() + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/ip_basic/tasks/main.yaml b/tests/integration/targets/ip_basic/tasks/main.yaml new file mode 100644 index 00000000..ce9e7524 --- /dev/null +++ b/tests/integration/targets/ip_basic/tasks/main.yaml @@ -0,0 +1,53 @@ +- name: ip + block: + - set_fact: + r: "{{ 1000000000 | random }}" + + - name: Create a Linode Instance + linode.cloud.instance: + label: 'ansible-test-{{ r }}' + region: us-southeast + type: g6-standard-1 + image: linode/alpine3.19 + state: present + firewall_id: '{{ firewall_id }}' + register: create_instance + + - name: Allocate a new IP to the Linode + linode.cloud.ip: + linode_id: '{{ create_instance.instance.id }}' + public: true + type: ipv4 + state: present + register: allocate_ip + + - name: Assert changes + assert: + that: + - allocate_ip.ip.linode_id == create_instance.instance.id + - allocate_ip.ip.type == 'ipv4' + - allocate_ip.ip.region == create_instance.instance.region + +# - name: Delete an IP +# linode.cloud.ip: +# address: allocate_ip.ip.address +# state: absent +# register: delete_ip + + always: + - ignore_errors: true + block: + - name: Delete instance + linode.cloud.instance: + label: '{{ create_instance.instance.label }}' + state: absent + + + environment: + LINODE_UA_PREFIX: '{{ ua_prefix }}' + LINODE_API_TOKEN: '{{ api_token }}' + LINODE_API_URL: '{{ api_url }}' + LINODE_API_VERSION: '{{ api_version }}' + LINODE_CA: '{{ ca_file or "" }}' + +