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

APPS-916 REST API for configuration #20

Merged
merged 15 commits into from
Oct 17, 2023
7 changes: 4 additions & 3 deletions cmd/backup/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ func run() int {
// set default logger
slog.SetDefault(slog.New(util.LogHandler(logLevel)))
// read configuration file
config, err := readConfiguration(configFile)
server.ConfigurationManager = service.NewConfigurationManager(configFile)
config, err := readConfiguration()
if err != nil {
return err
}
Expand Down Expand Up @@ -73,8 +74,8 @@ func systemCtx() context.Context {
return ctx
}

func readConfiguration(configFile string) (*model.Config, error) {
config, err := model.ReadConfiguration(configFile)
func readConfiguration() (*model.Config, error) {
config, err := server.ConfigurationManager.ReadConfiguration()
if err != nil {
slog.Error("failed to read configuration file", "error", err)
return nil, err
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/aws/aws-sdk-go-v2 v1.21.0
github.com/aws/aws-sdk-go-v2/config v1.18.42
github.com/aws/aws-sdk-go-v2/service/s3 v1.39.0
github.com/aws/smithy-go v1.14.2
github.com/prometheus/client_golang v1.16.0
github.com/spf13/cobra v1.7.0
golang.org/x/time v0.3.0
Expand All @@ -27,7 +28,6 @@ require (
github.com/aws/aws-sdk-go-v2/service/sso v1.14.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.22.0 // indirect
github.com/aws/smithy-go v1.14.2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
Expand Down
319 changes: 319 additions & 0 deletions internal/server/config_handlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,319 @@
package server

import (
"encoding/json"
"net/http"

"github.com/aerospike/backup/pkg/model"
"github.com/aerospike/backup/pkg/service"
)

var ConfigurationManager service.ConfigurationManager

// readConfig
// @Summary Returns the configuration for the service.
// @Router /config [get]
// @Produce json
// @Success 200 {array} model.Config
func (ws *HTTPServer) readConfig(w http.ResponseWriter) {
configuration, err := json.MarshalIndent(ws.config, "", " ") // pretty print
if err != nil {
http.Error(w, "Failed to parse service configuration", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_, _ = w.Write(configuration)
}

// updateConfig
// @Summary Updates the configuration for the service.
// @Router /config [post]
// @Accept json
// @Param storage body model.Config true "config"
// @Success 200 ""
func (ws *HTTPServer) updateConfig(w http.ResponseWriter, r *http.Request) {
var newConfig model.Config

err := json.NewDecoder(r.Body).Decode(&newConfig)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
ws.config = &newConfig
err = ConfigurationManager.WriteConfiguration(&newConfig)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
}

// addAerospikeCluster
// @Summary adds an Aerospike cluster to the config.
// @Router /config/cluster [post]
// @Accept json
// @Param cluster body model.AerospikeCluster true "cluster info"
// @Success 200 ""
func (ws *HTTPServer) addAerospikeCluster(w http.ResponseWriter, r *http.Request) {
var newCluster model.AerospikeCluster
err := json.NewDecoder(r.Body).Decode(&newCluster)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
err = service.AddCluster(ws.config, &newCluster)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
err = ConfigurationManager.WriteConfiguration(ws.config)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
}
}

// readAerospikeClusters reads all Aerospike clusters from the configuration.
// @Summary Reads all Aerospike clusters from the configuration.
// @Router /config/cluster [get]
// @Produce json
// @Success 200 {array} model.AerospikeCluster
func (ws *HTTPServer) readAerospikeClusters(w http.ResponseWriter) {
clusters := ws.config.AerospikeClusters
jsonResponse, err := json.Marshal(clusters)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(jsonResponse)
}

// updateAerospikeCluster updates an existing Aerospike cluster in the configuration.
// @Summary Updates an existing Aerospike cluster in the configuration.
// @Router /config/cluster [put]
// @Accept json
// @Param storage body model.AerospikeCluster true "aerospike cluster"
// @Success 200 {string} string "OK"
// @Failure 400 {string} string "Bad Request"
func (ws *HTTPServer) updateAerospikeCluster(w http.ResponseWriter, r *http.Request) {
var updatedCluster model.AerospikeCluster
err := json.NewDecoder(r.Body).Decode(&updatedCluster)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
err = service.UpdateCluster(ws.config, &updatedCluster)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
err = ConfigurationManager.WriteConfiguration(ws.config)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
}
}

// deleteAerospikeCluster
// @Summary Deletes a cluster from the configuration by name.
// @Router /config/cluster [delete]
// @Param name query string true "Cluster Name"
// @Success 200 {string} string "OK"
// @Failure 400 {string} string "Bad Request"
func (ws *HTTPServer) deleteAerospikeCluster(w http.ResponseWriter, r *http.Request) {
clusterName := r.URL.Query().Get("name")
if clusterName == "" {
http.Error(w, "Cluster name is required", http.StatusBadRequest)
return
}

err := service.DeleteCluster(ws.config, &clusterName)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

err = ConfigurationManager.WriteConfiguration(ws.config)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
}
}

// addStorage
// @Summary adds a storage cluster to the config.
// @Router /config/storage [post]
// @Accept json
// @Param storage body model.BackupStorage true "backup storage"
// @Success 200 ""
func (ws *HTTPServer) addStorage(w http.ResponseWriter, r *http.Request) {
var newStorage model.BackupStorage
err := json.NewDecoder(r.Body).Decode(&newStorage)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
err = service.AddStorage(ws.config, &newStorage)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
err = ConfigurationManager.WriteConfiguration(ws.config)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
}
}

// readStorages reads all storages from the configuration.
// @Summary Reads all storages from the configuration.
// @Router /config/storage [get]
// @Produce json
// @Success 200 {array} model.BackupStorage
func (ws *HTTPServer) readStorages(w http.ResponseWriter) {
storage := ws.config.BackupStorage
jsonResponse, err := json.Marshal(storage)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(jsonResponse)
}

// updateStorage updates an existing storage in the configuration.
// @Summary Updates an existing storage in the configuration.
// @Router /config/storage [put]
// @Accept json
// @Param storage body model.BackupStorage true "backup storage"
// @Success 200 {string} string "OK"
// @Failure 400 {string} string "Bad Request"
func (ws *HTTPServer) updateStorage(w http.ResponseWriter, r *http.Request) {
var updatedStorage model.BackupStorage
err := json.NewDecoder(r.Body).Decode(&updatedStorage)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
err = service.UpdateStorage(ws.config, &updatedStorage)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
err = ConfigurationManager.WriteConfiguration(ws.config)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
}
}

// deleteStorage
// @Summary Deletes a storage from the configuration by name.
// @Router /config/storage [delete]
// @Param name query string true "Storage Name"
// @Success 200 {string} string "OK"
// @Failure 400 {string} string "Bad Request"
func (ws *HTTPServer) deleteStorage(w http.ResponseWriter, r *http.Request) {
storageName := r.URL.Query().Get("name")
if storageName == "" {
http.Error(w, "Storage name is required", http.StatusBadRequest)
return
}

err := service.DeleteStorage(ws.config, &storageName)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

err = ConfigurationManager.WriteConfiguration(ws.config)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
}
}

// addPolicy
// @Summary adds a policy to the config.
// @Router /config/policy [post]
// @Accept json
// @Param storage body model.BackupPolicy true "backup policy"
// @Success 200 ""
func (ws *HTTPServer) addPolicy(w http.ResponseWriter, r *http.Request) {
var newPolicy model.BackupPolicy
err := json.NewDecoder(r.Body).Decode(&newPolicy)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
err = service.AddPolicy(ws.config, &newPolicy)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
err = ConfigurationManager.WriteConfiguration(ws.config)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
}
}

