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 string(secret.Data["aws_session_token"]),
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 err = json.Unmarshal([]byte(records[index].Id), &selected)
73 if err != nil {
74 impl.Log.Error(err, "fail to unmarshal the selector")
75 return v1alpha1.NotInjected, err
76 }
77
78 _, err = ec2client.DetachVolume(context.TODO(), &ec2.DetachVolumeInput{
79 VolumeId: selected.EbsVolume,
80 Device: selected.DeviceName,
81 Force: true,
82 InstanceId: &selected.Ec2Instance,
83 })
84
85 if err != nil {
86 impl.Log.Error(err, "fail to detach the volume")
87 return v1alpha1.NotInjected, err
88 }
89
90 return v1alpha1.Injected, nil
91 }
92
93 func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) {
94 awschaos := obj.(*v1alpha1.AWSChaos)
95
96 opts := []func(*awscfg.LoadOptions) error{
97 awscfg.WithRegion(awschaos.Spec.AWSRegion),
98 }
99 if awschaos.Spec.SecretName != nil {
100 secret := &v1.Secret{}
101 err := impl.Client.Get(ctx, types.NamespacedName{
102 Name: *awschaos.Spec.SecretName,
103 Namespace: awschaos.Namespace,
104 }, secret)
105 if err != nil {
106 impl.Log.Error(err, "fail to get cloud secret")
107 return v1alpha1.Injected, err
108 }
109 opts = append(opts, awscfg.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(
110 string(secret.Data["aws_access_key_id"]),
111 string(secret.Data["aws_secret_access_key"]),
112 string(secret.Data["aws_session_token"]),
113 )))
114 }
115 cfg, err := awscfg.LoadDefaultConfig(ctx, opts...)
116 if err != nil {
117 impl.Log.Error(err, "unable to load aws SDK config")
118 return v1alpha1.Injected, err
119 }
120 ec2client := ec2.NewFromConfig(cfg)
121
122 var selected v1alpha1.AWSSelector
123 err = json.Unmarshal([]byte(records[index].Id), &selected)
124 if err != nil {
125 impl.Log.Error(err, "fail to unmarshal the selector")
126 return v1alpha1.NotInjected, err
127 }
128
129 _, err = ec2client.AttachVolume(context.TODO(), &ec2.AttachVolumeInput{
130 Device: selected.DeviceName,
131 InstanceId: &selected.Ec2Instance,
132 VolumeId: selected.EbsVolume,
133 })
134
135 if err != nil {
136 impl.Log.Error(err, "fail to attach the volume")
137 return v1alpha1.Injected, err
138 }
139
140 return v1alpha1.NotInjected, nil
141 }
142
143 func NewImpl(c client.Client, log logr.Logger) *Impl {
144 return &Impl{
145 Client: c,
146 Log: log.WithName("detachvolume"),
147 }
148 }
149