Skip to content

Commit

Permalink
Merge pull request #1 from fabi200123/json-schema
Browse files Browse the repository at this point in the history
Adding unit-tests and json schema validation
  • Loading branch information
gabriel-samfira authored May 9, 2024
2 parents b343553 + 0144930 commit d0af9a8
Show file tree
Hide file tree
Showing 988 changed files with 379,146 additions and 19 deletions.
44 changes: 44 additions & 0 deletions .github/workflows/go-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Go Tests

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
go-tests-linux:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v3

- name: Setup Golang
uses: actions/setup-go@v3
with:
go-version-file: go.mod

- run: go version

- name: Run GARM Go Tests
run: make go-test

go-tests-windows:
runs-on: windows-latest

steps:
- name: Checkout
uses: actions/checkout@v3

- name: Setup Golang
uses: actions/setup-go@v3
with:
go-version-file: go.mod

- run: go version

- name: Run GARM Go Tests
run: go test -v ./... -timeout=15m -parallel=4
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
SHELL := bash

.PHONY: go-test

go-test:
go test -v ./... $(TEST_ARGS) -timeout=15m -parallel=4
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ To this end, this provider supports the following extra specs schema:
"type": "string",
"description": "The hardware reservation ID to use."
}
}
},
"additionalProperties": false
}
```

Expand Down
80 changes: 80 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright 2024 Cloudbase Solutions SRL
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package config

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestValidate(t *testing.T) {
tests := []struct {
name string
cfg Config
errString string
}{
{
name: "valid config",
cfg: Config{
AuthToken: "token",
MetroCode: "code",
HardwareReservationID: nil,
ProjectID: "project",
},
errString: "",
},
{
name: "missing auth token",
cfg: Config{
MetroCode: "code",
HardwareReservationID: nil,
ProjectID: "project",
},
errString: "auth_token is required",
},
{
name: "missing metro code",
cfg: Config{
AuthToken: "token",
HardwareReservationID: nil,
ProjectID: "project",
},
errString: "metro_code is required",
},
{
name: "missing project id",
cfg: Config{
AuthToken: "token",
MetroCode: "code",
HardwareReservationID: nil,
},
errString: "project_id is required",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.cfg.Validate()
if tt.errString != "" {
require.Error(t, err)
assert.ErrorContains(t, err, tt.errString)
} else {
require.NoError(t, err)
}
})
}
}
6 changes: 6 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,23 @@ require (
github.com/juju/clock v1.0.3
github.com/juju/retry v1.0.0
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.9.0
github.com/xeipuuv/gojsonschema v1.2.0
golang.org/x/sync v0.6.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/felixge/httpsnoop v1.0.3 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/juju/errors v0.0.0-20220203013757-bd733f3c86b9 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/minio/sio v0.3.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/sys v0.11.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
Expand Down
16 changes: 15 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/cloudbase/garm-provider-common v0.1.2-0.20240127222153-ceeb0b7cc5d7 h1:BXso9ORSZvB6CrHaX/qhZ8urFZlFkl7ySXjdL7lbsSw=
github.com/cloudbase/garm-provider-common v0.1.2-0.20240127222153-ceeb0b7cc5d7/go.mod h1:igxJRT3OlykERYc6ssdRQXcb+BCaeSfnucg6I0OSoDc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/equinix/equinix-sdk-go v0.31.0 h1:BVD67nmpPEutsCGkYDuy0rykGNeQ5H3FIX+Dz5DpP7w=
github.com/equinix/equinix-sdk-go v0.31.0/go.mod h1:qnpdRzVftHFNaJFk1VSIrAOTLrIoeDrxzUr3l8ARyvQ=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
Expand Down Expand Up @@ -32,11 +34,23 @@ github.com/minio/sio v0.3.1 h1:d59r5RTHb1OsQaSl1EaTWurzMMDRLA5fgNmjzD4eVu4=
github.com/minio/sio v0.3.1/go.mod h1:S0ovgVgc+sTlQyhiXA1ppBLv7REM7TYi5yyq2qL/Y6o=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 h1:xzABM9let0HLLqFypcxvLmlvEciCHL7+Lv+4vwZqecI=
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569/go.mod h1:2Ly+NIftZN4de9zRmENdYbvPQeaVIYKWpLFStLFEBgI=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
Expand Down
58 changes: 54 additions & 4 deletions internal/spec/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,63 @@ import (
"github.com/cloudbase/garm-provider-common/cloudconfig"
"github.com/cloudbase/garm-provider-common/params"
"github.com/cloudbase/garm-provider-common/util"
"github.com/xeipuuv/gojsonschema"
)

const (
ControllerIDTagName = "garm-controller-id"
PoolIDTagName = "garm-pool-id"
)

type ToolFetchFunc func(osType params.OSType, osArch params.OSArch, tools []params.RunnerApplicationDownload) (params.RunnerApplicationDownload, error)

type GetCloudConfigFunc func(bootstrapParams params.BootstrapInstance, tools params.RunnerApplicationDownload, runnerName string) (string, error)

var (
DefaultToolFetch ToolFetchFunc = util.GetTools
DefaultGetCloudconfig GetCloudConfigFunc = cloudconfig.GetCloudConfig
)

const jsonSchema string = `
{
"$schema": "http://cloudbase.it/garm-provider-equinix/schemas/extra_specs#",
"type": "object",
"description": "Schema defining supported extra specs for the Garm Equinix Metal Provider",
"properties": {
"metro_code": {
"type": "string",
"description": "The metro in which this pool will create runners."
},
"hardware_reservation_id": {
"type": "string",
"description": "The hardware reservation ID to use."
}
},
"additionalProperties": false
}
`

func jsonSchemaValidation(schema json.RawMessage) error {
schemaLoader := gojsonschema.NewStringLoader(jsonSchema)
extraSpecsLoader := gojsonschema.NewBytesLoader(schema)
result, err := gojsonschema.Validate(schemaLoader, extraSpecsLoader)
if err != nil {
return fmt.Errorf("failed to validate schema: %w", err)
}
if !result.Valid() {
return fmt.Errorf("schema validation failed: %s", result.Errors())
}
return nil
}

func newExtraSpecsFromBootstrapData(data params.BootstrapInstance) (extraSpecs, error) {
spec := extraSpecs{}

if len(data.ExtraSpecs) > 0 {
if err := jsonSchemaValidation(data.ExtraSpecs); err != nil {
return extraSpecs{}, fmt.Errorf("failed to validate extra specs: %w", err)
}

if err := json.Unmarshal(data.ExtraSpecs, &spec); err != nil {
return extraSpecs{}, fmt.Errorf("failed to unmarshal extra specs: %w", err)
}
Expand All @@ -43,13 +89,13 @@ func newExtraSpecsFromBootstrapData(data params.BootstrapInstance) (extraSpecs,
type extraSpecs struct {
// MetroCode is the metro (usually a two letter code) to use for the instance.
// See: https://deploy.equinix.com/developers/docs/metal/locations/metros/
MetroCode string `toml:"metro_code"`
MetroCode string `json:"metro_code"`
// HardwareReservationID is the UUID representing the hardware reservation to use.
HardwareReservationID *string `toml:"hardware_reservation_id,omitempty"`
HardwareReservationID *string `json:"hardware_reservation_id,omitempty"`
}

func GetRunnerSpecFromBootstrapParams(data params.BootstrapInstance, controllerID string) (*RunnerSpec, error) {
tools, err := util.GetTools(data.OSType, data.OSArch, data.Tools)
tools, err := DefaultToolFetch(data.OSType, data.OSArch, data.Tools)
if err != nil {
return nil, fmt.Errorf("failed to get tools: %s", err)
}
Expand Down Expand Up @@ -118,7 +164,7 @@ func (r *RunnerSpec) ComposeUserData() (string, error) {
return "", fmt.Errorf("unsupported OS type for cloud config: %s", r.BootstrapParams.OSType)
}

udata, err := cloudconfig.GetCloudConfig(r.BootstrapParams, r.Tools, r.BootstrapParams.Name)
udata, err := DefaultGetCloudconfig(r.BootstrapParams, r.Tools, r.BootstrapParams.Name)
if err != nil {
return "", fmt.Errorf("failed to generate userdata: %w", err)
}
Expand All @@ -127,3 +173,7 @@ func (r *RunnerSpec) ComposeUserData() (string, error) {
}
return udata, nil
}

func Ptr[T any](v T) *T {
return &v
}
Loading

0 comments on commit d0af9a8

Please sign in to comment.