Skip to content

Commit

Permalink
nomad provider
Browse files Browse the repository at this point in the history
  • Loading branch information
mkvolkov committed May 29, 2024
1 parent ef5fbbc commit b80ec2a
Show file tree
Hide file tree
Showing 6 changed files with 536 additions and 9 deletions.
25 changes: 25 additions & 0 deletions examples/read-nomad/httpecho.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
job "httpecho" {
datacenters = ["dc1"]

group "echo" {
count = 5
network {
port "http" {}
}

task "server" {
driver = "docker"

config {
image = "hashicorp/http-echo:latest"

ports = ["http"]

args = [
"-listen", ":${NOMAD_PORT_http}",
"-text", "Hello and welcome to ${NOMAD_IP_http} running on port ${NOMAD_PORT_http}",
]
}
}
}
}
282 changes: 282 additions & 0 deletions examples/read-nomad/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
package main

import (
"encoding/json"
"fmt"
"log"
"os"
"os/exec"
"strconv"

"github.com/hashicorp/nomad/api"
"github.com/knadh/koanf/v2"
"github.com/knadh/koanf/v2/providers/nomad"
)

// Example and test
// Requirements:
//
// - Docker installed
// - Docker daemon running
// - Nomad installed
// - Nomad running
// (sudo nomad agent -dev)
// - Nomad echo project running
// (nomad run httpecho.hcl)
// - curl
func main() {
fmt.Printf("Checking...\n")
var k = koanf.New(".")
var k2 = koanf.New(".")
var k3 = koanf.New(".")

// allocs
out, err := exec.Command("curl", "http://localhost:4646/v1/allocations").Output()
if err != nil {
log.Fatalf("error retreiving allocs from curl: %v\n", err)
}

var aListStub = []api.AllocationListStub{}
if err = json.Unmarshal(out, &aListStub); err != nil {
log.Fatalf("error unmarshalling alloc list: %s\n", err)
}

nAllocs := len(aListStub)
allocsHTTPData := make([]api.Allocation, nAllocs)

for i := 0; i < nAllocs; i++ {
cmdPath := fmt.Sprintf("http://localhost:4646/v1/allocation/%s", aListStub[i].ID)
out, err := exec.Command("curl", cmdPath).Output()
if err != nil {
log.Fatalf("error retrieving alloc with ID = %s: %s\n", aListStub[i].ID, err)
}

json.Unmarshal(out, &allocsHTTPData[i])
}

nmdAllocs, err := nomad.Provider(nil, "allocs")
if err != nil {
log.Fatalf("error creating provider: %v\n", err)
}

if err = k.Load(nmdAllocs, nil); err != nil {
log.Fatalf("error loading allocs: %v\n", err)
}

// allocs: checking
for i1 := 0; i1 < nAllocs; i1++ {
ID := allocsHTTPData[i1].ID

var key string
var flagFound bool = false

// finding alloc with this ID
for i2 := 0; i2 < nAllocs; i2++ {
key = "echo" + strconv.Itoa(i2)
if k.String(key+".ID") == ID {
flagFound = true
break
}
}

if !flagFound {
log.Fatalf("Alloc ID not found: test failed\n")
}

// comparing all data
if k.String(key+".Namespace") != allocsHTTPData[i1].Namespace {
fmt.Printf("Alloc Namespace: test failed\n")
os.Exit(1)
}

if k.String(key+".EvalID") != allocsHTTPData[i1].EvalID {
fmt.Printf("Alloc EvalID: test failed\n")
os.Exit(1)
}

if k.String(key+".Name") != allocsHTTPData[i1].Name {
fmt.Printf("Alloc Name: test failed\n")
os.Exit(1)
}

if k.String(key+".NodeID") != allocsHTTPData[i1].NodeID {
fmt.Printf("Alloc NodeID: test failed\n")
os.Exit(1)
}

if k.String(key+".NodeName") != allocsHTTPData[i1].NodeName {
fmt.Printf("Alloc NodeName: test failed\n")
os.Exit(1)
}

if k.String(key+".JobID") != allocsHTTPData[i1].JobID {
fmt.Printf("Alloc JobID: test failed\n")
os.Exit(1)
}

if k.String(key+".TaskGroup") != allocsHTTPData[i1].TaskGroup {
fmt.Printf("Alloc TaskGroup: test failed\n")
os.Exit(1)
}

if k.String(key+".DesiredStatus") != allocsHTTPData[i1].DesiredStatus {
fmt.Printf("Alloc DesiredStatus: test failed\n")
os.Exit(1)
}

if k.String(key+".ClientStatus") != allocsHTTPData[i1].ClientStatus {
fmt.Printf("Alloc ClientStatus: test failed\n")
os.Exit(1)
}

if k.String(key+".DeploymentID") != allocsHTTPData[i1].DeploymentID {
fmt.Printf("Alloc DeploymentID: test failed\n")
os.Exit(1)
}

if k.String(key+".DeploymentID") == allocsHTTPData[i1].ID {
fmt.Printf("Alloc DeploymentID = ID: test failed\n")
os.Exit(1)
}

// network comparison
for k1 := 0; k1 < len(allocsHTTPData[i1].Resources.Networks); k1++ {
ipSearch := allocsHTTPData[i1].Resources.Networks[k1].IP

// ipSearch in koanf
// koanf key
var keyNetwork string
for k2 := 0; k2 < len(allocsHTTPData[i1].Resources.Networks); k2++ {
keyNetwork = key + ".Network" + strconv.Itoa(k1) + ".IP"
if ipSearch == k.String(keyNetwork) {
break
}
}

// port search
for k2 := 0; k2 < len(allocsHTTPData[i1].Resources.Networks[k1].DynamicPorts); k2++ {
flagPort := false
for k3 := 0; k3 <= k2; k3++ {
keyPort := key + ".Network" + strconv.Itoa(k1) + ".Port" + strconv.Itoa(k3)
if k.Int(keyPort) == allocsHTTPData[i1].Resources.Networks[k1].DynamicPorts[k2].Value {
flagPort = true
break
}
}

if flagPort {
flagPort = false
} else {
fmt.Printf(
"Alloc ports: test failed, port %d isn't found\n",
allocsHTTPData[i1].Resources.Networks[k1].DynamicPorts[k2].Value)
os.Exit(1)
}
}
}
}

fmt.Printf("Allocations: test passed\n")

// raft
out, err = exec.Command("curl", "http://localhost:4646/v1/operator/raft/configuration").Output()
if err != nil {
log.Fatalf("error retreiving raft configuration from curl: %v\n", err)
}

raftCfg := api.RaftConfiguration{}
if err = json.Unmarshal(out, &raftCfg); err != nil {
log.Fatalf("error unmarshalling raft configuration: %s\n", err)
}

nmdRaft, err := nomad.Provider(nil, "raft")
if err != nil {
log.Fatalf("error creating provider: %v\n", err)
}

if err = k2.Load(nmdRaft, nil); err != nil {
log.Fatalf("error loading allocs: %v\n", err)
}

nServers := len(raftCfg.Servers)

// raft: checking
for i1 := 0; i1 < nServers; i1++ {
ID := raftCfg.Servers[i1].ID

var key string
var flagFound bool = false

// finding alloc with this ID
for i2 := 0; i2 < nServers; i2++ {
key = "server" + strconv.Itoa(i2)
if k2.String(key+".ID") == ID {
flagFound = true
break
}
}

if !flagFound {
log.Fatalf("Raft server ID not found: test failed")
}

if k2.String(key+".Node") != raftCfg.Servers[i1].Node {
log.Fatalf("Raft server node: test failed")
}

if k2.String(key+".Address") != raftCfg.Servers[i1].Address {
log.Fatalf("Raft server address: test failed")
}

if k2.Bool(key+".Leader") != raftCfg.Servers[i1].Leader {
log.Fatalf("Raft server leader: test failed")
}

if k2.Bool(key+".Voter") != raftCfg.Servers[i1].Voter {
log.Fatalf("Raft server voter: test failed")
}

if k2.String(key+".RaftProtocol") != raftCfg.Servers[i1].RaftProtocol {
log.Fatalf("Raft server protocol: test failed")
}
}

fmt.Printf("Raft configuration: test passed\n")

// vars
_, err = exec.Command(
"curl",
"--header",
"Content-Type: application/json",
"--request",
"POST",
"--data",
`{"Path": "databases/sql", "Items": {"mysql": "75cp21", "postgresql": "52pg24"}}`,
"http://localhost:4646/v1/var/databases/sql",
).Output()
if err != nil {
log.Fatalf("Couldn't create variables: %v\n", err)
}

nmdVars, err := nomad.Provider(nil, "vars")
if err != nil {
log.Fatalf("error creating provider: %v\n", err)
}

if err = k3.Load(nmdVars, nil); err != nil {
log.Fatalf("error loading vars: %v\n", err)
}

// vars: checking
if k3.String("databases/sql.mysql") != "75cp21" {
log.Fatalf("Vars: test failed\n")
}

if k3.String("databases/sql.postgresql") != "52pg24" {
log.Fatalf("Vars: test failed\n")
}

fmt.Printf("Vars: test passed\n")

fmt.Printf("ALL TESTS PASSED\n")
}
20 changes: 16 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,24 @@ go 1.18

