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

openstack backend #170

Open
wants to merge 62 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
b4dfab2
New openstack backend
sergiocazzolato Apr 11, 2023
99a6884
First change for the openstack backend implementation
sergiocazzolato May 30, 2023
ccd286b
Changes done to support openstack bakend after testing in canonistack
sergiocazzolato Jun 1, 2023
81ec212
adding network and security groups to systems
sergiocazzolato Jun 9, 2023
6adfc24
openstack: tweak function returns and messages
mvo5 Jul 5, 2023
b08c9ca
spread: rever change in {google,humbox,lindode}.go
mvo5 Jul 5, 2023
e0052c3
openstack: two more tweak about error message
mvo5 Jul 5, 2023
c82e63f
support networks and rename groups intead of security-groups in opens…
sergiocazzolato Jul 19, 2023
b741ae6
Add new test to validate openstack backend
sergiocazzolato Jul 19, 2023
ba946a3
Add new checks for errors and improve error management and messages
sergiocazzolato Jul 29, 2023
5e22375
Test spread -gc
sergiocazzolato Jul 29, 2023
5c7f2bb
openstack: add unit test for "openstackName()"
mvo5 Aug 17, 2023
0e4f033
openstack: add unit tests for findImage()
mvo5 Aug 17, 2023
8fbae16
spread: improve openstackName() test and make it similar to "google" …
mvo5 Aug 17, 2023
c83cc17
improve how error messages are determined
sergiocazzolato Aug 17, 2023
b17804a
openstack: add unit tests for openstack.go:errorMsg()
mvo5 Aug 18, 2023
8aa5ae9
Added groups and networks info to the readme
sergiocazzolato Aug 21, 2023
6c293f0
README.md: revert unrelated changes
mvo5 Sep 25, 2023
2d98f1b
spread: add tests that test/illustrate how openstaack.FindImage() works
mvo5 Sep 25, 2023
463c503
spread: fix TestOpenstackFindImageComplex test
mvo5 Sep 25, 2023
d82abf5
return an error when the server list does not contain the address
sergiocazzolato Sep 25, 2023
c9bd783
revert undesired change
sergiocazzolato Sep 26, 2023
e0fe707
remove openstackReadyMarker from openstack backend
sergiocazzolato Oct 5, 2023
94519f6
openstack: add comment about why openstackReadyMarker is not used
mvo5 Oct 12, 2023
417feb6
openstack: use similar image matching strategy as google
mvo5 Oct 13, 2023
f1209f3
openstack: extend tests to check that term matching works
mvo5 Oct 13, 2023
8c3401c
openstack: tweak error handling as suggested by Gustavo
mvo5 Oct 13, 2023
c3762f2
openstack: remove unused cleanup() helper
mvo5 Oct 13, 2023
7aed549
openstack: remove (currently) unused image cache and add TODO about it
mvo5 Oct 13, 2023
cbd1b4b
spread: remove unused aRegion(), openstackMissing{Project,Region}
mvo5 Oct 13, 2023
90ff9a9
spread: remove unused openstack{Project,AvailabilityZone}
mvo5 Oct 13, 2023
b06d4b9
spread: tweak findFirstNetwork()
mvo5 Oct 13, 2023
cb5957e
openstack: fix typos (thanks to Zeyhad)
mvo5 Oct 16, 2023
f20de8f
spread: mention that "Plan" is also used by openstack (thanks to Zeyhad)
mvo5 Oct 16, 2023
8d5f947
spread: remove unneeded comment
mvo5 Oct 16, 2023
5104e7b
openstack: follow the wait patterns from the google backend
mvo5 Oct 17, 2023
6b1df95
openstack: tweak error handling to be consistent with standard librar…
ZeyadYasser Oct 20, 2023
c74a8e9
openstack: use %q specifier for user input as suggested by Gustavo
ZeyadYasser Oct 20, 2023
5703817
openstack: add unit tests for waitServerComplete{Building,Setup}
ZeyadYasser Oct 23, 2023
78edd9b
tests/openstack: fix error matching to use quotes
ZeyadYasser Oct 25, 2023
12e2fad
openstack: fix minor typo
ZeyadYasser Oct 25, 2023
bca797c
openstack: pass labels when retrieving machines for garbage collection
ZeyadYasser Nov 21, 2023
1b481f0
test that the halt-timeout of the instance is used when it is set
sergiocazzolato Nov 21, 2023
0eb485d
support check serial console
sergiocazzolato Dec 4, 2023
7578146
Using get console action instead of get serial
sergiocazzolato Dec 6, 2023
391f32e
Don't try waiting ssh when the serial output failed because of timeout
sergiocazzolato Dec 6, 2023
e93ff91
Update errors to make sure we retry ssh connection on serial console …
sergiocazzolato Dec 6, 2023
8a2c853
adjust timeouts and messages getting error retrieving serial console
sergiocazzolato Dec 6, 2023
5cb6810
spread/openstack: refactor openstack backend
ZeyadYasser Feb 20, 2024
b18bfde
spread/tests/openstack: update test for serial output method
ZeyadYasser Feb 22, 2024
15c7274
Addressed comments
sergiocazzolato Feb 28, 2024
da9a266
Improve the README to explain which env vars are required to authenti…
sergiocazzolato Mar 6, 2024
ec72ad6
spread/openstack: remove exported types in unit tests
ZeyadYasser Mar 7, 2024
d2d54a3
spread/openstack: fix fallback logic
ZeyadYasser Mar 8, 2024
0484ab2
Allow to define a .env file with the env vars required to autheticate
sergiocazzolato Mar 9, 2024
5f673c8
Allow authentication with key and secret
sergiocazzolato Mar 13, 2024
755dc0e
add more details in the openstack test to explain -gc
sergiocazzolato Mar 19, 2024
86b398d
Fix README formatting
ZeyadYasser Mar 25, 2024
701600c
openstack: comment out existing ssh configs that conflicts
ZeyadYasser Mar 25, 2024
027ba48
openstack: rename goose{C,c}lient package
ZeyadYasser Mar 25, 2024
58c7fad
openstack: drop spread tests
ZeyadYasser Mar 25, 2024
7f84982
Fix cloud-init config to make openstack work again
sergiocazzolato May 21, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:

