Skip to content

Commit

Permalink
openstack: add initial support
Browse files Browse the repository at this point in the history
  • Loading branch information
malt3 committed Feb 20, 2024
1 parent 9730d61 commit 4853556
Show file tree
Hide file tree
Showing 9 changed files with 284 additions and 9 deletions.
70 changes: 70 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ project = "myproject-123456"
location = "europe-west3"
bucket = "my-bucket"

[base.openstack]
# OpenStack specific configuration that is applied to every variant.
cloud = "mycloud"
tags = ["tag-a", "tag-b"]
minDiskGB = 32

[variant.foo]
# Variant specific configuration that overrides the base configuration.
provider = "aws"
Expand Down Expand Up @@ -364,3 +370,67 @@ Will be created if it does not exist.
- Template: yes

Name of the temporary blob within `bucket`. Image is uploaded to this blob before being converted to an image.

### `base.openstack.cloud` / `variant.<name>.openstack.cloud`

- Default: none
- Required: yes

Name in OpenStack's cloud.yaml used for authentication.

### `base.openstack.imageName` / `variant.<name>.openstack.imageName`

- Default: `"{{.Name}}-{{.Version}}"`
- Required: no
- Template: yes

Name of the image to create. Example: `"my-image-1.0.0"`.

### `base.openstack.visibility` / `variant.<name>.openstack.visibility`

- Default: `"public"`
- Required: no

