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

Release 20240401 #224

Merged
merged 3 commits into from
Apr 1, 2024
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
36 changes: 36 additions & 0 deletions api/environment/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,39 @@ type Status struct {
type DetailResponse struct {
Response Env `yaml:"resp,omitempty" json:"resp,omitempty"`
}

type Operation struct {
Name string `yaml:"name,omitempty" json:"name,omitempty"`
Data interface{} `yaml:"data,omitempty" json:"data,omitempty"`
}

type OperationRequest struct {
Operations []Operation `yaml:"operations,omitempty" json:"operations,omitempty"`
}

type OperationConsent struct {
Name string `yaml:"name,omitempty" json:"name,omitempty"`
IsFeedbackRequired bool `yaml:"is_feedback_required,omitempty" json:"is_feedback_required,omitempty"`
Message string `yaml:"message,omitempty" json:"message,omitempty"`
}

type OperationValidationResponseBody struct {
Operations []OperationConsent `yaml:"operations,omitempty" json:"operations,omitempty"`
}

type OperationValidationResponse struct {
Response OperationValidationResponseBody `yaml:"resp,omitempty" json:"resp,omitempty"`
}

type OperationOutput struct {
Name string `yaml:"name,omitempty" json:"name,omitempty"`
Message string `yaml:"message,omitempty" json:"message,omitempty"`
}

type OperationResponseBody struct {
Operations []OperationOutput `yaml:"operations,omitempty" json:"operations,omitempty"`
}

type OperationResponse struct {
Response OperationResponseBody `yaml:"resp,omitempty" json:"resp,omitempty"`
}
2 changes: 1 addition & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ type application struct {
// App (Application) interface
var App application = application{
Name: "odin",
Version: "1.3.4",
Version: "1.4.0",
}
24 changes: 24 additions & 0 deletions internal/backend/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,27 @@ func (e *Env) EnvTypes() (envResp.EnvTypesResponse, error) {

return envResponse, err
}

func (e *Env) ValidateOperation(envName string, data envResp.OperationRequest) (envResp.OperationValidationResponse, error) {
client := newApiClient()

response := client.actionWithRetry(path.Join(envEntity, envName)+"/operate/validate/", "GET", data)
response.Process(true)

var validateOperationResponse envResp.OperationValidationResponse
err := json.Unmarshal(response.Body, &validateOperationResponse)

return validateOperationResponse, err
}

func (e *Env) OperateEnv(envName string, data envResp.OperationRequest) (envResp.OperationResponse, error) {
client := newApiClient()

response := client.actionWithRetry(path.Join(envEntity, envName)+"/operate/", "PUT", data)
response.Process(true)

var operationResponse envResp.OperationResponse
err := json.Unmarshal(response.Body, &operationResponse)

return operationResponse, err
}
9 changes: 9 additions & 0 deletions internal/backend/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,12 @@ func (o *Operation) ListServiceOperations() ([]operationapi.Operation, error) {
err := json.Unmarshal(response.Body, &listResponse)
return listResponse.Response, err
}

func (o *Operation) ListEnvOperations() ([]operationapi.Operation, error) {
client := newApiClient()
response := client.actionWithRetry(path.Join("envs", "operations", "all"), "GET", nil)
response.Process(true) // process response and exit if error
var listResponse operationapi.ListOperation
err := json.Unmarshal(response.Body, &listResponse)
return listResponse.Response, err
}
3 changes: 3 additions & 0 deletions internal/command/command_catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ func CommandsCatalog() map[string]cli.CommandFactory {
"set env": func() (cli.Command, error) {
return &commands.Env{Set: true}, nil
},
"operate env": func() (cli.Command, error) {
return &commands.Env{Operate: true}, nil
},
"list env-type": func() (cli.Command, error) {
return &commands.EnvType{List: true}, nil
},
Expand Down
106 changes: 105 additions & 1 deletion internal/command/commands/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@ func (e *Env) Run(args []string) int {
component := flagSet.String("component", "", "component name to filter out describe environment")
providerAccount := flagSet.String("account", "", "account name to provision the environment in")
id := flagSet.Int("id", 0, "unique id of a changelog of an env")
filePath := flagSet.String("file", "", "file to update env")
filePath := flagSet.String("file", "", "file to update env or provide options for environment operations")
data := flagSet.String("data", "", "data for updating the env")
displayAll := flagSet.Bool("all", false, "whether to display all environments")
operation := flagSet.String("operation", "", "name of the operation to performed on the environment")
options := flagSet.String("options", "", "options for environment operations")

err := flagSet.Parse(args)
if err != nil {
Expand Down Expand Up @@ -380,6 +382,93 @@ func (e *Env) Run(args []string) int {
return 0
}

if e.Operate {
if *name == "" {
*name = utils.FetchKey(ENV_NAME_KEY)
}

isNamePresent := len(*name) > 0
isOptionsPresent := len(*options) > 0
isFilePresent := len(*filePath) > 0
isOperationPresnt := len(*operation) > 0

if !isNamePresent {
e.Logger.Error("--name cannot be blank")
return 1
}
if !isOperationPresnt {
e.Logger.Error("--operation cannot be blank")
return 1
}
if isOptionsPresent && isFilePresent {
e.Logger.Error("You can provide either --options or --file but not both")
return 1
}

var optionsData map[string]interface{}

if isFilePresent {
parsedConfig, err := parseFile(*filePath)
if err != nil {
e.Logger.Error("Error while parsing service file " + *filePath + " : " + err.Error())
return 1
}
optionsData = parsedConfig.(map[string]interface{})
} else if isOptionsPresent {
err = json.Unmarshal([]byte(*options), &optionsData)
if err != nil {
e.Logger.Error("Unable to parse JSON data " + err.Error())
return 1
}
}

data := environment.OperationRequest{
Operations: []environment.Operation{
{
Name: *operation,
Data: optionsData,
},
},
}

e.Logger.Info("Validating the operation: " + *operation + " on the environment: " + *name)

validateOperateResponse, err := envClient.ValidateOperation(*name, data)
if err != nil {
e.Logger.Error(err.Error())
return 1
}

for _, operation := range validateOperateResponse.Response.Operations {
if operation.IsFeedbackRequired {
consentMessage := fmt.Sprintf("\n%s", operation.Message)
allowedInputs := map[string]struct{}{"Y": {}, "n": {}}
val, err := e.Input.AskWithConstraints(consentMessage, allowedInputs)
if err != nil {
e.Logger.Error(err.Error())
return 1
}
if val != "Y" {
e.Logger.Info("Aborting the operation")
return 1
}
} else {
e.Logger.Info("Validations succeeded. Proceeding...")
}
}

operateResponse, err := envClient.OperateEnv(*name, data)
if err != nil {
e.Logger.Error(err.Error())
return 1
}

for _, operation := range operateResponse.Response.Operations {
e.Logger.Output(operation.Message)
}
return 0
}

e.Logger.Error("Not a valid command")
return 127
}
Expand Down Expand Up @@ -464,6 +553,15 @@ func (e *Env) Help() string {
})
}

if e.Operate {
return commandHelper("operate", "environment", "", []Options{
{Flag: "--name", Description: "name of environment"},
{Flag: "--operation", Description: "name of the operation to be performed on the environment"},
{Flag: "--options", Description: "options for the operation in JSON format"},
{Flag: "--file", Description: "path of the file which contains the options for the operation in JSON format"},
})
}

return defaultHelper()
}

Expand Down Expand Up @@ -496,9 +594,15 @@ func (e *Env) Synopsis() string {
if e.Set {
return "Set a default env"
}

if e.Update {
return "update an env"
}

if e.Operate {
return "operate an environment"
}

return defaultHelper()
}

Expand Down
Loading
Loading