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

Add docker, nomad and k8s manifests for exporter #35

Merged
merged 11 commits into from
Jul 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
31 changes: 31 additions & 0 deletions .github/workflows/docker-integration-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: docker-integration-test
on: [push]
jobs:
docker-integration-test:
runs-on: ubuntu-latest
steps:
-
name: Checkout code
uses: actions/checkout@v3
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 github actions are mainly lift and shift but I updated the versions to the latest.

-
name: Go build
run: CGO_ENABLED=0 GOOS=linux go build -o grid-intensity .
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Binary is named grid-intensity in the dockerfile not grid-intensity-go for consistency with the CLI

-
name: Set up QEMU
uses: docker/setup-qemu-action@v2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
name: Docker build
uses: docker/build-push-action@v3
with:
context: .
load: true
tags: thegreenwebfoundation/grid-intensity:integration-test
-
name: Docker run
run: docker run -d -e GRID_INTENSITY_REGION=GBR -p 8000:8000 thegreenwebfoundation/grid-intensity:integration-test exporter
-
name: Run integration test
run: go test -v -tags=dockerrequired ./integration/test/exporter
49 changes: 49 additions & 0 deletions .github/workflows/kubernetes-integration-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: kubernetes-integration-test
on: [push]
jobs:
kubernetes-integration-test:
runs-on: ubuntu-latest
steps:
-
name: Checkout code
uses: actions/checkout@v3
-
name: Go build
run: CGO_ENABLED=0 GOOS=linux go build -o grid-intensity .
-
name: Set up QEMU
uses: docker/setup-qemu-action@v2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
name: Docker build
uses: docker/build-push-action@v3
with:
context: .
load: true
tags: thegreenwebfoundation/grid-intensity:integration-test
-
name: Create kubernetes Kind Cluster
uses: helm/[email protected]
-
name: Load image into Kind cluster
run: kind load docker-image --name chart-testing thegreenwebfoundation/grid-intensity:integration-test
-
name: Set up Helm
uses: azure/setup-helm@v3
-
name: Helm install
run: helm install grid-intensity-exporter helm/grid-intensity-exporter --set image.tag=integration-test
-
name: Set up Kubectl
uses: azure/setup-kubectl@v3
-
name: Wait for ready pod
run: kubectl wait --for=condition=ready -l app.kubernetes.io/name=grid-intensity-exporter pod
-
name: Create port forward to metrics port
run: kubectl port-forward deployment/grid-intensity-exporter 8000:8000 &
-
name: Run integration test
run: go test -v -tags=dockerrequired ./integration/test/exporter
43 changes: 43 additions & 0 deletions .github/workflows/nomad-integration-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: nomad-integration-test
on: [push]
jobs:
nomad-integration-test:
runs-on: ubuntu-latest
steps:
-
name: Checkout code
uses: actions/checkout@v3
-
name: Go build
run: CGO_ENABLED=0 GOOS=linux go build -o grid-intensity .
-
name: Set up QEMU
uses: docker/setup-qemu-action@v2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
name: Docker build
uses: docker/build-push-action@v3
with:
context: .
load: true
tags: thegreenwebfoundation/grid-intensity:integration-test
-
name: Add HashiCorp GPG key
run: curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
-
name: Add HashiCorp Linux repository
run: sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
-
name: Install nomad
run: sudo apt-get update && sudo apt-get install nomad
-
name: Start running nomad in agent mode, then background it
run: nomad agent --dev &
-
name: Submit the grid-intensity-exporter.nomad job to nomad
run: nomad run ./nomad/grid-intensity-exporter.nomad
-
name: Run integration test
run: go test -v -tags=dockerrequired ./integration/test/exporter
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,8 @@

dist/

grid-intensity
grid-intenity-go

# Dependency directories (remove the comment below to include it)
# vendor/
9 changes: 9 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM alpine:3.16
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 to the latest alpine.

We could automate with dependabot here to update the docker base image, go packages and the github actions.


RUN apk add --no-cache ca-certificates

ADD ./grid-intensity /grid-intensity

EXPOSE 8000/tcp

ENTRYPOINT ["/grid-intensity"]
44 changes: 0 additions & 44 deletions cmd/cmd.go

This file was deleted.

91 changes: 91 additions & 0 deletions cmd/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package cmd

import (
"errors"
"os"
"path/filepath"

"github.com/spf13/viper"
)

const (
electricityMapAPITokenEnvVar = "ELECTRICITY_MAP_API_TOKEN"
wattTimeUserEnvVar = "WATT_TIME_USER"
wattTimePasswordEnvVar = "WATT_TIME_PASSWORD"
)

func getConfigFile() (string, error) {
homeDir, err := os.UserHomeDir()
if err != nil {
return "", nil
}

return filepath.Join(homeDir, configDir, configFileName), nil
}