Visibility of the image to create. Possible values are "public", "private", "shared", "community"`.

### `base.openstack.hidden` / `variant.<name>.openstack.hidden`

- Default: `false`
- Required: no

Hidden status of the image in listings.

### `base.openstack.tags` / `variant.<name>.openstack.tags`

- Default: `[]`
- Required: no

Tags added to the image.

### `base.openstack.minDiskGB` / `variant.<name>.openstack.minDiskGB`

- Default: `0`
- Required: no

Minimum disk size of the image in GB.

### `base.openstack.minRamMB` / `variant.<name>.openstack.minRamMB`

- Default: `0`
- Required: no

Minimum amount of RAM reserved for a VM created from this image.

### `base.openstack.protected` / `variant.<name>.openstack.protected`

- Default: `false`
- Required: no

If set, prevents accidential deletion of the image.

### `base.openstack.properties` / `variant.<name>.openstack.properties`

- Default: `{}`
- Required: no

Extra key-value pairs attached to the image. Example: `{"hw_firmware_type" = "uefi", "os_type" = "linux"}`.
7 changes: 7 additions & 0 deletions cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/edgelesssys/uplosi/azure"
"github.com/edgelesssys/uplosi/config"
"github.com/edgelesssys/uplosi/gcp"
"github.com/edgelesssys/uplosi/openstack"
"github.com/spf13/cobra"
"golang.org/x/mod/semver"
)
Expand Down Expand Up @@ -158,6 +159,12 @@ func uploadVariant(ctx context.Context, imagePath, variant string, config config
if err != nil {
return nil, fmt.Errorf("creating gcp uploader: %w", err)
}
case "openstack":
prepper = &openstack.Prepper{}
upload, err = openstack.NewUploader(config, logger)
if err != nil {
return nil, fmt.Errorf("creating openstack uploader: %w", err)
}
default:
return nil, fmt.Errorf("unknown provider: %s", config.Provider)
}
Expand Down
35 changes: 28 additions & 7 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,22 @@ var defaultConfig = Config{
ImageFamily: "{{.Name}}",
BlobName: "{{.Name}}-{{replaceAll .Version \".\" \"-\"}}.tar.gz",
},
OpenStack: OpenStackConfig{
ImageName: "{{.Name}}-{{.Version}}",
Visibility: "public",
Protected: Some(false),
},
}

type Config struct {
Provider string `toml:"provider"`
ImageVersion string `toml:"imageVersion"`
ImageVersionFile string `toml:"imageVersionFile"`
Name string `toml:"name"`
AWS AWSConfig `toml:"aws,omitempty"`
Azure AzureConfig `toml:"azure,omitempty"`
GCP GCPConfig `toml:"gcp,omitempty"`
Provider string `toml:"provider"`
ImageVersion string `toml:"imageVersion"`
ImageVersionFile string `toml:"imageVersionFile"`
Name string `toml:"name"`
AWS AWSConfig `toml:"aws,omitempty"`
Azure AzureConfig `toml:"azure,omitempty"`
GCP GCPConfig `toml:"gcp,omitempty"`
OpenStack OpenStackConfig `toml:"openstack,omitempty"`
}

func (c *Config) Merge(other Config) error {
Expand Down Expand Up @@ -82,6 +88,9 @@ func (c *Config) Render(fileLookup func(name string) ([]byte, error)) error {
if err := c.renderTemplates(&c.GCP); err != nil {
return err
}
if err := c.renderTemplates(&c.OpenStack); err != nil {
return err
}

v := Validator{}

Expand Down Expand Up @@ -199,6 +208,18 @@ type GCPConfig struct {
BlobName string `toml:"blobName,omitempty" template:"true"`
}

type OpenStackConfig struct {
Cloud string `toml:"cloud"`
ImageName string `toml:"imageName,omitempty" template:"true"`
Visibility string `toml:"visibility,omitempty"`
Hidden Option[bool] `toml:"hidden,omitempty"`
Tags []string `toml:"tags,omitempty"`
MinDiskGB int `toml:"minDiskGB,omitempty"`
MinRamMB int `toml:"minRamMB,omitempty"`
Protected Option[bool] `toml:"protected,omitempty"`
Properties map[string]string `toml:"properties"`
}

type ConfigFile struct {
Base Config `toml:"base"`
Variants map[string]Config `toml:"variant"`
Expand Down
14 changes: 13 additions & 1 deletion config/validation.rego
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,14 @@ deny[msg] {
msg = sprintf("field bucket must be between 1 and 63 characters for provider gcp, got %d", [count(input.GCP.Bucket)])
}

deny[msg] {
input.Provider == "openstack"
input.OpenStack.Visibility != ""
allowed := ["public", "private", "shared", "community"]
not input.OpenStack.Visibility in allowed

msg = sprintf("field visibility must be one of %s for provider openstack", allowed)
}

deny[msg] {
some provider in valid_csps
Expand Down Expand Up @@ -395,7 +403,7 @@ begin_and_end_with(s, charset) = begin_and_end {
])
}

valid_csps := [ "aws", "azure", "gcp" ]
valid_csps := [ "aws", "azure", "gcp", "openstack" ]

required_fields := {
"aws": {
Expand Down Expand Up @@ -429,6 +437,10 @@ required_fields := {
"bucket": input.GCP.Bucket,
"blobName": input.GCP.BlobName,
},
"openstack": {
"cloud": input.OpenStack.Cloud,
"imageName": input.OpenStack.ImageName,
},
}

lowercase_letters := {
Expand Down
2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
version = "0.1.2";
src = ./.;
# this needs to be updated together with go.mod / go.sum
vendorHash = "sha256-eZ0/piSxMUC1ZM7qBhFW40l9p8ZPMIj1HyrS2Dy4wJQ=";
vendorHash = "sha256-XKVkZrvEuj3+6Sxl687Tce88VhRxEAKfjOJzBd2c/Ac=";

CGO_ENABLED = 0;

Expand Down
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ require (
github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/prometheus/client_golang v1.16.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
Expand Down Expand Up @@ -92,6 +94,8 @@ require (
github.com/aws/smithy-go v1.19.0
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/uuid v1.5.0 // indirect
github.com/gophercloud/gophercloud v1.9.0
github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
Expand Down
15 changes: 15 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,17 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfF
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
github.com/gophercloud/gophercloud v1.3.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
github.com/gophercloud/gophercloud v1.9.0 h1:zKvmHOmHuaZlnx9d2DJpEgbMxrGt/+CJ/bKOKQh9Xzo=
github.com/gophercloud/gophercloud v1.9.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 h1:sH7xkTfYzxIEgzq1tDHIMKRh1vThOEOGNsettdEeLbE=
github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56/go.mod h1:VSalo4adEk+3sNkmVJLnhHoOyOYYS8sTWLG4mv5BKto=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
Expand All @@ -196,6 +203,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zk
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/open-policy-agent/opa v0.60.0 h1:ZPoPt4yeNs5UXCpd/P/btpSyR8CR0wfhVoh9BOwgJNs=
github.com/open-policy-agent/opa v0.60.0/go.mod h1:aD5IK6AiLNYBjNXn7E02++yC8l4Z+bRDvgM6Ss0bBzA=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
Expand Down Expand Up @@ -263,6 +272,7 @@ go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v8
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
Expand All @@ -280,6 +290,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
Expand All @@ -298,19 +309,23 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
Expand Down
18 changes: 18 additions & 0 deletions openstack/prepper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: Apache-2.0
*/

package openstack

import (
"context"
)

type Prepper struct{}

func (p *Prepper) Prepare(_ context.Context, imagePath, _ string) (string, error) {
// OpenStack does not need any preparation.
return imagePath, nil
}
Loading

0 comments on commit 4853556

Please sign in to comment.