Skip to content

Add cortex env rename command #2165

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

Merged
merged 5 commits into from
May 11, 2021
Merged
Show file tree
Hide file tree
Changes from 4 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
8 changes: 4 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@ commands:
steps:
- run:
name: Create Cluster
command: cortex cluster up << parameters.config >> --configure-env aws -y
command: cortex cluster up << parameters.config >> --configure-env cortex -y
- run:
name: Run E2E Tests
no_output_timeout: 30m
command: |
pytest -v test/e2e/tests --env aws --skip-autoscaling --skip-load --skip-long-running
pytest -v test/e2e/tests --env aws -k test_autoscaling
pytest -v test/e2e/tests --env aws -k test_load
pytest -v test/e2e/tests --env cortex --skip-autoscaling --skip-load --skip-long-running
pytest -v test/e2e/tests --env cortex -k test_autoscaling
pytest -v test/e2e/tests --env cortex -k test_load
- run:
name: Delete Cluster
command: cortex cluster down --config << parameters.config >> -y
Expand Down
39 changes: 22 additions & 17 deletions cli/cmd/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ var _eksctlPrefixRegex = regexp.MustCompile(`^.*[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]

func clusterInit() {
_clusterUpCmd.Flags().SortFlags = false
_clusterUpCmd.Flags().StringVarP(&_flagClusterUpEnv, "configure-env", "e", "aws", "name of environment to configure")
_clusterUpCmd.Flags().StringVarP(&_flagClusterUpEnv, "configure-env", "e", "", "name of environment to configure (default: the name of your cluster)")
_clusterUpCmd.Flags().BoolVarP(&_flagClusterDisallowPrompt, "yes", "y", false, "skip prompts")
_clusterCmd.AddCommand(_clusterUpCmd)

Expand Down Expand Up @@ -144,26 +144,31 @@ var _clusterUpCmd = &cobra.Command{

clusterConfigFile := args[0]

envExists, err := isEnvConfigured(_flagClusterUpEnv)
if err != nil {
if _, err := docker.GetDockerClient(); err != nil {
exit.Error(err)
}
if envExists {
if _flagClusterDisallowPrompt {
fmt.Printf("found an existing environment named \"%s\", which will be overwritten to connect to this cluster once it's created\n\n", _flagClusterUpEnv)
} else {
prompt.YesOrExit(fmt.Sprintf("found an existing environment named \"%s\"; would you like to overwrite it to connect to this cluster once it's created?", _flagClusterUpEnv), "", "you can specify a different environment name to be configured to connect to this cluster by specifying the --configure-env flag (e.g. `cortex cluster up --configure-env prod`); or you can list your environments with `cortex env list` and delete an environment with `cortex env delete ENV_NAME`")
}
}

if _, err := docker.GetDockerClient(); err != nil {
accessConfig, err := getNewClusterAccessConfig(clusterConfigFile)
if err != nil {
exit.Error(err)
}

accessConfig, err := getNewClusterAccessConfig(clusterConfigFile)
envName := _flagClusterUpEnv
if envName == "" {
envName = accessConfig.ClusterName
}

envExists, err := isEnvConfigured(envName)
if err != nil {
exit.Error(err)
}
if envExists {
if _flagClusterDisallowPrompt {
fmt.Printf("found an existing environment named \"%s\", which will be overwritten to connect to this cluster once it's created\n\n", envName)
} else {
prompt.YesOrExit(fmt.Sprintf("found an existing environment named \"%s\"; would you like to overwrite it to connect to this cluster once it's created?", envName), "", "you can specify a different environment name to be configured to connect to this cluster by specifying the --configure-env flag (e.g. `cortex cluster up --configure-env prod`); or you can list your environments with `cortex env list` and delete an environment with `cortex env delete ENV_NAME`")
}
}

awsClient, err := newAWSClient(accessConfig.Region, true)
if err != nil {
Expand Down Expand Up @@ -290,23 +295,23 @@ var _clusterUpCmd = &cobra.Command{

loadBalancer, err := getLoadBalancer(clusterConfig.ClusterName, OperatorLoadBalancer, awsClient)
if err != nil {
exit.Error(errors.Append(err, fmt.Sprintf("\n\nyou can attempt to resolve this issue and configure your cli environment by running `cortex cluster info --configure-env %s`", _flagClusterUpEnv)))
exit.Error(errors.Append(err, fmt.Sprintf("\n\nyou can attempt to resolve this issue and configure your cli environment by running `cortex cluster info --configure-env %s`", envName)))
}

newEnvironment := cliconfig.Environment{
Name: _flagClusterUpEnv,
Name: envName,
OperatorEndpoint: "https://" + *loadBalancer.DNSName,
}

err = addEnvToCLIConfig(newEnvironment, true)
if err != nil {
exit.Error(errors.Append(err, fmt.Sprintf("\n\nyou can attempt to resolve this issue and configure your cli environment by running `cortex cluster info --configure-env %s`", _flagClusterUpEnv)))
exit.Error(errors.Append(err, fmt.Sprintf("\n\nyou can attempt to resolve this issue and configure your cli environment by running `cortex cluster info --configure-env %s`", envName)))
}

if envExists {
fmt.Printf(console.Bold("\nthe environment named \"%s\" has been updated to point to this cluster (and was set as the default environment)\n"), _flagClusterUpEnv)
fmt.Printf(console.Bold("\nthe environment named \"%s\" has been updated to point to this cluster (and was set as the default environment)\n"), envName)
} else {
fmt.Printf(console.Bold("\nan environment named \"%s\" has been configured to point to this cluster (and was set as the default environment)\n"), _flagClusterUpEnv)
fmt.Printf(console.Bold("\nan environment named \"%s\" has been configured to point to this cluster (and was set as the default environment)\n"), envName)
}
},
}
Expand Down
21 changes: 21 additions & 0 deletions cli/cmd/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ func envInit() {
_envDefaultCmd.Flags().SortFlags = false
_envCmd.AddCommand(_envDefaultCmd)

_envRenameCmd.Flags().SortFlags = false
_envCmd.AddCommand(_envRenameCmd)

_envDeleteCmd.Flags().SortFlags = false
_envCmd.AddCommand(_envDeleteCmd)
}
Expand Down Expand Up @@ -160,6 +163,24 @@ var _envDefaultCmd = &cobra.Command{
},
}

var _envRenameCmd = &cobra.Command{
Use: "rename EXISTING_NAME NEW_NAME",
Short: "rename an environment",
Args: cobra.ExactArgs(2),
Run: func(cmd *cobra.Command, args []string) {
telemetry.Event("cli.env.rename")

oldEnvName := args[0]
newEnvName := args[1]

if err := renameEnv(oldEnvName, newEnvName); err != nil {
exit.Error(err)
}

print.BoldFirstLine(fmt.Sprintf("renamed the %s environment to %s", oldEnvName, newEnvName))
},
}

var _envDeleteCmd = &cobra.Command{
Use: "delete [ENVIRONMENT_NAME]",
Short: "delete an environment configuration",
Expand Down
1 change: 0 additions & 1 deletion cli/cmd/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ const (
ErrCortexYAMLNotFound = "cli.cortex_yaml_not_found"
ErrDockerCtrlC = "cli.docker_ctrl_c"
ErrResponseUnknown = "cli.response_unknown"
ErrOnlyAWSClusterFlagSet = "cli.only_aws_cluster_flag_set"
ErrMissingAWSCredentials = "cli.missing_aws_credentials"
ErrCredentialsInClusterConfig = "cli.credentials_in_cluster_config"
ErrClusterUp = "cli.cluster_up"
Expand Down
34 changes: 34 additions & 0 deletions cli/cmd/lib_cli_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,40 @@ func setDefaultEnv(envName string) error {
return nil
}

func renameEnv(oldEnvName string, newEnvName string) error {
cliConfig, err := readCLIConfig()
if err != nil {
return err
}

renamedEnv := false

for _, env := range cliConfig.Environments {
if env.Name == newEnvName {
return cliconfig.ErrorEnvironmentAlreadyConfigured(newEnvName)
}

if env.Name == oldEnvName {
env.Name = newEnvName
renamedEnv = true
}
}

if !renamedEnv {
return cliconfig.ErrorEnvironmentNotConfigured(oldEnvName)
}

if cliConfig.DefaultEnvironment != nil && *cliConfig.DefaultEnvironment == oldEnvName {
cliConfig.DefaultEnvironment = &newEnvName
}

if err := writeCLIConfig(cliConfig); err != nil {
return err
}

return nil
}

func readTelemetryConfig() (bool, error) {
cliConfig, err := readCLIConfig()
if err != nil {
Expand Down
14 changes: 11 additions & 3 deletions cli/types/cliconfig/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,22 @@ import (
)

const (
ErrEnvironmentNotConfigured = "cliconfig.environment_not_configured"
ErrDuplicateEnvironmentNames = "cliconfig.duplicate_environment_names"
ErrEnvironmentNotConfigured = "cliconfig.environment_not_configured"
ErrEnvironmentAlreadyConfigured = "cliconfig.environment_already_configured"
ErrDuplicateEnvironmentNames = "cliconfig.duplicate_environment_names"
)

func ErrorEnvironmentNotConfigured(envName string) error {
return errors.WithStack(&errors.Error{
Kind: ErrEnvironmentNotConfigured,
Message: fmt.Sprintf("%s environment is not configured", envName),
Message: fmt.Sprintf("there is no environment named %s", envName),
})
}

func ErrorEnvironmentAlreadyConfigured(envName string) error {
return errors.WithStack(&errors.Error{
Kind: ErrEnvironmentAlreadyConfigured,
Message: fmt.Sprintf("there is already an environment named %s", envName),
})
}

Expand Down
1 change: 1 addition & 0 deletions dev/generate_cli_md.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ commands=(
"env configure"
"env list"
"env default"
"env rename"
"env delete"
"version"
"completion"
Expand Down
14 changes: 13 additions & 1 deletion docs/clients/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ Usage:
cortex cluster up CLUSTER_CONFIG_FILE [flags]

Flags:
-e, --configure-env string name of environment to configure (default "aws")
-e, --configure-env string name of environment to configure (default: the name of your cluster)
-y, --yes skip prompts
-h, --help help for up
```
Expand Down Expand Up @@ -225,6 +225,18 @@ Flags:
-h, --help help for default
```

## env rename

```text
rename an environment

Usage:
cortex env rename EXISTING_NAME NEW_NAME [flags]

Flags:
-h, --help help for rename
```

## env delete

```text
Expand Down
4 changes: 2 additions & 2 deletions docs/clusters/management/environments.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Environments

When you create a cluster with `cortex cluster up`, an environment named `aws` is automatically created to point to your cluster and is configured to be the default environment. You can name the environment something else via the `--configure-env` flag, e.g. `cortex cluster up --configure-env prod`. You can also use the `--configure-env` flag with `cortex cluster info` to create / update the specified environment.
When you create a cluster with `cortex cluster up`, an environment with the same name as your cluster is automatically created to point to your cluster and is configured to be the default environment. You can name the environment something else via the `--configure-env` flag, e.g. `cortex cluster up --configure-env prod`. You can also use the `--configure-env` flag with `cortex cluster info` to create / update the specified environment.

You can list your environments with `cortex env list`, change the default environment with `cortex env default`, delete an environment with `cortex env delete`, and create/update an environment with `cortex env configure`.
You can list your environments with `cortex env list`, change the default environment with `cortex env default`, rename an environment with `cortex env rename`, delete an environment with `cortex env delete`, and create/update an environment with `cortex env configure`.

## Multiple clusters

Expand Down
5 changes: 3 additions & 2 deletions docs/clusters/management/update.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ cortex cluster up cluster.yaml

In production environments, you can upgrade your cluster without downtime if you have a backend service or DNS in front of your Cortex cluster:

1. Spin up a new cluster. For example: `cortex cluster up new-cluster.yaml --configure-env new` (this will create a CLI environment named `new` for accessing the new cluster).
1. Re-deploy your APIs in your new cluster. For example, if the name of your CLI environment for your existing cluster is `previous`, you can use `cortex get --env previous` to list all running APIs in your cluster, and re-deploy them in the new cluster by changing directories to each API's project folder and running `cortex deploy --env new`. Alternatively, you can run `cortex cluster export --name <previous_cluster_name> --region <region>` to export all of your APIs (including configuration and application code), change directories into each API/ID subfolder that was exported, and run `cortex deploy --env new`.
1. Spin up a new cluster. For example: `cortex cluster up new-cluster.yaml --configure-env cortex2` (this will create a CLI environment named `cortex2` for accessing the new cluster).
1. Re-deploy your APIs in your new cluster. For example, if the name of your CLI environment for your existing cluster is `cortex`, you can use `cortex get --env cortex` to list all running APIs in your cluster, and re-deploy them in the new cluster by changing directories to each API's project folder and running `cortex deploy --env cortex2`. Alternatively, you can run `cortex cluster export --name <previous_cluster_name> --region <region>` to export all of your APIs (including configuration and application code), change directories into each API/ID subfolder that was exported, and run `cortex deploy --env cortex2`.
1. Route requests to your new cluster.
* If you are using a custom domain: update the A record in your Route 53 hosted zone to point to your new cluster's API load balancer.
* If you have a backend service which makes requests to Cortex: update your backend service to make requests to the new cluster's endpoints.
* If you have a self-managed API Gateway in front of your Cortex cluster: update the routes to use new cluster's endpoints.
1. Spin down your previous cluster. If you updated DNS settings, wait 24-48 hours before spinning down your previous cluster to allow the DNS cache to be flushed.
1. You may now rename your new CLI environment name if you'd like (e.g. to rename it back to "cortex": `cortex env rename cortex2 cortex`)
2 changes: 1 addition & 1 deletion docs/workloads/batch/example.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ cortex get image-classifier
import cortex
import requests

cx = cortex.client("aws")
cx = cortex.client("cortex")
batch_endpoint = cx.get_api("image-classifier")["endpoint"]

dest_s3_dir = # specify S3 directory for the results, e.g. "s3://my-bucket/dir" (make sure your cluster has access to this bucket)
Expand Down
2 changes: 1 addition & 1 deletion docs/workloads/dependencies/example.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ api_spec = {
}
}

