diff --git a/cmd/cli/main.go b/cmd/cli/main.go index b74db59..ceca766 100644 --- a/cmd/cli/main.go +++ b/cmd/cli/main.go @@ -16,7 +16,7 @@ import ( func printUsage() { fmt.Printf(` -Usage: hailstorm [OPTIONS] COMMAND +Usage: run [OPTIONS] COMMAND Run any application in the cloud and on the edge @@ -26,6 +26,11 @@ Options: Commands: endpoint Create a new endpoint [options... endpoint "myendpoint"] + +Subcommands: +create Create a new endpoint [options... endpoint create "myendpoint"] +list List current endpoints + deploy Deploy an app to the cloud [deploy ] help Show usage @@ -78,6 +83,8 @@ func main() { printUsage() } switch args[1] { + case "rollback": + command.handleRollback(args) case "create": command.handleCreateEndpoint(args) case "list": @@ -98,6 +105,31 @@ type command struct { client *client.Client } +// endpoint rollback +func (c command) handleRollback(args []string) { + if len(args) != 4 { + printUsage() + } + endpointID, err := uuid.Parse(args[2]) + if err != nil { + printErrorAndExit(err) + } + deployID, err := uuid.Parse(args[3]) + if err != nil { + printErrorAndExit(err) + } + params := api.CreateRollbackParams{DeployID: deployID} + resp, err := c.client.RollbackEndpoint(endpointID, params) + if err != nil { + printErrorAndExit(err) + } + b, err := json.MarshalIndent(resp, "", " ") + if err != nil { + printErrorAndExit(err) + } + fmt.Println(string(b)) +} + func (c command) handleListEndpoints(args []string) { endpoints, err := c.client.ListEndpoints() if err != nil { @@ -132,7 +164,6 @@ func (c command) handleCreateEndpoint(args []string) { func (c command) handleDeploy(args []string) { if len(args) != 2 { printUsage() - return } id, err := uuid.Parse(args[0]) if err != nil { diff --git a/pkg/api/server.go b/pkg/api/server.go index aa344d2..e22102d 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -150,6 +150,10 @@ type CreateRollbackParams struct { DeployID uuid.UUID `json:"deploy_id"` } +type CreateRollbackResponse struct { + DeployID uuid.UUID `json:"deploy_id"` +} + func (s *Server) handleCreateRollback(w http.ResponseWriter, r *http.Request) error { endpointID, err := uuid.Parse(chi.URLParam(r, "id")) if err != nil { @@ -167,6 +171,11 @@ func (s *Server) handleCreateRollback(w http.ResponseWriter, r *http.Request) er return writeJSON(w, http.StatusBadRequest, ErrorResponse(err)) } + if currentDeployID.String() == params.DeployID.String() { + err := fmt.Errorf("deploy %s already active", params.DeployID) + return writeJSON(w, http.StatusBadRequest, ErrorResponse(err)) + } + deploy, err := s.store.GetDeploy(params.DeployID) if err != nil { return writeJSON(w, http.StatusNotFound, ErrorResponse(err)) @@ -174,6 +183,7 @@ func (s *Server) handleCreateRollback(w http.ResponseWriter, r *http.Request) er updateParams := storage.UpdateEndpointParams{ ActiveDeployID: deploy.ID, + Deploys: []*types.Deploy{deploy}, } if err := s.store.UpdateEndpoint(endpointID, updateParams); err != nil { return writeJSON(w, http.StatusBadRequest, ErrorResponse(err)) @@ -181,7 +191,8 @@ func (s *Server) handleCreateRollback(w http.ResponseWriter, r *http.Request) er s.cache.Delete(currentDeployID) - return writeJSON(w, http.StatusOK, map[string]any{"deploy": deploy.ID}) + resp := CreateRollbackResponse{DeployID: deploy.ID} + return writeJSON(w, http.StatusOK, resp) } func (s *Server) handleGetEndpointMetrics(w http.ResponseWriter, r *http.Request) error { diff --git a/pkg/client/client.go b/pkg/client/client.go index 5dc8950..f070b41 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -40,6 +40,32 @@ func New(config Config) *Client { } } +func (c *Client) RollbackEndpoint(endpointID uuid.UUID, params api.CreateRollbackParams) (*api.CreateRollbackResponse, error) { + b, err := json.Marshal(params) + if err != nil { + return nil, err + } + url := fmt.Sprintf("%s/endpoint/%s/rollback", c.config.url, endpointID) + req, err := http.NewRequest("POST", url, bytes.NewReader(b)) + if err != nil { + return nil, err + } + req.Header.Add("Content-Type", "application/json") + resp, err := c.Do(req) + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("api responded with a non 200 status code: %d", resp.StatusCode) + } + var rollbackResponse api.CreateRollbackResponse + if err := json.NewDecoder(resp.Body).Decode(&rollbackResponse); err != nil { + return nil, err + } + resp.Body.Close() + return &rollbackResponse, nil +} + func (c *Client) CreateEndpoint(params api.CreateEndpointParams) (*types.Endpoint, error) { b, err := json.Marshal(params) if err != nil { @@ -47,10 +73,10 @@ func (c *Client) CreateEndpoint(params api.CreateEndpointParams) (*types.Endpoin } url := fmt.Sprintf("%s/%s", c.config.url, "endpoint") req, err := http.NewRequest("POST", url, bytes.NewReader(b)) - req.Header.Add("Content-Type", "application/json") if err != nil { return nil, err } + req.Header.Add("Content-Type", "application/json") resp, err := c.Do(req) if err != nil { return nil, err @@ -62,6 +88,7 @@ func (c *Client) CreateEndpoint(params api.CreateEndpointParams) (*types.Endpoin if err := json.NewDecoder(resp.Body).Decode(&endpoint); err != nil { return nil, err } + resp.Body.Close() return &endpoint, nil } @@ -83,6 +110,7 @@ func (c *Client) CreateDeploy(endpointID uuid.UUID, blob io.Reader, params api.C if err := json.NewDecoder(resp.Body).Decode(&deploy); err != nil { return nil, err } + resp.Body.Close() return &deploy, nil } @@ -101,6 +129,6 @@ func (c *Client) ListEndpoints() ([]types.Endpoint, error) { if err := json.NewDecoder(resp.Body).Decode(&endpoints); err != nil { return nil, err } - + resp.Body.Close() return endpoints, nil }