diff --git a/cli/cmd/cluster.go b/cli/cmd/cluster.go index 8b6353c1f1..1135007cf0 100644 --- a/cli/cmd/cluster.go +++ b/cli/cmd/cluster.go @@ -218,27 +218,11 @@ var _clusterUpCmd = &cobra.Command{ exit.Error(err) } - if clusterConfig.APIGatewaySetting == clusterconfig.PublicAPIGatewaySetting { - err = createOrReplaceAPIGateway(awsClient, clusterConfig.ClusterName, clusterConfig.Tags) - if err != nil { - exit.Error(err) - } - } - out, exitCode, err := runManagerWithClusterConfig("/root/install.sh", clusterConfig, awsCreds, nil, nil) if err != nil { - if clusterConfig.APIGatewaySetting == clusterconfig.PublicAPIGatewaySetting { - awsClient.DeleteAPIGatewayByTag(clusterconfig.ClusterNameTag, clusterConfig.ClusterName) // best effort deletion - awsClient.DeleteVPCLinkByTag(clusterconfig.ClusterNameTag, clusterConfig.ClusterName) // best effort deletion - } exit.Error(err) } if exitCode == nil || *exitCode != 0 { - if clusterConfig.APIGatewaySetting == clusterconfig.PublicAPIGatewaySetting { - awsClient.DeleteAPIGatewayByTag(clusterconfig.ClusterNameTag, clusterConfig.ClusterName) // best effort deletion - awsClient.DeleteVPCLinkByTag(clusterconfig.ClusterNameTag, clusterConfig.ClusterName) // best effort deletion - } - eksCluster, err := awsClient.EKSClusterOrNil(clusterConfig.ClusterName) if err != nil { helpStr := "\ndebugging tips (may or may not apply to this error):" @@ -512,27 +496,6 @@ var _clusterDownCmd = &cobra.Command{ prompt.YesOrExit(fmt.Sprintf("your cluster named \"%s\" in %s will be spun down and all apis will be deleted, are you sure you want to continue?", *accessConfig.ClusterName, *accessConfig.Region), "", "") } - fmt.Print("○ deleting api gateway ") - deletedAPIGateway, errAPIGateway := awsClient.DeleteAPIGatewayByTag(clusterconfig.ClusterNameTag, *accessConfig.ClusterName) - _, errVPCLink := awsClient.DeleteVPCLinkByTag(clusterconfig.ClusterNameTag, *accessConfig.ClusterName) - if errAPIGateway != nil { - fmt.Printf("\n\nunable to delete cortex's api gateway (see error below); if it still exists after the cluster has been deleted, please delete it via the api gateway console: https://%s.console.aws.amazon.com/apigateway/main/apis\n", *accessConfig.Region) - errors.PrintError(errAPIGateway) - } - if errVPCLink != nil { - fmt.Printf("\n\nunable to delete cortex's vpc link (see error below); if it still exists after the cluster has been deleted, please delete it via the api gateway console: https://%s.console.aws.amazon.com/apigateway/main/vpc-links\n", *accessConfig.Region) - errors.PrintError(errVPCLink) - } - if errAPIGateway == nil && errVPCLink == nil { - if deletedAPIGateway != nil { - fmt.Println("✓") - } else { - fmt.Println("(n/a)") - } - } else { - fmt.Println() - } - fmt.Print("○ deleting dashboard ") err = awsClient.DeleteDashboard(*accessConfig.ClusterName) if err != nil { @@ -1107,32 +1070,6 @@ func createOrClearDashboard(awsClient *aws.Client, dashboardName string) error { return nil } -// createOrReplaceAPIGateway creates an API gateway for the cluster (or clears an existing one if it already exists) -func createOrReplaceAPIGateway(awsClient *aws.Client, clusterName string, tags map[string]string) error { - fmt.Print("○ creating api gateway: ", clusterName) - - _, err := awsClient.DeleteVPCLinkByTag(clusterconfig.ClusterNameTag, clusterName) - if err != nil { - fmt.Print("\n\n") - return errors.Append(err, fmt.Sprintf("\n\nunable to delete existing vpc link with tag %s=%s; please delete it via the api gateway console: https://%s.console.aws.amazon.com/apigateway/main/vpc-links", clusterconfig.ClusterNameTag, clusterName, awsClient.Region)) - } - - _, err = awsClient.DeleteAPIGatewayByTag(clusterconfig.ClusterNameTag, clusterName) - if err != nil { - fmt.Print("\n\n") - return errors.Append(err, fmt.Sprintf("\n\nunable to delete existing api gateway with tag %s=%s; please delete it via the api gateway console: https://%s.console.aws.amazon.com/apigateway/main/apis", clusterconfig.ClusterNameTag, clusterName, awsClient.Region)) - } - - _, err = awsClient.CreateAPIGateway(clusterName, tags) - if err != nil { - fmt.Print("\n\n") - return err - } - - fmt.Println(" ✓") - return nil -} - // Will return error if load balancer can't be found func getAWSOperatorLoadBalancer(clusterName string, awsClient *aws.Client) (*elbv2.LoadBalancer, error) { loadBalancer, err := awsClient.FindLoadBalancer(map[string]string{ diff --git a/cli/cmd/lib_cluster_config_aws.go b/cli/cmd/lib_cluster_config_aws.go index c7fe892de1..995d6d5d60 100644 --- a/cli/cmd/lib_cluster_config_aws.go +++ b/cli/cmd/lib_cluster_config_aws.go @@ -333,11 +333,6 @@ func setConfigFieldsFromCached(userClusterConfig *clusterconfig.Config, cachedCl } userClusterConfig.OperatorLoadBalancerScheme = cachedClusterConfig.OperatorLoadBalancerScheme - if userClusterConfig.APIGatewaySetting != cachedClusterConfig.APIGatewaySetting { - return clusterconfig.ErrorConfigCannotBeChangedOnUpdate(clusterconfig.APIGatewaySettingKey, cachedClusterConfig.APIGatewaySetting) - } - userClusterConfig.APIGatewaySetting = cachedClusterConfig.APIGatewaySetting - if s.Obj(cachedClusterConfig.VPCCIDR) != s.Obj(userClusterConfig.VPCCIDR) { return clusterconfig.ErrorConfigCannotBeChangedOnUpdate(clusterconfig.VPCCIDRKey, cachedClusterConfig.VPCCIDR) } @@ -404,10 +399,7 @@ func setConfigFieldsFromCached(userClusterConfig *clusterconfig.Config, cachedCl userClusterConfig.Spot = cachedClusterConfig.Spot if userClusterConfig.Spot != nil && *userClusterConfig.Spot { - err := userClusterConfig.FillEmptySpotFields(awsClient) - if err != nil { - return err - } + userClusterConfig.FillEmptySpotFields() } if userClusterConfig.SpotConfig != nil && s.Obj(userClusterConfig.SpotConfig) != s.Obj(cachedClusterConfig.SpotConfig) { @@ -541,10 +533,6 @@ func confirmInstallClusterConfig(clusterConfig *clusterconfig.Config, awsCreds A } fmt.Printf("cortex will also create an s3 bucket (%s) and a cloudwatch log group (%s)%s\n\n", clusterConfig.Bucket, clusterConfig.ClusterName, privateSubnetMsg) - if clusterConfig.APIGatewaySetting == clusterconfig.NoneAPIGatewaySetting { - fmt.Print(fmt.Sprintf("warning: you've disabled API Gateway cluster-wide, so APIs will not be able to create API Gateway endpoints (they will still be reachable via the API load balancer; see https://docs.cortex.dev/v/%s/ for more information)\n\n", consts.CortexVersionMinor)) - } - if clusterConfig.OperatorLoadBalancerScheme == clusterconfig.InternalLoadBalancerScheme { fmt.Print(fmt.Sprintf("warning: you've configured the operator load balancer to be internal; you must configure VPC Peering to connect your CLI to your cluster operator (see https://docs.cortex.dev/v/%s/)\n\n", consts.CortexVersionMinor)) } @@ -618,16 +606,13 @@ func clusterConfigConfirmationStr(clusterConfig clusterconfig.Config, awsCreds A if clusterConfig.OperatorLoadBalancerScheme != defaultConfig.OperatorLoadBalancerScheme { items.Add(clusterconfig.OperatorLoadBalancerSchemeUserKey, clusterConfig.OperatorLoadBalancerScheme) } - if clusterConfig.APIGatewaySetting != defaultConfig.APIGatewaySetting { - items.Add(clusterconfig.APIGatewaySettingUserKey, clusterConfig.APIGatewaySetting) - } if clusterConfig.Spot != nil && *clusterConfig.Spot != *defaultConfig.Spot { items.Add(clusterconfig.SpotUserKey, s.YesNo(clusterConfig.Spot != nil && *clusterConfig.Spot)) if clusterConfig.SpotConfig != nil { defaultSpotConfig := clusterconfig.SpotConfig{} - clusterconfig.AutoGenerateSpotConfig(awsClient, &defaultSpotConfig, *clusterConfig.Region, *clusterConfig.InstanceType) + clusterconfig.AutoGenerateSpotConfig(&defaultSpotConfig, *clusterConfig.Region, *clusterConfig.InstanceType) if !strset.New(clusterConfig.SpotConfig.InstanceDistribution...).IsEqual(strset.New(defaultSpotConfig.InstanceDistribution...)) { items.Add(clusterconfig.InstanceDistributionUserKey, clusterConfig.SpotConfig.InstanceDistribution) diff --git a/dev/find_missing_docs_links.py b/dev/find_missing_docs_links.py index c488103f0d..2972687126 100644 --- a/dev/find_missing_docs_links.py +++ b/dev/find_missing_docs_links.py @@ -56,7 +56,7 @@ def get_links_from_file(file): with open(file) as f: for line in f: for link in re.findall(r"\]\((.+?)\)", line): - if link.startswith("http"): + if is_external_link(link): link_infos.append((file, n, link, None, None)) continue if link.startswith("#"): @@ -87,7 +87,7 @@ def check_links(link_infos): for link_info in link_infos: src_file, line_num, original_link_text, target_file, header = link_info - if original_link_text.startswith("http"): + if is_external_link(original_link_text): http_link_infos.append(link_info) continue @@ -174,5 +174,9 @@ def err_str(src_file, line_num, original_link_text, reason): return f"{clean_src_file}:{line_num}: {original_link_text} ({reason})" +def is_external_link(link): + return link.startswith("http://") or link.startswith("https://") + + if __name__ == "__main__": main() diff --git a/dev/format.sh b/dev/format.sh index d8bd71dbee..e40988b8e6 100755 --- a/dev/format.sh +++ b/dev/format.sh @@ -68,7 +68,7 @@ xargs -0 -L1 bash -c 'test "$(tail -c 1 "$0")" && echo "" >> "$0"' || true) ! -path "./.git/*" \ ! -name ".*" \ -print0 | \ -xargs -0 -L1 bash -c 'test "$(tail -c 2 "$0")" || (trimmed=$(printf "%s" "$(< $0)") && echo "$trimmed" > "$0")' || true) +xargs -0 -L1 bash -c 'test "$(tail -c 2 "$0")" || [ ! -s "$0" ] || (trimmed=$(printf "%s" "$(< $0)") && echo "$trimmed" > "$0")' || true) # Remove new lines at beginning of file (cd "$ROOT" && find . -type f \ @@ -77,4 +77,4 @@ xargs -0 -L1 bash -c 'test "$(tail -c 2 "$0")" || (trimmed=$(printf "%s" "$(< $0 ! -path "./.git/*" \ ! -name ".*" \ -print0 | \ -xargs -0 -L1 bash -c 'test "$(head -c 1 "$0")" || (trimmed=$(sed '"'"'/./,$!d'"'"' "$0") && echo "$trimmed" > "$0")' || true) +xargs -0 -L1 bash -c 'test "$(head -c 1 "$0")" || [ ! -s "$0" ] || (trimmed=$(sed '"'"'/./,$!d'"'"' "$0") && echo "$trimmed" > "$0")' || true) diff --git a/docs/clusters/aws/custom-domain.md b/docs/clusters/aws/custom-domain.md deleted file mode 100644 index 3c99c6b479..0000000000 --- a/docs/clusters/aws/custom-domain.md +++ /dev/null @@ -1,220 +0,0 @@ -# Set up a custom domain - -You can use any custom domain (that you own) for your prediction endpoints. For example, you can make your API accessible via `api.example.com/text-generator`. This guide will demonstrate how to create a dedicated subdomain in AWS Route 53 and use an SSL certificate provisioned by AWS Certificate Manager (ACM). - -There are two methods for achieving this, and which method to use depends on whether you're using API Gateway or not (without API Gateway, requests are sent directly to the API load balancer instead). API Gateway is enabled by default. - -The first set of steps are the same whether or not you're using API Gateway. If you aren't using API gateway, follow this guide before creating your Cortex cluster. - -_note: you must own a domain and be able to modify its DNS records to complete this guide._ - -## Generate a certificate for your domain - -### Step 1 - -Decide on a subdomain that you want to dedicate to Cortex APIs. For example if your domain is `example.com`, a valid subdomain can be `api.example.com`. - -This guide will use `cortexlabs.dev` as the example domain and `api.cortexlabs.dev` as the subdomain. - -### Step 2 - -We will set up a hosted zone on Route 53 to manage the DNS records for the subdomain. Go to the [Route 53 console](https://console.aws.amazon.com/route53/home) and click "Hosted Zones". - -![step 2](https://user-images.githubusercontent.com/4365343/82210754-a6b07d00-98dd-11ea-9cec-9f6b07282aa8.png) - -### Step 3 - -Click "Create Hosted Zone" and then enter your subdomain as the domain name for your hosted zone and click "Create". - -![step 3](https://user-images.githubusercontent.com/4365343/82211091-4968fb80-98de-11ea-8ec4-8d26d1aea77a.png) - -### Step 4 - -Take note of the values in the NS record. - -![step 4](https://user-images.githubusercontent.com/4365343/82211656-386cba00-98df-11ea-8c86-4961082b5f49.png) - -### Step 5 - -Navigate to your root DNS service provider (e.g. Google Domains, AWS Route 53, Go Daddy). Your root DNS service provider is typically the registrar where you purchased your domain (unless you have transferred DNS management elsewhere). The procedure for adding DNS records may vary based on your service provider. - -We are going to add an NS (name server) record that specifies that any traffic to your subdomain should use the name servers of your hosted zone in Route 53 for DNS resolution. - -`cortexlabs.dev` is managed by Google Domains. The image below is a screenshot for adding a DNS record in Google Domains (your UI may differ based on your DNS service provider). - -![step 5](https://user-images.githubusercontent.com/4365343/82211959-bcbf3d00-98df-11ea-834d-692b3bcf9332.png) - -### Step 6 - -We are now going to create an SSL certificate for your subdomain. Go to the [ACM console](https://us-west-2.console.aws.amazon.com/acm/home) and click "Get Started" under the "Provision certificates" section. - -![step 6](https://user-images.githubusercontent.com/4365343/82202340-c04ac800-98cf-11ea-9472-89dd6d67eb0d.png) - -### Step 7 - -Select "Request a public certificate" and then "Request a certificate". - -![step 7](https://user-images.githubusercontent.com/4365343/82202654-3e0ed380-98d0-11ea-8c57-025f0b69c54f.png) - -### Step 8 - -Enter your subdomain and then click "Next". - -![step 8](https://user-images.githubusercontent.com/4365343/82224652-1cbedf00-98f2-11ea-912b-466cee2f6e25.png) - -### Step 9 - -Select "DNS validation" and then click "Next". - -![step 9](https://user-images.githubusercontent.com/4365343/82205311-66003600-98d4-11ea-90e3-da7e8b0b2b9c.png) - -### Step 10 - -Add tags for searchability (optional) then click "Review". - -![step 10](https://user-images.githubusercontent.com/4365343/82206485-52ee6580-98d6-11ea-95a9-1d0ebafc178a.png) - -### Step 11 - -Click "Confirm and request". - -![step 11](https://user-images.githubusercontent.com/4365343/82206602-84ffc780-98d6-11ea-9f2f-ce383404ec67.png) - -### Step 12 - -Click "Create record in Route 53". A popup will appear indicating that a Record is going to be added to Route 53. Click "Create" to automatically add the DNS record to your subdomain's hosted zone. Then click "Continue". - -![step 12](https://user-images.githubusercontent.com/4365343/82223539-c8ffc600-98f0-11ea-93a2-044aa0c9670d.png) - -### Step 13 - -Wait for the Certificate Status to be "issued". This might take a few minutes. - -![step 13](https://user-images.githubusercontent.com/4365343/82209663-a616e700-98db-11ea-95cb-c6efedadb942.png) - -### Step 14 - -Take note of the certificate's ARN. The certificate is ineligible for renewal because it is currently not being used. It will be eligible for renewal after it is used in Cortex. - -![step 14](https://user-images.githubusercontent.com/4365343/82222684-9e613d80-98ef-11ea-98c0-5a20b457f062.png) - -If you are using API Gateway, continue to the next section to [configure API Gateway](#configure-api-gateway). Otherwise (i.e. clients connect directly to your API load balancer) skip to [configure the API load balancer](#configure-the-api-load-balancer). - -## Configure API Gateway - -_If you aren't using API Gateway (i.e. clients connect directly to your API load balancer), skip this section and [configure the API load balancer](#configure-the-api-load-balancer) instead._ - -### Step 1 - -Navigate to the [API Gateway console](https://us-west-2.console.aws.amazon.com/apigateway) (make sure that the region in top right matches your Cortex region). Click "Custom domain names" and then click "Create". - -![step 1](https://user-images.githubusercontent.com/808475/84082403-a105fe80-a994-11ea-8015-0df9aeef07b1.png) - -### Step 2 - -Type in the name of your domain and choose the Regional endpoint type, TLS 1.2, and the ACM certificate that you created earlier. Then click "Create". - -![step 2](https://user-images.githubusercontent.com/808475/84082448-b8dd8280-a994-11ea-9ef7-6bb33b3a403b.png) - -### Step 3 - -This should take you back to the custom domains page, and you should see your new custom domain. Make sure your API is selected. Take note of the API Gateway domain name (we will use this later), and click "Configure API mappings". - -![step 3](https://user-images.githubusercontent.com/808475/84084960-62267780-a999-11ea-8a6b-4be9cfca2a9c.png) - -### Step 4 - -Click "Add new mapping". - -![step 4](https://user-images.githubusercontent.com/808475/84082516-d7dc1480-a994-11ea-9cae-d4fb1ac1e767.png) - -### Step 5 - -Select your API Gateway, choose the "$default" stage, and lave "Path" blank. Click Save. - -![step 5](https://user-images.githubusercontent.com/808475/84082553-e5919a00-a994-11ea-9bc3-cf5f9eb869eb.png) - -### Step 6 - -Go back to the [Route 53 console](https://console.aws.amazon.com/route53/home#hosted-zones:) and select the hosted zone you created earlier. Click "Create Record Set", and add an Alias record that routes traffic to your Cortex cluster's API Gateway (the target name should match the "API Gateway domain name" show in step 3). Leave "Name" blank. - -![step 6](https://user-images.githubusercontent.com/808475/84083366-54232780-a996-11ea-9bc6-2c9945a160d4.png) - -Proceed to [using your new endpoint](#using-your-new-endpoint). - -## Configure the API load balancer - -_If you are using API Gateway, this section does not apply; follow the instructions above to [configure API Gateway](#configure-api-gateway) instead._ - -### Step 1 - -Add the following field to your cluster configuration: - -```yaml -# cluster.yaml - -... - -ssl_certificate_arn: -``` - -and then create a Cortex cluster. - -```bash -$ cortex cluster up --config cluster.yaml -``` - -### Step 2 - -After your cluster has been created, navigate to your [EC2 Load Balancer console](https://us-west-2.console.aws.amazon.com/ec2/v2/home#LoadBalancers:sort=loadBalancerName) and locate the Cortex API load balancer. You can determine which is the API load balancer by inspecting the `kubernetes.io/service-name` tag. - -Take note of the load balancer's name. - -![step 2](https://user-images.githubusercontent.com/808475/80142777-961c1980-8560-11ea-9202-40964dbff5e9.png) - -### Step 3 - -Go back to the [Route 53 console](https://console.aws.amazon.com/route53/home#hosted-zones:) and select the hosted zone you created earlier. Click "Create Record Set", and add an Alias record that routes traffic to your Cortex cluster's API load balancer (leave "Name" blank). - -![step 3](https://user-images.githubusercontent.com/808475/84083422-6ac97e80-a996-11ea-9679-be37268a2133.png) - -## Using your new endpoint - -Wait a few minutes to allow the DNS changes to propagate. You may now use your subdomain in place of your API load balancer endpoint in your client. For example, this curl request: - -```bash -curl http://a5044e34a352d44b0945adcd455c7fa3-32fa161d3e5bcbf9.elb.us-west-2.amazonaws.com/text-generator -X POST -H "Content-Type: application/json" -d @sample.json -``` - -Would become: - -```bash -# replace loadbalancer url with your subdomain -curl https://api.cortexlabs.dev/text-generator -X POST -H "Content-Type: application/json" -d @sample.json -``` - -## Debugging connectivity issues - -You could run into connectivity issues if you make a request to your API without waiting long enough for your DNS records to propagate after creating them (it usually takes 5-10 mintues). If you are updating existing DNS records, it could take anywhere from a few minutes to 48 hours for the DNS cache to expire (until then, your previous DNS configuration will be used). - -To test connectivity, try the following steps: - -1. Deploy any api (e.g. examples/pytorch/iris-classifier). -1. Make an HTTPS GET request to the your api e.g. `curl https://api.cortexlabs.dev/iris-classifier` or enter the url in your browser. -1. If you run into an error such as `curl: (6) Could not resolve host: api.cortexlabs.dev` wait a few minutes and make the HTTPS Get request from another device that hasn't made a request to that url in a while. A successful request looks like this: - -```text -{"message":"make a prediction by sending a post request to this endpoint with a json payload",...} -``` - -## Cleanup - -Spin down your Cortex cluster. - -Delete the hosted zone for your subdomain in the [Route 53 console](https://console.aws.amazon.com/route53/home#hosted-zones:): - -![delete hosted zone](https://user-images.githubusercontent.com/4365343/82228729-81306d00-98f7-11ea-8570-e9de15f5267f.png) - -Delete your certificate from the [ACM console](https://us-west-2.console.aws.amazon.com/acm/home): - -![delete certificate](https://user-images.githubusercontent.com/4365343/82228835-a624e000-98f7-11ea-92e2-cb4fb0f591e2.png) diff --git a/docs/clusters/aws/install.md b/docs/clusters/aws/install.md index 8885807835..f5d428503a 100644 --- a/docs/clusters/aws/install.md +++ b/docs/clusters/aws/install.md @@ -62,16 +62,13 @@ api_load_balancer_scheme: internet-facing # note: if using "internal", you must configure VPC Peering to connect your CLI to your cluster operator operator_load_balancer_scheme: internet-facing -# API Gateway [public (API Gateway will be used by default, can be disabled per API) | none (API Gateway will be disabled for all APIs)] -api_gateway: public - # additional tags to assign to AWS resources (all resources will automatically be tagged with cortex.dev/cluster-name: ) tags: # : map of key/value pairs # enable spot instances spot: false -# SSL certificate ARN (only necessary when using a custom domain without API Gateway) +# SSL certificate ARN (only necessary when using a custom domain) ssl_certificate_arn: # primary CIDR block for the cluster's VPC diff --git a/docs/clusters/aws/networking.md b/docs/clusters/aws/networking.md deleted file mode 100644 index 1f694d1dfd..0000000000 --- a/docs/clusters/aws/networking.md +++ /dev/null @@ -1,118 +0,0 @@ -# Networking - -![api architecture diagram](https://user-images.githubusercontent.com/808475/84695323-8507dd00-aeff-11ea-8b32-5a55cef76c79.png) - -APIs are deployed with a public API Gateway by default (the API Gateway forwards requests to the API load balancer). Each API can be independently configured to not create the API Gateway endpoint by setting `api_gateway: none` in the `networking` field of the Realtime API configuration and Batch API configuration. If the API Gateway endpoint is not created, your API can still be accessed via the API load balancer; `cortex get API_NAME` will show the load balancer endpoint if API Gateway is disabled. API Gateway is enabled by default, and is generally recommended unless it doesn't support your use case due to limitations such as the 29 second request timeout, or if you are keeping your APIs private to your VPC. See below for common configurations. To disable API Gateway cluster-wide (thereby enforcing that all APIs cannot create API Gateway endpoints), set `api_gateway: none` in your [cluster configuration](install.md) file (before creating your cluster). - -By default, the API load balancer is public. You can configure your API load balancer to be private by setting `api_load_balancer_scheme: internal` in your [cluster configuration](install.md) file (before creating your cluster). This will force external traffic to go through your API Gateway endpoint, or if you disabled API Gateway for your API, it will make your API only accessible through VPC Peering. Note that if API Gateway is used, endpoints will be public regardless of `api_load_balancer_scheme`. See below for common configurations. - -The API Gateway that Cortex creates in AWS is the "HTTP" type. If you need to use AWS's "REST" API Gateway, see [here](rest-api-gateway.md). - -## Common API networking configurations - -### Public https endpoint (with API Gateway) - -This is the most common configuration for public APIs. [Custom domains](custom-domain.md) can be used with this setup, but are not required. - -```yaml -# cluster.yaml - -api_load_balancer_scheme: internal -``` - -```yaml -# cortex.yaml - -- name: my-api - ... - networking: - api_gateway: public # this is the default, so can be omitted -``` - -### Private https endpoint - -You can configure your API to be private. If you do this, you must use [VPC Peering](vpc-peering.md) to connect to your APIs. - -The SSL certificate on the API load balancer is autogenerated during installation using `localhost` as the Common Name (CN). Therefore, clients will need to skip certificate verification when making HTTPS requests (e.g. `curl -k`). Alternatively, you can set up a [custom domain](custom-domain.md), which will use ACM to provision SSL certs for your domain. - -```yaml -# cluster.yaml - -api_load_balancer_scheme: internal # this is the default, so can be omitted - -# use this to configure a custom domain -# if you don't use a custom domain, clients will need to skip certificate verification when making HTTPS requests (e.g. `curl -k`) -ssl_certificate_arn: arn:aws:acm:us-west-2:***:certificate/*** -``` - -```yaml -# cortex.yaml - -- name: my-api - ... - networking: - api_gateway: none -``` - -### Private http endpoint - -You can configure your API to be private. If you do this, you must use [VPC Peering](vpc-peering.md) to connect to your APIs. - -```yaml -# cluster.yaml - -api_load_balancer_scheme: internal # this is the default, so can be omitted -``` - -```yaml -# cortex.yaml - -- name: my-api - ... - networking: - api_gateway: none -``` - -### Public https endpoint (without API Gateway) - -API gateway is generally recommended for public https APIs, but there may be a situation where you don't wish to use it (e.g. requests take longer than 29 seconds to complete, which is the max for API Gateway). In this case, clients can connect directly to the API load balancer. - -The SSL certificate on the API load balancer is autogenerated during installation using `localhost` as the Common Name (CN). Therefore, clients will need to skip certificate verification when making HTTPS requests (e.g. `curl -k`). Alternatively, you can set up a [custom domain](custom-domain.md), which will use ACM to provision SSL certs for your domain. - -```yaml -# cluster.yaml - -api_load_balancer_scheme: internet-facing # this is the default, so can be omitted - -# use this to configure a custom domain -# if you don't use a custom domain, clients will need to skip certificate verification when making HTTPS requests (e.g. `curl -k`) -ssl_certificate_arn: arn:aws:acm:us-west-2:***:certificate/*** -``` - -```yaml -# cortex.yaml - -- name: my-api - ... - networking: - api_gateway: none -``` - -### Public http endpoint - -If you don't wish to use https for your public API, you can simply disable API gateway (your API will be accessed directly via the API load balancer): - -```yaml -# cluster.yaml - -api_load_balancer_scheme: internet-facing # this is the default, so can be omitted -``` - -```yaml -# cortex.yaml - -- name: my-api - ... - networking: - api_gateway: none -``` diff --git a/docs/clusters/aws/networking/custom-domain.md b/docs/clusters/aws/networking/custom-domain.md new file mode 100644 index 0000000000..8fd3ca9054 --- /dev/null +++ b/docs/clusters/aws/networking/custom-domain.md @@ -0,0 +1,136 @@ +# Custom domain + +You can use any custom domain (that you own) for your prediction endpoints. For example, you can make your API accessible via `api.example.com/text-generator`. This guide will demonstrate how to create a dedicated subdomain in AWS Route 53 and, if desired, configure your API load balancer to use an SSL certificate provisioned by AWS Certificate Manager. + +## Configure DNS + +Decide on a subdomain that you want to dedicate to Cortex APIs. For example if your domain is `example.com`, a valid subdomain can be `api.example.com`. This guide will use `cortexlabs.dev` as the example domain and `api.cortexlabs.dev` as the subdomain. + +We will set up a hosted zone on Route 53 to manage the DNS records for the subdomain. Go to the [Route 53 console](https://console.aws.amazon.com/route53/home) and click "Hosted Zones". + +![](https://user-images.githubusercontent.com/4365343/82210754-a6b07d00-98dd-11ea-9cec-9f6b07282aa8.png) + +Click "Create Hosted Zone" and then enter your subdomain as the domain name for your hosted zone and click "Create". + +![](https://user-images.githubusercontent.com/4365343/82211091-4968fb80-98de-11ea-8ec4-8d26d1aea77a.png) + +Take note of the values in the NS record. + +![](https://user-images.githubusercontent.com/4365343/82211656-386cba00-98df-11ea-8c86-4961082b5f49.png) + +Navigate to your root DNS service provider (e.g. Google Domains, AWS Route 53, Go Daddy). Your root DNS service provider is typically the registrar where you purchased your domain (unless you have transferred DNS management elsewhere). The procedure for adding DNS records may vary based on your service provider. + +We are going to add an NS (name server) record that specifies that any traffic to your subdomain should use the name servers of your hosted zone in Route 53 for DNS resolution. + +`cortexlabs.dev` is managed by Google Domains. The image below is a screenshot for adding a DNS record in Google Domains (your UI may differ based on your DNS service provider). + +![](https://user-images.githubusercontent.com/4365343/82211959-bcbf3d00-98df-11ea-834d-692b3bcf9332.png) + +## Generate an SSL certificate + +You can skip this section (and continue to [add the DNS record](#add-dns-record)) if you don't need an SSL certificate for your custom domain. If you don't use an SSL certificate, you will need to skip certificate verification when making HTTPS requests to your APIs (e.g. `curl -k https://***`), or make HTTP requests instead (e.g. `curl http://***`). + +To create an SSL certificate, go to the [ACM console](https://us-west-2.console.aws.amazon.com/acm/home) and click "Get Started" under the "Provision certificates" section. + +![](https://user-images.githubusercontent.com/4365343/82202340-c04ac800-98cf-11ea-9472-89dd6d67eb0d.png) + +Select "Request a public certificate" and then "Request a certificate". + +![](https://user-images.githubusercontent.com/4365343/82202654-3e0ed380-98d0-11ea-8c57-025f0b69c54f.png) + +Enter your subdomain and then click "Next". + +![](https://user-images.githubusercontent.com/4365343/82224652-1cbedf00-98f2-11ea-912b-466cee2f6e25.png) + +Select "DNS validation" and then click "Next". + +![](https://user-images.githubusercontent.com/4365343/82205311-66003600-98d4-11ea-90e3-da7e8b0b2b9c.png) + +Add tags for searchability (optional) then click "Review". + +![](https://user-images.githubusercontent.com/4365343/82206485-52ee6580-98d6-11ea-95a9-1d0ebafc178a.png) + +Click "Confirm and request". + +![](https://user-images.githubusercontent.com/4365343/82206602-84ffc780-98d6-11ea-9f2f-ce383404ec67.png) + +Click "Create record in Route 53". A popup will appear indicating that a Record is going to be added to Route 53. Click "Create" to automatically add the DNS record to your subdomain's hosted zone. Then click "Continue". + +![](https://user-images.githubusercontent.com/4365343/82223539-c8ffc600-98f0-11ea-93a2-044aa0c9670d.png) + +Wait for the Certificate Status to be "issued". This might take a few minutes. + +![](https://user-images.githubusercontent.com/4365343/82209663-a616e700-98db-11ea-95cb-c6efedadb942.png) + +Take note of the certificate's ARN. The certificate is ineligible for renewal because it is currently not being used. It will be eligible for renewal once it's used in Cortex. + +![](https://user-images.githubusercontent.com/4365343/82222684-9e613d80-98ef-11ea-98c0-5a20b457f062.png) + +Add the following field to your cluster configuration: + +```yaml +# cluster.yaml + +... + +ssl_certificate_arn: +``` + +Create a Cortex cluster: + +```bash +$ cortex cluster up --config cluster.yaml +``` + +## Add DNS record + +Navigate to your [EC2 Load Balancer console](https://us-west-2.console.aws.amazon.com/ec2/v2/home#LoadBalancers:sort=loadBalancerName) and locate the Cortex API load balancer. You can determine which is the API load balancer by inspecting the `kubernetes.io/service-name` tag. + +Take note of the load balancer's name. + +![](https://user-images.githubusercontent.com/808475/80142777-961c1980-8560-11ea-9202-40964dbff5e9.png) + +Go back to the [Route 53 console](https://console.aws.amazon.com/route53/home#hosted-zones:) and select the hosted zone you created earlier. Click "Create Record Set", and add an Alias record that routes traffic to your Cortex cluster's API load balancer (leave "Name" blank). + +![](https://user-images.githubusercontent.com/808475/84083422-6ac97e80-a996-11ea-9679-be37268a2133.png) + +## Use your new endpoint + +Wait a few minutes to allow the DNS changes to propagate. You may now use your subdomain in place of your API load balancer endpoint in your client. For example, this curl request: + +```bash +curl http://a5044e34a352d44b0945adcd455c7fa3-32fa161d3e5bcbf9.elb.us-west-2.amazonaws.com/text-generator -X POST -H "Content-Type: application/json" -d @sample.json +``` + +Would become: + +```bash +# add the `-k` flag or use http:// instead of https:// if you didn't configure an SSL certificate +curl https://api.cortexlabs.dev/text-generator -X POST -H "Content-Type: application/json" -d @sample.json +``` + +## Debugging connectivity issues + +You could run into connectivity issues if you make a request to your API without waiting long enough for your DNS records to propagate after creating them (it usually takes 5-10 mintues). If you are updating existing DNS records, it could take anywhere from a few minutes to 48 hours for the DNS cache to expire (until then, your previous DNS configuration will be used). + +To test connectivity, try the following steps: + +1. Deploy any api (e.g. examples/pytorch/iris-classifier). +1. Make a GET request to the your api (e.g. `curl https://api.cortexlabs.dev/iris-classifier` or paste the url into your browser). +1. If you run into an error such as `curl: (6) Could not resolve host: api.cortexlabs.dev` wait a few minutes and make the GET request from another device that hasn't made a request to that url in a while. A successful request looks like this: + +```text +{"message":"make a prediction by sending a post request to this endpoint with a json payload",...} +``` + +## Cleanup + +Spin down your Cortex cluster. + +Delete the hosted zone for your subdomain in the [Route 53 console](https://console.aws.amazon.com/route53/home#hosted-zones:): + +![](https://user-images.githubusercontent.com/4365343/82228729-81306d00-98f7-11ea-8570-e9de15f5267f.png) + +If you created an SSL certificate, delete it from the [ACM console](https://us-west-2.console.aws.amazon.com/acm/home): + +![](https://user-images.githubusercontent.com/4365343/82228835-a624e000-98f7-11ea-92e2-cb4fb0f591e2.png) diff --git a/docs/clusters/aws/networking/https.md b/docs/clusters/aws/networking/https.md new file mode 100644 index 0000000000..54cdf819a2 --- /dev/null +++ b/docs/clusters/aws/networking/https.md @@ -0,0 +1,152 @@ +# HTTPS (via API Gateway) + +If you would like to support HTTPS endpoints for your Cortex APIs, here are a few options: + +* Custom domain with an SSL certificate: See [here](custom-domain.md) for instructions. +* AWS API Gateway: This is the simplest approach if a custom domain is not required; continue reading this guide for instructions. + +Please note that one limitation of API Gateway is that there is a 30-second time limit for all requests. + +If your API load balancer is internet-facing (which is the default, or you set `api_load_balancer_scheme: internet-facing` in your cluster configuration file before creating your cluster), use the [first section](#internet-facing-load-balancer) of this guide. + +If your API load balancer is internal (i.e. you set `api_load_balancer_scheme: internal` in your cluster configuration file before creating your cluster), use the [second section](#internal-load-balancer) of this guide. + +## Internet-facing load balancer + +_This section applies if your API load balancer is internet-facing (which is the default, or you set `api_load_balancer_scheme: internet-facing` in your cluster configuration file before creating your cluster). If your API load balancer is internal, see the [internal load balancer](#internal-load-balancer) section below._ + +### Create an API Gateway + +Go to the [API Gateway console](https://console.aws.amazon.com/apigateway/home), select "REST API" under "Choose an API type", and click "Build". + +![](https://user-images.githubusercontent.com/808475/78293216-18269e80-74dd-11ea-9e68-86922c2cbc7c.png) + +Select "REST" and "New API", name your API (e.g. "cortex"), select either "Regional" or "Edge optimized" (depending on your preference), and click "Create API". + +![](https://user-images.githubusercontent.com/808475/78293434-66d43880-74dd-11ea-92d6-692158171a3f.png) + +Select "Actions" > "Create Resource": + +![](https://user-images.githubusercontent.com/808475/80154502-8b6b7f80-8574-11ea-9c78-7d9f277bf55b.png) + +Select "Configure as proxy resource" and "Enable API Gateway CORS", and click "Create Resource" + +![](https://user-images.githubusercontent.com/808475/80154565-ad650200-8574-11ea-8753-808cd35902e2.png) + +Select "HTTP Proxy" and set "Endpoint URL" to "http:///{proxy}". You can get your API load balancer endpoint via `cortex cluster info`; make sure to prepend `http://` and append `/{proxy}`. For example, mine is: `http://a9eaf69fd125947abb1065f62de59047-81cdebc0275f7d96.elb.us-west-2.amazonaws.com/{proxy}`. + +Leave "Content Handling" set to "Passthrough" and Click "Save". + +![](https://user-images.githubusercontent.com/808475/80154735-13ea2000-8575-11ea-83ca-58f182df83c6.png) + +Select "Actions" > "Deploy API" + +![](https://user-images.githubusercontent.com/808475/80154802-2c5a3a80-8575-11ea-9ab3-de89885fd658.png) + +Create a new stage (e.g. "dev") and click "Deploy" + +![](https://user-images.githubusercontent.com/808475/80154859-4431be80-8575-11ea-9305-50384b1f9847.png) + +Copy your "Invoke URL" + +![](https://user-images.githubusercontent.com/808475/80154911-5dd30600-8575-11ea-9682-1a7328783011.png) + +### Use your new endpoint + +You may now use the "Invoke URL" in place of your API load balancer endpoint in your client. For example, this curl request: + +```bash +curl http://a9eaf69fd125947abb1065f62de59047-81cdebc0275f7d96.elb.us-west-2.amazonaws.com/iris-classifier -X POST -H "Content-Type: application/json" -d @sample.json +``` + +Would become: + +```bash +curl https://31qjv48rs6.execute-api.us-west-2.amazonaws.com/dev/iris-classifier -X POST -H "Content-Type: application/json" -d @sample.json +``` + +### Cleanup + +Delete the API Gateway before spinning down your Cortex cluster: + +![](https://user-images.githubusercontent.com/808475/80155073-bdc9ac80-8575-11ea-99a1-95c0579da79e.png) + +## Internal load balancer + +_This section applies if your API load balancer is internal (i.e. you set `api_load_balancer_scheme: internal` in your cluster configuration file before creating your cluster). If your API load balancer is internet-facing, see the [internet-facing load balancer](#internet-facing-load-balancer) section above._ + +### Create a VPC Link + +Navigate to AWS's EC2 Load Balancer dashboard and locate the Cortex API load balancer. You can determine which is the API load balancer by inspecting the `kubernetes.io/service-name` tag: + +![](https://user-images.githubusercontent.com/808475/80142777-961c1980-8560-11ea-9202-40964dbff5e9.png) + +Take note of the load balancer's name. + +Go to the [API Gateway console](https://console.aws.amazon.com/apigateway/home), click "VPC Links" on the left sidebar, and click "Create" + +![](https://user-images.githubusercontent.com/808475/80142466-0c6c4c00-8560-11ea-8293-eb5e5572b797.png) + +Select "VPC link for REST APIs", name your VPC link (e.g. "cortex"), select the API load balancer, and click "Create". + +![](https://user-images.githubusercontent.com/808475/80143027-03c84580-8561-11ea-92de-9ed0a5dfa593.png) + +Wait for the VPC link to be created (it will take a few minutes) + +![](https://user-images.githubusercontent.com/808475/80144088-bbaa2280-8562-11ea-901b-8520eb253df7.png) + +### Create an API Gateway + +Go to the [API Gateway console](https://console.aws.amazon.com/apigateway/home), select "REST API" under "Choose an API type", and click "Build" + +![](https://user-images.githubusercontent.com/808475/78293216-18269e80-74dd-11ea-9e68-86922c2cbc7c.png) + +Select "REST" and "New API", name your API (e.g. "cortex"), select either "Regional" or "Edge optimized" (depending on your preference), and click "Create API" + +![](https://user-images.githubusercontent.com/808475/78293434-66d43880-74dd-11ea-92d6-692158171a3f.png) + +Select "Actions" > "Create Resource" + +![](https://user-images.githubusercontent.com/808475/80141938-3cffb600-855f-11ea-9c1c-132ca4503b7a.png) + +Select "Configure as proxy resource" and "Enable API Gateway CORS", and click "Create Resource" + +![](https://user-images.githubusercontent.com/808475/80142124-80f2bb00-855f-11ea-8e4e-9413146e0815.png) + +Select "VPC Link", select "Use Proxy Integration", choose your newly-created VPC Link, and set "Endpoint URL" to "http:///{proxy}". You can get your API load balancer endpoint via `cortex cluster info`; make sure to prepend `http://` and append `/{proxy}`. For example, mine is: `http://a5044e34a352d44b0945adcd455c7fa3-32fa161d3e5bcbf9.elb.us-west-2.amazonaws.com/{proxy}`. Click "Save" + +![](https://user-images.githubusercontent.com/808475/80147407-4f322200-8568-11ea-8ef5-df5164c1375f.png) + +Select "Actions" > "Deploy API" + +![](https://user-images.githubusercontent.com/808475/80147555-86083800-8568-11ea-86af-1b1e38c9d322.png) + +Create a new stage (e.g. "dev") and click "Deploy" + +![](https://user-images.githubusercontent.com/808475/80147631-a7692400-8568-11ea-8a09-13dbd50b17b9.png) + +Copy your "Invoke URL" + +![](https://user-images.githubusercontent.com/808475/80147716-c798e300-8568-11ea-9aef-7dd6fdf4a68a.png) + +### Use your new endpoint + +You may now use the "Invoke URL" in place of your API load balancer endpoint in your client. For example, this curl request: + +```bash +curl http://a5044e34a352d44b0945adcd455c7fa3-32fa161d3e5bcbf9.elb.us-west-2.amazonaws.com/iris-classifier -X POST -H "Content-Type: application/json" -d @sample.json +``` + +Would become: + +```bash +curl https://lrivodooqh.execute-api.us-west-2.amazonaws.com/dev/iris-classifier -X POST -H "Content-Type: application/json" -d @sample.json +``` + +### Cleanup + +Delete the API Gateway and VPC Link before spinning down your Cortex cluster: + +![](https://user-images.githubusercontent.com/808475/80149163-05970680-856b-11ea-9f82-61f4061a3321.png) + +![](https://user-images.githubusercontent.com/808475/80149204-1ba4c700-856b-11ea-83f7-9741c78b6b95.png) diff --git a/docs/clusters/aws/networking/index.md b/docs/clusters/aws/networking/index.md new file mode 100644 index 0000000000..1388c5cc18 --- /dev/null +++ b/docs/clusters/aws/networking/index.md @@ -0,0 +1,9 @@ +# Networking + +![api architecture diagram](https://user-images.githubusercontent.com/808475/103417256-dd6e9700-4b3e-11eb-901e-90425f1f8fd4.png) + +All APIs share a single API load balancer. By default, the API load balancer is public. You can configure your API load balancer to be private by setting `api_load_balancer_scheme: internal` in your cluster configuration file (before creating your cluster). This will make your API only accessible through [VPC Peering](vpc-peering.md). + +The SSL certificate on the API load balancer is autogenerated during installation using `localhost` as the Common Name (CN). Therefore, clients will need to skip certificate verification when making HTTPS requests to your APIs (e.g. `curl -k https://***`), or make HTTP requests instead (e.g. `curl http://***`). Alternatively, you can enable HTTPS by using a [custom domain](custom-domain.md) or by [creating an API Gateway](https.md) to forward requests to your API load balancer. + +There is a separate load balancer for the Cortex operator. By default, the operator load balancer is public. You can configure your operator load balancer to be private by setting `operator_load_balancer_scheme: internal` in your cluster configuration file (before creating your cluster). You can use [VPC Peering](vpc-peering.md) to enable your Cortex CLI to connect to your cluster operator from another VPC. diff --git a/docs/clusters/aws/vpc-peering.md b/docs/clusters/aws/networking/vpc-peering.md similarity index 59% rename from docs/clusters/aws/vpc-peering.md rename to docs/clusters/aws/networking/vpc-peering.md index 1c635590a9..4443de4466 100644 --- a/docs/clusters/aws/vpc-peering.md +++ b/docs/clusters/aws/networking/vpc-peering.md @@ -2,71 +2,67 @@ If you are using an internal operator load balancer (i.e. you set `operator_load_balancer_scheme: internal` in your cluster configuration file before creating your cluster), you can use VPC Peering to enable your Cortex CLI to connect to your cluster operator from another VPC so that you may run `cortex` commands. Note that because the operator validates that the CLI user is an active IAM user in the same AWS account as the Cortex cluster, it is usually unnecessary to configure the operator's load balancer to be internal. -If you are using an internal API load balancer (i.e. you set `api_load_balancer_scheme: internal` in your cluster configuration file before creating your cluster) and you disabled API Gateway for your API (i.e. you set `api_gateway: none` in the `networking` field of your api configuration), you can use VPC Peering to enable prediction requests from another VPC. +If you are using an internal API load balancer (i.e. you set `api_load_balancer_scheme: internal` in your cluster configuration file before creating your cluster), you can use VPC Peering to make prediction requests from another VPC. This guide illustrates how to create a VPC Peering connection between a VPC of your choice and the Cortex load balancers. -## Step 1 +## Gather Cortex's VPC information Navigate to AWS's EC2 Load Balancer dashboard and locate the Cortex operator's load balancer. You can determine which is the operator load balancer by inspecting the `kubernetes.io/service-name` tag: -![step 1a](https://user-images.githubusercontent.com/808475/80126132-804e2a80-8547-11ea-8ce4-57d3fd96e2c4.png) +![](https://user-images.githubusercontent.com/808475/80126132-804e2a80-8547-11ea-8ce4-57d3fd96e2c4.png) Click back to the "Description" tab and note the VPC ID of the load balancer and the ID of each of the subnets associated with the load balancer: -![step 1b](https://user-images.githubusercontent.com/808475/80127144-c2c43700-8548-11ea-95b4-ce9d1df024cc.png) +![](https://user-images.githubusercontent.com/808475/80127144-c2c43700-8548-11ea-95b4-ce9d1df024cc.png) Navigate to AWS's VPC dashboard and identify the ID and CIDR block of Cortex's VPC: -![step 1c](https://user-images.githubusercontent.com/808475/80125554-af17d100-8546-11ea-96ec-00e2aaee7100.png) +![](https://user-images.githubusercontent.com/808475/80125554-af17d100-8546-11ea-96ec-00e2aaee7100.png) The VPC ID here should match that of the load balancer. -## Step 2 +## Create peering connection Identify the ID and CIDR block of the VPC from which you'd like to connect to the Cortex VPC. In my case, I have a VPC in the same AWS account and region, and I can locate its ID and CIDR block from AWS's VPC dashboard: -![step 2](https://user-images.githubusercontent.com/808475/80125729-eb4b3180-8546-11ea-8d20-6bc2478747ae.png) - -## Step 3 +![](https://user-images.githubusercontent.com/808475/80125729-eb4b3180-8546-11ea-8d20-6bc2478747ae.png) From AWS's VPC dashboard, navigate to the "Peering Connections" page, and click "Create Peering Connection": -![step 3a](https://user-images.githubusercontent.com/808475/80127600-67df0f80-8549-11ea-9e10-765a6e273b54.png) +![](https://user-images.githubusercontent.com/808475/80127600-67df0f80-8549-11ea-9e10-765a6e273b54.png) -Name your new VPC Peering Connection (I used "cortex-operator", but "cortex" or "cortex-api" may make more sense depending on your use case). Then configure the connection such that the "Requester" is the VPC from which you'll connect to the Cortex VPC, and the "Accepter" is Cortex's VPC (from step 1). +Name your new VPC Peering Connection (I used "cortex-operator", but "cortex" or "cortex-api" may make more sense depending on your use case). Then configure the connection such that the "Requester" is the VPC from which you'll connect to the Cortex VPC, and the "Accepter" is Cortex's VPC. -![step 3b](https://user-images.githubusercontent.com/808475/80131545-3f5a1400-854f-11ea-9ca0-c51433d3fa3d.png) +![](https://user-images.githubusercontent.com/808475/80131545-3f5a1400-854f-11ea-9ca0-c51433d3fa3d.png) Click "Create Peering Connection", navigate back to the Peering Connections dashboard, select the newly created peering connection, and click "Actions" > "Accept Request": -![step 3c](https://user-images.githubusercontent.com/808475/80132168-21d97a00-8550-11ea-8c22-79c65710d369.png) +![](https://user-images.githubusercontent.com/808475/80132168-21d97a00-8550-11ea-8c22-79c65710d369.png) -![step 3d](https://user-images.githubusercontent.com/808475/80132179-26059780-8550-11ea-80fc-6670fcab7026.png) +![](https://user-images.githubusercontent.com/808475/80132179-26059780-8550-11ea-80fc-6670fcab7026.png) -## Step 4 +## Update route tables Navigate to the VPC Route Tables page. Select the route table for the VPC from which you'd like to connect to the Cortex cluster (in my case, I just have one route table for this VPC). Select the "Routes" tab, and click "Edit routes": -![step 4a](https://user-images.githubusercontent.com/808475/80135180-b940cc00-8554-11ea-8162-c7409090897b.png) +![](https://user-images.githubusercontent.com/808475/80135180-b940cc00-8554-11ea-8162-c7409090897b.png) -Add a route where the "Destination" is the CIDR block for Cortex's VPC (identified in Step 1), and the "Target" is the newly-created Peering Connection: +Add a route where the "Destination" is the CIDR block for Cortex's VPC, and the "Target" is the newly-created Peering Connection: -![step 4b](https://user-images.githubusercontent.com/808475/80137033-78968200-8557-11ea-9d84-9221b772f0fc.png) +![](https://user-images.githubusercontent.com/808475/80137033-78968200-8557-11ea-9d84-9221b772f0fc.png) Do not create new route tables or change subnet associations. -## Step 5 - -Navigate back to the VPC Route Tables page. There will be a route table for each of the subnets associated with the Cortex operator load balancer (identified in Step 1): +Navigate back to the VPC Route Tables page. There will be a route table for each of the subnets associated with the Cortex operator load balancer: -![step 5a](https://user-images.githubusercontent.com/808475/80138244-5dc50d00-8559-11ea-9248-fc201d011530.png) +![](https://user-images.githubusercontent.com/808475/80138244-5dc50d00-8559-11ea-9248-fc201d011530.png) -For each of these route tables, click "Edit routes" and add a new route where the "Destination" is the CIDR block for the VPC from which you will be connecting to the Cortex cluster (identified in Step 2), and the "Target" is the newly-created Peering Connection: +For each of these route tables, click "Edit routes" and add a new route where the "Destination" is the CIDR block for the VPC from which you will be connecting to the Cortex cluster, and the "Target" is the newly-created Peering Connection: -![step 5b](https://user-images.githubusercontent.com/808475/80138653-f78cba00-8559-11ea-8444-406e218c3bab.png) +![](https://user-images.githubusercontent.com/808475/80138653-f78cba00-8559-11ea-8444-406e218c3bab.png) Repeat adding this route for each route table associated with the Cortex operator's subnets; in my case there were three. Do not create new route tables or change subnet associations. @@ -76,4 +72,4 @@ You should now be able to use the Cortex CLI and make prediction requests from y Delete the VPC Peering connection before spinning down your Cortex cluster: -![cleanup](https://user-images.githubusercontent.com/808475/80138851-57836080-855a-11ea-92f1-06d501932a41.png) +![](https://user-images.githubusercontent.com/808475/80138851-57836080-855a-11ea-92f1-06d501932a41.png) diff --git a/docs/clusters/aws/rest-api-gateway.md b/docs/clusters/aws/rest-api-gateway.md deleted file mode 100644 index c5abdea21d..0000000000 --- a/docs/clusters/aws/rest-api-gateway.md +++ /dev/null @@ -1,193 +0,0 @@ -# REST API Gateway - -When `api_gateway: public` is set in your API's `networking` configuration (which is the default setting), Cortex will create an "HTTP" API Gateway in AWS for your API (see the [networking docs](networking.md) for more information). - -However, there may be situations where you need to use AWS's "REST" API Gateway, e.g. to enforce IAM-based auth. Until [#1197](https://github.com/cortexlabs/cortex/issues/1197) is resolved, a REST API Gateway can be used by following these steps. - -If your API load balancer is internet-facing (which is the default, or you explicitly set `api_load_balancer_scheme: internet-facing` in your cluster configuration file before creating your cluster), use the [first section](#if-your-api-load-balancer-is-internet-facing) of this guide. - -If your API load balancer is internal (i.e. you set `api_load_balancer_scheme: internal` in your cluster configuration file before creating your cluster), use the [second section](#if-your-api-load-balancer-is-internal) of this guide. - -## If your API load balancer is internet-facing - -### Step 1 - -Disable the default API Gateway: - -* If you haven't created your cluster yet, you can set `api_gateway: none` in your cluster configuration file before creating your cluster. -* If you have already created your cluster, you can set `api_gateway: none` in the `networking` field of your Realtime API configuration and/or Batch API configuration, and then re-deploy your API. - -### Step 2 - -Go to the [API Gateway console](https://console.aws.amazon.com/apigateway/home), select "REST API" under "Choose an API type", and click "Build" - -![step 1](https://user-images.githubusercontent.com/808475/78293216-18269e80-74dd-11ea-9e68-86922c2cbc7c.png) - -### Step 3 - -Select "REST" and "New API", name your API (e.g. "cortex"), select either "Regional" or "Edge optimized" (depending on your preference), and click "Create API" - -![step 2](https://user-images.githubusercontent.com/808475/78293434-66d43880-74dd-11ea-92d6-692158171a3f.png) - -### Step 4 - -Select "Actions" > "Create Resource" - -![step 3](https://user-images.githubusercontent.com/808475/80154502-8b6b7f80-8574-11ea-9c78-7d9f277bf55b.png) - -### Step 5 - -Select "Configure as proxy resource" and "Enable API Gateway CORS", and click "Create Resource" - -![step 4](https://user-images.githubusercontent.com/808475/80154565-ad650200-8574-11ea-8753-808cd35902e2.png) - -### Step 6 - -Select "HTTP Proxy" and set "Endpoint URL" to "http:///{proxy}". You can get your base API endpoint via `cortex cluster info`; make sure to prepend `http://` and append `/{proxy}`. For example, mine is: `http://a9eaf69fd125947abb1065f62de59047-81cdebc0275f7d96.elb.us-west-2.amazonaws.com/{proxy}`. - -Leave "Content Handling" set to "Passthrough" and Click "Save". - -![step 5](https://user-images.githubusercontent.com/808475/80154735-13ea2000-8575-11ea-83ca-58f182df83c6.png) - -### Step 7 - -Select "Actions" > "Deploy API" - -![step 6](https://user-images.githubusercontent.com/808475/80154802-2c5a3a80-8575-11ea-9ab3-de89885fd658.png) - -### Step 8 - -Create a new stage (e.g. "dev") and click "Deploy" - -![step 7](https://user-images.githubusercontent.com/808475/80154859-4431be80-8575-11ea-9305-50384b1f9847.png) - -### Step 9 - -Copy your "Invoke URL" - -![step 8](https://user-images.githubusercontent.com/808475/80154911-5dd30600-8575-11ea-9682-1a7328783011.png) - -### Using your new endpoint - -You may now use the "Invoke URL" in place of your APIs endpoint in your client. For example, this curl request: - -```bash -curl http://a9eaf69fd125947abb1065f62de59047-81cdebc0275f7d96.elb.us-west-2.amazonaws.com/iris-classifier -X POST -H "Content-Type: application/json" -d @sample.json -``` - -Would become: - -```bash -curl https://31qjv48rs6.execute-api.us-west-2.amazonaws.com/dev/iris-classifier -X POST -H "Content-Type: application/json" -d @sample.json -``` - -### Cleanup - -Delete the API Gateway before spinning down your Cortex cluster: - -![delete api gateway](https://user-images.githubusercontent.com/808475/80155073-bdc9ac80-8575-11ea-99a1-95c0579da79e.png) - -## If your API load balancer is internal - -### Step 1 - -Disable the default API Gateway: - -* If you haven't created your cluster yet, you can set `api_gateway: none` in your cluster configuration file before creating your cluster. -* If you have already created your cluster, you can set `api_gateway: none` in the `networking` field of your Realtime API configuration and/or Batch API configuration, and then re-deploy your API. - -### Step 2 - -Navigate to AWS's EC2 Load Balancer dashboard and locate the Cortex API load balancer. You can determine which is the API load balancer by inspecting the `kubernetes.io/service-name` tag: - -![step 1](https://user-images.githubusercontent.com/808475/80142777-961c1980-8560-11ea-9202-40964dbff5e9.png) - -Take note of the load balancer's name. - -### Step 3 - -Go to the [API Gateway console](https://console.aws.amazon.com/apigateway/home), click "VPC Links" on the left sidebar, and click "Create" - -![step 2](https://user-images.githubusercontent.com/808475/80142466-0c6c4c00-8560-11ea-8293-eb5e5572b797.png) - -### Step 4 - -Select "VPC link for REST APIs", name your VPC link (e.g. "cortex"), select the API load balancer (identified in Step 1), and click "Create" - -![step 3](https://user-images.githubusercontent.com/808475/80143027-03c84580-8561-11ea-92de-9ed0a5dfa593.png) - -### Step 5 - -Wait for the VPC link to be created (it will take a few minutes) - -![step 4](https://user-images.githubusercontent.com/808475/80144088-bbaa2280-8562-11ea-901b-8520eb253df7.png) - -### Step 6 - -Go to the [API Gateway console](https://console.aws.amazon.com/apigateway/home), select "REST API" under "Choose an API type", and click "Build" - -![step 5](https://user-images.githubusercontent.com/808475/78293216-18269e80-74dd-11ea-9e68-86922c2cbc7c.png) - -### Step 7 - -Select "REST" and "New API", name your API (e.g. "cortex"), select either "Regional" or "Edge optimized" (depending on your preference), and click "Create API" - -![step 6](https://user-images.githubusercontent.com/808475/78293434-66d43880-74dd-11ea-92d6-692158171a3f.png) - -### Step 8 - -Select "Actions" > "Create Resource" - -![step 7](https://user-images.githubusercontent.com/808475/80141938-3cffb600-855f-11ea-9c1c-132ca4503b7a.png) - -### Step 9 - -Select "Configure as proxy resource" and "Enable API Gateway CORS", and click "Create Resource" - -![step 8](https://user-images.githubusercontent.com/808475/80142124-80f2bb00-855f-11ea-8e4e-9413146e0815.png) - -### Step 10 - -Select "VPC Link", select "Use Proxy Integration", choose your newly-created VPC Link, and set "Endpoint URL" to "http:///{proxy}". You can get your base API endpoint via `cortex cluster info`; make sure to prepend `http://` and append `/{proxy}`. For example, mine is: `http://a5044e34a352d44b0945adcd455c7fa3-32fa161d3e5bcbf9.elb.us-west-2.amazonaws.com/{proxy}`. Click "Save" - -![step 9](https://user-images.githubusercontent.com/808475/80147407-4f322200-8568-11ea-8ef5-df5164c1375f.png) - -### Step 11 - -Select "Actions" > "Deploy API" - -![step 10](https://user-images.githubusercontent.com/808475/80147555-86083800-8568-11ea-86af-1b1e38c9d322.png) - -### Step 12 - -Create a new stage (e.g. "dev") and click "Deploy" - -![step 11](https://user-images.githubusercontent.com/808475/80147631-a7692400-8568-11ea-8a09-13dbd50b17b9.png) - -### Step 13 - -Copy your "Invoke URL" - -![step 12](https://user-images.githubusercontent.com/808475/80147716-c798e300-8568-11ea-9aef-7dd6fdf4a68a.png) - -### Using your new endpoint - -You may now use the "Invoke URL" in place of your APIs endpoint in your client. For example, this curl request: - -```bash -curl http://a5044e34a352d44b0945adcd455c7fa3-32fa161d3e5bcbf9.elb.us-west-2.amazonaws.com/iris-classifier -X POST -H "Content-Type: application/json" -d @sample.json -``` - -Would become: - -```bash -curl https://lrivodooqh.execute-api.us-west-2.amazonaws.com/dev/iris-classifier -X POST -H "Content-Type: application/json" -d @sample.json -``` - -### Cleanup - -Delete the API Gateway and VPC Link before spinning down your Cortex cluster: - -![delete api](https://user-images.githubusercontent.com/808475/80149163-05970680-856b-11ea-9f82-61f4061a3321.png) - -![delete vpc link](https://user-images.githubusercontent.com/808475/80149204-1ba4c700-856b-11ea-83f7-9741c78b6b95.png) diff --git a/docs/clusters/aws/security.md b/docs/clusters/aws/security.md index e2d400a5b1..7abb474068 100644 --- a/docs/clusters/aws/security.md +++ b/docs/clusters/aws/security.md @@ -6,11 +6,11 @@ By default, instances are created in public subnets and are assigned public IP a ## Private APIs -See [networking](networking.md) for a discussion of API visibility. +See [networking](networking/index.md) for a discussion of API visibility. ## Private operator -By default, the Cortex cluster operator's load balancer is internet-facing, and therefore publicly accessible (the operator is what the `cortex` CLI connects to). The operator validates that the CLI user is an active IAM user in the same AWS account as the Cortex cluster (see [below](#cli)). Therefore it is usually unnecessary to configure the operator's load balancer to be private, but this can be done by by setting `operator_load_balancer_scheme: internal` in your [cluster configuration](install.md) file. If you do this, you will need to configure [VPC Peering](vpc-peering.md) to allow your CLI to connect to the Cortex operator (this will be necessary to run any `cortex` commands). +By default, the Cortex cluster operator's load balancer is internet-facing, and therefore publicly accessible (the operator is what the `cortex` CLI connects to). The operator validates that the CLI user is an active IAM user in the same AWS account as the Cortex cluster (see [below](#cli)). Therefore it is usually unnecessary to configure the operator's load balancer to be private, but this can be done by by setting `operator_load_balancer_scheme: internal` in your [cluster configuration](install.md) file. If you do this, you will need to configure [VPC Peering](networking/vpc-peering.md) to allow your CLI to connect to the Cortex operator (this will be necessary to run any `cortex` commands). ## IAM permissions @@ -42,7 +42,7 @@ It is recommended to use an IAM user with the `AdministratorAccess` policy to cr A process called the Cortex operator runs on your cluster and is responsible for deploying and managing your APIs on the cluster. The operator will use the designated cluster credentials (e.g. `--cluster-aws-key` or `$CLUSTER_AWS_ACCESS_KEY_ID`) if specified, otherwise it will default to using the credentials used to spin up the cluster (e.g. `--aws-key` or `$AWS_ACCESS_KEY_ID`). -The operator requires read permissions for any S3 bucket containing exported models, read/write permissions for the Cortex S3 bucket, read permissions for ECR, read permissions for ELB, read/write permissions for API Gateway, read/write permissions for CloudWatch metrics, and read/write permissions for the Cortex CloudWatch log group. The policy below may be used to restrict the Operator's access: +The operator requires read permissions for any S3 bucket containing exported models, read/write permissions for the Cortex S3 bucket, read permissions for ECR, read permissions for ELB, read/write permissions for CloudWatch metrics, and read/write permissions for the Cortex CloudWatch log group. The policy below may be used to restrict the Operator's access: ```json { @@ -59,7 +59,6 @@ The operator requires read permissions for any S3 bucket containing exported mod "ecr:GetAuthorizationToken", "ecr:BatchGetImage", "elasticloadbalancing:Describe*", - "apigateway:*", "cloudwatch:*", "logs:*", "sqs:*" diff --git a/docs/clusters/aws/uninstall.md b/docs/clusters/aws/uninstall.md index 7fa23e09a6..ca6a4654b9 100644 --- a/docs/clusters/aws/uninstall.md +++ b/docs/clusters/aws/uninstall.md @@ -25,7 +25,7 @@ aws s3 rb --force s3:// aws logs describe-log-groups --log-group-name-prefix= --query logGroups[*].[logGroupName] --output text | xargs -I {} aws logs delete-log-group --log-group-name {} ``` -If you've configured a custom domain for your APIs, you can remove the SSL Certificate and Hosted Zone for the domain by following these [instructions](custom-domain.md#cleanup). +If you've configured a custom domain for your APIs, you can remove the SSL Certificate and Hosted Zone for the domain by following these [instructions](networking/custom-domain.md#cleanup). ## Troubleshooting @@ -43,4 +43,4 @@ On rare occasions, `cortex cluster down` may not be able to spin down your Corte If deleting the stack fails, navigate to the EC2 dashboard in the AWS console, delete the load balancers that are associated with the cluster, and try again (you can determine which load balancers are associated with the cluster by setting the correct region in the console and checking the `cortex.dev/cluster-name` tag on all load balancers). If the problem still persists, delete any other AWS resources that are blocking the stack deletion and try again. -1. In rare cases, you may need to delete other AWS resources associated with your Cortex cluster. For each the following resources, go to the appropriate AWS Dashboard (in the region that your cluster was in), and confirm that there are no resources left behind by the cluster: API Gateway API, API Gateway VPC Link, CloudWatch Dashboard, SQS Queues, S3 Bucket, and CloudWatch LogGroups (the Cortex bucket and log groups are not deleted by `cluster down` in order to preserve your data). +1. In rare cases, you may need to delete other AWS resources associated with your Cortex cluster. For each the following resources, go to the appropriate AWS Dashboard (in the region that your cluster was in), and confirm that there are no resources left behind by the cluster: CloudWatch Dashboard, SQS Queues, S3 Bucket, and CloudWatch LogGroups (the Cortex bucket and log groups are not deleted by `cluster down` in order to preserve your data). diff --git a/docs/clusters/aws/update.md b/docs/clusters/aws/update.md index d5f6959fb7..30af4288b7 100644 --- a/docs/clusters/aws/update.md +++ b/docs/clusters/aws/update.md @@ -29,7 +29,7 @@ In production environments, you can upgrade your cluster without downtime if you 1. Spin up a new cluster. For example: `cortex cluster up --config 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 old cluster is `old`, you can use `cortex get --env old` to list all running APIs in your old cluster, and re-deploy them in the new cluster by changing directories to each API's project folder and running `cortex deploy --env new`. 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 Gateway (if you are using API Gateway) or API load balancer (if clients connect directly to the API load balancer). + * 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 old cluster. If you updated DNS settings, wait 24-48 hours before spinning down your old cluster to allow the DNS cache to be flushed. diff --git a/docs/summary.md b/docs/summary.md index d7f3ce747c..fe62c1b376 100644 --- a/docs/summary.md +++ b/docs/summary.md @@ -41,10 +41,10 @@ * [Update](clusters/aws/update.md) * [Security](clusters/aws/security.md) * [Spot instances](clusters/aws/spot.md) - * [Networking](clusters/aws/networking.md) - * [VPC peering](clusters/aws/vpc-peering.md) - * [Custom domain](clusters/aws/custom-domain.md) - * [REST API Gateway](clusters/aws/rest-api-gateway.md) + * [Networking](clusters/aws/networking/index.md) + * [Custom domain](clusters/aws/networking/custom-domain.md) + * [HTTPS (via API Gateway)](clusters/aws/networking/https.md) + * [VPC peering](clusters/aws/networking/vpc-peering.md) * [Setting up kubectl](clusters/aws/kubectl.md) * [Uninstall](clusters/aws/uninstall.md) * GCP diff --git a/docs/workloads/batch/configuration.md b/docs/workloads/batch/configuration.md index a6d72fd96c..3204333a21 100644 --- a/docs/workloads/batch/configuration.md +++ b/docs/workloads/batch/configuration.md @@ -17,7 +17,6 @@ shm_size: # size of shared memory (/dev/shm) for sharing data between multiple processes, e.g. 64Mi or 1Gi (default: Null) networking: endpoint: # the endpoint for the API (default: ) - api_gateway: public | none # whether to create a public API Gateway endpoint for this API (if not, the API will still be accessible via the load balancer) (default: public, unless disabled cluster-wide) compute: cpu: # CPU request per worker. One unit of CPU corresponds to one virtual CPU; fractional requests are allowed, and can be specified as a floating point number or via the "m" suffix (default: 200m) gpu: # GPU request per worker. One unit of GPU corresponds to one virtual GPU (default: 0) @@ -54,7 +53,6 @@ shm_size: # size of shared memory (/dev/shm) for sharing data between multiple processes, e.g. 64Mi or 1Gi (default: Null) networking: endpoint: # the endpoint for the API (default: ) - api_gateway: public | none # whether to create a public API Gateway endpoint for this API (if not, the API will still be accessible via the load balancer) (default: public, unless disabled cluster-wide) compute: cpu: # CPU request per worker. One unit of CPU corresponds to one virtual CPU; fractional requests are allowed, and can be specified as a floating point number or via the "m" suffix (default: 200m) gpu: # GPU request per worker. One unit of GPU corresponds to one virtual GPU (default: 0) @@ -85,7 +83,6 @@ shm_size: # size of shared memory (/dev/shm) for sharing data between multiple processes, e.g. 64Mi or 1Gi (default: Null) networking: endpoint: # the endpoint for the API (default: ) - api_gateway: public | none # whether to create a public API Gateway endpoint for this API (if not, the API will still be accessible via the load balancer) (default: public, unless disabled cluster-wide) compute: cpu: # CPU request per worker. One unit of CPU corresponds to one virtual CPU; fractional requests are allowed, and can be specified as a floating point number or via the "m" suffix (default: 200m) gpu: # GPU request per worker. One unit of GPU corresponds to one virtual GPU (default: 0) diff --git a/docs/workloads/realtime/configuration.md b/docs/workloads/realtime/configuration.md index 20280ab5d3..907ca5e0ab 100644 --- a/docs/workloads/realtime/configuration.md +++ b/docs/workloads/realtime/configuration.md @@ -31,7 +31,6 @@ shm_size: # size of shared memory (/dev/shm) for sharing data between multiple processes, e.g. 64Mi or 1Gi (default: Null) networking: endpoint: # the endpoint for the API (default: ) - api_gateway: public | none # whether to create a public API Gateway endpoint for this API (if not, the API will still be accessible via the load balancer) (default: public, unless disabled cluster-wide) (aws only) compute: cpu: # CPU request per replica. One unit of CPU corresponds to one virtual CPU; fractional requests are allowed, and can be specified as a floating point number or via the "m" suffix (default: 200m) gpu: # GPU request per replica. One unit of GPU corresponds to one virtual GPU (default: 0) @@ -89,7 +88,6 @@ shm_size: # size of shared memory (/dev/shm) for sharing data between multiple processes, e.g. 64Mi or 1Gi (default: Null) networking: endpoint: # the endpoint for the API (default: ) - api_gateway: public | none # whether to create a public API Gateway endpoint for this API (if not, the API will still be accessible via the load balancer) (default: public, unless disabled cluster-wide) (aws only) compute: cpu: # CPU request per replica. One unit of CPU corresponds to one virtual CPU; fractional requests are allowed, and can be specified as a floating point number or via the "m" suffix (default: 200m) gpu: # GPU request per replica. One unit of GPU corresponds to one virtual GPU (default: 0) @@ -141,7 +139,6 @@ shm_size: # size of shared memory (/dev/shm) for sharing data between multiple processes, e.g. 64Mi or 1Gi (default: Null) networking: endpoint: # the endpoint for the API (default: ) - api_gateway: public | none # whether to create a public API Gateway endpoint for this API (if not, the API will still be accessible via the load balancer) (default: public, unless disabled cluster-wide) (aws only) compute: cpu: # CPU request per replica. One unit of CPU corresponds to one virtual CPU; fractional requests are allowed, and can be specified as a floating point number or via the "m" suffix (default: 200m) gpu: # GPU request per replica. One unit of GPU corresponds to one virtual GPU (default: 0) diff --git a/docs/workloads/realtime/troubleshooting.md b/docs/workloads/realtime/troubleshooting.md index 956fa21ea9..184a08e10f 100644 --- a/docs/workloads/realtime/troubleshooting.md +++ b/docs/workloads/realtime/troubleshooting.md @@ -7,7 +7,7 @@ When making prediction requests to your API, it's possible to get a `{"message": 1. It's possible that your API is simply not ready yet. You can check the status of your API with `cortex get API_NAME`, and stream the logs with `cortex logs API_NAME`. 1. Your API may have errored during initialization or while responding to a previous request. `cortex get API_NAME` will show the status of your API, and you can view the logs with `cortex logs API_NAME`. -It is also possible to receive a `{"message":"Service Unavailable"}` error message (with HTTP status code `503`) if you are using an API Gateway endpoint for your API and if your request exceeds API Gateway's 29 second timeout. If you don't know whether you are using API Gateway, you can run `cortex get ` and check if `networking.api_gateway` is not set to `none` in the api configuration. If the request is exceeding the API Gateway timeout, your client should receive the `{"message":"Service Unavailable"}` response ~29 seconds after making the request. To confirm that this is the issue, you can modify your `predict()` function to immediately return a response (e.g. `return "ok"`), re-deploy your API, wait for the update to complete, and try making a request. If your client successfully receives the "ok" response, it is likely that the API Gateway timeout is occurring. You can either modify your `predict()` implementation to take less time, run on faster hardware (e.g. GPUs), or disable API Gateway for this API by setting `api_gateway: none` in the `networking` field of the API configuration. +It is also possible to receive a `{"message":"Service Unavailable"}` error message (with HTTP status code `503`) if you are using API Gateway in front of your API endpoints and if your request exceeds API Gateway's 29 second timeout. If the request is exceeding the API Gateway timeout, your client should receive the `{"message":"Service Unavailable"}` response ~29 seconds after making the request. To confirm that this is the issue, you can modify your `predict()` function to immediately return a response (e.g. `return "ok"`), re-deploy your API, wait for the update to complete, and try making a request. If your client successfully receives the "ok" response, it is likely that the API Gateway timeout is occurring. You can either modify your `predict()` implementation to take less time, run on faster hardware (e.g. GPUs), or don't use API Gateway (there is no timeout when using the API's endpoint). ## API is stuck updating diff --git a/docs/workloads/traffic-splitter/configuration.md b/docs/workloads/traffic-splitter/configuration.md index 423d382ee3..2111153b75 100644 --- a/docs/workloads/traffic-splitter/configuration.md +++ b/docs/workloads/traffic-splitter/configuration.md @@ -5,7 +5,6 @@ kind: TrafficSplitter networking: endpoint: # the endpoint for the Traffic Splitter (default: ) - api_gateway: public | none # whether to create a public API Gateway endpoint for this API (if not, the API will still be accessible via the load balancer) (default: public, unless disabled cluster-wide) apis: # list of Realtime APIs to target - name: # name of a Realtime API that is already running or is included in the same configuration file (required) weight: # percentage of traffic to route to the Realtime API (all weights must sum to 100) (required) diff --git a/manager/create_gateway_integration.py b/manager/create_gateway_integration.py deleted file mode 100644 index 574ee4a8c2..0000000000 --- a/manager/create_gateway_integration.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2020 Cortex Labs, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import boto3 -import sys -import os - - -def get_istio_api_gateway_elb_arn(client_elb): - paginator = client_elb.get_paginator("describe_load_balancers") - for elb_page in paginator.paginate(): - for elb in elb_page["LoadBalancers"]: - elb_arn = elb["LoadBalancerArn"] - elb_tags = client_elb.describe_tags(ResourceArns=[elb_arn])["TagDescriptions"][0][ - "Tags" - ] - - is_from_cluster = False - is_api_load_balancer = False - for tag in elb_tags: - if ( - tag["Key"] == "cortex.dev/cluster-name" - and tag["Value"] == os.environ["CORTEX_CLUSTER_NAME"] - ): - is_from_cluster = True - if ( - tag["Key"] == "kubernetes.io/service-name" - and tag["Value"] == "istio-system/ingressgateway-apis" - ): - is_api_load_balancer = True - - if is_from_cluster and is_api_load_balancer: - return elb_arn - - raise Exception("Could not find ingressgateway-apis ELB") - - -def get_listener_arn(elb_arn, client_elb): - paginator = client_elb.get_paginator("describe_listeners") - for listener_page in paginator.paginate(LoadBalancerArn=elb_arn): - for listener in listener_page["Listeners"]: - if listener["Port"] == 80: - return listener["ListenerArn"] - raise Exception(f"Could not find port 80 listener on elb {elb_arn}") - - -def create_gateway_integration(api_id, vpc_link_id): - client_elb = boto3.client("elbv2", region_name=os.environ["CORTEX_REGION"]) - client_apigateway = boto3.client("apigatewayv2", region_name=os.environ["CORTEX_REGION"]) - - elb_arn = get_istio_api_gateway_elb_arn(client_elb) - listener_arn = get_listener_arn(elb_arn, client_elb) - - client_apigateway.create_integration( - ApiId=api_id, - ConnectionId=vpc_link_id, - ConnectionType="VPC_LINK", - IntegrationType="HTTP_PROXY", - IntegrationUri=listener_arn, - PayloadFormatVersion="1.0", - IntegrationMethod="ANY", - ) - - -if __name__ == "__main__": - api_id = str(sys.argv[1]) - vpc_link_id = str(sys.argv[2]) - create_gateway_integration(api_id, vpc_link_id) diff --git a/manager/get_api_gateway_endpoint.py b/manager/get_api_gateway_endpoint.py deleted file mode 100644 index 4a185704be..0000000000 --- a/manager/get_api_gateway_endpoint.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2020 Cortex Labs, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import boto3 -import os - - -def get_api_gateway_endpoint(): - cluster_name = os.environ["CORTEX_CLUSTER_NAME"] - region = os.environ["CORTEX_REGION"] - client_apigateway = boto3.client("apigatewayv2", region_name=region) - - paginator = client_apigateway.get_paginator("get_apis") - for api_gateway_page in paginator.paginate(): - for api_gateway in api_gateway_page["Items"]: - if api_gateway["Tags"].get("cortex.dev/cluster-name") == cluster_name: - return api_gateway["ApiEndpoint"] - - raise Exception( - f"your cluster's api gateway (in {region} with tag cortex.dev/cluster-name={cluster_name}) does not exist" - ) - - -if __name__ == "__main__": - print(get_api_gateway_endpoint(), end="") diff --git a/manager/get_api_gateway_id.py b/manager/get_api_gateway_id.py deleted file mode 100644 index ba25790ddb..0000000000 --- a/manager/get_api_gateway_id.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2020 Cortex Labs, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import boto3 -import os - - -def get_api_gateway_id(): - cluster_name = os.environ["CORTEX_CLUSTER_NAME"] - region = os.environ["CORTEX_REGION"] - client_apigateway = boto3.client("apigatewayv2", region_name=region) - - paginator = client_apigateway.get_paginator("get_apis") - for api_gateway_page in paginator.paginate(): - for api_gateway in api_gateway_page["Items"]: - if api_gateway["Tags"].get("cortex.dev/cluster-name") == cluster_name: - return api_gateway["ApiId"] - - raise Exception( - f"your cluster's api gateway (in {region} with tag cortex.dev/cluster-name={cluster_name}) does not exist" - ) - - -if __name__ == "__main__": - print(get_api_gateway_id(), end="") diff --git a/manager/info.sh b/manager/info.sh index a682d17f8b..0dc75895da 100755 --- a/manager/info.sh +++ b/manager/info.sh @@ -26,10 +26,6 @@ function get_api_load_balancer_endpoint() { kubectl -n=istio-system get service ingressgateway-apis -o json | tr -d '[:space:]' | sed 's/.*{\"hostname\":\"\(.*\)\".*/\1/' } -function get_api_gateway_endpoint() { - python get_api_gateway_endpoint.py -} - if ! eksctl utils describe-stacks --cluster=$CORTEX_CLUSTER_NAME --region=$CORTEX_REGION >/dev/null 2>&1; then echo "error: there is no cluster named \"$CORTEX_CLUSTER_NAME\" in $CORTEX_REGION; please update your configuration to point to an existing cortex cluster or create a cortex cluster with \`cortex cluster up\`" exit 1 @@ -40,13 +36,7 @@ out=$(kubectl get pods 2>&1 || true); if [[ "$out" == *"must be logged in to the operator_endpoint=$(get_operator_endpoint) api_load_balancer_endpoint=$(get_api_load_balancer_endpoint) -if [ "$CORTEX_API_GATEWAY" == "public" ]; then - api_gateway_endpoint=$(get_api_gateway_endpoint) -fi echo -e "\033[1mendpoints:\033[0m" echo "operator: $operator_endpoint" # before modifying this, search for this prefix echo "api load balancer: $api_load_balancer_endpoint" -if [ "$CORTEX_API_GATEWAY" == "public" ]; then - echo "api gateway: $api_gateway_endpoint" -fi diff --git a/manager/install.sh b/manager/install.sh index 46e1805943..b76846de96 100755 --- a/manager/install.sh +++ b/manager/install.sh @@ -44,10 +44,6 @@ function cluster_up_aws() { start_pre_download_images - if [ "$CORTEX_API_LOAD_BALANCER_SCHEME" == "internal" ] && [ "$CORTEX_API_GATEWAY" == "public" ]; then - create_vpc_link - fi - echo -n "○ updating cluster configuration " setup_configmap setup_secrets @@ -85,10 +81,6 @@ function cluster_up_aws() { echo "✓" fi - if [ "$CORTEX_API_LOAD_BALANCER_SCHEME" == "internal" ] && [ "$CORTEX_API_GATEWAY" == "public" ]; then - create_vpc_link_integration - fi - restart_operator validate_cortex @@ -404,48 +396,6 @@ function suspend_az_rebalance() { fi } -function create_vpc_link() { - # get VPC ID - vpc_id=$(aws ec2 describe-vpcs --region $CORTEX_REGION --filters Name=tag:cortex.dev/cluster-name,Values=$CORTEX_CLUSTER_NAME | jq .Vpcs[0].VpcId | tr -d '"') - if [ "$vpc_id" = "" ] || [ "$vpc_id" = "null" ]; then - echo "unable to find cortex vpc" - exit 1 - fi - - # filter all private subnets belonging to cortex cluster - private_subnets=$(aws ec2 describe-subnets --region $CORTEX_REGION --filters Name=vpc-id,Values=$vpc_id Name=tag:Name,Values=*Private* | jq -s '.[].Subnets[].SubnetId' | tr -d '"') - if [ "$private_subnets" = "" ] || [ "$private_subnets" = "null" ]; then - echo "unable to find cortex private subnets" - exit 1 - fi - - # get default security group for cortex VPC - default_security_group=$(aws ec2 describe-security-groups --region $CORTEX_REGION --filters Name=vpc-id,Values=$vpc_id Name=group-name,Values=default | jq -c .SecurityGroups[].GroupId | tr -d '"') - if [ "$default_security_group" = "" ] || [ "$default_security_group" = "null" ]; then - echo "unable to find cortex default security group" - exit 1 - fi - - # create VPC Link - create_vpc_link_output=$(aws apigatewayv2 create-vpc-link --region $CORTEX_REGION --tags "$CORTEX_TAGS_JSON" --name $CORTEX_CLUSTER_NAME --subnet-ids $private_subnets --security-group-ids $default_security_group) - vpc_link_id=$(echo $create_vpc_link_output | jq .VpcLinkId | tr -d '"') - if [ "$vpc_link_id" = "" ] || [ "$vpc_link_id" = "null" ]; then - echo -e "unable to extract vpc link ID from create-vpc-link output:\n$create_vpc_link_output" - exit 1 - fi -} - -# must be called after create_vpc_link() since $vpc_link_id is reused -function create_vpc_link_integration() { - echo -n "○ creating api gateway vpc link integration " - api_id=$(python get_api_gateway_id.py) - python create_gateway_integration.py $api_id $vpc_link_id - echo "✓" - echo -n "○ waiting for api gateway vpc link integration " - until [ "$(aws apigatewayv2 get-vpc-link --region $CORTEX_REGION --vpc-link-id $vpc_link_id | jq .VpcLinkStatus | tr -d '"')" = "AVAILABLE" ]; do echo -n "."; sleep 3; done - echo " ✓" -} - function setup_istio() { envsubst < manifests/istio-namespace.yaml | kubectl apply -f - >/dev/null @@ -773,15 +723,9 @@ function print_endpoints_aws() { operator_endpoint=$(get_operator_endpoint_aws) api_load_balancer_endpoint=$(get_api_load_balancer_endpoint_aws) - if [ "$CORTEX_API_GATEWAY" == "public" ]; then - api_gateway_endpoint=$(get_api_gateway_endpoint) - fi echo "operator: $operator_endpoint" # before modifying this, search for this prefix echo "api load balancer: $api_load_balancer_endpoint" - if [ "$CORTEX_API_GATEWAY" == "public" ]; then - echo "api gateway: $api_gateway_endpoint" - fi } function get_operator_endpoint_aws() { @@ -792,10 +736,6 @@ function get_api_load_balancer_endpoint_aws() { kubectl -n=istio-system get service ingressgateway-apis -o json | tr -d '[:space:]' | sed 's/.*{\"hostname\":\"\(.*\)\".*/\1/' } -function get_api_gateway_endpoint() { - python get_api_gateway_endpoint.py -} - function print_endpoints_gcp() { echo "" diff --git a/pkg/operator/config/config.go b/pkg/operator/config/config.go index 78d27194c0..85eccfd52e 100644 --- a/pkg/operator/config/config.go +++ b/pkg/operator/config/config.go @@ -34,7 +34,6 @@ import ( ) const _clusterConfigPath = "/configs/cluster/cluster.yaml" -const _clusterConfigBackupPath = "/configs/cluster-aws/cluster-aws.yaml" var ( Provider types.ProviderType @@ -84,34 +83,6 @@ func Init() error { } Cluster.OperatorID = hashedAccountID Cluster.ClusterID = hash.String(Cluster.ClusterName + *Cluster.Region + hashedAccountID) - - if Cluster.APIGatewaySetting == clusterconfig.PublicAPIGatewaySetting { - apiGateway, err := AWS.GetAPIGatewayByTag(clusterconfig.ClusterNameTag, Cluster.ClusterName) - if err != nil { - return err - } else if apiGateway == nil { - return ErrorNoAPIGateway() - } - Cluster.APIGateway = apiGateway - - if Cluster.APILoadBalancerScheme == clusterconfig.InternalLoadBalancerScheme { - vpcLink, err := AWS.GetVPCLinkByTag(clusterconfig.ClusterNameTag, Cluster.ClusterName) - if err != nil { - return err - } else if vpcLink == nil { - return ErrorNoVPCLink() - } - Cluster.VPCLink = vpcLink - - integration, err := AWS.GetVPCLinkIntegration(*Cluster.APIGateway.ApiId, *Cluster.VPCLink.VpcLinkId) - if err != nil { - return err - } else if integration == nil { - return ErrorNoVPCLinkIntegration() - } - Cluster.VPCLinkIntegration = integration - } - } } else { AWS, err = aws.NewAnonymousClient() if err != nil { diff --git a/pkg/operator/config/errors.go b/pkg/operator/config/errors.go deleted file mode 100644 index 67fc3cb35b..0000000000 --- a/pkg/operator/config/errors.go +++ /dev/null @@ -1,48 +0,0 @@ -/* -Copyright 2020 Cortex Labs, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package config - -import ( - "github.com/cortexlabs/cortex/pkg/lib/errors" -) - -const ( - ErrNoAPIGateway = "config.no_api_gateway" - ErrNoVPCLink = "config.no_vpc_link" - ErrNoVPCLinkIntegration = "config.no_vpc_link_integration" -) - -func ErrorNoAPIGateway() error { - return errors.WithStack(&errors.Error{ - Kind: ErrNoAPIGateway, - Message: "unable to locate cortex's api gateway", - }) -} - -func ErrorNoVPCLink() error { - return errors.WithStack(&errors.Error{ - Kind: ErrNoVPCLink, - Message: "unable to locate cortex's vpc link", - }) -} - -func ErrorNoVPCLinkIntegration() error { - return errors.WithStack(&errors.Error{ - Kind: ErrNoVPCLinkIntegration, - Message: "unable to locate cortex's api gateway vpc link integration", - }) -} diff --git a/pkg/operator/operator/gateway.go b/pkg/operator/operator/gateway.go deleted file mode 100644 index 1828da75b6..0000000000 --- a/pkg/operator/operator/gateway.go +++ /dev/null @@ -1,173 +0,0 @@ -/* -Copyright 2020 Cortex Labs, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package operator - -import ( - "github.com/cortexlabs/cortex/pkg/lib/aws" - "github.com/cortexlabs/cortex/pkg/lib/urls" - "github.com/cortexlabs/cortex/pkg/operator/config" - "github.com/cortexlabs/cortex/pkg/types/clusterconfig" - "github.com/cortexlabs/cortex/pkg/types/spec" - "github.com/cortexlabs/cortex/pkg/types/userconfig" - istioclientnetworking "istio.io/client-go/pkg/apis/networking/v1beta1" -) - -func AddAPIToAPIGateway(endpoint string, apiGatewayType userconfig.APIGatewayType) error { - if config.Cluster.APIGateway == nil { - return nil - } - - if apiGatewayType == userconfig.NoneAPIGatewayType { - return nil - } - - apiGatewayID := *config.Cluster.APIGateway.ApiId - - // check if API Gateway route already exists - existingRoute, err := config.AWS.GetRoute(apiGatewayID, endpoint) - if err != nil { - return err - } else if existingRoute != nil { - return nil - } - - if config.Cluster.APILoadBalancerScheme == clusterconfig.InternalLoadBalancerScheme { - err = config.AWS.CreateRoute(apiGatewayID, *config.Cluster.VPCLinkIntegration.IntegrationId, endpoint) - if err != nil { - return err - } - } - - if config.Cluster.APILoadBalancerScheme == clusterconfig.InternetFacingLoadBalancerScheme { - loadBalancerURL, err := APILoadBalancerURL() - if err != nil { - return err - } - - targetEndpoint := urls.Join(loadBalancerURL, endpoint) - - integrationID, err := config.AWS.CreateHTTPIntegration(apiGatewayID, targetEndpoint) - if err != nil { - return err - } - - err = config.AWS.CreateRoute(apiGatewayID, integrationID, endpoint) - if err != nil { - return err - } - } - - return nil -} - -func RemoveAPIFromAPIGateway(endpoint string, apiGatewayType userconfig.APIGatewayType) error { - if config.Cluster.APIGateway == nil { - return nil - } - - if apiGatewayType == userconfig.NoneAPIGatewayType { - return nil - } - - apiGatewayID := *config.Cluster.APIGateway.ApiId - - route, err := config.AWS.DeleteRoute(apiGatewayID, endpoint) - if err != nil { - return err - } - - if config.Cluster.APILoadBalancerScheme == clusterconfig.InternetFacingLoadBalancerScheme && route != nil { - integrationID := aws.ExtractRouteIntegrationID(route) - if integrationID != "" { - err = config.AWS.DeleteIntegration(apiGatewayID, integrationID) - if err != nil { - return err - } - } - } - - return nil -} - -func UpdateAPIGateway( - prevEndpoint string, - prevAPIGatewayType userconfig.APIGatewayType, - newEndpoint string, - newAPIGatewayType userconfig.APIGatewayType, -) error { - if config.Cluster.APIGateway == nil { - return nil - } - - if prevAPIGatewayType == userconfig.NoneAPIGatewayType && newAPIGatewayType == userconfig.NoneAPIGatewayType { - return nil - } - - if prevAPIGatewayType == userconfig.PublicAPIGatewayType && newAPIGatewayType == userconfig.NoneAPIGatewayType { - return RemoveAPIFromAPIGateway(prevEndpoint, prevAPIGatewayType) - } - - if prevAPIGatewayType == userconfig.NoneAPIGatewayType && newAPIGatewayType == userconfig.PublicAPIGatewayType { - return AddAPIToAPIGateway(newEndpoint, newAPIGatewayType) - } - - if prevEndpoint == newEndpoint { - return nil - } - - // the endpoint has changed - if err := AddAPIToAPIGateway(newEndpoint, newAPIGatewayType); err != nil { - return err - } - if err := RemoveAPIFromAPIGateway(prevEndpoint, prevAPIGatewayType); err != nil { - return err - } - - return nil -} - -func RemoveAPIFromAPIGatewayK8s(virtualService *istioclientnetworking.VirtualService) error { - if virtualService == nil { - return nil // API is not running - } - - apiGatewayType, err := userconfig.APIGatewayFromAnnotations(virtualService) - if err != nil { - return err - } - - endpoint, err := GetEndpointFromVirtualService(virtualService) - if err != nil { - return err - } - - return RemoveAPIFromAPIGateway(endpoint, apiGatewayType) -} - -func UpdateAPIGatewayK8s(prevVirtualService *istioclientnetworking.VirtualService, newAPI *spec.API) error { - prevAPIGatewayType, err := userconfig.APIGatewayFromAnnotations(prevVirtualService) - if err != nil { - return err - } - - prevEndpoint, err := GetEndpointFromVirtualService(prevVirtualService) - if err != nil { - return err - } - - return UpdateAPIGateway(prevEndpoint, prevAPIGatewayType, *newAPI.Networking.Endpoint, newAPI.Networking.APIGateway) -} diff --git a/pkg/operator/operator/k8s.go b/pkg/operator/operator/k8s.go index 6bb1196bcc..7f11248550 100644 --- a/pkg/operator/operator/k8s.go +++ b/pkg/operator/operator/k8s.go @@ -979,15 +979,11 @@ func APIEndpoint(api *spec.API) (string, error) { var err error baseAPIEndpoint := "" - if config.Provider == types.AWSProviderType && api.Networking.APIGateway == userconfig.PublicAPIGatewayType && config.Cluster.APIGateway != nil { - baseAPIEndpoint = *config.Cluster.APIGateway.ApiEndpoint - } else { - baseAPIEndpoint, err = APILoadBalancerURL() - if err != nil { - return "", err - } - baseAPIEndpoint = strings.Replace(baseAPIEndpoint, "https://", "http://", 1) + baseAPIEndpoint, err = APILoadBalancerURL() + if err != nil { + return "", err } + baseAPIEndpoint = strings.Replace(baseAPIEndpoint, "https://", "http://", 1) return urls.Join(baseAPIEndpoint, *api.Networking.Endpoint), nil } diff --git a/pkg/operator/resources/batchapi/api.go b/pkg/operator/resources/batchapi/api.go index 8d3ea44a5e..9984ffecdf 100644 --- a/pkg/operator/resources/batchapi/api.go +++ b/pkg/operator/resources/batchapi/api.go @@ -58,17 +58,6 @@ func UpdateAPI(apiConfig *userconfig.API, projectID string) (*spec.API, string, return nil, "", err } - err = operator.AddAPIToAPIGateway(*api.Networking.Endpoint, api.Networking.APIGateway) - if err != nil { - routines.RunWithPanicHandler(func() { - deleteK8sResources(api.Name) - }, false) - routines.RunWithPanicHandler(func() { - operator.RemoveAPIFromAPIGateway(*api.Networking.Endpoint, api.Networking.APIGateway) - }, false) - return nil, "", err - } - err := ensureLogGroupForAPI(api.Name) if err != nil { return nil, "", err @@ -87,10 +76,6 @@ func UpdateAPI(apiConfig *userconfig.API, projectID string) (*spec.API, string, return nil, "", err } - if err := operator.UpdateAPIGatewayK8s(prevVirtualService, api); err != nil { - return nil, "", err - } - return api, fmt.Sprintf("updated %s", api.Resource.UserString()), nil } @@ -99,12 +84,7 @@ func UpdateAPI(apiConfig *userconfig.API, projectID string) (*spec.API, string, func DeleteAPI(apiName string, keepCache bool) error { // best effort deletion, so don't handle error yet - virtualService, vsErr := config.K8s.GetVirtualService(operator.K8sName(apiName)) - err := parallel.RunFirstErr( - func() error { - return vsErr - }, func() error { return deleteK8sResources(apiName) }, @@ -117,14 +97,6 @@ func DeleteAPI(apiName string, keepCache bool) error { func() error { return config.AWS.DeleteQueuesWithPrefix(apiQueueNamePrefix(apiName)) }, - func() error { - err := operator.RemoveAPIFromAPIGatewayK8s(virtualService) - if err != nil { - return err - } - - return nil - }, ) if err != nil { diff --git a/pkg/operator/resources/errors.go b/pkg/operator/resources/errors.go index 4b658e7203..31f4c5ed55 100644 --- a/pkg/operator/resources/errors.go +++ b/pkg/operator/resources/errors.go @@ -35,7 +35,6 @@ const ( ErrJobIDRequired = "resources.job_id_required" ErrRealtimeAPIUsedByTrafficSplitter = "resources.realtime_api_used_by_traffic_splitter" ErrAPIsNotDeployed = "resources.apis_not_deployed" - ErrAPIGatewayDisabled = "resources.api_gateway_disabled" ) func ErrorOperationIsOnlySupportedForKind(resource operator.DeployedResource, supportedKind userconfig.Kind, supportedKinds ...userconfig.Kind) error { @@ -101,10 +100,3 @@ func ErrorAPIsNotDeployed(notDeployedAPIs []string) error { Message: message, }) } - -func ErrorAPIGatewayDisabled(apiGatewayType userconfig.APIGatewayType) error { - return errors.WithStack(&errors.Error{ - Kind: ErrAPIGatewayDisabled, - Message: fmt.Sprintf("%s is not permitted because api gateway is disabled cluster-wide (valid values are %s)", s.UserStr(apiGatewayType), s.UserStrsAnd(userconfig.APIGatewayTypeStrings())), - }) -} diff --git a/pkg/operator/resources/realtimeapi/api.go b/pkg/operator/resources/realtimeapi/api.go index ef52006798..c903f20134 100644 --- a/pkg/operator/resources/realtimeapi/api.go +++ b/pkg/operator/resources/realtimeapi/api.go @@ -75,13 +75,6 @@ func UpdateAPI(apiConfig *userconfig.API, projectID string, force bool) (*spec.A } if config.Provider == types.AWSProviderType { - err = operator.AddAPIToAPIGateway(*api.Networking.Endpoint, api.Networking.APIGateway) - if err != nil { - routines.RunWithPanicHandler(func() { - deleteK8sResources(api.Name) - }, false) - return nil, "", err - } err = addAPIToDashboard(config.Cluster.ClusterName, api.Name) if err != nil { errors.PrintError(err) @@ -112,11 +105,6 @@ func UpdateAPI(apiConfig *userconfig.API, projectID string, force bool) (*spec.A if err := applyK8sResources(api, prevDeployment, prevService, prevVirtualService); err != nil { return nil, "", err } - if config.Provider == types.AWSProviderType { - if err := operator.UpdateAPIGatewayK8s(prevVirtualService, api); err != nil { - return nil, "", err - } - } return api, fmt.Sprintf("updating %s", api.Resource.UserString()), nil } @@ -177,13 +165,7 @@ func RefreshAPI(apiName string, force bool) (string, error) { } func DeleteAPI(apiName string, keepCache bool) error { - // best effort deletion, so don't handle error yet - virtualService, vsErr := config.K8s.GetVirtualService(operator.K8sName(apiName)) - err := parallel.RunFirstErr( - func() error { - return vsErr - }, func() error { return deleteK8sResources(apiName) }, @@ -195,13 +177,6 @@ func DeleteAPI(apiName string, keepCache bool) error { deleteBucketResources(apiName) return nil }, - // delete API from API Gateway - func() error { - if config.Provider == types.AWSProviderType { - return operator.RemoveAPIFromAPIGatewayK8s(virtualService) - } - return nil - }, // delete api from cloudwatch dashboard func() error { if config.Provider == types.AWSProviderType { diff --git a/pkg/operator/resources/trafficsplitter/api.go b/pkg/operator/resources/trafficsplitter/api.go index a4d0654cab..578d0d6723 100644 --- a/pkg/operator/resources/trafficsplitter/api.go +++ b/pkg/operator/resources/trafficsplitter/api.go @@ -51,13 +51,6 @@ func UpdateAPI(apiConfig *userconfig.API, force bool) (*spec.API, string, error) return nil, "", err } - err = operator.AddAPIToAPIGateway(*api.Networking.Endpoint, api.Networking.APIGateway) - if err != nil { - routines.RunWithPanicHandler(func() { - deleteK8sResources(api.Name) - }, false) - return nil, "", err - } return api, fmt.Sprintf("created %s", api.Resource.UserString()), nil } @@ -70,9 +63,6 @@ func UpdateAPI(apiConfig *userconfig.API, force bool) (*spec.API, string, error) return nil, "", err } - if err := operator.UpdateAPIGatewayK8s(prevVirtualService, api); err != nil { - return nil, "", err - } return api, fmt.Sprintf("updated %s", api.Resource.UserString()), nil } @@ -80,12 +70,7 @@ func UpdateAPI(apiConfig *userconfig.API, force bool) (*spec.API, string, error) } func DeleteAPI(apiName string, keepCache bool) error { - // best effort deletion, so don't handle error yet - virtualService, vsErr := config.K8s.GetVirtualService(operator.K8sName(apiName)) err := parallel.RunFirstErr( - func() error { - return vsErr - }, func() error { return deleteK8sResources(apiName) }, @@ -97,14 +82,6 @@ func DeleteAPI(apiName string, keepCache bool) error { deleteS3Resources(apiName) return nil }, - // delete API from API Gateway - func() error { - err := operator.RemoveAPIFromAPIGatewayK8s(virtualService) - if err != nil { - return err - } - return nil - }, ) if err != nil { diff --git a/pkg/operator/resources/validations.go b/pkg/operator/resources/validations.go index 1b4babd7be..a078258187 100644 --- a/pkg/operator/resources/validations.go +++ b/pkg/operator/resources/validations.go @@ -29,7 +29,6 @@ import ( "github.com/cortexlabs/cortex/pkg/operator/config" "github.com/cortexlabs/cortex/pkg/operator/operator" "github.com/cortexlabs/cortex/pkg/types" - "github.com/cortexlabs/cortex/pkg/types/clusterconfig" "github.com/cortexlabs/cortex/pkg/types/spec" "github.com/cortexlabs/cortex/pkg/types/userconfig" istioclientnetworking "istio.io/client-go/pkg/apis/networking/v1beta1" @@ -125,10 +124,6 @@ func ValidateClusterAPIs(apis []userconfig.API, projectFiles spec.ProjectFiles) return errors.Wrap(err, api.Identify()) } } - - if config.Provider == types.AWSProviderType && api.Networking.APIGateway != userconfig.NoneAPIGatewayType && config.Cluster.APIGatewaySetting == clusterconfig.NoneAPIGatewaySetting { - return errors.Wrap(ErrorAPIGatewayDisabled(api.Networking.APIGateway), api.Identify(), userconfig.NetworkingKey, userconfig.APIGatewayKey) - } } dups := spec.FindDuplicateNames(apis) diff --git a/pkg/types/clusterconfig/api_gateway_setting.go b/pkg/types/clusterconfig/api_gateway_setting.go deleted file mode 100644 index 2546bbd612..0000000000 --- a/pkg/types/clusterconfig/api_gateway_setting.go +++ /dev/null @@ -1,75 +0,0 @@ -/* -Copyright 2020 Cortex Labs, Inc. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package clusterconfig - -type APIGatewaySetting int - -const ( - UnknownAPIGatewaySetting APIGatewaySetting = iota - PublicAPIGatewaySetting - NoneAPIGatewaySetting -) - -var _apiGatewaySettings = []string{ - "unknown", - "public", - "none", -} - -func APIGatewaySettingFromString(s string) APIGatewaySetting { - for i := 0; i < len(_apiGatewaySettings); i++ { - if s == _apiGatewaySettings[i] { - return APIGatewaySetting(i) - } - } - return UnknownAPIGatewaySetting -} - -func APIGatewaySettingStrings() []string { - return _apiGatewaySettings[1:] -} - -func (t APIGatewaySetting) String() string { - return _apiGatewaySettings[t] -} - -// MarshalText satisfies TextMarshaler -func (t APIGatewaySetting) MarshalText() ([]byte, error) { - return []byte(t.String()), nil -} - -// UnmarshalText satisfies TextUnmarshaler -func (t *APIGatewaySetting) UnmarshalText(text []byte) error { - enum := string(text) - for i := 0; i < len(_apiGatewaySettings); i++ { - if enum == _apiGatewaySettings[i] { - *t = APIGatewaySetting(i) - return nil - } - } - - *t = UnknownAPIGatewaySetting - return nil -} - -// UnmarshalBinary satisfies BinaryUnmarshaler -// Needed for msgpack -func (t *APIGatewaySetting) UnmarshalBinary(data []byte) error { - return t.UnmarshalText(data) -} - -// MarshalBinary satisfies BinaryMarshaler -func (t APIGatewaySetting) MarshalBinary() ([]byte, error) { - return []byte(t.String()), nil -} diff --git a/pkg/types/clusterconfig/cluster_config_aws.go b/pkg/types/clusterconfig/cluster_config_aws.go index 2b131af6d0..c34dc090a5 100644 --- a/pkg/types/clusterconfig/cluster_config_aws.go +++ b/pkg/types/clusterconfig/cluster_config_aws.go @@ -26,7 +26,6 @@ import ( "strings" "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/apigatewayv2" "github.com/cortexlabs/cortex/pkg/consts" "github.com/cortexlabs/cortex/pkg/lib/aws" cr "github.com/cortexlabs/cortex/pkg/lib/configreader" @@ -72,7 +71,6 @@ type Config struct { NATGateway NATGateway `json:"nat_gateway" yaml:"nat_gateway"` APILoadBalancerScheme LoadBalancerScheme `json:"api_load_balancer_scheme" yaml:"api_load_balancer_scheme"` OperatorLoadBalancerScheme LoadBalancerScheme `json:"operator_load_balancer_scheme" yaml:"operator_load_balancer_scheme"` - APIGatewaySetting APIGatewaySetting `json:"api_gateway" yaml:"api_gateway"` VPCCIDR *string `json:"vpc_cidr,omitempty" yaml:"vpc_cidr,omitempty"` Telemetry bool `json:"telemetry" yaml:"telemetry"` ImageOperator string `json:"image_operator" yaml:"image_operator"` @@ -103,14 +101,11 @@ type InternalConfig struct { Config // Populated by operator - APIVersion string `json:"api_version"` - OperatorID string `json:"operator_id"` - ClusterID string `json:"cluster_id"` - IsOperatorInCluster bool `json:"is_operator_in_cluster"` - InstanceMetadata aws.InstanceMetadata `json:"instance_metadata"` - APIGateway *apigatewayv2.Api `json:"api_gateway"` - VPCLink *apigatewayv2.VpcLink `json:"vpc_link"` - VPCLinkIntegration *apigatewayv2.Integration `json:"vpc_link_integration"` + APIVersion string `json:"api_version"` + OperatorID string `json:"operator_id"` + ClusterID string `json:"cluster_id"` + IsOperatorInCluster bool `json:"is_operator_in_cluster"` + InstanceMetadata aws.InstanceMetadata `json:"instance_metadata"` } // The bare minimum to identify a cluster @@ -344,16 +339,6 @@ var UserValidation = &cr.StructValidation{ return LoadBalancerSchemeFromString(str), nil }, }, - { - StructField: "APIGatewaySetting", - StringValidation: &cr.StringValidation{ - AllowedValues: APIGatewaySettingStrings(), - Default: PublicAPIGatewaySetting.String(), - }, - Parser: func(str string) (interface{}, error) { - return APIGatewaySettingFromString(str), nil - }, - }, { StructField: "VPCCIDR", StringPtrValidation: &cr.StringPtrValidation{ @@ -617,7 +602,7 @@ func (cc *Config) Validate(awsClient *aws.Client) error { } if cc.Spot != nil && *cc.Spot { - cc.FillEmptySpotFields(awsClient) + cc.FillEmptySpotFields() primaryInstance := aws.InstanceMetadatas[*cc.Region][primaryInstanceType] @@ -740,7 +725,7 @@ func CheckSpotInstancePriceCompatibility(target aws.InstanceMetadata, suggested return nil } -func AutoGenerateSpotConfig(awsClient *aws.Client, spotConfig *SpotConfig, region string, instanceType string) error { +func AutoGenerateSpotConfig(spotConfig *SpotConfig, region string, instanceType string) { primaryInstance := aws.InstanceMetadatas[region][instanceType] cleanedDistribution := []string{instanceType} for _, spotInstance := range spotConfig.InstanceDistribution { @@ -773,19 +758,13 @@ func AutoGenerateSpotConfig(awsClient *aws.Client, spotConfig *SpotConfig, regio spotConfig.InstancePools = pointer.Int64(int64(_maxInstancePools)) } } - - return nil } -func (cc *Config) FillEmptySpotFields(awsClient *aws.Client) error { +func (cc *Config) FillEmptySpotFields() { if cc.SpotConfig == nil { cc.SpotConfig = &SpotConfig{} } - err := AutoGenerateSpotConfig(awsClient, cc.SpotConfig, *cc.Region, *cc.InstanceType) - if err != nil { - return err - } - return nil + AutoGenerateSpotConfig(cc.SpotConfig, *cc.Region, *cc.InstanceType) } func applyPromptDefaults(defaults Config) *Config { @@ -1141,7 +1120,6 @@ func (cc *Config) UserTable() table.KeyValuePairs { items.Add(NATGatewayUserKey, cc.NATGateway) items.Add(APILoadBalancerSchemeUserKey, cc.APILoadBalancerScheme) items.Add(OperatorLoadBalancerSchemeUserKey, cc.OperatorLoadBalancerScheme) - items.Add(APIGatewaySettingUserKey, cc.APIGatewaySetting) if cc.VPCCIDR != nil { items.Add(VPCCIDRKey, *cc.VPCCIDR) } @@ -1216,7 +1194,6 @@ func (cc *Config) TelemetryEvent() map[string]interface{} { event["nat_gateway"] = cc.NATGateway event["api_load_balancer_scheme"] = cc.APILoadBalancerScheme event["operator_load_balancer_scheme"] = cc.OperatorLoadBalancerScheme - event["api_gateway"] = cc.APIGatewaySetting if cc.VPCCIDR != nil { event["vpc_cidr._is_defined"] = true } diff --git a/pkg/types/clusterconfig/config_key.go b/pkg/types/clusterconfig/config_key.go index f65d8226f7..8f8fa35fee 100644 --- a/pkg/types/clusterconfig/config_key.go +++ b/pkg/types/clusterconfig/config_key.go @@ -47,7 +47,6 @@ const ( NATGatewayKey = "nat_gateway" APILoadBalancerSchemeKey = "api_load_balancer_scheme" OperatorLoadBalancerSchemeKey = "operator_load_balancer_scheme" - APIGatewaySettingKey = "api_gateway" VPCCIDRKey = "vpc_cidr" TelemetryKey = "telemetry" ImageOperatorKey = "image_operator" @@ -96,7 +95,6 @@ const ( NATGatewayUserKey = "nat gateway" APILoadBalancerSchemeUserKey = "api load balancer scheme" OperatorLoadBalancerSchemeUserKey = "operator load balancer scheme" - APIGatewaySettingUserKey = "api gateway" VPCCIDRUserKey = "vpc cidr" TelemetryUserKey = "telemetry" ImageOperatorUserKey = "operator image" diff --git a/pkg/types/spec/validations.go b/pkg/types/spec/validations.go index 4f2c8cd9f8..5ca1ba5ba0 100644 --- a/pkg/types/spec/validations.go +++ b/pkg/types/spec/validations.go @@ -263,35 +263,6 @@ func networkingValidation( }, } - if provider == types.AWSProviderType || provider == types.LocalProviderType { - defaultAPIGatewayType := userconfig.PublicAPIGatewayType - if awsClusterConfig != nil && awsClusterConfig.APIGatewaySetting == clusterconfig.NoneAPIGatewaySetting { - defaultAPIGatewayType = userconfig.NoneAPIGatewayType - } - - structFieldValidation = append(structFieldValidation, &cr.StructFieldValidation{ - StructField: "APIGateway", - StringValidation: &cr.StringValidation{ - AllowedValues: userconfig.APIGatewayTypeStrings(), - Default: defaultAPIGatewayType.String(), - }, - Parser: func(str string) (interface{}, error) { - return userconfig.APIGatewayTypeFromString(str), nil - }, - }) - } else { - structFieldValidation = append(structFieldValidation, &cr.StructFieldValidation{ - StructField: "APIGateway", - StringValidation: &cr.StringValidation{ - CantBeSpecifiedErrStr: pointer.String("only supported on AWS clusters"), - Default: userconfig.NoneAPIGatewayType.String(), - }, - Parser: func(str string) (interface{}, error) { - return userconfig.APIGatewayTypeFromString(str), nil - }, - }) - } - if kind == userconfig.RealtimeAPIKind { structFieldValidation = append(structFieldValidation, &cr.StructFieldValidation{ StructField: "LocalPort", diff --git a/pkg/types/userconfig/api.go b/pkg/types/userconfig/api.go index 74ff3f2b0d..027c2726a8 100644 --- a/pkg/types/userconfig/api.go +++ b/pkg/types/userconfig/api.go @@ -88,9 +88,8 @@ type ServerSideBatching struct { } type Networking struct { - Endpoint *string `json:"endpoint" yaml:"endpoint"` - LocalPort *int `json:"local_port" yaml:"local_port"` - APIGateway APIGatewayType `json:"api_gateway" yaml:"api_gateway"` + Endpoint *string `json:"endpoint" yaml:"endpoint"` + LocalPort *int `json:"local_port" yaml:"local_port"` } type Compute struct { @@ -201,7 +200,6 @@ func (api *API) ToK8sAnnotations() map[string]string { if api.Networking != nil { annotations[EndpointAnnotationKey] = *api.Networking.Endpoint - annotations[APIGatewayAnnotationKey] = api.Networking.APIGateway.String() } if api.Autoscaling != nil { @@ -220,14 +218,6 @@ func (api *API) ToK8sAnnotations() map[string]string { return annotations } -func APIGatewayFromAnnotations(k8sObj kmeta.Object) (APIGatewayType, error) { - apiGatewayType := APIGatewayTypeFromString(k8sObj.GetAnnotations()[APIGatewayAnnotationKey]) - if apiGatewayType == UnknownAPIGatewayType { - return UnknownAPIGatewayType, ErrorUnknownAPIGatewayType() - } - return apiGatewayType, nil -} - func AutoscalingFromAnnotations(k8sObj kmeta.Object) (*Autoscaling, error) { a := Autoscaling{} @@ -450,9 +440,6 @@ func (networking *Networking) UserStr(provider types.ProviderType) string { if provider != types.LocalProviderType && networking.Endpoint != nil { sb.WriteString(fmt.Sprintf("%s: %s\n", EndpointKey, *networking.Endpoint)) } - if provider == types.AWSProviderType { - sb.WriteString(fmt.Sprintf("%s: %s\n", APIGatewayKey, networking.APIGateway)) - } return sb.String() } @@ -576,7 +563,6 @@ func (api *API) TelemetryEvent(provider types.ProviderType) map[string]interface if api.Networking != nil { event["networking._is_defined"] = true - event["networking.api_gateway"] = api.Networking.APIGateway if api.Networking.Endpoint != nil { event["networking.endpoint._is_defined"] = true if urls.CanonicalizeEndpoint(api.Name) != *api.Networking.Endpoint { diff --git a/pkg/types/userconfig/api_gateway_type.go b/pkg/types/userconfig/api_gateway_type.go deleted file mode 100644 index 6b3cdacf29..0000000000 --- a/pkg/types/userconfig/api_gateway_type.go +++ /dev/null @@ -1,78 +0,0 @@ -/* -Copyright 2020 Cortex Labs, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package userconfig - -type APIGatewayType int - -const ( - UnknownAPIGatewayType APIGatewayType = iota - PublicAPIGatewayType - NoneAPIGatewayType -) - -var _apiGatewayTypes = []string{ - "unknown", - "public", - "none", -} - -func APIGatewayTypeFromString(s string) APIGatewayType { - for i := 0; i < len(_apiGatewayTypes); i++ { - if s == _apiGatewayTypes[i] { - return APIGatewayType(i) - } - } - return UnknownAPIGatewayType -} - -func APIGatewayTypeStrings() []string { - return _apiGatewayTypes[1:] -} - -func (t APIGatewayType) String() string { - return _apiGatewayTypes[t] -} - -// MarshalText satisfies TextMarshaler -func (t APIGatewayType) MarshalText() ([]byte, error) { - return []byte(t.String()), nil -} - -// UnmarshalText satisfies TextUnmarshaler -func (t *APIGatewayType) UnmarshalText(text []byte) error { - enum := string(text) - for i := 0; i < len(_apiGatewayTypes); i++ { - if enum == _apiGatewayTypes[i] { - *t = APIGatewayType(i) - return nil - } - } - - *t = UnknownAPIGatewayType - return nil -} - -// UnmarshalBinary satisfies BinaryUnmarshaler -// Needed for msgpack -func (t *APIGatewayType) UnmarshalBinary(data []byte) error { - return t.UnmarshalText(data) -} - -// MarshalBinary satisfies BinaryMarshaler -func (t APIGatewayType) MarshalBinary() ([]byte, error) { - return []byte(t.String()), nil -} diff --git a/pkg/types/userconfig/config_key.go b/pkg/types/userconfig/config_key.go index f0a651374e..154c06cfa3 100644 --- a/pkg/types/userconfig/config_key.go +++ b/pkg/types/userconfig/config_key.go @@ -64,9 +64,8 @@ const ( ModelsNameKey = "name" // Networking - APIGatewayKey = "api_gateway" - EndpointKey = "endpoint" - LocalPortKey = "local_port" + EndpointKey = "endpoint" + LocalPortKey = "local_port" // Compute CPUKey = "cpu" @@ -94,7 +93,6 @@ const ( // K8s annotation EndpointAnnotationKey = "networking.cortex.dev/endpoint" - APIGatewayAnnotationKey = "networking.cortex.dev/api-gateway" ProcessesPerReplicaAnnotationKey = "predictor.cortex.dev/processes-per-replica" ThreadsPerProcessAnnotationKey = "predictor.cortex.dev/threads-per-process" MinReplicasAnnotationKey = "autoscaling.cortex.dev/min-replicas" diff --git a/pkg/types/userconfig/errors.go b/pkg/types/userconfig/errors.go deleted file mode 100644 index ae752120a8..0000000000 --- a/pkg/types/userconfig/errors.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright 2020 Cortex Labs, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package userconfig - -import ( - "github.com/cortexlabs/cortex/pkg/lib/errors" -) - -const ( - ErrUnknownAPIGatewayType = "userconfig.unknown_api_gateway_type" -) - -func ErrorUnknownAPIGatewayType() error { - return errors.WithStack(&errors.Error{ - Kind: ErrUnknownAPIGatewayType, - Message: "unknown api gateway type", - }) -}