diff --git a/.changelog/516798334aa149998c84c0f9f62d13bb.json b/.changelog/516798334aa149998c84c0f9f62d13bb.json new file mode 100644 index 00000000000..ba481c1b98b --- /dev/null +++ b/.changelog/516798334aa149998c84c0f9f62d13bb.json @@ -0,0 +1,9 @@ +{ + "id": "51679833-4aa1-4999-8c84-c0f9f62d13bb", + "type": "bugfix", + "description": "Switch to generated waiters, removing the dependency on go-jmespath and fixing broken waiters that used ordering comparators.", + "modules": [ + "service/autoscaling", + "service/cloudwatch" + ] +} \ No newline at end of file diff --git a/SMITHY_GO_CODEGEN_VERSION b/SMITHY_GO_CODEGEN_VERSION index 107e69ef333..2964b066f5c 100644 --- a/SMITHY_GO_CODEGEN_VERSION +++ b/SMITHY_GO_CODEGEN_VERSION @@ -1 +1 @@ -a7d0f1ef5f730836889f670f8d739456fc940779 +d708d1d4ae7dc9bc80ae20d1e09623fba519e9d7 diff --git a/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/customization/AwsWaiters2.java b/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/customization/AwsWaiters2.java index 2ac74322436..80cd1190ec1 100644 --- a/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/customization/AwsWaiters2.java +++ b/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/customization/AwsWaiters2.java @@ -12,7 +12,9 @@ public class AwsWaiters2 extends Waiters2 { public static final List PHASED_ROLLOUT_SERVICES = List.of( - ShapeId.from("com.amazonaws.ec2#AmazonEC2") + ShapeId.from("com.amazonaws.ec2#AmazonEC2"), + ShapeId.from("com.amazonaws.autoscaling#AutoScaling_2011_01_01"), + ShapeId.from("com.amazonaws.cloudwatch#GraniteServiceVersion20100801") ); @Override diff --git a/service/autoscaling/api_op_DescribeAutoScalingGroups.go b/service/autoscaling/api_op_DescribeAutoScalingGroups.go index d6eefbef045..1bc272e512a 100644 --- a/service/autoscaling/api_op_DescribeAutoScalingGroups.go +++ b/service/autoscaling/api_op_DescribeAutoScalingGroups.go @@ -11,7 +11,6 @@ import ( smithytime "github.com/aws/smithy-go/time" smithyhttp "github.com/aws/smithy-go/transport/http" smithywaiter "github.com/aws/smithy-go/waiter" - jmespath "github.com/jmespath/go-jmespath" "strconv" "time" ) @@ -341,43 +340,31 @@ func (w *GroupExistsWaiter) WaitForOutput(ctx context.Context, params *DescribeA func groupExistsStateRetryable(ctx context.Context, input *DescribeAutoScalingGroupsInput, output *DescribeAutoScalingGroupsOutput, err error) (bool, error) { if err == nil { - pathValue, err := jmespath.Search("length(AutoScalingGroups) > `0`", output) - if err != nil { - return false, fmt.Errorf("error evaluating waiter state: %w", err) - } - + v1 := output.AutoScalingGroups + v2 := len(v1) + v3 := 0 + v4 := int64(v2) > int64(v3) expectedValue := "true" bv, err := strconv.ParseBool(expectedValue) if err != nil { return false, fmt.Errorf("error parsing boolean from string %w", err) } - value, ok := pathValue.(bool) - if !ok { - return false, fmt.Errorf("waiter comparator expected bool value got %T", pathValue) - } - - if value == bv { + if v4 == bv { return false, nil } } if err == nil { - pathValue, err := jmespath.Search("length(AutoScalingGroups) > `0`", output) - if err != nil { - return false, fmt.Errorf("error evaluating waiter state: %w", err) - } - + v1 := output.AutoScalingGroups + v2 := len(v1) + v3 := 0 + v4 := int64(v2) > int64(v3) expectedValue := "false" bv, err := strconv.ParseBool(expectedValue) if err != nil { return false, fmt.Errorf("error parsing boolean from string %w", err) } - value, ok := pathValue.(bool) - if !ok { - return false, fmt.Errorf("waiter comparator expected bool value got %T", pathValue) - } - - if value == bv { + if v4 == bv { return true, nil } } @@ -548,43 +535,103 @@ func (w *GroupInServiceWaiter) WaitForOutput(ctx context.Context, params *Descri func groupInServiceStateRetryable(ctx context.Context, input *DescribeAutoScalingGroupsInput, output *DescribeAutoScalingGroupsOutput, err error) (bool, error) { if err == nil { - pathValue, err := jmespath.Search("contains(AutoScalingGroups[].[length(Instances[?LifecycleState=='InService']) >= MinSize][], `false`)", output) - if err != nil { - return false, fmt.Errorf("error evaluating waiter state: %w", err) - } + v1 := output.AutoScalingGroups + var v2 [][]bool + for _, v := range v1 { + v3 := v.Instances + var v4 []types.Instance + for _, v := range v3 { + v5 := v.LifecycleState + v6 := "InService" + v7 := string(v5) == string(v6) + if v7 { + v4 = append(v4, v) + } + } + v8 := len(v4) + v9 := v.MinSize + var v10 bool + if v9 == nil { + v9 = new(int32) + *v9 = 0 + } + if v9 != nil { + v10 = int64(v8) >= int64(*v9) + } + v11 := []bool{} + v11 = append(v11, v10) + v2 = append(v2, v11) + } + var v12 []bool + for _, v := range v2 { + v12 = append(v12, v...) + } + v13 := false + var v14 bool + for _, v := range v12 { + if v == v13 { + v14 = true + break + } + } expectedValue := "false" bv, err := strconv.ParseBool(expectedValue) if err != nil { return false, fmt.Errorf("error parsing boolean from string %w", err) } - value, ok := pathValue.(bool) - if !ok { - return false, fmt.Errorf("waiter comparator expected bool value got %T", pathValue) - } - - if value == bv { + if v14 == bv { return false, nil } } if err == nil { - pathValue, err := jmespath.Search("contains(AutoScalingGroups[].[length(Instances[?LifecycleState=='InService']) >= MinSize][], `false`)", output) - if err != nil { - return false, fmt.Errorf("error evaluating waiter state: %w", err) - } + v1 := output.AutoScalingGroups + var v2 [][]bool + for _, v := range v1 { + v3 := v.Instances + var v4 []types.Instance + for _, v := range v3 { + v5 := v.LifecycleState + v6 := "InService" + v7 := string(v5) == string(v6) + if v7 { + v4 = append(v4, v) + } + } + v8 := len(v4) + v9 := v.MinSize + var v10 bool + if v9 == nil { + v9 = new(int32) + *v9 = 0 + } + if v9 != nil { + v10 = int64(v8) >= int64(*v9) + } + v11 := []bool{} + v11 = append(v11, v10) + v2 = append(v2, v11) + } + var v12 []bool + for _, v := range v2 { + v12 = append(v12, v...) + } + v13 := false + var v14 bool + for _, v := range v12 { + if v == v13 { + v14 = true + break + } + } expectedValue := "true" bv, err := strconv.ParseBool(expectedValue) if err != nil { return false, fmt.Errorf("error parsing boolean from string %w", err) } - value, ok := pathValue.(bool) - if !ok { - return false, fmt.Errorf("waiter comparator expected bool value got %T", pathValue) - } - - if value == bv { + if v14 == bv { return true, nil } } @@ -755,43 +802,31 @@ func (w *GroupNotExistsWaiter) WaitForOutput(ctx context.Context, params *Descri func groupNotExistsStateRetryable(ctx context.Context, input *DescribeAutoScalingGroupsInput, output *DescribeAutoScalingGroupsOutput, err error) (bool, error) { if err == nil { - pathValue, err := jmespath.Search("length(AutoScalingGroups) > `0`", output) - if err != nil { - return false, fmt.Errorf("error evaluating waiter state: %w", err) - } - + v1 := output.AutoScalingGroups + v2 := len(v1) + v3 := 0 + v4 := int64(v2) > int64(v3) expectedValue := "false" bv, err := strconv.ParseBool(expectedValue) if err != nil { return false, fmt.Errorf("error parsing boolean from string %w", err) } - value, ok := pathValue.(bool) - if !ok { - return false, fmt.Errorf("waiter comparator expected bool value got %T", pathValue) - } - - if value == bv { + if v4 == bv { return false, nil } } if err == nil { - pathValue, err := jmespath.Search("length(AutoScalingGroups) > `0`", output) - if err != nil { - return false, fmt.Errorf("error evaluating waiter state: %w", err) - } - + v1 := output.AutoScalingGroups + v2 := len(v1) + v3 := 0 + v4 := int64(v2) > int64(v3) expectedValue := "true" bv, err := strconv.ParseBool(expectedValue) if err != nil { return false, fmt.Errorf("error parsing boolean from string %w", err) } - value, ok := pathValue.(bool) - if !ok { - return false, fmt.Errorf("waiter comparator expected bool value got %T", pathValue) - } - - if value == bv { + if v4 == bv { return true, nil } } diff --git a/service/autoscaling/api_op_DescribeAutoScalingGroups_test.go b/service/autoscaling/api_op_DescribeAutoScalingGroups_test.go new file mode 100644 index 00000000000..8e0c9962b45 --- /dev/null +++ b/service/autoscaling/api_op_DescribeAutoScalingGroups_test.go @@ -0,0 +1,191 @@ +package autoscaling + +import ( + "context" + "fmt" + "testing" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/autoscaling/types" +) + +// manually tests the most complex jmespath expression in the entire SDK +func TestGroupInServiceStateRetryable(t *testing.T) { + for name, tt := range map[string]struct { + Output *DescribeAutoScalingGroupsOutput + Expect bool + }{ + // terminal cases: there are no groups that have NOT spun up yet, + // indicated by # of InService < MinSize + "empty output": { + Output: &DescribeAutoScalingGroupsOutput{}, + Expect: false, + }, + "empty group list": { + Output: &DescribeAutoScalingGroupsOutput{ + AutoScalingGroups: []types.AutoScalingGroup{}, + }, + Expect: false, + }, + "empty instance list": { + Output: &DescribeAutoScalingGroupsOutput{ + AutoScalingGroups: []types.AutoScalingGroup{ + { + Instances: []types.Instance{}, + }, + }, + }, + Expect: false, + }, + "1 !InService": { + Output: &DescribeAutoScalingGroupsOutput{ + AutoScalingGroups: []types.AutoScalingGroup{ + { + Instances: []types.Instance{ + {LifecycleState: types.LifecycleStateQuarantined}, + }, + }, + }, + }, + Expect: false, + }, + "1 InService, MinSize nil": { + Output: &DescribeAutoScalingGroupsOutput{ + AutoScalingGroups: []types.AutoScalingGroup{ + { + Instances: []types.Instance{ + {LifecycleState: types.LifecycleStateInService}, + }, + }, + }, + }, + Expect: false, + }, + "1 InService, MinSize 0": { + Output: &DescribeAutoScalingGroupsOutput{ + AutoScalingGroups: []types.AutoScalingGroup{ + { + Instances: []types.Instance{ + {LifecycleState: types.LifecycleStateInService}, + }, + MinSize: aws.Int32(0), + }, + }, + }, + Expect: false, + }, + "1 InService, MinSize 1": { + Output: &DescribeAutoScalingGroupsOutput{ + AutoScalingGroups: []types.AutoScalingGroup{ + { + Instances: []types.Instance{ + {LifecycleState: types.LifecycleStateInService}, + }, + MinSize: aws.Int32(1), + }, + }, + }, + Expect: false, + }, + // retry cases: at least one group is spinning up + "0 InService(nil slice), MinSize 2": { + Output: &DescribeAutoScalingGroupsOutput{ + AutoScalingGroups: []types.AutoScalingGroup{ + { + MinSize: aws.Int32(2), + }, + }, + }, + Expect: true, + }, + "0 InService(empty slice), MinSize 2": { + Output: &DescribeAutoScalingGroupsOutput{ + AutoScalingGroups: []types.AutoScalingGroup{ + { + Instances: []types.Instance{}, + MinSize: aws.Int32(2), + }, + }, + }, + Expect: true, + }, + "1 Pending, MinSize 2": { + Output: &DescribeAutoScalingGroupsOutput{ + AutoScalingGroups: []types.AutoScalingGroup{ + { + Instances: []types.Instance{ + {LifecycleState: types.LifecycleStatePending}, + }, + MinSize: aws.Int32(2), + }, + }, + }, + Expect: true, + }, + "1 Pending, 1 InService, MinSize 2": { + Output: &DescribeAutoScalingGroupsOutput{ + AutoScalingGroups: []types.AutoScalingGroup{ + { + Instances: []types.Instance{ + {LifecycleState: types.LifecycleStatePending}, + {LifecycleState: types.LifecycleStateInService}, + }, + MinSize: aws.Int32(2), + }, + }, + }, + Expect: true, + }, + // one group is done but another is spinning up + // it's unclear if the service would ever return something like this, + // but that's how the waiter is written + "(1/2) + (2/2)": { + Output: &DescribeAutoScalingGroupsOutput{ + AutoScalingGroups: []types.AutoScalingGroup{ + { + Instances: []types.Instance{ + {LifecycleState: types.LifecycleStatePending}, + {LifecycleState: types.LifecycleStateInService}, + }, + MinSize: aws.Int32(2), + }, + { + Instances: []types.Instance{ + {LifecycleState: types.LifecycleStateInService}, + {LifecycleState: types.LifecycleStateInService}, + }, + MinSize: aws.Int32(2), + }, + }, + }, + Expect: true, + }, + // and then a terminal case where it spun up + "2 InService, MinSize 2": { + Output: &DescribeAutoScalingGroupsOutput{ + AutoScalingGroups: []types.AutoScalingGroup{ + { + Instances: []types.Instance{ + {LifecycleState: types.LifecycleStateInService}, + {LifecycleState: types.LifecycleStateInService}, + }, + MinSize: aws.Int32(2), + }, + }, + }, + Expect: false, + }, + } { + t.Run(name, func(t *testing.T) { + fmt.Println(name) + retryable, err := groupInServiceStateRetryable(context.Background(), nil, tt.Output, nil) + if err != nil { + t.Fatal(err) + } + + if tt.Expect != retryable { + t.Errorf("%s: expected retryable=%v, got %v", name, tt.Expect, retryable) + } + }) + } +} diff --git a/service/autoscaling/generated.json b/service/autoscaling/generated.json index eb092498430..f9801793d8c 100644 --- a/service/autoscaling/generated.json +++ b/service/autoscaling/generated.json @@ -3,8 +3,7 @@ "github.com/aws/aws-sdk-go-v2": "v1.4.0", "github.com/aws/aws-sdk-go-v2/internal/configsources": "v0.0.0-00010101000000-000000000000", "github.com/aws/aws-sdk-go-v2/internal/endpoints/v2": "v2.0.0-00010101000000-000000000000", - "github.com/aws/smithy-go": "v1.4.0", - "github.com/jmespath/go-jmespath": "v0.4.0" + "github.com/aws/smithy-go": "v1.4.0" }, "files": [ "api_client.go", diff --git a/service/autoscaling/go.mod b/service/autoscaling/go.mod index 8f60f097e33..479372134c5 100644 --- a/service/autoscaling/go.mod +++ b/service/autoscaling/go.mod @@ -7,7 +7,6 @@ require ( github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.28 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.28 github.com/aws/smithy-go v1.22.2 - github.com/jmespath/go-jmespath v0.4.0 ) replace github.com/aws/aws-sdk-go-v2 => ../../ diff --git a/service/autoscaling/go.sum b/service/autoscaling/go.sum index 3df7c5c8b09..cad7e6ad46a 100644 --- a/service/autoscaling/go.sum +++ b/service/autoscaling/go.sum @@ -1,14 +1,2 @@ github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/service/cloudwatch/api_op_DescribeAlarms.go b/service/cloudwatch/api_op_DescribeAlarms.go index 1f125dc1042..0d7ea9a4db0 100644 --- a/service/cloudwatch/api_op_DescribeAlarms.go +++ b/service/cloudwatch/api_op_DescribeAlarms.go @@ -11,7 +11,6 @@ import ( smithytime "github.com/aws/smithy-go/time" smithyhttp "github.com/aws/smithy-go/transport/http" smithywaiter "github.com/aws/smithy-go/waiter" - jmespath "github.com/jmespath/go-jmespath" "strconv" "time" ) @@ -387,22 +386,16 @@ func (w *AlarmExistsWaiter) WaitForOutput(ctx context.Context, params *DescribeA func alarmExistsStateRetryable(ctx context.Context, input *DescribeAlarmsInput, output *DescribeAlarmsOutput, err error) (bool, error) { if err == nil { - pathValue, err := jmespath.Search("length(MetricAlarms[]) > `0`", output) - if err != nil { - return false, fmt.Errorf("error evaluating waiter state: %w", err) - } - + v1 := output.MetricAlarms + v2 := len(v1) + v3 := 0 + v4 := int64(v2) > int64(v3) expectedValue := "true" bv, err := strconv.ParseBool(expectedValue) if err != nil { return false, fmt.Errorf("error parsing boolean from string %w", err) } - value, ok := pathValue.(bool) - if !ok { - return false, fmt.Errorf("waiter comparator expected bool value got %T", pathValue) - } - - if value == bv { + if v4 == bv { return false, nil } } @@ -575,22 +568,16 @@ func (w *CompositeAlarmExistsWaiter) WaitForOutput(ctx context.Context, params * func compositeAlarmExistsStateRetryable(ctx context.Context, input *DescribeAlarmsInput, output *DescribeAlarmsOutput, err error) (bool, error) { if err == nil { - pathValue, err := jmespath.Search("length(CompositeAlarms[]) > `0`", output) - if err != nil { - return false, fmt.Errorf("error evaluating waiter state: %w", err) - } - + v1 := output.CompositeAlarms + v2 := len(v1) + v3 := 0 + v4 := int64(v2) > int64(v3) expectedValue := "true" bv, err := strconv.ParseBool(expectedValue) if err != nil { return false, fmt.Errorf("error parsing boolean from string %w", err) } - value, ok := pathValue.(bool) - if !ok { - return false, fmt.Errorf("waiter comparator expected bool value got %T", pathValue) - } - - if value == bv { + if v4 == bv { return false, nil } } diff --git a/service/cloudwatch/generated.json b/service/cloudwatch/generated.json index 4c3d7f8bc01..1815386c46f 100644 --- a/service/cloudwatch/generated.json +++ b/service/cloudwatch/generated.json @@ -3,8 +3,7 @@ "github.com/aws/aws-sdk-go-v2": "v1.4.0", "github.com/aws/aws-sdk-go-v2/internal/configsources": "v0.0.0-00010101000000-000000000000", "github.com/aws/aws-sdk-go-v2/internal/endpoints/v2": "v2.0.0-00010101000000-000000000000", - "github.com/aws/smithy-go": "v1.4.0", - "github.com/jmespath/go-jmespath": "v0.4.0" + "github.com/aws/smithy-go": "v1.4.0" }, "files": [ "api_client.go", diff --git a/service/cloudwatch/go.mod b/service/cloudwatch/go.mod index c7345ee47a2..c72a037f310 100644 --- a/service/cloudwatch/go.mod +++ b/service/cloudwatch/go.mod @@ -7,7 +7,6 @@ require ( github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.28 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.28 github.com/aws/smithy-go v1.22.2 - github.com/jmespath/go-jmespath v0.4.0 ) replace github.com/aws/aws-sdk-go-v2 => ../../ diff --git a/service/cloudwatch/go.sum b/service/cloudwatch/go.sum index 3df7c5c8b09..cad7e6ad46a 100644 --- a/service/cloudwatch/go.sum +++ b/service/cloudwatch/go.sum @@ -1,14 +1,2 @@ github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=