cx = cortex.client("aws")
cx = cortex.client("cortex")
cx.deploy(api_spec, project_dir=".")
```

Expand Down
8 changes: 4 additions & 4 deletions docs/workloads/realtime/metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ response code counts (summed over the past 2 weeks) for your APIs:
```bash
cortex get

env api status up-to-date requested last update avg request 2XX
aws iris-classifier live 1 1 17m 24ms 1223
aws text-generator live 1 1 8m 180ms 433
aws image-classifier-resnet50 live 2 2 1h 32ms 1121126
env api status up-to-date requested last update avg request 2XX
cortex iris-classifier live 1 1 17m 24ms 1223
cortex text-generator live 1 1 8m 180ms 433
cortex image-classifier-resnet50 live 2 2 1h 32ms 1121126
```

The `cortex get API_NAME` command also provides a link to a Grafana dashboard:
Expand Down
2 changes: 1 addition & 1 deletion docs/workloads/realtime/multi-model/example.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ requirements = ["tensorflow", "transformers", "wget", "fasttext"]

api_spec = {"name": "multi-model", "kind": "RealtimeAPI"}

cx = cortex.client("aws")
cx = cortex.client("cortex")
cx.deploy_realtime_api(api_spec, handler=Handler, requirements=requirements)
```

Expand Down
2 changes: 1 addition & 1 deletion docs/workloads/realtime/traffic-splitter/example.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ api_spec_gpu = {
},
}

cx = cortex.client("aws")
cx = cortex.client("cortex")
cx.deploy_realtime_api(api_spec_cpu, handler=Handler, requirements=requirements)
cx.deploy_realtime_api(api_spec_gpu, handler=Handler, requirements=requirements)
```
Expand Down
2 changes: 1 addition & 1 deletion docs/workloads/task/example.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ Or, using Python `requests`:
import cortex
import requests

cx = cortex.client("aws") # "aws" is the name of the Cortex environment used in this example
cx = cortex.client("cortex") # "cortex" is the name of the Cortex environment used in this example
task_endpoint = cx.get_api("train-iris")["endpoint"]

dest_s3_dir = # S3 directory where the model will be uploaded, e.g. "s3://my-bucket/dir"
Expand Down
Loading