Skip to content

Commit 1bf7c9b

Browse files
authored
Miscellaneous UI improvements (#1065)
1 parent 2849c58 commit 1bf7c9b

File tree

10 files changed

+57
-57
lines changed

10 files changed

+57
-57
lines changed

cli/cmd/lib_cluster_config.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func readCachedClusterConfigFile(clusterConfig *clusterconfig.Config, filePath s
7474
func readUserClusterConfigFile(clusterConfig *clusterconfig.Config) error {
7575
errs := cr.ParseYAMLFile(clusterConfig, clusterconfig.UserValidation, _flagClusterConfig)
7676
if errors.HasError(errs) {
77-
return errors.FirstError(errs...)
77+
return errors.Append(errors.FirstError(errs...), fmt.Sprintf("\n\ncluster configuration schema can be found here: https://www.cortex.dev/v/%s/cluster-management/config", consts.CortexVersionMinor))
7878
}
7979

8080
return nil
@@ -89,7 +89,7 @@ func getClusterAccessConfig(disallowPrompt bool) (*clusterconfig.AccessConfig, e
8989
if _flagClusterConfig != "" {
9090
errs := cr.ParseYAMLFile(accessConfig, clusterconfig.AccessValidation, _flagClusterConfig)
9191
if errors.HasError(errs) {
92-
return nil, errors.FirstError(errs...)
92+
return nil, errors.Append(errors.FirstError(errs...), fmt.Sprintf("\n\ncluster configuration schema can be found here: https://www.cortex.dev/v/%s/cluster-management/config", consts.CortexVersionMinor))
9393
}
9494
}
9595

@@ -157,7 +157,7 @@ func getInstallClusterConfig(awsCreds AWSCredentials, envName string, disallowPr
157157
}
158158
promptIfNotAdmin(awsClient, disallowPrompt)
159159

160-
err = clusterconfig.InstallPrompt(clusterConfig, awsClient, disallowPrompt)
160+
err = clusterconfig.InstallPrompt(clusterConfig, disallowPrompt)
161161
if err != nil {
162162
return nil, err
163163
}

docs/cluster-management/spot-instances.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ spot: false
1212

1313
spot_config:
1414
# additional instances with identical or better specs than the primary instance type (defaults to only the primary instance)
15-
instance_distribution: [similar_instance_type_1, similar_instance_type_2]
15+
instance_distribution: # [similar_instance_type_1, similar_instance_type_2]
1616

1717
# minimum number of on demand instances (default: 0)
1818
on_demand_base_capacity: 0
@@ -22,7 +22,7 @@ spot_config:
2222
on_demand_percentage_above_base_capacity: 0
2323

2424
# max price for spot instances (default: the on-demand price of the primary instance type)
25-
max_price: <float>
25+
max_price: # <float>
2626

2727
# number of spot instance pools across which to allocate spot instances [1, 20] (default: number of instances in instance distribution)
2828
instance_pools: 3

pkg/lib/aws/ec2.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ func (c *Client) ListRegions() (strset.Set, strset.Set, error) {
128128
return allRegions, enabledRegions, nil
129129
}
130130

131-
func (c *Client) ListAvailabilityZones() (strset.Set, error) {
131+
func (c *Client) ListAvailabilityZonesInRegion() (strset.Set, error) {
132132
input := &ec2.DescribeAvailabilityZonesInput{
133133
Filters: []*ec2.Filter{
134134
{

pkg/lib/aws/s3.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ func (c *Client) ListS3Prefix(bucket string, prefix string, includeDirObjects bo
553553
})
554554

555555
if err != nil {
556-
return nil, err
556+
return nil, errors.Wrap(err, S3Path(bucket, prefix))
557557
}
558558

559559
return allObjects, nil

pkg/lib/files/files.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,10 +822,23 @@ func HashFile(path string, paths ...string) (string, error) {
822822
return "", err
823823
}
824824

825+
// Skip directories
826+
fileInfo, err := f.Stat()
827+
if err != nil {
828+
f.Close()
829+
return "", errors.WithStack(err)
830+
}
831+
if fileInfo.IsDir() {
832+
f.Close()
833+
continue
834+
}
835+
825836
if _, err := io.Copy(md5Hash, f); err != nil {
826837
f.Close()
827838
return "", errors.Wrap(err, path)
828839
}
840+
841+
io.WriteString(md5Hash, path)
829842
f.Close()
830843
}
831844

@@ -865,6 +878,7 @@ func HashDirectory(dir string, ignoreFns ...IgnoreFn) (string, error) {
865878
return errors.Wrap(err, path)
866879
}
867880

881+
io.WriteString(md5Hash, path)
868882
return nil
869883
})
870884

pkg/types/clusterconfig/availability_zones.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func (cc *Config) setDefaultAvailabilityZones(awsClient *aws.Client, extraInstan
4242
zones, err := awsClient.ListSupportedAvailabilityZones(*cc.InstanceType, extraInstances...)
4343
if err != nil {
4444
// Try again without checking instance types
45-
zones, err = awsClient.ListAvailabilityZones()
45+
zones, err = awsClient.ListAvailabilityZonesInRegion()
4646
if err != nil {
4747
return nil // Let eksctl choose the availability zones
4848
}
@@ -67,14 +67,14 @@ func (cc *Config) setDefaultAvailabilityZones(awsClient *aws.Client, extraInstan
6767
}
6868

6969
func (cc *Config) validateUserAvailabilityZones(awsClient *aws.Client, extraInstances ...string) error {
70-
allZones, err := awsClient.ListAvailabilityZones()
70+
allZones, err := awsClient.ListAvailabilityZonesInRegion()
7171
if err != nil {
7272
return nil // Skip validation
7373
}
7474

7575
for _, userZone := range cc.AvailabilityZones {
7676
if !allZones.Has(userZone) {
77-
return ErrorInvalidAvailabilityZone(userZone, allZones)
77+
return ErrorInvalidAvailabilityZone(userZone, allZones, awsClient.Region)
7878
}
7979
}
8080

pkg/types/clusterconfig/clusterconfig.go

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -498,9 +498,28 @@ func (cc *Config) Validate(awsClient *aws.Client) error {
498498
return ErrorNATRequiredWithPrivateSubnetVisibility()
499499
}
500500

501-
bucketRegion, _ := aws.GetBucketRegion(cc.Bucket)
502-
if bucketRegion != "" && bucketRegion != *cc.Region { // if the bucket didn't exist, we will create it in the correct region, so there is no error
503-
return ErrorS3RegionDiffersFromCluster(cc.Bucket, bucketRegion, *cc.Region)
501+
if cc.Bucket == "" {
502+
accountID, _, err := awsClient.GetCachedAccountID()
503+
if err != nil {
504+
return err
505+
}
506+
507+
bucketID := hash.String(accountID + *cc.Region)[:10]
508+
509+
defaultBucket := cc.ClusterName + "-" + bucketID
510+
if len(defaultBucket) > 63 {
511+
defaultBucket = defaultBucket[:63]
512+
}
513+
if strings.HasSuffix(defaultBucket, "-") {
514+
defaultBucket = defaultBucket[:len(defaultBucket)-1]
515+
}
516+
517+
cc.Bucket = defaultBucket
518+
} else {
519+
bucketRegion, _ := aws.GetBucketRegion(cc.Bucket)
520+
if bucketRegion != "" && bucketRegion != *cc.Region { // if the bucket didn't exist, we will create it in the correct region, so there is no error
521+
return ErrorS3RegionDiffersFromCluster(cc.Bucket, bucketRegion, *cc.Region)
522+
}
504523
}
505524

506525
primaryInstanceType := *cc.InstanceType
@@ -740,26 +759,10 @@ func RegionPrompt(clusterConfig *Config, disallowPrompt bool) error {
740759
return nil
741760
}
742761

743-
func InstallPrompt(clusterConfig *Config, awsClient *aws.Client, disallowPrompt bool) error {
762+
func InstallPrompt(clusterConfig *Config, disallowPrompt bool) error {
744763
defaults := applyPromptDefaults(*clusterConfig)
745-
accountID, _, err := awsClient.GetCachedAccountID()
746-
if err != nil {
747-
return err
748-
}
749-
bucketID := hash.String(accountID + *clusterConfig.Region)[:10]
750-
751-
defaultBucket := clusterConfig.ClusterName + "-" + bucketID
752-
if len(defaultBucket) > 63 {
753-
defaultBucket = defaultBucket[:63]
754-
}
755-
if strings.HasSuffix(defaultBucket, "-") {
756-
defaultBucket = defaultBucket[:len(defaultBucket)-1]
757-
}
758764

759765
if disallowPrompt {
760-
if clusterConfig.Bucket == "" {
761-
clusterConfig.Bucket = defaultBucket
762-
}
763766
if clusterConfig.InstanceType == nil {
764767
clusterConfig.InstanceType = defaults.InstanceType
765768
}
@@ -775,18 +778,6 @@ func InstallPrompt(clusterConfig *Config, awsClient *aws.Client, disallowPrompt
775778
remainingPrompts := &cr.PromptValidation{
776779
SkipNonEmptyFields: true,
777780
PromptItemValidations: []*cr.PromptItemValidation{
778-
{
779-
StructField: "Bucket",
780-
PromptOpts: &prompt.Options{
781-
Prompt: BucketUserKey,
782-
},
783-
StringValidation: &cr.StringValidation{
784-
Default: defaultBucket,
785-
MinLength: 3,
786-
MaxLength: 63,
787-
Validator: validateBucketName,
788-
},
789-
},
790781
{
791782
StructField: "InstanceType",
792783
PromptOpts: &prompt.Options{
@@ -823,7 +814,7 @@ func InstallPrompt(clusterConfig *Config, awsClient *aws.Client, disallowPrompt
823814
},
824815
}
825816

826-
err = cr.ReadPrompt(clusterConfig, remainingPrompts)
817+
err := cr.ReadPrompt(clusterConfig, remainingPrompts)
827818
if err != nil {
828819
return err
829820
}

pkg/types/clusterconfig/errors.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,10 @@ func ErrorConfigCannotBeChangedOnUpdate(configKey string, prevVal interface{}) e
145145
})
146146
}
147147

148-
func ErrorInvalidAvailabilityZone(userZone string, allZones strset.Set) error {
148+
func ErrorInvalidAvailabilityZone(userZone string, allZones strset.Set, region string) error {
149149
return errors.WithStack(&errors.Error{
150150
Kind: ErrInvalidAvailabilityZone,
151-
Message: fmt.Sprintf("%s is not an availability zone; please choose from the following availability zones: %s", s.UserStr(userZone), s.UserStrsOr(allZones.SliceSorted())),
151+
Message: fmt.Sprintf("%s is not an availability zone in %s; please choose from the following availability zones: %s", s.UserStr(userZone), region, s.UserStrsOr(allZones.SliceSorted())),
152152
})
153153
}
154154

pkg/types/spec/errors.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ const (
3939
ErrInitReplicasLessThanMin = "spec.init_replicas_less_than_min"
4040
ErrInvalidSurgeOrUnavailable = "spec.invalid_surge_or_unavailable"
4141
ErrSurgeAndUnavailableBothZero = "spec.surge_and_unavailable_both_zero"
42-
ErrImplDoesNotExist = "spec.impl_does_not_exist"
4342
ErrFileNotFound = "spec.file_not_found"
4443
ErrDirIsEmpty = "spec.dir_is_empty"
4544
ErrS3FileNotFound = "spec.s3_file_not_found"
@@ -166,13 +165,6 @@ func ErrorSurgeAndUnavailableBothZero() error {
166165
})
167166
}
168167

169-
func ErrorImplDoesNotExist(path string) error {
170-
return errors.WithStack(&errors.Error{
171-
Kind: ErrImplDoesNotExist,
172-
Message: fmt.Sprintf("%s: implementation file does not exist", path),
173-
})
174-
}
175-
176168
func ErrorFileNotFound(path string) error {
177169
return errors.WithStack(&errors.Error{
178170
Kind: ErrFileNotFound,

pkg/types/spec/validations.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package spec
1818

1919
import (
20+
"fmt"
2021
"math"
2122
"path/filepath"
2223
"strconv"
@@ -158,7 +159,8 @@ func monitoringValidation() *cr.StructFieldValidation {
158159
return &cr.StructFieldValidation{
159160
StructField: "Monitoring",
160161
StructValidation: &cr.StructValidation{
161-
DefaultNil: true,
162+
DefaultNil: true,
163+
AllowExplicitNull: true,
162164
StructFieldValidations: []*cr.StructFieldValidation{
163165
{
164166
StructField: "Key",
@@ -410,7 +412,8 @@ func ExtractAPIConfigs(configBytes []byte, provider types.ProviderType, projectF
410412
errs := cr.Struct(&api, data, apiValidation(provider))
411413
if errors.HasError(errs) {
412414
name, _ := data[userconfig.NameKey].(string)
413-
return nil, errors.Wrap(errors.FirstError(errs...), userconfig.IdentifyAPI(filePath, name, i))
415+
err = errors.Wrap(errors.FirstError(errs...), userconfig.IdentifyAPI(filePath, name, i))
416+
return nil, errors.Append(err, fmt.Sprintf("\n\napi configuration schema can be found here: https://www.cortex.dev/v/%s/deployments/api-configuration", consts.CortexVersionMinor))
414417
}
415418
api.Index = i
416419
api.FilePath = filePath
@@ -483,7 +486,7 @@ func validatePredictor(predictor *userconfig.Predictor, projectFiles ProjectFile
483486

484487
if _, err := projectFiles.GetFile(predictor.Path); err != nil {
485488
if errors.GetKind(err) == files.ErrFileDoesNotExist {
486-
return errors.Wrap(ErrorImplDoesNotExist(predictor.Path), userconfig.PathKey)
489+
return errors.Wrap(files.ErrorFileDoesNotExist(predictor.Path), userconfig.PathKey)
487490
}
488491
return errors.Wrap(err, userconfig.PathKey)
489492
}
@@ -766,7 +769,7 @@ func validatePythonPath(pythonPath string, projectFiles ProjectFiles) error {
766769
}
767770
}
768771
if !validPythonPath {
769-
return ErrorImplDoesNotExist(pythonPath)
772+
return files.ErrorFileDoesNotExist(pythonPath)
770773
}
771774
return nil
772775
}

0 commit comments

Comments
 (0)