func configFileExists(configFile string) (bool, error) {
_, err := os.Stat(configFile)
if err == nil {
return true, nil
}
if errors.Is(err, os.ErrNotExist) {
return false, nil
}

return false, err
}

func readConfig() (string, string, error) {
configFile, err := getConfigFile()
if err != nil {
return "", "", err
}

viper.SetConfigFile(configFile)

err = viper.ReadInConfig()
if errors.Is(err, os.ErrNotExist) {
// Config file may not be available e.g. when running as a container.
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 config file support and docker where not playing nicely so I refactored this part.

We now try to use the config file but it can't be written we still use the CLI arguments or env vars. As this will work better when run in nomad or k8s.

Copy link
Member

Choose a reason for hiding this comment

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

oh thanks Ross.

this is what the providerName := viper.GetString(provider) gubbins is all about, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes totally, under the hood viper is just a key value store. The viper.GetString is to fetch a key.

In front of the k/v store you can use flags, env vars, or config files. These changes mean we handle when there isn't a config file and we can't write to the filesystem.

} else if err != nil {
return "", "", err
}

providerName := viper.GetString(provider)
regionCode := viper.GetString(region)

return providerName, regionCode, nil
}

func writeConfig() error {
configFile, err := getConfigFile()
if err != nil {
return err
}

fileExists, err := configFileExists(configFile)
if err != nil {
return err
}

if !fileExists {
// Create config dir if it doesn't exist.
err = os.MkdirAll(filepath.Dir(configFile), os.ModePerm)
if err != nil && !os.IsExist(err) {
return nil
}

// Create config file if it doesn't exist.
_, err = os.Create(configFile)
if err != nil {
// If we can't create file don't try to write config.
return nil
}
}

err = viper.WriteConfig()
if err != nil {
return err
}

return nil
}
5 changes: 2 additions & 3 deletions cmd/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/spf13/cobra"
"github.com/spf13/viper"

gridintensity "github.com/thegreenwebfoundation/grid-intensity-go/api"
"github.com/thegreenwebfoundation/grid-intensity-go/carbonintensity"
Expand Down Expand Up @@ -229,7 +228,7 @@ func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
}

func runExporter() error {
providerName, regionCode, err := getConfig()
providerName, regionCode, err := readConfig()
if err != nil {
return err
}
Expand All @@ -239,7 +238,7 @@ func runExporter() error {
return err
}

err = viper.WriteConfig()
err = writeConfig()
if err != nil {
return err
}
Expand Down
9 changes: 7 additions & 2 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ func init() {

viper.BindPFlag(provider, rootCmd.PersistentFlags().Lookup(provider))
viper.BindPFlag(region, rootCmd.PersistentFlags().Lookup(region))

// Also support environment variables.
viper.SetEnvPrefix("grid_intensity")
viper.BindEnv(provider)
viper.BindEnv(region)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This adds support for the GRID_INTENSITY_PROVIDER and GRID_INTENSITY_REGION env vars we were using with the exporter.

}

func getEmberGridIntensityForCountry(countryCode string) error {
Expand Down Expand Up @@ -143,7 +148,7 @@ func getCountryCode() (string, error) {
func runRoot() error {
ctx := context.Background()

providerName, regionCode, err := getConfig()
providerName, regionCode, err := readConfig()
if err != nil {
return err
}
Expand Down Expand Up @@ -172,7 +177,7 @@ func runRoot() error {
return fmt.Errorf("provider %q not recognized", providerName)
}

err = viper.WriteConfig()
err = writeConfig()
if err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.17

require (
github.com/Xuanwo/go-locale v1.1.0
github.com/cenkalti/backoff/v4 v4.1.3
github.com/gofrs/flock v0.8.1
github.com/jellydator/ttlcache/v2 v2.11.1
github.com/prometheus/client_golang v1.12.2
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=
github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
Expand Down
5 changes: 5 additions & 0 deletions helm/grid-intensity-exporter/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
apiVersion: "v1"
description: "A prometheus exporter for understanding the carbon intensity of compute."
home: "https://github.com/thegreenwebfoundation/grid-intensity-go"
name: "grid-intensity-exporter"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here comes the YAML 😂

I've kept the helm chart named grid-intensity-exporter as I don't think there is a good use case for running the CLI in k8s.

version: "0.1.0"
9 changes: 9 additions & 0 deletions helm/grid-intensity-exporter/templates/configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}
labels:
app.kubernetes.io/name: {{ .Release.Name }}
data:
gridIntensityProvider: {{ .Values.gridIntensity.provider | quote }}
gridIntensityRegion: {{ .Values.gridIntensity.region | quote }}
Loading