Skip to content

Commit

Permalink
Merge pull request #19 from OpenCHAMI/allend/groups
Browse files Browse the repository at this point in the history
Add API to manage groups in meta-data
  • Loading branch information
davidallendj authored Nov 7, 2024
2 parents cae495e + 918eb99 commit e0cecb0
Show file tree
Hide file tree
Showing 7 changed files with 588 additions and 34 deletions.
181 changes: 181 additions & 0 deletions cmd/cloud-init-server/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func NewCiHandler(s ciStore, c *smdclient.SMDClient) *CiHandler {

// Enumeration for cloud-init data categories
type ciDataKind uint

// Takes advantage of implicit repetition and iota's auto-incrementing
const (
UserData ciDataKind = iota
Expand Down Expand Up @@ -213,3 +214,183 @@ func (h CiHandler) DeleteEntry(w http.ResponseWriter, r *http.Request) {

render.JSON(w, r, map[string]string{"status": "success"})
}

func (h CiHandler) AddGroups(w http.ResponseWriter, r *http.Request) {
// type alias to simplify abstraction
var (
data citypes.GroupData
err error
)

data, err = parseData(w, r)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

// add a new group to meta-data if it doesn't already exist
err = h.store.AddGroups(data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

}

func (h CiHandler) GetGroups(w http.ResponseWriter, r *http.Request) {
var (
data citypes.GroupData
bytes []byte
err error
)

// get group data from MemStore if it exists
data, err = h.store.GetGroups()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

// marshal to YAML and print the group data to standard output
bytes, err = yaml.Marshal(data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Write(bytes)

}

// UpdateGroupData expects a request containing POST data as a JSON. The data
// received in the request should ONLY contain the data to be included for a
// "meta-data.groups" and NOT "meta-data". See "AddGroup" in 'ciMemStore.go'
// for an example.
func (h CiHandler) UpdateGroups(w http.ResponseWriter, r *http.Request) {
// type alias to simplify abstraction
var (
data citypes.GroupData
err error
)

data, err = parseData(w, r)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

// update groups in meta-data
err = h.store.UpdateGroups(data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}

func (h CiHandler) RemoveGroups(w http.ResponseWriter, r *http.Request) {
// remove group data with specified name
var err = h.store.RemoveGroups()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}

func (h CiHandler) AddGroupData(w http.ResponseWriter, r *http.Request) {
var (
id string = chi.URLParam(r, "id")
data citypes.GroupData
err error
)

data, err = parseData(w, r)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

err = h.store.AddGroupData(id, data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

}

func (h CiHandler) GetGroupData(w http.ResponseWriter, r *http.Request) {
var (
id string = chi.URLParam(r, "id")
data citypes.GroupData
bytes []byte
err error
)

data, err = h.store.GetGroupData(id)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

bytes, err = yaml.Marshal(data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Write(bytes)
}
func (h CiHandler) UpdateGroupData(w http.ResponseWriter, r *http.Request) {
var (
id string = chi.URLParam(r, "id")
data citypes.GroupData
err error
)

data, err = parseData(w, r)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

// update group key-value data
err = h.store.UpdateGroupData(id, data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}

func (h CiHandler) RemoveGroupData(w http.ResponseWriter, r *http.Request) {
var (
id string = chi.URLParam(r, "id")
err error
)
err = h.store.RemoveGroupData(id)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}

func writeInternalError(w http.ResponseWriter, err string) {
http.Error(w, err, http.StatusInternalServerError)
// log.Error().Err(err)
}

func parseData(w http.ResponseWriter, r *http.Request) (citypes.GroupData, error) {
var (
body []byte
err error
data citypes.GroupData
)

// read the POST body for JSON data
body, err = io.ReadAll(r.Body)
if err != nil {
return nil, err
}
// unmarshal data to add to group data
err = json.Unmarshal(body, &data)
if err != nil {
return nil, err
}
return data, nil
}
23 changes: 21 additions & 2 deletions cmd/cloud-init-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@ import (
"flag"
"fmt"
"net/http"
"os"
"time"

"github.com/OpenCHAMI/cloud-init/internal/memstore"
"github.com/OpenCHAMI/cloud-init/internal/smdclient"
"github.com/OpenCHAMI/jwtauth/v5"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/rs/zerolog"
zlog "github.com/rs/zerolog/log"

openchami_authenticator "github.com/openchami/chi-middleware/auth"
openchami_logger "github.com/openchami/chi-middleware/log"
)

var (
Expand Down Expand Up @@ -43,6 +49,10 @@ func main() {
fmt.Println("No JWKS URL provided; secure route will be disabled")
}

// Setup logger
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
logger := zlog.Output(zerolog.ConsoleWriter{Out: os.Stderr})

// Primary router and shared SMD client
router := chi.NewRouter()
router.Use(
Expand All @@ -51,7 +61,8 @@ func main() {
middleware.Logger,
middleware.Recoverer,
middleware.StripSlashes,
middleware.Timeout(60 * time.Second),
middleware.Timeout(60*time.Second),
openchami_logger.OpenCHAMILogger(logger),
)
sm := smdclient.NewSMDClient(smdEndpoint, tokenEndpoint)

Expand All @@ -69,7 +80,7 @@ func main() {
router_sec := chi.NewRouter()
router_sec.Use(
jwtauth.Verifier(keyset),
jwtauth.Authenticator(keyset),
openchami_authenticator.AuthenticatorWithRequiredClaims(keyset, []string{"sub", "iss", "aud"}),
)
initCiRouter(router_sec, ciHandler_sec)
router.Mount("/cloud-init-secure", router_sec)
Expand All @@ -92,4 +103,12 @@ func initCiRouter(router chi.Router, handler *CiHandler) {
router.Get("/{id}/vendor-data", handler.GetDataByMAC(VendorData))
router.Put("/{id}", handler.UpdateEntry)
router.Delete("/{id}", handler.DeleteEntry)
router.Post("/groups", handler.AddGroups)
router.Get("/groups", handler.GetGroups)
router.Put("/groups", handler.UpdateGroups)
router.Delete("/groups", handler.RemoveGroups)
router.Post("/groups/{id}", handler.AddGroupData)
router.Get("/groups/{id}", handler.GetGroupData)
router.Put("/groups/{id}", handler.UpdateGroupData)
router.Delete("/groups/{id}", handler.RemoveGroupData)
}
12 changes: 12 additions & 0 deletions cmd/cloud-init-server/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,16 @@ type ciStore interface {
List() (map[string]citypes.CI, error)
Update(name string, ci citypes.CI) error
Remove(name string) error

// metadata groups API
AddGroups(groupsData citypes.GroupData) error
GetGroups() (citypes.GroupData, error)
UpdateGroups(groupsData citypes.GroupData) error
RemoveGroups() error

// extended group API
AddGroupData(groupName string, groupData citypes.GroupData) error
GetGroupData(groupName string) (citypes.GroupData, error)
UpdateGroupData(groupName string, groupData citypes.GroupData) error
RemoveGroupData(groupName string) error
}
19 changes: 11 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,26 @@ module github.com/OpenCHAMI/cloud-init
go 1.21

require (
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed
github.com/OpenCHAMI/jwtauth/v5 v5.0.0-20240321222802-e6cb468a2a18
github.com/OpenCHAMI/smd/v2 v2.12.15
github.com/go-chi/chi/v5 v5.1.0
github.com/go-chi/render v1.0.3
github.com/lestrrat-go/jwx/v2 v2.0.20
github.com/lestrrat-go/jwx/v2 v2.1.1
github.com/openchami/chi-middleware/auth v0.0.0-20240812224658-b16b83c70700
github.com/openchami/chi-middleware/log v0.0.0-20240812224658-b16b83c70700
github.com/rs/zerolog v1.33.0
)

require (
github.com/ajg/form v1.5.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc v1.0.4 // indirect
github.com/lestrrat-go/httprc v1.0.6 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/segmentio/asm v1.2.0 // indirect
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
Expand Down Expand Up @@ -47,10 +50,10 @@ require (
github.com/ryanuber/go-glob v1.0.0 // indirect
github.com/samber/lo v1.39.0
github.com/sirupsen/logrus v1.9.3 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.3.0 // indirect
gopkg.in/yaml.v2 v2.4.0
)
Loading

0 comments on commit e0cecb0

Please sign in to comment.