Skip to content

Commit

Permalink
Merge pull request #666 from linode/dev
Browse files Browse the repository at this point in the history
v5.54.0
  • Loading branch information
zliang-akamai authored Oct 30, 2024
2 parents 7991606 + afdc3b2 commit 8bc7bbe
Show file tree
Hide file tree
Showing 39 changed files with 910 additions and 176 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/docker-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ jobs:
- name: Build the Docker image
run: docker build . --file Dockerfile --tag linode/cli:$(date +%s) --build-arg="github_token=$GITHUB_TOKEN"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
57 changes: 57 additions & 0 deletions .github/workflows/e2e-suite-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,60 @@ jobs:
conclusion: process.env.conclusion
});
return result;
apply-calico-rules:
runs-on: ubuntu-latest
needs: [integration-fork-windows]
if: ${{ success() || failure() }}

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: 'recursive'

- name: Download kubectl and calicoctl for LKE clusters
run: |
curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"
curl -LO "https://github.com/projectcalico/calico/releases/download/v3.25.0/calicoctl-linux-amd64"
chmod +x calicoctl-linux-amd64 kubectl
mv calicoctl-linux-amd64 /usr/local/bin/calicoctl
mv kubectl /usr/local/bin/kubectl
- name: Apply Calico Rules to LKE
run: |
cd e2e_scripts/cloud_security_scripts/lke_calico_rules/ && ./lke_calico_rules_e2e.sh
env:
LINODE_TOKEN: ${{ secrets.LINODE_TOKEN_2 }}

add-fw-to-remaining-instances:
runs-on: ubuntu-latest
needs: [integration-fork-windows]
if: ${{ success() || failure() }}

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

- name: Install Linode CLI
run: |
pip install linode-cli
- name: Create Firewall and Attach to Instances
run: |
FIREWALL_ID=$(linode-cli firewalls create --label "e2e-fw-$(date +%s)" --rules.inbound_policy "DROP" --rules.outbound_policy "ACCEPT" --text --format=id --no-headers)
echo "Created Firewall with ID: $FIREWALL_ID"
for instance_id in $(linode-cli linodes list --format "id" --text --no-header); do
echo "Attaching firewall to instance: $instance_id"
if linode-cli firewalls device-create "$FIREWALL_ID" --id "$instance_id" --type linode; then
echo "Firewall attached to instance $instance_id successfully."
else
echo "An error occurred while attaching firewall to instance $instance_id. Skipping..."
fi
done
env:
LINODE_CLI_TOKEN: ${{ secrets.LINODE_TOKEN_2 }}
100 changes: 70 additions & 30 deletions .github/workflows/e2e-suite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ on:
description: 'Use minimal test account'
required: false
default: 'false'
test_path:
description: "The path from 'test/integration' to the target to be tested, e.g. 'cli'"
module:
description: "The module from 'test/integration' to the target to be tested, e.g. 'cli, domains, events, etc'"
required: false
sha:
description: 'The hash value of the commit.'
required: false
required: true
default: ''
pull_request_number:
description: 'The number of the PR. Ensure sha value is provided'
Expand All @@ -28,15 +28,6 @@ jobs:
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' && inputs.sha != '' || github.event_name == 'push' || github.event_name == 'pull_request'
steps:
- name: Validate Test Path
uses: actions-ecosystem/action-regex-match@v2
id: validate-tests
if: ${{ inputs.test_path != '' }}
with:
text: ${{ inputs.test_path }}
regex: '[^a-z0-9-:.\/_]' # Tests validation
flags: gi

- name: Checkout Repository with SHA
if: ${{ inputs.sha != '' }}
uses: actions/checkout@v4
Expand Down Expand Up @@ -91,14 +82,6 @@ jobs:
pip install certifi -U && \
pip install .[obj,dev]
- name: Download kubectl and calicoctl for LKE clusters
run: |
curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"
curl -LO "https://github.com/projectcalico/calico/releases/download/v3.25.0/calicoctl-linux-amd64"
chmod +x calicoctl-linux-amd64 kubectl
mv calicoctl-linux-amd64 /usr/local/bin/calicoctl
mv kubectl /usr/local/bin/kubectl
- name: Install Package
run: make install
env:
Expand All @@ -112,18 +95,10 @@ jobs:
run: |
timestamp=$(date +'%Y%m%d%H%M')
report_filename="${timestamp}_cli_test_report.xml"
make testint TEST_ARGS="--junitxml=${report_filename}"
if: ${{ steps.validate-tests.outputs.match == '' || inputs.test_path == '' }}
make testint TEST_ARGS="--junitxml=${report_filename}" MODULE="${{ inputs.module }}"
env:
LINODE_CLI_TOKEN: ${{ env.LINODE_CLI_TOKEN }}

