1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package detachvolume
17
18 import (
19 "context"
20 "encoding/json"
21
22 awscfg "github.com/aws/aws-sdk-go-v2/config"
23 "github.com/aws/aws-sdk-go-v2/credentials"
24 "github.com/aws/aws-sdk-go-v2/service/ec2"
25 "github.com/go-logr/logr"
26 v1 "k8s.io/api/core/v1"
27 "k8s.io/apimachinery/pkg/types"
28 "sigs.k8s.io/controller-runtime/pkg/client"
29
30 "github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
31 impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types"
32 )
33
34 var _ impltypes.ChaosImpl = (*Impl)(nil)
35
36 type Impl struct {
37 client.Client
38
39 Log logr.Logger
40 }
41
42 func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) {
43 awschaos := obj.(*v1alpha1.AWSChaos)
44
45 opts := []func(*awscfg.LoadOptions) error{
46 awscfg.WithRegion(awschaos.Spec.AWSRegion),
47 }
48 if awschaos.Spec.SecretName != nil {
49 secret := &v1.Secret{}
50 err := impl.Client.Get(ctx, types.NamespacedName{
51 Name: *awschaos.Spec.SecretName,
52 Namespace: awschaos.Namespace,
53 }, secret)
54 if err != nil {
55 impl.Log.Error(err, "fail to get cloud secret")
56 return v1alpha1.NotInjected, err
57 }
58 opts = append(opts, awscfg.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(
59 string(secret.Data["aws_access_key_id"]),
60 string(secret.Data["aws_secret_access_key"]),
61 "",
62 )))
63 }
64 cfg, err := awscfg.LoadDefaultConfig(ctx, opts...)
65 if err != nil {
66 impl.Log.Error(err, "unable to load aws SDK config")
67 return v1alpha1.NotInjected, err
68 }
69 ec2client := ec2.NewFromConfig(cfg)
70
71 var selected v1alpha1.AWSSelector
72 json.Unmarshal([]byte(records[index].Id), &selected)
73 _, err = ec2client.DetachVolume(context.TODO(), &ec2.DetachVolumeInput{
74 VolumeId: selected.EbsVolume,
75 Device: selected.DeviceName,
76 Force: true,
77 InstanceId: &selected.Ec2Instance,
78 })
79
80 if err != nil {
81 impl.Log.Error(err, "fail to detach the volume")
82 return v1alpha1.NotInjected, err
83 }
84
85 return v1alpha1.Injected, nil
86 }
87
88 func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) {
89 awschaos := obj.(*v1alpha1.AWSChaos)
90
91 opts := []func(*awscfg.LoadOptions) error{
92 awscfg.WithRegion(awschaos.Spec.AWSRegion),
93 }
94 if awschaos.Spec.SecretName != nil {
95 secret := &v1.Secret{}
96 err := impl.Client.Get(ctx, types.NamespacedName{
97 Name: *awschaos.Spec.SecretName,
98 Namespace: awschaos.Namespace,
99 }, secret)
100 if err != nil {
101 impl.Log.Error(err, "fail to get cloud secret")
102 return v1alpha1.Injected, err
103 }
104 opts = append(opts, awscfg.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(
105 string(secret.Data["aws_access_key_id"]),
106 string(secret.Data["aws_secret_access_key"]),
107 "",
108 )))
109 }
110 cfg, err := awscfg.LoadDefaultConfig(ctx, opts...)
111 if err != nil {
112 impl.Log.Error(err, "unable to load aws SDK config")
113 return v1alpha1.Injected, err
114 }
115 ec2client := ec2.NewFromConfig(cfg)
116
117 var selected v1alpha1.AWSSelector
118 json.Unmarshal([]byte(records[index].Id), &selected)
119
120 _, err = ec2client.AttachVolume(context.TODO(), &ec2.AttachVolumeInput{
121 Device: selected.DeviceName,
122 InstanceId: &selected.Ec2Instance,
123 VolumeId: selected.EbsVolume,
124 })
125
126 if err != nil {
127 impl.Log.Error(err, "fail to attach the volume")
128 return v1alpha1.Injected, err
129 }
130
131 return v1alpha1.NotInjected, nil
132 }
133
134 func NewImpl(c client.Client, log logr.Logger) *Impl {
135 return &Impl{
136 Client: c,
137 Log: log.WithName("detachvolume"),
138 }
139 }
140