require (
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1
github.com/hashicorp/nomad/api v0.0.0-20240528130403-9fb2b10ab63d
github.com/knadh/koanf/maps v0.1.1
github.com/mitchellh/copystructure v1.2.0
)

require github.com/mitchellh/reflectwalk v1.0.2 // indirect
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/cronexpr v1.1.2 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

retract (
v2.0.2 // Tagged as minor version, but contains breaking changes.
)
retract v2.0.2 // Tagged as minor version, but contains breaking changes.
31 changes: 31 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,8 +1,39 @@
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/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 h1:TQcrn6Wq+sKGkpyPvppOz99zsMBaUOKXq6HSv655U1c=
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A=
github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/nomad/api v0.0.0-20240528130403-9fb2b10ab63d h1:7JpW+CLlTdBLFejoKNx8Tu7VY8eiFkMmOLPnkYbLVrw=
github.com/hashicorp/nomad/api v0.0.0-20240528130403-9fb2b10ab63d/go.mod h1:svtxn6QnrQ69P23VvIWMR34tg3vmwLz4UdUzm1dSCgE=
github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs=
github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
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/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
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/shoenig/test v1.7.1 h1:UJcjSAI3aUKx52kfcfhblgyhZceouhvvs3OYdWgn+PY=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Loading

0 comments on commit b80ec2a

Please sign in to comment.