Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions cli/cmd/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"os"
"time"

"github.com/cortexlabs/cortex/pkg/lib/aws"
cr "github.com/cortexlabs/cortex/pkg/lib/configreader"
"github.com/cortexlabs/cortex/pkg/lib/errors"
"github.com/cortexlabs/cortex/pkg/lib/exit"
Expand Down Expand Up @@ -110,6 +111,17 @@ var _upCmd = &cobra.Command{
if err != nil {
exit.Error(err)
}

err = CreateBucketIfNotFound(awsClient, clusterConfig.Bucket)
if err != nil {
exit.Error(err)
}

err = CreateLogGroupIfNotFound(awsClient, clusterConfig.LogGroup)
if err != nil {
exit.Error(err)
}

out, exitCode, err := runManagerUpdateCommand("/root/install.sh", clusterConfig, awsCreds)
if err != nil {
exit.Error(err)
Expand Down Expand Up @@ -452,3 +464,40 @@ func assertClusterStatus(accessConfig *clusterconfig.AccessConfig, status cluste
func getCloudFormationURLWithAccessConfig(accessConfig *clusterconfig.AccessConfig) string {
return getCloudFormationURL(*accessConfig.ClusterName, *accessConfig.Region)
}

func CreateBucketIfNotFound(awsClient *aws.Client, bucket string) error {
bucketFound, err := awsClient.DoesBucketExist(bucket)
if err != nil {
return err
}
if !bucketFound {
fmt.Print("○ creating a new s3 bucket: ", bucket)
err = awsClient.CreateBucket(bucket)
if err != nil {
return err
}
fmt.Println(" ✓")
} else {
fmt.Println("○ using existing s3 bucket:", bucket, "✓")
}
return nil
}

func CreateLogGroupIfNotFound(awsClient *aws.Client, logGroup string) error {
logGroupFound, err := awsClient.DoesLogGroupExist(logGroup)
if err != nil {
return err
}
if !logGroupFound {
fmt.Print("○ creating a new cloudwatch log group: ", logGroup)
err = awsClient.CreateLogGroup(logGroup)
if err != nil {
return err
}
fmt.Println(" ✓")
} else {
fmt.Println("○ using existing cloudwatch log group:", logGroup, "✓")
}

return nil
}
5 changes: 5 additions & 0 deletions cli/cmd/lib_cluster_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,11 @@ func getClusterUpdateConfig(cachedClusterConfig clusterconfig.Config, awsCreds A
}
userClusterConfig.Bucket = cachedClusterConfig.Bucket

if userClusterConfig.LogGroup != "" && userClusterConfig.LogGroup != cachedClusterConfig.LogGroup {
return nil, clusterconfig.ErrorConfigCannotBeChangedOnUpdate(clusterconfig.LogGroupKey, cachedClusterConfig.LogGroup)
}
userClusterConfig.LogGroup = cachedClusterConfig.LogGroup

if userClusterConfig.InstanceType != nil && *userClusterConfig.InstanceType != *cachedClusterConfig.InstanceType {
return nil, clusterconfig.ErrorConfigCannotBeChangedOnUpdate(clusterconfig.InstanceTypeKey, *cachedClusterConfig.InstanceType)
}
Expand Down
37 changes: 0 additions & 37 deletions manager/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,6 @@ function ensure_eks() {
function main() {
mkdir -p $CORTEX_CLUSTER_WORKSPACE

setup_bucket
setup_cloudwatch_logs

ensure_eks

eksctl utils write-kubeconfig --cluster=$CORTEX_CLUSTER_NAME --region=$CORTEX_REGION | grep -v "saved kubeconfig as" | grep -v "using region" | grep -v "eksctl version" || true
Expand Down Expand Up @@ -211,40 +208,6 @@ function main() {
echo -e "\ncortex is ready!"
}

function setup_bucket() {
if ! aws s3api head-bucket --bucket $CORTEX_BUCKET --output json 2>/dev/null; then
if aws s3 ls "s3://$CORTEX_BUCKET" --output json 2>&1 | grep -q 'NoSuchBucket'; then
echo -n "○ creating s3 bucket: $CORTEX_BUCKET "
if [ "$CORTEX_REGION" == "us-east-1" ]; then
aws s3api create-bucket --bucket $CORTEX_BUCKET \
--region $CORTEX_REGION \
>/dev/null
else
aws s3api create-bucket --bucket $CORTEX_BUCKET \
--region $CORTEX_REGION \
--create-bucket-configuration LocationConstraint=$CORTEX_REGION \
>/dev/null
fi
echo "✓"
else
echo "error: a bucket named \"${CORTEX_BUCKET}\" already exists, but you do not have access to it"
exit 1
fi
else
echo "○ using existing s3 bucket: $CORTEX_BUCKET"
fi
}

function setup_cloudwatch_logs() {
if ! aws logs list-tags-log-group --log-group-name $CORTEX_LOG_GROUP --region $CORTEX_REGION --output json 2>&1 | grep -q "\"tags\":"; then
echo -n "○ creating cloudwatch log group: $CORTEX_LOG_GROUP "
aws logs create-log-group --log-group-name $CORTEX_LOG_GROUP --region $CORTEX_REGION
echo "✓"
else
echo "○ using existing cloudwatch log group: $CORTEX_LOG_GROUP"
fi
}

function setup_configmap() {
kubectl -n=default create configmap 'cluster-config' \
--from-file='cluster.yaml'=$CORTEX_CLUSTER_CONFIG_FILE \
Expand Down
48 changes: 48 additions & 0 deletions pkg/lib/aws/cloudwatch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
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 aws

import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
"github.com/cortexlabs/cortex/pkg/lib/errors"
)

func (c *Client) DoesLogGroupExist(logGroup string) (bool, error) {
_, err := c.CloudWatchLogs().ListTagsLogGroup(&cloudwatchlogs.ListTagsLogGroupInput{
LogGroupName: aws.String(logGroup),
})
if err != nil {
if CheckErrCode(err, "ResourceNotFoundException") {
return false, nil
}
return false, errors.Wrap(err, "log group "+logGroup)
}

return true, nil
}

func (c *Client) CreateLogGroup(logGroup string) error {
_, err := c.CloudWatchLogs().CreateLogGroup(&cloudwatchlogs.CreateLogGroupInput{
LogGroupName: aws.String(logGroup),
})
if err != nil {
return errors.Wrap(err, "creating log group "+logGroup)
}

return nil
}
6 changes: 5 additions & 1 deletion pkg/lib/aws/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ func IsNoSuchBucketErr(err error) bool {
return CheckErrCode(err, "NoSuchBucket")
}

func IsForbiddenErr(err error) bool {
return CheckErrCode(err, "Forbidden")
}

func IsGenericNotFoundErr(err error) bool {
return IsNotFoundErr(err) || IsNoSuchKeyErr(err) || IsNoSuchBucketErr(err)
}
Expand Down Expand Up @@ -94,7 +98,7 @@ func ErrorAuth() error {
func ErrorBucketInaccessible(bucket string) error {
return errors.WithStack(&errors.Error{
Kind: ErrBucketInaccessible,
Message: fmt.Sprintf("bucket \"%s\" not found or insufficient permissions", bucket),
Message: fmt.Sprintf("bucket \"%s\" is not accessible with the specified AWS credentials", bucket),
})
}

Expand Down
38 changes: 38 additions & 0 deletions pkg/lib/aws/s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"strings"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/endpoints"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
Expand Down Expand Up @@ -429,6 +430,43 @@ func (c *Client) DeletePrefix(bucket string, prefix string, continueIfFailure bo
return nil
}

func (c *Client) CreateBucket(bucket string) error {
var bucketConfiguration *s3.CreateBucketConfiguration
if c.Region != "us-east-1" {
bucketConfiguration = &s3.CreateBucketConfiguration{
LocationConstraint: aws.String(c.Region),
}
}
_, err := c.S3().CreateBucket(&s3.CreateBucketInput{
Bucket: aws.String(bucket),
CreateBucketConfiguration: bucketConfiguration,
})
if err != nil {
return errors.Wrap(err, "creating bucket "+bucket)
}
return nil
}

// Checks bucket existence and accessibility with credentials
func (c *Client) DoesBucketExist(bucket string) (bool, error) {
_, err := c.S3().HeadBucket(&s3.HeadBucketInput{
Bucket: aws.String(bucket),
})
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
case "NotFound":
return false, nil
case "Forbidden":
return false, ErrorBucketInaccessible(bucket)
}
}
return false, errors.Wrap(err, "bucket "+bucket)
}

return true, nil
}

func GetBucketRegion(bucket string) (string, error) {
sess := session.Must(session.NewSession()) // credentials are not necessary for this request, and will not be used
region, err := s3manager.GetBucketRegion(aws.BackgroundContext(), sess, bucket, endpoints.UsWest2RegionID)
Expand Down