// readPolicies reads all backup policies from the configuration.
// @Summary Reads all policies from the configuration.
// @Router /config/policy [get]
// @Produce json
// @Success 200 {array} model.BackupPolicy
func (ws *HTTPServer) readPolicies(w http.ResponseWriter) {
policies := ws.config.BackupPolicy
jsonResponse, err := json.Marshal(policies)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(jsonResponse)
}

// updatePolicy updates an existing policy in the configuration.
// @Summary Updates an existing policy in the configuration.
// @Router /config/policy [put]
// @Accept json
// @Param storage body model.BackupPolicy true "backup policy"
// @Success 200 {string} string "OK"
// @Failure 400 {string} string "Bad Request"
func (ws *HTTPServer) updatePolicy(w http.ResponseWriter, r *http.Request) {
var updatedPolicy model.BackupPolicy
err := json.NewDecoder(r.Body).Decode(&updatedPolicy)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
err = service.UpdatePolicy(ws.config, &updatedPolicy)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
err = ConfigurationManager.WriteConfiguration(ws.config)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
}
}

// deletePolicy
// @Summary Deletes a policy from the configuration by name.
// @Router /config/policy [delete]
// @Param name query string true "Policy Name"
// @Success 200 {string} string "OK"
// @Failure 400 {string} string "Bad Request"
func (ws *HTTPServer) deletePolicy(w http.ResponseWriter, r *http.Request) {
policyName := r.URL.Query().Get("name")
if policyName == "" {
http.Error(w, "Policy name is required", http.StatusBadRequest)
return
}

err := service.DeletePolicy(ws.config, &policyName)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

err = ConfigurationManager.WriteConfiguration(ws.config)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
}
}
Loading