- name: Apply Calico Rules to LKE
if: always()
run: |
cd scripts && ./lke_calico_rules_e2e.sh
env:
LINODE_TOKEN: ${{ env.LINODE_CLI_TOKEN }}

- name: Upload test results
if: always()
run: |
Expand Down Expand Up @@ -168,10 +143,75 @@ jobs:
});
return result;
apply-calico-rules:
runs-on: ubuntu-latest
needs: [integration_tests]
if: ${{ success() || failure() }}

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: 'recursive'

- name: Set LINODE_CLI_TOKEN
run: |
echo "LINODE_CLI_TOKEN=${{ secrets[inputs.use_minimal_test_account == 'true' && 'MINIMAL_LINODE_TOKEN' || 'LINODE_TOKEN'] }}" >> $GITHUB_ENV
- name: Download kubectl and calicoctl for LKE clusters
run: |
curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"
curl -LO "https://github.com/projectcalico/calico/releases/download/v3.25.0/calicoctl-linux-amd64"
chmod +x calicoctl-linux-amd64 kubectl
mv calicoctl-linux-amd64 /usr/local/bin/calicoctl
mv kubectl /usr/local/bin/kubectl
- name: Apply Calico Rules to LKE
run: |
cd e2e_scripts/cloud_security_scripts/lke_calico_rules/ && ./lke_calico_rules_e2e.sh
env:
LINODE_TOKEN: ${{ env.LINODE_CLI_TOKEN }}

add-fw-to-remaining-instances:
runs-on: ubuntu-latest
needs: [integration_tests]
if: ${{ success() || failure() }}

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

- name: Install Linode CLI
run: |
pip install linode-cli
- name: Set LINODE_CLI_TOKEN
run: |
echo "LINODE_CLI_TOKEN=${{ secrets[inputs.use_minimal_test_account == 'true' && 'MINIMAL_LINODE_TOKEN' || 'LINODE_TOKEN'] }}" >> $GITHUB_ENV
- name: Create Firewall and Attach to Instances
run: |
FIREWALL_ID=$(linode-cli firewalls create --label "e2e-fw-$(date +%s)" --rules.inbound_policy "DROP" --rules.outbound_policy "ACCEPT" --text --format=id --no-headers)
echo "Created Firewall with ID: $FIREWALL_ID"
for instance_id in $(linode-cli linodes list --format "id" --text --no-header); do
echo "Attaching firewall to instance: $instance_id"
if linode-cli firewalls device-create "$FIREWALL_ID" --id "$instance_id" --type linode; then
echo "Firewall attached to instance $instance_id successfully."
else
echo "An error occurred while attaching firewall to instance $instance_id. Skipping..."
fi
done
env:
LINODE_CLI_TOKEN: ${{ env.LINODE_CLI_TOKEN }}

notify-slack:
runs-on: ubuntu-latest
needs: [integration_tests]
if: always() && github.repository == 'linode/linode-cli' # Run even if integration tests fail and only on main repository
if: ${{ (success() || failure()) && github.repository == 'linode/linode-cli' }} # Run even if integration tests fail and only on main repository

steps:
- name: Notify Slack
Expand Down
30 changes: 30 additions & 0 deletions .github/workflows/release-notify-slack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Notify Dev DX Channel on Release
on:
release:
types: [published]
workflow_dispatch: null

jobs:
notify:
if: github.repository == 'linode/linode-cli'
runs-on: ubuntu-latest
steps:
- name: Notify Slack - Main Message
id: main_message
uses: slackapi/[email protected]
with:
channel-id: ${{ secrets.CLI_SLACK_CHANNEL_ID }}
payload: |
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*New Release Published: _linode-cli_ <${{ github.event.release.html_url }}|${{ github.event.release.tag_name }}> is now live!* :tada:"
}
}
]
}
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
FROM python:3.11-slim AS builder

ARG linode_cli_version

ARG github_token

WORKDIR /src
Expand Down
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#
# Makefile for more convenient building of the Linode CLI and its baked content
#

# Test-related arguments
MODULE :=
TEST_CASE_COMMAND :=
TEST_ARGS :=
Expand All @@ -9,7 +11,6 @@ ifdef TEST_CASE
TEST_CASE_COMMAND = -k $(TEST_CASE)
endif


