Skip to content

Commit

Permalink
new: Implement E2E framework; fix various package issues (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
lgarber-akamai authored Oct 17, 2023
1 parent 603556a commit ae24332
Show file tree
Hide file tree
Showing 15 changed files with 274 additions and 34 deletions.
19 changes: 19 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Whether API requests and responses should be displayed in stderr.
LINODE_DEBUG ?= 0

# The path to the pubkey to configure the E2E testing instance with.
TEST_PUBKEY ?= ~/.ssh/id_rsa.pub

# Installs dependencies required to run the remote E2E suite.
test-deps:
pip3 install --upgrade ansible -r https://raw.githubusercontent.com/linode/ansible_linode/main/requirements.txt
ansible-galaxy collection install linode.cloud

# Runs the E2E test suite on a host provisioned by Ansible.
e2e:
ANSIBLE_HOST_KEY_CHECKING=False ANSIBLE_STDOUT_CALLBACK=debug ansible-playbook -v --extra-vars="debug=${LINODE_DEBUG} ssh_pubkey_path=${TEST_PUBKEY}" ./hack/run-e2e.yml

# Runs the E2E test suite locally.
# NOTE: E2E tests must be run from within a Linode.
e2e-local:
cd test/integration && make e2e-local
4 changes: 2 additions & 2 deletions client.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package metadata

import (
"context"
Expand Down Expand Up @@ -88,7 +88,7 @@ func NewClient(ctx context.Context, opts *ClientCreateOptions) (*Client, error)
}

func (c *Client) UseToken(token string) *Client {
c.resty.SetHeader("X-Metadata-Token", token)
c.resty.SetHeader("Metadata-Token", token)
return c
}

Expand Down
9 changes: 4 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
module github.com/linode/go-metadata

go 1.19
go 1.20

require (
github.com/go-resty/resty/v2 v2.7.0 // indirect
golang.org/x/net v0.0.0-20211029224645-99673261e6eb // indirect
)
require github.com/go-resty/resty/v2 v2.7.0

require golang.org/x/net v0.0.0-20211029224645-99673261e6eb // indirect
105 changes: 105 additions & 0 deletions hack/run-e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
---
- name: Deploy Test Linode
hosts: localhost
vars:
ssh_pubkey_path: ~/.ssh/id_rsa.pub
label: go-metadata-test
type: g6-standard-2
region: us-iad
temp_token_name: go-metadata-dev
token_duration_seconds: 3600
tasks:
- set_fact:
run_id: '{{ ansible_date_time.epoch }}'
temp_token_name: '{{ temp_token_name }}'

- name: Create a temporary token for the plugin to consume
linode.cloud.token:
label: "{{ temp_token_name }}-{{ run_id }}"
scopes: "events:read_write linodes:read_write"

# This token should expire in an hour by default
expiry: "{{ '%Y-%m-%dT%H:%M:%S' | strftime((ansible_date_time.epoch | int + token_duration_seconds), utc=True) }}"

state: present
register: temp_token

- name: Ensure the test instance is created
linode.cloud.instance:
label: "{{ label }}"
type: "{{ type }}"
region: "{{ region }}"
image: linode/ubuntu22.04
booted: true
authorized_keys:
- "{{ lookup('file', ssh_pubkey_path) }}"
state: present
register: create_inst

- name: Wait for SSH to be ready
wait_for: host="{{ create_inst.instance.ipv4[0] }}" port=22 delay=1 timeout=300

- name: Append host to the in-memory inventory
add_host:
hostname: "test-runner"
ansible_host: "{{ create_inst.instance.ipv4[0] }}"
groups: test_runner
ansible_user: root
temp_token: "{{ temp_token.token.token }}"
run_id: "{{ run_id }}"

- name: Configure the test instance
hosts: test_runner
remote_user: root
gather_facts: no
vars:
debug: 0
tasks:
- block:
- name: Update repositories and install necessary packages
apt:
name: golang,make
update_cache: true

- name: Copy the local project to the remote
synchronize:
src: ../../
dest: "/go-metadata-{{ run_id }}"
rsync_opts:
- "--exclude=.git"
- "--exclude=venv"

- name: Write the configuration to an env file
copy:
dest: "/go-metadata-{{ run_id }}/.test.env"
content: |
export LINODE_DEBUG={{ debug }}
export LINODE_TOKEN={{ temp_token }}
no_log: true

- name: Run the E2E test suite
args:
executable: /bin/bash
shell: |
cd /go-metadata-{{ run_id }} && \
source .test.env && \
make e2e-local
register: run_tests

rescue:
- debug:
msg: Failed to run E2E tests, rescuing for cleanup...

- name: Clean up
hosts: localhost
gather_facts: no
tasks:
- name: Remove the temp token
linode.cloud.token:
label: "{{ temp_token_name }}-{{ run_id }}"
state: absent

- name: Exit if tests failed
assert:
that:
- "'ansible_failed_result' not in hostvars['test-runner']"
32 changes: 18 additions & 14 deletions instance.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
package main
package metadata

import (
"context"
)
import "context"

type InstanceBackupsData struct {
Enabled bool `json:"enabled"`
Status *string `json:"status"`
}

type InstanceSpecsData struct {
VCPUs int `json:"vcpus"`
Memory int `json:"memory"`
GPUs int `json:"gpus"`
Transfer int `json:"transfer"`
Disk int `json:"disk"`
}

type InstanceData struct {
LocalHostname string `json:"local-hostname"`
Region string `json:"region"`
Type string `json:"type"`
Machine string `json:"string"`
ID int `json:"id"`
InstanceID int `json:"instance-id"`
CPUs int `json:"cpus"`
Memory int `json:"memory"`
Disk int `json:"disk"`
Backups InstanceBackupsData `json:"backups"`
ID int `json:"id"`
Label string `json:"label"`
Region string `json:"region"`
Type string `json:"type"`
HostUUID string `json:"host_uuid"`
Tags []string `json:"tags"`
Specs InstanceSpecsData `json:"specs"`
Backups InstanceBackupsData `json:"backups"`
}

func (c *Client) GetInstance(ctx context.Context) (*InstanceData, error) {
Expand Down
2 changes: 1 addition & 1 deletion network.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package metadata

import (
"context"
Expand Down
6 changes: 2 additions & 4 deletions sshkeys.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package main
package metadata

import (
"context"
)
import "context"

type SSHKeysUserData struct {
Root []string `json:"root"`
Expand Down
2 changes: 2 additions & 0 deletions test/integration/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
e2e-local:
go test -v --tags=integration ./...
25 changes: 25 additions & 0 deletions test/integration/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// This module stores testing dependencies that we want to keep
// separate from the main package.

module github.com/linode/go-metadata/test/integration

go 1.20

require (
github.com/linode/go-metadata v0.0.0
github.com/linode/linodego v1.23.0
)

require github.com/stretchr/testify v1.8.4 // indirect

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-resty/resty/v2 v2.7.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/net v0.15.0 // indirect
golang.org/x/text v0.13.0 // indirect
gopkg.in/ini.v1 v1.66.6 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

replace github.com/linode/go-metadata => ../../
27 changes: 27 additions & 0 deletions test/integration/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/linode/linodego v1.23.0 h1:s0ReCZtuN9Z1IoUN9w1RLeYO1dMZUGPwOQ/IBFsBHtU=
github.com/linode/linodego v1.23.0/go.mod h1:0U7wj/UQOqBNbKv1FYTXiBUXueR8DY4HvIotwE0ENgg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
32 changes: 32 additions & 0 deletions test/integration/helper_e2e_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//go:build integration

package integration

import (
"context"
"github.com/linode/go-metadata"
"github.com/linode/linodego"
"log"
"os"
)

var testToken = os.Getenv("LINODE_TOKEN")
var metadataClient *metadata.Client
var linodeClient *linodego.Client

func init() {
if testToken == "" {
log.Fatal("LINODE_TOKEN must be specified to run the E2E test suite")
}

mdsClient, err := metadata.NewClient(context.Background(), nil)
if err != nil {
log.Fatalf("failed to create client: %s", err)
}

apiClient := linodego.NewClient(nil)
apiClient.SetToken(testToken)

metadataClient = mdsClient
linodeClient = &apiClient
}
31 changes: 31 additions & 0 deletions test/integration/instance_e2e_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//go:build integration

package integration

import (
"context"
"github.com/stretchr/testify/assert"
"testing"
)

func TestGetInstance(t *testing.T) {
mdInst, err := metadataClient.GetInstance(context.Background())
assert.NoError(t, err)

assert.NotEqual(t, t, mdInst.ID, 0)

apiInst, err := linodeClient.GetInstance(context.Background(), mdInst.ID)
assert.NoError(t, err)

assert.Equal(t, apiInst.Label, mdInst.Label)
assert.Equal(t, apiInst.Region, mdInst.Region)
assert.Equal(t, apiInst.Type, mdInst.Type)
assert.Equal(t, apiInst.Tags, mdInst.Tags)
assert.Equal(t, apiInst.HostUUID, mdInst.HostUUID)

assert.Equal(t, apiInst.Specs.Disk, mdInst.Specs.Disk)
assert.Equal(t, apiInst.Specs.Memory, mdInst.Specs.Memory)
assert.Equal(t, apiInst.Specs.VCPUs, mdInst.Specs.VCPUs)
assert.Equal(t, apiInst.Specs.GPUs, mdInst.Specs.GPUs)
assert.Equal(t, apiInst.Specs.Transfer, mdInst.Specs.Transfer)
}
4 changes: 2 additions & 2 deletions token.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package metadata

import (
"context"
Expand Down Expand Up @@ -32,7 +32,7 @@ func (c *Client) GenerateToken(ctx context.Context, opts GenerateTokenOptions) (
tokenExpirySeconds = opts.ExpirySeconds
}

req.SetHeader("X-Metadata-Token-Expiry-Seconds", strconv.Itoa(tokenExpirySeconds))
req.SetHeader("Metadata-Token-Expiry-Seconds", strconv.Itoa(tokenExpirySeconds))

resp, err := req.Put("token")
if err != nil {
Expand Down
6 changes: 2 additions & 4 deletions userdata.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package main
package metadata

import (
"context"
)
import "context"

func (c *Client) GetUserData(ctx context.Context) (string, error) {
// Getting user-data requires the text/plain content type
Expand Down
4 changes: 2 additions & 2 deletions version.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package metadata

import (
"fmt"
Expand Down Expand Up @@ -30,5 +30,5 @@ func init() {
}
}

DefaultUserAgent = fmt.Sprintf("linodego/%s https://github.com/linode/go-metadata", Version)
DefaultUserAgent = fmt.Sprintf("go-metadata/%s https://github.com/linode/go-metadata", Version)
}

0 comments on commit ae24332

Please sign in to comment.