- name: Run tests
run: |
spread google:
spread google:ubuntu-20.04-64: google:ubuntu-22.04-64-devstack:tests/openstack
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happened here? If this makes sense (unclear for now), it should be documented so it's more obvious what was disabled and what was enabled here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, thanks for the review,

In order to test openstack backend against a real openstack interface, we pre-configured a new image with devstack already installed. The main raeson was to speed up and simplify the test (so that image is only used to test openstack). Should I add this explanation in the workflow?


- name: Discard spread workers
if: always()
Expand Down
63 changes: 62 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ Spread
[Fetching artifacts](#artifacts)
[LXD backend](#lxd)
[QEMU backend](#qemu)
[Google backend](#google)
[Google backend](#google)
ZeyadYasser marked this conversation as resolved.
Show resolved Hide resolved
[Openstack backend](#openstack)
[Linode backend](#linode)
[AdHoc backend](#adhoc)
[More on parallelism](#parallelism)
Expand Down Expand Up @@ -899,6 +900,66 @@ and need to be removed by hand.
For long term use, a dedicated project in the Google Cloud Platform is
recommended to prevent automated manipulation of important machines.

<a name="openstack"/>

## Openstack backend

The Openstack backend is easy to setup and use, and allows distributing
your tasks to an openstack environment.

_$PROJECT/spread.yaml_
```
(...)

backends:
openstack:
plan: cpu2-ram4-disk10
halt-timeout: 2h
systems:
- ubuntu-20.04:
mvo5 marked this conversation as resolved.
Show resolved Hide resolved
image: ubuntu-focal-daily-amd64
workers: 5

# Extended syntax:
- another-system:
image: some-other-image
networks:
- network_external
- network_pvn
groups:
- group_external

```

The Openstack backend gets all the information to authenticate from the
environment variables. The following variables have to be set:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not look like a great practice, as it's sending real authentication data to every single test run. It also disagrees with what we do with the Google backend, and every other backend maybe?

I'm almost certainly not the first one to point this out, so what is the actual alternative practice inside the OpenStack community?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The most common mechanism to connect a client through the Openstack API is by sourcing a file with teh environment variables (like the one we get to use openstack client in canonistack). For example in PS5, in the environment I also see the openstack env vars in my environment (they are managed by vault tool), so I presume juju is using those to connect to openstack.

I agree with you this is not a good practice because this means we need to have an env var with the user and password. I'll research which workaround we could use.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the documentation to explain better which env vars need to be defined. It is also supported to authenticate by using a key (similar to what we have in google). The key has to be stored in an env var to be loaded.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An improvement could be to load the vars from a file (as we hav in google) instead of the env. @niemeyer What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finally I added a similar approach that the used in google.

```
OS_AUTH_URL
OS_PROJECT_ID
OS_PROJECT_NAME
OS_USER_DOMAIN_NAME
OS_PROJECT_DOMAIN_ID (optional)
OS_TENANT_ID
OS_TENANT_NAME
OS_USERNAME
OS_PASSWORD
OS_REGION_NAME
OS_INTERFACE
OS_IDENTITY_API_VERSION
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to the above, which of those variables have a direct equivalent in the Google backend setup?

Copy link
Contributor Author

@sergiocazzolato sergiocazzolato Feb 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In google we use the env var SPREAD_GOOGLE_KEY which has a link to the file with the following data:
"type"
"project_id"
"private_key_id"
"private_key"
"client_email"
"client_id"
"auth_uri"
"token_uri"
"auth_provider_x509_cert_url"
"client_x509_cert_url"

I updated the list of environment variables in the docs and I understand that the equivalent are:
project_id <-> OS_PROJECT_ID
auth_uri <-> OS_AUTH_URL
private_key_id <-> OS_ACCESS_KEY
private_key <-> OS_SECRET_KEY
client_id <-> ( OS_PROJECT_DOMAIN_NAME | OS_USER_DOMAIN_NAME )

```

You can set up those variables by sourcing the Openstack RC file.
For more information about the environment setup please read
https://docs.openstack.org/ocata/user-guide/common/cli-set-environment-variables-using-openstack-rc.html

Images are located by first attempting to match the provided value exactly
against the image name, if there is not exact match the most recent image
mvo5 marked this conversation as resolved.
Show resolved Hide resolved
with partial match will be selected.

When these machines terminate running, they will be removed. If anything
happens that prevents the immediate removal, they will remain in the account
and need to be removed by hand.


<a name="linode"/>

Expand Down
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ module github.com/snapcore/spread
go 1.13

require (
github.com/go-goose/goose v2.0.1+incompatible // indirect
github.com/go-goose/goose/v5 v5.0.0-20230421180421-abaee9096e3a
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
golang.org/x/net v0.0.0-20210716203947-853a461950ff
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637
Expand Down
112 changes: 104 additions & 8 deletions go.sum

Large diffs are not rendered by default.

20 changes: 17 additions & 3 deletions spread.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ backends:
- ubuntu-20.04-64:
image: ubuntu-2004-64-virt-enabled
workers: 1
- ubuntu-22.04-64-devstack:
image: ubuntu-jammy-devstack
plan: n2-standard-2
storage: 20G
workers: 1

qemu:
systems:
Expand All @@ -31,9 +36,13 @@ backends:
password: ubuntu

exclude:
- .git
- .spread-reuse.yaml
- tests/.spread-reuse.yaml
- $CACHE_DISABLED
- "*.snap"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the quotes only on this one? Also, where do the snap files come from?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed




ZeyadYasser marked this conversation as resolved.
Show resolved Hide resolved
path: /home/test/src/github.com/snapcore/spread

Expand All @@ -42,11 +51,16 @@ suites:
summary: Integration tests

prepare: |
ZeyadYasser marked this conversation as resolved.
Show resolved Hide resolved
DEBS="git qemu-kvm lxd tree"
DEBS="git qemu-kvm tree"
if ! dpkg -l $DEBS; then
apt update
apt install -y $DEBS
fi

if ! snap list lxd; then
snap install lxd
fi

# Cache is only available if SEND_CACHE=1 is set.
mkdir -p tests/cache

Expand Down Expand Up @@ -78,8 +92,8 @@ prepare: |
# - Export image: > lxc image export <IAMGE-ID> tests/cache/lxd-ubuntu-16.04
# - Extract metadata: > cd tests/cache/lxd-ubuntu-16.04 && tar -xvf <METADATA-FILE>
if [ -d tests/cache/lxd-ubuntu-16.04 ]; then
if ! lxc image list | grep '16\.04'; then
lxc image import tests/cache/lxd-ubuntu-16.04
if ! lxd.lxc image list | grep '16\.04'; then
lxd.lxc image import tests/cache/lxd-ubuntu-16.04
fi
fi
# Start lxd instance
Expand Down
89 changes: 89 additions & 0 deletions spread/export_openstack_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package spread

import (
"context"
"time"

gooseClient "github.com/go-goose/goose/v5/client"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/gooseClient/gooseclient/

Package names in Go are not typically cammel-cased.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

"github.com/go-goose/goose/v5/glance"
)

var (
OpenstackName = openstackName
)

type (
OpenstackProvider = openstackProvider
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the types themselves being exposed?

Copy link

@ZeyadYasser ZeyadYasser Mar 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, Thank you!

I refactored the tests to avoid the need to export internal types.

GlanceImageClient = glanceImageClient
OpenstackServerData = openstackServerData
)

func MockOpenstackImageClient(opst *OpenstackProvider, newIC glanceImageClient) (restore func()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newIC, newIC, but then "timeout" and "retry" shortly below. Let's stick to the latter convention please and have "imageClient" and "computeClient" instead as these are more readable.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, Thank you!

oldGlanceImageClient := opst.imageClient
opst.imageClient = newIC
return func() {
opst.imageClient = oldGlanceImageClient
}
}

func MockOpenstackComputeClient(opst *OpenstackProvider, newIC novaComputeClient) (restore func()) {
oldNovaImageClient := opst.computeClient
opst.computeClient = newIC
return func() {
opst.computeClient = oldNovaImageClient
}
}

func MockOpenstackGooseClient(opst *OpenstackProvider, newC gooseClient.Client) (restore func()) {
oldOsClient := opst.osClient
opst.osClient = newC
return func() {
opst.osClient = oldOsClient
}
}

func MockOpenstackProvisionTimeout(timeout, retry time.Duration) (restore func()) {
oldTimeout := openstackProvisionTimeout
oldRetry := openstackProvisionRetry
openstackProvisionTimeout = timeout
openstackProvisionRetry = retry
return func() {
openstackProvisionTimeout = oldTimeout
openstackProvisionRetry = oldRetry
}
}

func MockOpenstackServerBootTimeout(timeout, retry time.Duration) (restore func()) {
oldTimeout := openstackServerBootTimeout
oldRetry := openstackServerBootRetry
openstackServerBootTimeout = timeout
openstackServerBootRetry = retry
return func() {
openstackServerBootTimeout = oldTimeout
openstackServerBootRetry = oldRetry
}
}

func (opst *OpenstackProvider) FindImage(name string) (*glance.ImageDetail, error) {
return opst.findImage(name)
}

func (opst *openstackProvider) WaitProvision(ctx context.Context, serverData OpenstackServerData) error {
server := &openstackServer{
p: opst,
d: serverData,
}
return opst.waitProvision(ctx, server)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is adding a fake method, with a real internal type that has been renamed to be public, and then before calling the internal type it actually changes the call signature by cooking another internal type over with a fake object as well. To close it all, some methods are defined in the type that has been renamed, and some methods are defined in the original internal type name.

It would be nice to have a cleaner API here.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, Thank you!

I updated to use a simpler signature only exposing params relevant to the tests:

  • OpenstackWaitProvision(p Provider, ctx context.Context, serverID, serverName string)
  • OpenstackWaitServerBoot(p Provider, ctx context.Context, serverID, serverName string, serverNetworks []string)

}

func (opst *openstackProvider) WaitServerBoot(ctx context.Context, serverData OpenstackServerData) error {
server := &openstackServer{
p: opst,
d: serverData,
}
return opst.waitServerBoot(ctx, server)
}

func NewOpenstackError(gooseError error) error {
return &openstackError{gooseError}
}
8 changes: 8 additions & 0 deletions spread/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,12 @@ func MockSshDial(f func(network, addr string, config *ssh.ClientConfig) (*ssh.Cl
}
}

func MockTimeNow(f func() time.Time) (restore func()) {
oldTimeNow := timeNow
timeNow = f
return func() {
timeNow = oldTimeNow
}
}

var QemuCmd = qemuCmd
Loading
Loading