SPEC_VERSION ?= latest
ifndef SPEC
override SPEC = $(shell ./resolve_spec_url ${SPEC_VERSION})
Expand Down
20 changes: 9 additions & 11 deletions linodecli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,7 @@
from linodecli import plugins
from linodecli.exit_codes import ExitCodes

from .arg_helpers import (
bake_command,
register_args,
register_plugin,
remove_plugin,
)
from .arg_helpers import register_args, register_plugin, remove_plugin
from .cli import CLI
from .completion import get_completions
from .configuration import ENV_TOKEN_NAME
Expand Down Expand Up @@ -101,25 +96,28 @@ def main(): # pylint: disable=too-many-branches,too-many-statements
# handle a bake - this is used to parse a spec and bake it as a pickle
if parsed.command == "bake":
if parsed.action is None:
print("No spec provided, cannot bake")
print("No spec provided, cannot bake", file=sys.stderr)
sys.exit(ExitCodes.ARGUMENT_ERROR)
bake_command(cli, parsed.action)
cli.bake(parsed.action)
sys.exit(ExitCodes.SUCCESS)
elif cli.ops is None:
# if not spec was found and we weren't baking, we're doomed
sys.exit(ExitCodes.ARGUMENT_ERROR)

if parsed.command == "register-plugin":
if parsed.action is None:
print("register-plugin requires a module name!")
print("register-plugin requires a module name!", file=sys.stderr)
sys.exit(ExitCodes.ARGUMENT_ERROR)
msg, code = register_plugin(parsed.action, cli.config, cli.ops)
print(msg)
sys.exit(code)

if parsed.command == "remove-plugin":
if parsed.action is None:
print("remove-plugin requires a plugin name to remove!")
print(
"remove-plugin requires a plugin name to remove!",
file=sys.stderr,
)
sys.exit(ExitCodes.ARGUMENT_ERROR)
msg, code = remove_plugin(parsed.action, cli.config)
print(msg)
Expand Down Expand Up @@ -216,7 +214,7 @@ def main(): # pylint: disable=too-many-branches,too-many-statements
and parsed.command not in plugins.available(cli.config)
and parsed.command not in HELP_TOPICS
):
print(f"Unrecognized command {parsed.command}")
print(f"Unrecognized command {parsed.command}", file=sys.stderr)
sys.exit(ExitCodes.UNRECOGNIZED_COMMAND)

# handle a help for a command - either --help or no action triggers this
Expand Down
3 changes: 3 additions & 0 deletions linodecli/api_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,9 @@ def _print_request_debug_info(method, url, headers, body):
"""
print(f"> {method.__name__.upper()} {url}", file=sys.stderr)
for k, v in headers.items():
# If this is the Authorization header, sanitize the token
if k.lower() == "authorization":
v = "Bearer " + "*" * 64
print(f"> {k}: {v}", file=sys.stderr)
print("> Body:", file=sys.stderr)
print("> ", body or "", file=sys.stderr)
Expand Down
32 changes: 4 additions & 28 deletions linodecli/arg_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,10 @@
"""
Argument parser for the linode CLI
"""

import os
import sys
from importlib import import_module

import requests
import yaml

from linodecli import plugins
from linodecli.exit_codes import ExitCodes
from linodecli.helpers import (
register_args_shared,
register_debug_arg,
Expand Down Expand Up @@ -107,7 +101,10 @@ def register_plugin(module, config, ops):

reregistering = False
if plugin_name in plugins.available(config):
print(f"WARNING: Plugin {plugin_name} is already registered.\n\n")
print(
f"WARNING: Plugin {plugin_name} is already registered.\n\n",
file=sys.stderr,
)
answer = input(f"Allow re-registration of {plugin_name}? [y/N] ")
if not answer or answer not in "yY":
return "Registration aborted.", 0
Expand Down Expand Up @@ -166,24 +163,3 @@ def remove_plugin(plugin_name, config):

config.write_config()
return f"Plugin {plugin_name} removed", 0


def bake_command(cli, spec_loc):
"""
Handle a bake command from args
"""
try:
if os.path.exists(os.path.expanduser(spec_loc)):
with open(os.path.expanduser(spec_loc), encoding="utf-8") as f:
spec = yaml.safe_load(f.read())
else: # try to GET it
resp = requests.get(spec_loc, timeout=120)
if resp.status_code == 200:
spec = yaml.safe_load(resp.content)
else:
raise RuntimeError(f"Request failed to {spec_loc}")
except Exception as e:
print(f"Could not load spec: {e}")
sys.exit(ExitCodes.REQUEST_FAILED)

cli.bake(spec)
Loading

0 comments on commit 8bc7bbe

Please sign in to comment.