diff --git a/config/default/manager_image_patch.yaml b/config/default/manager_image_patch.yaml index ab107435..5ba6ed4c 100644 --- a/config/default/manager_image_patch.yaml +++ b/config/default/manager_image_patch.yaml @@ -8,5 +8,5 @@ spec: spec: containers: # Change the value of image field below to your controller image URL - - image: keikoproj/rolling-upgrade-controller:0.1-dev + - image: keikoproj/rolling-upgrade-controller:0.2-dev name: manager diff --git a/controllers/rollingupgrade_controller.go b/controllers/rollingupgrade_controller.go index 432daf71..0eabfac2 100644 --- a/controllers/rollingupgrade_controller.go +++ b/controllers/rollingupgrade_controller.go @@ -19,8 +19,6 @@ import ( "context" "errors" "fmt" - "k8s.io/apimachinery/pkg/util/intstr" - "log" "os" "os/exec" "strconv" @@ -28,17 +26,20 @@ import ( "sync" "time" + "k8s.io/apimachinery/pkg/util/intstr" + corev1 "k8s.io/api/core/v1" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" + awsclient "github.com/aws/aws-sdk-go/aws/client" + "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/autoscaling" "github.com/aws/aws-sdk-go/service/autoscaling/autoscalingiface" - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/aws/aws-sdk-go/service/ec2/ec2iface" "github.com/go-logr/logr" + "github.com/keikoproj/upgrade-manager/pkg/log" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" @@ -75,6 +76,14 @@ const ( ShellBinary = "/bin/sh" ) +var DefaultRetryer = awsclient.DefaultRetryer{ + NumMaxRetries: 250, + MinThrottleDelay: time.Second * 5, + MaxThrottleDelay: time.Second * 20, + MinRetryDelay: time.Second * 1, + MaxRetryDelay: time.Second * 5, +} + // RollingUpgradeReconciler reconciles a RollingUpgrade object type RollingUpgradeReconciler struct { client.Client @@ -89,7 +98,6 @@ type RollingUpgradeReconciler struct { func runScript(script string, background bool, objName string) (string, error) { log.Printf("%s: Running script %s", objName, script) - if background { log.Printf("%s: Running script in background. Logs not available.", objName) exec.Command(ShellBinary, "-c", script).Run() @@ -212,20 +220,23 @@ func (r *RollingUpgradeReconciler) CallKubectlDrain(ctx context.Context, nodeNam } // TerminateNode actually terminates the given node. -func (r *RollingUpgradeReconciler) TerminateNode(ruObj *upgrademgrv1alpha1.RollingUpgrade, instanceID string, svc ec2iface.EC2API) error { +func (r *RollingUpgradeReconciler) TerminateNode(ruObj *upgrademgrv1alpha1.RollingUpgrade, instanceID string, svc autoscalingiface.AutoScalingAPI) error { - input := &ec2.TerminateInstancesInput{ - InstanceIds: []*string{ - aws.String(instanceID), - }, + input := &autoscaling.TerminateInstanceInAutoScalingGroupInput{ + InstanceId: aws.String(instanceID), + ShouldDecrementDesiredCapacity: aws.Bool(false), } - result, err := svc.TerminateInstances(input) + result, err := svc.TerminateInstanceInAutoScalingGroup(input) if err != nil { if aerr, ok := err.(awserr.Error); ok { switch aerr.Code() { case "InvalidInstanceID.NotFound": log.Printf("Instance %s not found. Moving on\n", instanceID) + case autoscaling.ErrCodeScalingActivityInProgressFault: + log.Println(autoscaling.ErrCodeScalingActivityInProgressFault, aerr.Error()) + case autoscaling.ErrCodeResourceContentionFault: + log.Println(autoscaling.ErrCodeResourceContentionFault, aerr.Error()) return nil default: log.Println(aerr.Error()) @@ -345,7 +356,7 @@ func loadEnvironmentVariables(ruObj *upgrademgrv1alpha1.RollingUpgrade, nodeInst return nil } -func (r *RollingUpgradeReconciler) runRestack(ctx *context.Context, ruObj *upgrademgrv1alpha1.RollingUpgrade, svc ec2iface.EC2API, KubeCtlCall string) (int, error) { +func (r *RollingUpgradeReconciler) runRestack(ctx *context.Context, ruObj *upgrademgrv1alpha1.RollingUpgrade, svc autoscalingiface.AutoScalingAPI, KubeCtlCall string) (int, error) { // Setting default values for the Strategy in rollup object r.setDefaultsForRollingUpdateStrategy(ruObj) @@ -413,11 +424,15 @@ func (r *RollingUpgradeReconciler) Process(ctx *context.Context, ruObj *upgradem r.setDefaults(ruObj) - sess, _ := session.NewSession(&aws.Config{ - Region: aws.String(ruObj.Spec.Region)}, - ) + config := aws.NewConfig().WithRegion(ruObj.Spec.Region) + config = config.WithCredentialsChainVerboseErrors(true) + config = request.WithRetryer(config, log.NewRetryLogger(DefaultRetryer)) + sess, err := session.NewSession(config) + if err != nil { + log.Fatalf("failed to create asg client, %v", err) + } svc := autoscaling.New(sess) - err := r.populateAsg(ruObj, svc) + err = r.populateAsg(ruObj, svc) if err != nil { return r.finishExecution(StatusError, 0, ctx, ruObj) } @@ -443,13 +458,8 @@ func (r *RollingUpgradeReconciler) Process(ctx *context.Context, ruObj *upgradem ruObj.Status.TotalNodes = len(asg.Instances) r.Update(*ctx, ruObj) - ec2Sess, _ := session.NewSession(&aws.Config{ - Region: aws.String(ruObj.Spec.Region)}, - ) - ec2Svc := ec2.New(ec2Sess) - // Run the restack that acutally performs the rolling update. - nodesProcessed, err := r.runRestack(ctx, ruObj, ec2Svc, KubeCtlBinary) + nodesProcessed, err := r.runRestack(ctx, ruObj, svc, KubeCtlBinary) if err != nil { return r.finishExecution(StatusError, nodesProcessed, ctx, ruObj) } @@ -623,7 +633,7 @@ func (r *RollingUpgradeReconciler) setDefaultsForRollingUpdateStrategy(ruObj *up // RandomUpdate treats all the azs as a single unit and picks random nodes for update // and rolls out the update based on the input parameters -func (r *RollingUpgradeReconciler) RandomUpdate(ctx *context.Context, ruObj *upgrademgrv1alpha1.RollingUpgrade, svc ec2iface.EC2API, KubeCtlCall string) (int, error) { +func (r *RollingUpgradeReconciler) RandomUpdate(ctx *context.Context, ruObj *upgrademgrv1alpha1.RollingUpgrade, svc autoscalingiface.AutoScalingAPI, KubeCtlCall string) (int, error) { value, ok := r.ruObjNameToASG.Load(ruObj.Name) if !ok { @@ -694,7 +704,7 @@ func (r *RollingUpgradeReconciler) RandomUpdate(ctx *context.Context, ruObj *upg return nodesProcessed, nil } -func (r *RollingUpgradeReconciler) UpdateInstance(ctx *context.Context, ruObj *upgrademgrv1alpha1.RollingUpgrade, i *autoscaling.Instance, currentLaunchConfigName string, KubeCtlCall string, svc ec2iface.EC2API, drainTimeout int, ch chan error) { +func (r *RollingUpgradeReconciler) UpdateInstance(ctx *context.Context, ruObj *upgrademgrv1alpha1.RollingUpgrade, i *autoscaling.Instance, currentLaunchConfigName string, KubeCtlCall string, svc autoscalingiface.AutoScalingAPI, drainTimeout int, ch chan error) { targetLaunchConfigName := aws.StringValue(i.LaunchConfigurationName) targetInstanceID := aws.StringValue(i.InstanceId) diff --git a/controllers/rollingupgrade_controller_test.go b/controllers/rollingupgrade_controller_test.go index fc4144ff..9c343c83 100644 --- a/controllers/rollingupgrade_controller_test.go +++ b/controllers/rollingupgrade_controller_test.go @@ -3,8 +3,6 @@ package controllers import ( "encoding/json" "fmt" - "gopkg.in/yaml.v2" - "k8s.io/apimachinery/pkg/util/intstr" "log" "os" "path/filepath" @@ -12,10 +10,13 @@ import ( "testing" "time" + "k8s.io/apimachinery/pkg/util/intstr" + + "gopkg.in/yaml.v2" + + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/autoscaling/autoscalingiface" - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/aws/aws-sdk-go/service/ec2/ec2iface" "github.com/pkg/errors" "github.com/aws/aws-sdk-go/service/autoscaling" @@ -284,22 +285,21 @@ func TestDrainNodePostDrainFailureToDrain(t *testing.T) { g.Expect(err).To(gomega.Not(gomega.BeNil())) } -type MockEC2Instance struct { - ec2iface.EC2API +type MockAutoscalingGroup struct { + autoscalingiface.AutoScalingAPI errorFlag bool awsErr awserr.Error } -func (mockEC2Instance MockEC2Instance) TerminateInstances(input *ec2.TerminateInstancesInput) (*ec2.TerminateInstancesOutput, error) { - output := &ec2.TerminateInstancesOutput{} - if mockEC2Instance.errorFlag { - if mockEC2Instance.awsErr != nil { - return output, mockEC2Instance.awsErr +func (mockAutoscalingGroup MockAutoscalingGroup) TerminateInstanceInAutoScalingGroup(input *autoscaling.TerminateInstanceInAutoScalingGroupInput) (*autoscaling.TerminateInstanceInAutoScalingGroupOutput, error) { + output := &autoscaling.TerminateInstanceInAutoScalingGroupOutput{} + if mockAutoscalingGroup.errorFlag { + if mockAutoscalingGroup.awsErr != nil { + return output, mockAutoscalingGroup.awsErr } } - name := input.InstanceIds[0] - instanceChange := ec2.InstanceStateChange{InstanceId: name} - output.TerminatingInstances = []*ec2.InstanceStateChange{&instanceChange} + asgChange := autoscaling.Activity{ActivityId: aws.String("xxx"), AutoScalingGroupName: aws.String("sss"), Cause: aws.String("xxx"), StartTime: aws.Time(time.Now()), StatusCode: aws.String("200"), StatusMessage: aws.String("success")} + output.Activity = &asgChange return output, nil } @@ -309,9 +309,8 @@ func TestTerminateNodeSuccess(t *testing.T) { ruObj := &upgrademgrv1alpha1.RollingUpgrade{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}} rcRollingUpgrade := &RollingUpgradeReconciler{ClusterState: NewClusterState()} - mockEC2Instance := MockEC2Instance{errorFlag: false, awsErr: nil} - - err := rcRollingUpgrade.TerminateNode(ruObj, mockNode, mockEC2Instance) + mockAutoscalingGroup := MockAutoscalingGroup{errorFlag: false, awsErr: nil} + err := rcRollingUpgrade.TerminateNode(ruObj, mockNode, mockAutoscalingGroup) g.Expect(err).To(gomega.BeNil()) } @@ -321,11 +320,11 @@ func TestTerminateNodeErrorNotFound(t *testing.T) { ruObj := &upgrademgrv1alpha1.RollingUpgrade{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}} rcRollingUpgrade := &RollingUpgradeReconciler{ClusterState: NewClusterState()} - mockEC2Instance := MockEC2Instance{errorFlag: true, awsErr: awserr.New("InvalidInstanceID.NotFound", + mockAutoscalingGroup := MockAutoscalingGroup{errorFlag: true, awsErr: awserr.New("InvalidInstanceID.NotFound", "some message", nil)} - err := rcRollingUpgrade.TerminateNode(ruObj, mockNode, mockEC2Instance) + err := rcRollingUpgrade.TerminateNode(ruObj, mockNode, mockAutoscalingGroup) g.Expect(err).To(gomega.BeNil()) } @@ -335,11 +334,11 @@ func TestTerminateNodeErrorOtherError(t *testing.T) { ruObj := &upgrademgrv1alpha1.RollingUpgrade{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}} rcRollingUpgrade := &RollingUpgradeReconciler{ClusterState: NewClusterState()} - mockEC2Instance := MockEC2Instance{errorFlag: true, awsErr: awserr.New("some-other-aws-error", + mockAutoscalingGroup := MockAutoscalingGroup{errorFlag: true, awsErr: awserr.New("some-other-aws-error", "some message", errors.New("some error"))} - err := rcRollingUpgrade.TerminateNode(ruObj, mockNode, mockEC2Instance) + err := rcRollingUpgrade.TerminateNode(ruObj, mockNode, mockAutoscalingGroup) g.Expect(err.Error()).To(gomega.ContainSubstring("some error")) } @@ -350,9 +349,9 @@ func TestTerminateNodePostTerminateScriptSuccess(t *testing.T) { ruObj := &upgrademgrv1alpha1.RollingUpgrade{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}} ruObj.Spec.PostTerminate.Script = "echo hello!" rcRollingUpgrade := &RollingUpgradeReconciler{ClusterState: NewClusterState()} - mockEC2Instance := MockEC2Instance{errorFlag: false, awsErr: nil} + mockAutoscalingGroup := MockAutoscalingGroup{errorFlag: false, awsErr: nil} - err := rcRollingUpgrade.TerminateNode(ruObj, mockNode, mockEC2Instance) + err := rcRollingUpgrade.TerminateNode(ruObj, mockNode, mockAutoscalingGroup) g.Expect(err).To(gomega.BeNil()) } @@ -363,9 +362,9 @@ func TestTerminateNodePostTerminateScriptErrorNotFoundFromServer(t *testing.T) { ruObj := &upgrademgrv1alpha1.RollingUpgrade{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}} ruObj.Spec.PostTerminate.Script = "echo 'Error from server (NotFound)'; exit 1" rcRollingUpgrade := &RollingUpgradeReconciler{ClusterState: NewClusterState()} - mockEC2Instance := MockEC2Instance{errorFlag: false, awsErr: nil} + mockAutoscalingGroup := MockAutoscalingGroup{errorFlag: false, awsErr: nil} - err := rcRollingUpgrade.TerminateNode(ruObj, mockNode, mockEC2Instance) + err := rcRollingUpgrade.TerminateNode(ruObj, mockNode, mockAutoscalingGroup) g.Expect(err).To(gomega.BeNil()) } @@ -376,9 +375,9 @@ func TestTerminateNodePostTerminateScriptErrorOtherError(t *testing.T) { ruObj := &upgrademgrv1alpha1.RollingUpgrade{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}} ruObj.Spec.PostTerminate.Script = "exit 1" rcRollingUpgrade := &RollingUpgradeReconciler{ClusterState: NewClusterState()} - mockEC2Instance := MockEC2Instance{errorFlag: false, awsErr: nil} + mockAutoscalingGroup := MockAutoscalingGroup{errorFlag: false, awsErr: nil} - err := rcRollingUpgrade.TerminateNode(ruObj, mockNode, mockEC2Instance) + err := rcRollingUpgrade.TerminateNode(ruObj, mockNode, mockAutoscalingGroup) g.Expect(err).To(gomega.Not(gomega.BeNil())) g.Expect(err.Error()).To(gomega.HavePrefix("Failed to run postTerminate script: ")) } @@ -704,7 +703,7 @@ func TestRunRestackSuccessOneNode(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}, Spec: upgrademgrv1alpha1.RollingUpgradeSpec{AsgName: someAsg}, } - mockEC2Instance := MockEC2Instance{} + mockAutoscalingGroup := MockAutoscalingGroup{} mgr, err := manager.New(cfg, manager.Options{}) g.Expect(err).NotTo(gomega.HaveOccurred()) @@ -729,7 +728,7 @@ func TestRunRestackSuccessOneNode(t *testing.T) { ctx := context.TODO() - nodesProcessed, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockEC2Instance, "exit 0;") + nodesProcessed, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockAutoscalingGroup, "exit 0;") g.Expect(nodesProcessed).To(gomega.Equal(1)) g.Expect(err).To(gomega.BeNil()) } @@ -750,7 +749,7 @@ func TestRunRestackSuccessMultipleNodes(t *testing.T) { ruObj := &upgrademgrv1alpha1.RollingUpgrade{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}, Spec: upgrademgrv1alpha1.RollingUpgradeSpec{AsgName: someAsg}} - mockEC2Instance := MockEC2Instance{} + mockAutoscalingGroup := MockAutoscalingGroup{} mgr, err := manager.New(cfg, manager.Options{}) g.Expect(err).NotTo(gomega.HaveOccurred()) @@ -776,7 +775,7 @@ func TestRunRestackSuccessMultipleNodes(t *testing.T) { ctx := context.TODO() - nodesProcessed, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockEC2Instance, "exit 0;") + nodesProcessed, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockAutoscalingGroup, "exit 0;") g.Expect(nodesProcessed).To(gomega.Equal(2)) g.Expect(err).To(gomega.BeNil()) } @@ -794,7 +793,7 @@ func TestRunRestackSameLaunchConfig(t *testing.T) { ruObj := &upgrademgrv1alpha1.RollingUpgrade{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}, Spec: upgrademgrv1alpha1.RollingUpgradeSpec{AsgName: someAsg}} - mockEC2Instance := MockEC2Instance{} + mockAutoscalingGroup := MockAutoscalingGroup{} mgr, err := manager.New(cfg, manager.Options{}) g.Expect(err).NotTo(gomega.HaveOccurred()) @@ -812,7 +811,7 @@ func TestRunRestackSameLaunchConfig(t *testing.T) { ctx := context.TODO() // This execution should not perform drain or termination, but should pass - nodesProcessed, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockEC2Instance, KubeCtlBinary) + nodesProcessed, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockAutoscalingGroup, KubeCtlBinary) g.Expect(nodesProcessed).To(gomega.Equal(1)) g.Expect(err).To(gomega.BeNil()) } @@ -821,12 +820,12 @@ func TestRunRestackRollingUpgradeNotInMap(t *testing.T) { g := gomega.NewGomegaWithT(t) ruObj := &upgrademgrv1alpha1.RollingUpgrade{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}} - mockEC2Instance := MockEC2Instance{} + mockAutoscalingGroup := MockAutoscalingGroup{} rcRollingUpgrade := &RollingUpgradeReconciler{ClusterState: NewClusterState()} ctx := context.TODO() g.Expect(rcRollingUpgrade.ruObjNameToASG.Load(ruObj.Name)).To(gomega.BeNil()) - int, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockEC2Instance, KubeCtlBinary) + int, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockAutoscalingGroup, KubeCtlBinary) g.Expect(int).To(gomega.Equal(0)) g.Expect(err).To(gomega.Not(gomega.BeNil())) g.Expect(err.Error()).To(gomega.HavePrefix("Failed to find rollingUpgrade/ name in map.")) @@ -846,7 +845,7 @@ func TestRunRestackRollingUpgradeNodeNameNotFound(t *testing.T) { ruObj := &upgrademgrv1alpha1.RollingUpgrade{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}, Spec: upgrademgrv1alpha1.RollingUpgradeSpec{AsgName: someAsg}} - mockEC2Instance := MockEC2Instance{} + mockAutoscalingGroup := MockAutoscalingGroup{} mgr, err := manager.New(cfg, manager.Options{}) g.Expect(err).NotTo(gomega.HaveOccurred()) @@ -866,7 +865,7 @@ func TestRunRestackRollingUpgradeNodeNameNotFound(t *testing.T) { ctx := context.TODO() // This execution gets past the different launch config check, but fails to be found at the node level - nodesProcessed, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockEC2Instance, KubeCtlBinary) + nodesProcessed, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockAutoscalingGroup, KubeCtlBinary) g.Expect(nodesProcessed).To(gomega.Equal(1)) g.Expect(err).To(gomega.BeNil()) } @@ -885,7 +884,7 @@ func TestRunRestackNoNodeName(t *testing.T) { ruObj := &upgrademgrv1alpha1.RollingUpgrade{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}, Spec: upgrademgrv1alpha1.RollingUpgradeSpec{AsgName: someAsg}} - mockEC2Instance := MockEC2Instance{} + mockAutoscalingGroup := MockAutoscalingGroup{} mgr, err := manager.New(cfg, manager.Options{}) g.Expect(err).NotTo(gomega.HaveOccurred()) @@ -910,7 +909,7 @@ func TestRunRestackNoNodeName(t *testing.T) { ctx := context.TODO() // This execution gets past the different launch config check, but since there is no node name, it is skipped - nodesProcessed, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockEC2Instance, KubeCtlBinary) + nodesProcessed, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockAutoscalingGroup, KubeCtlBinary) g.Expect(nodesProcessed).To(gomega.Equal(1)) g.Expect(err).To(gomega.BeNil()) } @@ -938,7 +937,7 @@ func TestRunRestackDrainNodeFail(t *testing.T) { PreDrain: somePreDrain, }, } - mockEC2Instance := MockEC2Instance{} + mockAutoscalingGroup := MockAutoscalingGroup{} mgr, err := manager.New(cfg, manager.Options{}) g.Expect(err).NotTo(gomega.HaveOccurred()) @@ -964,7 +963,7 @@ func TestRunRestackDrainNodeFail(t *testing.T) { ctx := context.TODO() // This execution gets past the different launch config check, but fails to drain the node because of a predrain failing script - nodesProcessed, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockEC2Instance, KubeCtlBinary) + nodesProcessed, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockAutoscalingGroup, KubeCtlBinary) g.Expect(nodesProcessed).To(gomega.Equal(0)) g.Expect(err.Error()).To(gomega.HavePrefix(ruObj.Name + ": Predrain script failed")) } @@ -984,7 +983,7 @@ func TestRunRestackTerminateNodeFail(t *testing.T) { ruObj := &upgrademgrv1alpha1.RollingUpgrade{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}, Spec: upgrademgrv1alpha1.RollingUpgradeSpec{AsgName: someAsg}} // Error flag set, should return error - mockEC2Instance := MockEC2Instance{errorFlag: true, awsErr: awserr.New("some-other-aws-error", + mockAutoscalingGroup := MockAutoscalingGroup{errorFlag: true, awsErr: awserr.New("some-other-aws-error", "some message", errors.New("some error"))} @@ -1012,7 +1011,7 @@ func TestRunRestackTerminateNodeFail(t *testing.T) { ctx := context.TODO() // This execution gets past the different launch config check, but fails to terminate node - nodesProcessed, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockEC2Instance, "exit 0;") + nodesProcessed, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockAutoscalingGroup, "exit 0;") g.Expect(nodesProcessed).To(gomega.Equal(0)) g.Expect(err.Error()).To(gomega.ContainSubstring("some error")) } @@ -1700,7 +1699,7 @@ func TestRunRestackNoNodeInAsg(t *testing.T) { Strategy: upgrademgrv1alpha1.UpdateStrategy{Type: upgrademgrv1alpha1.RandomUpdateStrategy}, }, } - mockEC2Instance := MockEC2Instance{} + mockAutoscalingGroup := MockAutoscalingGroup{} mgr, err := manager.New(cfg, manager.Options{}) g.Expect(err).NotTo(gomega.HaveOccurred()) @@ -1719,7 +1718,7 @@ func TestRunRestackNoNodeInAsg(t *testing.T) { ctx := context.TODO() // This execution gets past the different launch config check, but since there is no node name, it is skipped - nodesProcessed, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockEC2Instance, KubeCtlBinary) + nodesProcessed, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockAutoscalingGroup, KubeCtlBinary) g.Expect(nodesProcessed).To(gomega.Equal(0)) g.Expect(err).To(gomega.BeNil()) } @@ -1744,7 +1743,7 @@ func TestRunRestackWithNodesLessThanMaxUnavailable(t *testing.T) { }, }, } - mockEC2Instance := MockEC2Instance{} + mockAutoscalingGroup := MockAutoscalingGroup{} mgr, err := manager.New(cfg, manager.Options{}) g.Expect(err).NotTo(gomega.HaveOccurred()) @@ -1762,7 +1761,7 @@ func TestRunRestackWithNodesLessThanMaxUnavailable(t *testing.T) { ctx := context.TODO() // This execution should not perform drain or termination, but should pass - nodesProcessed, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockEC2Instance, KubeCtlBinary) + nodesProcessed, err := rcRollingUpgrade.runRestack(&ctx, ruObj, mockAutoscalingGroup, KubeCtlBinary) g.Expect(err).To(gomega.BeNil()) g.Expect(nodesProcessed).To(gomega.Equal(1)) } diff --git a/go.mod b/go.mod index 9df519db..1c3f805f 100644 --- a/go.mod +++ b/go.mod @@ -1,18 +1,24 @@ module github.com/keikoproj/upgrade-manager -go 1.12 +go 1.13 require ( - github.com/aws/aws-sdk-go v1.20.19 + github.com/aws/aws-sdk-go v1.25.0 github.com/go-logr/logr v0.1.0 + github.com/gogo/protobuf v1.2.1 // indirect + github.com/json-iterator/go v1.1.6 // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect github.com/onsi/ginkgo v1.8.0 github.com/onsi/gomega v1.5.0 github.com/pkg/errors v0.8.1 + github.com/sirupsen/logrus v1.4.2 + github.com/spf13/pflag v1.0.3 // indirect golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09 + golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872 // indirect + golang.org/x/text v0.3.2 // indirect gopkg.in/yaml.v2 v2.2.2 k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible sigs.k8s.io/controller-runtime v0.2.0-beta.2 - sigs.k8s.io/controller-tools v0.2.0-beta.2 // indirect ) diff --git a/go.sum b/go.sum index 629c4382..4d5625dc 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/appscode/jsonpatch v0.0.0-20190108182946-7c0e3b262f30 h1:Kn3rqvbUFqSepE2OqVu0Pn1CbDw9IuMlONapol0zuwk= github.com/appscode/jsonpatch v0.0.0-20190108182946-7c0e3b262f30/go.mod h1:4AJxUpXUhv4N+ziTvIcWWXgeorXpxPZOfk9HdEVr96M= -github.com/aws/aws-sdk-go v1.20.19 h1:RQDLGGlcffQzAceEXGdMu+uGGPGhNu+vNG3BrUZAMPI= -github.com/aws/aws-sdk-go v1.20.19/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.25.0 h1:MyXUdCesJLBvSSKYcaKeeEwxNUwUpG6/uqVYeH/Zzfo= +github.com/aws/aws-sdk-go v1.25.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -18,9 +18,6 @@ github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/zapr v0.1.0 h1:h+WVe9j6HAA01niTJPA/kKH0i7e0rLZBCwauQFcRE54= github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= -github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= -github.com/gobuffalo/envy v1.6.15 h1:OsV5vOpHYUpP7ZLS6sem1y40/lNX1BZj+ynMiRi21lQ= -github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= @@ -39,24 +36,23 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/markbates/inflect v1.0.4 h1:5fh1gzTFhfae06u3hzHYO9xe3l3v3nW5Pwt3naLTP5g= -github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -87,17 +83,15 @@ github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e h1:n/3MEhJQjQxrO github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273 h1:agujYaXJSxSo18YNX3jzl+4G6Bstwt+kqv47GS12uL0= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.2.2 h1:J7U/N7eRtzjhs26d6GqMh2HBuXP8/Z64Densiiieafo= -github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v1.0.2 h1:Fy0orTDgHdbnzHcsOgfCN4LtHf0ec3wwtiwJqwvf3Gc= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -113,7 +107,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90Pveol golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09 h1:KaQtG+aDELoNmXYas3TVkGNYRuq8JQ1aa7LJt8EXVyo= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs= @@ -124,6 +117,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872 h1:cGjJzUd8RgBw428LXP65YXni0aiGNA4Bl+ls8SmLOm8= golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= @@ -134,14 +128,11 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 h1:+DCIGbF/swA92ohVg0//6X2I golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190501045030-23463209683d h1:D7DVZUZEUgsSIDTivnUtVeGfN5AvhDIKtdIZAqx0ieE= -golang.org/x/tools v0.0.0-20190501045030-23463209683d/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -160,7 +151,6 @@ k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d h1:Jmdtdt1ZnoGfWWIIik61Z7 k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible h1:U5Bt+dab9K8qaUmXINrkXO135kA11/i5Kg1RUydgaMQ= k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= -k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0 h1:0VPpR+sizsiivjIfIAQH/rl8tan6jvWkS7lU+0di3lE= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/kube-openapi v0.0.0-20180731170545-e3762e86a74c h1:3KSCztE7gPitlZmWbNwue/2U0YruD65DqX3INopDAQM= @@ -169,8 +159,6 @@ k8s.io/utils v0.0.0-20190506122338-8fab8cb257d5 h1:VBM/0P5TWxwk+Nw6Z+lAw3DKgO76g k8s.io/utils v0.0.0-20190506122338-8fab8cb257d5/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= sigs.k8s.io/controller-runtime v0.2.0-beta.2 h1:hOWldx1qmGI9TsU+uUsq1xTgVmUV7AZo08VAYX0dwGI= sigs.k8s.io/controller-runtime v0.2.0-beta.2/go.mod h1:TSH2R0nSz4WAlUUlNnOFcOR/VUhfwBLlmtq2X6AiQCA= -sigs.k8s.io/controller-tools v0.2.0-beta.2 h1:ucniFzEuW7PFfFDuUxacdY4Fy4q065wPguVl+BE2/t0= -sigs.k8s.io/controller-tools v0.2.0-beta.2/go.mod h1:gC5UAnK1jbxWnDaqTi0yxKIsRsRwshzeRtTUGbM9vos= sigs.k8s.io/testing_frameworks v0.1.1 h1:cP2l8fkA3O9vekpy5Ks8mmA0NW/F7yBdXf8brkWhVrs= sigs.k8s.io/testing_frameworks v0.1.1/go.mod h1:VVBKrHmJ6Ekkfz284YKhQePcdycOzNH9qL6ht1zEr/U= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= diff --git a/pkg/log/log.go b/pkg/log/log.go new file mode 100644 index 00000000..95909cde --- /dev/null +++ b/pkg/log/log.go @@ -0,0 +1,200 @@ +package log + +import ( + "github.com/sirupsen/logrus" +) + +// Logger defines a set of methods for writing application logs. +type Logger interface { + Debug(args ...interface{}) + Debugf(format string, args ...interface{}) + Debugln(args ...interface{}) + Error(args ...interface{}) + Errorf(format string, args ...interface{}) + Errorln(args ...interface{}) + Fatal(args ...interface{}) + Fatalf(format string, args ...interface{}) + Fatalln(args ...interface{}) + Info(args ...interface{}) + Infof(format string, args ...interface{}) + Infoln(args ...interface{}) + Panic(args ...interface{}) + Panicf(format string, args ...interface{}) + Panicln(args ...interface{}) + Print(args ...interface{}) + Printf(format string, args ...interface{}) + Println(args ...interface{}) + Warn(args ...interface{}) + Warnf(format string, args ...interface{}) + Warning(args ...interface{}) + Warningf(format string, args ...interface{}) + Warningln(args ...interface{}) + Warnln(args ...interface{}) +} + +var defaultLogger *logrus.Logger + +func init() { + defaultLogger = newLogrusLogger() +} + +func NewLogger() *logrus.Logger { + return newLogrusLogger() +} + +func newLogrusLogger() *logrus.Logger { + l := logrus.New() + l.Level = logrus.InfoLevel + return l +} + +func SetLevel(logLevel string) { + switch logLevel { + case "debug": + defaultLogger.Level = logrus.DebugLevel + case "warning": + defaultLogger.Level = logrus.WarnLevel + case "info": + defaultLogger.Level = logrus.InfoLevel + default: + defaultLogger.Level = logrus.InfoLevel + } +} + +type Fields map[string]interface{} + +func (f Fields) With(k string, v interface{}) Fields { + f[k] = v + return f +} + +func (f Fields) WithFields(f2 Fields) Fields { + for k, v := range f2 { + f[k] = v + } + return f +} + +func WithFields(fields Fields) Logger { + return defaultLogger.WithFields(logrus.Fields(fields)) +} + +// Debug package-level convenience method. +func Debug(args ...interface{}) { + defaultLogger.Debug(args...) +} + +// Debugf package-level convenience method. +func Debugf(format string, args ...interface{}) { + defaultLogger.Debugf(format, args...) +} + +// Debugln package-level convenience method. +func Debugln(args ...interface{}) { + defaultLogger.Debugln(args...) +} + +// Error package-level convenience method. +func Error(args ...interface{}) { + defaultLogger.Error(args...) +} + +// Errorf package-level convenience method. +func Errorf(format string, args ...interface{}) { + defaultLogger.Errorf(format, args...) +} + +// Errorln package-level convenience method. +func Errorln(args ...interface{}) { + defaultLogger.Errorln(args...) +} + +// Fatal package-level convenience method. +func Fatal(args ...interface{}) { + defaultLogger.Fatal(args...) +} + +// Fatalf package-level convenience method. +func Fatalf(format string, args ...interface{}) { + defaultLogger.Fatalf(format, args...) +} + +// Fatalln package-level convenience method. +func Fatalln(args ...interface{}) { + defaultLogger.Fatalln(args...) +} + +// Info package-level convenience method. +func Info(args ...interface{}) { + defaultLogger.Info(args...) +} + +// Infof package-level convenience method. +func Infof(format string, args ...interface{}) { + defaultLogger.Infof(format, args...) +} + +// Infoln package-level convenience method. +func Infoln(args ...interface{}) { + defaultLogger.Infoln(args...) +} + +// Panic package-level convenience method. +func Panic(args ...interface{}) { + defaultLogger.Panic(args...) +} + +// Panicf package-level convenience method. +func Panicf(format string, args ...interface{}) { + defaultLogger.Panicf(format, args...) +} + +// Panicln package-level convenience method. +func Panicln(args ...interface{}) { + defaultLogger.Panicln(args...) +} + +// Print package-level convenience method. +func Print(args ...interface{}) { + defaultLogger.Print(args...) +} + +// Printf package-level convenience method. +func Printf(format string, args ...interface{}) { + defaultLogger.Printf(format, args...) +} + +// Println package-level convenience method. +func Println(args ...interface{}) { + defaultLogger.Println(args...) +} + +// Warn package-level convenience method. +func Warn(args ...interface{}) { + defaultLogger.Warn(args...) +} + +// Warnf package-level convenience method. +func Warnf(format string, args ...interface{}) { + defaultLogger.Warnf(format, args...) +} + +// Warning package-level convenience method. +func Warning(args ...interface{}) { + defaultLogger.Warning(args...) +} + +// Warningf package-level convenience method. +func Warningf(format string, args ...interface{}) { + defaultLogger.Warningf(format, args...) +} + +// Warningln package-level convenience method. +func Warningln(args ...interface{}) { + defaultLogger.Warningln(args...) +} + +// Warnln package-level convenience method. +func Warnln(args ...interface{}) { + defaultLogger.Warnln(args...) +} diff --git a/pkg/log/retry_logger.go b/pkg/log/retry_logger.go new file mode 100644 index 00000000..a3532ebe --- /dev/null +++ b/pkg/log/retry_logger.go @@ -0,0 +1,44 @@ +package log + +import ( + "fmt" + "time" + + "github.com/aws/aws-sdk-go/aws/client" + "github.com/aws/aws-sdk-go/aws/request" +) + +type RetryLogger struct { + client.DefaultRetryer +} + +var _ request.Retryer = &RetryLogger{} + +func NewRetryLogger(retryer client.DefaultRetryer) *RetryLogger { + return &RetryLogger{ + retryer, + } +} + +func (l RetryLogger) RetryRules(r *request.Request) time.Duration { + var ( + duration = l.DefaultRetryer.RetryRules(r) + service = r.ClientInfo.ServiceName + name string + err string + ) + + if r.Operation != nil { + name = r.Operation.Name + } + method := fmt.Sprintf("%v/%v", service, name) + + if r.Error != nil { + err = fmt.Sprintf("%v", r.Error) + } else { + err = fmt.Sprintf("%d %s", r.HTTPResponse.StatusCode, r.HTTPResponse.Status) + } + Debugf("retryable: %v -- %v, will retry after %v", err, method, duration) + + return duration +}