1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package diskloss
17
18 import (
19 "context"
20 "encoding/json"
21
22 "github.com/go-logr/logr"
23 "github.com/pkg/errors"
24 compute "google.golang.org/api/compute/v1"
25 "sigs.k8s.io/controller-runtime/pkg/client"
26
27 "github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
28 "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/gcpchaos/utils"
29 impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types"
30 )
31
32 var _ impltypes.ChaosImpl = (*Impl)(nil)
33
34 type Impl struct {
35 client.Client
36
37 Log logr.Logger
38 }
39
40 func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, chaos v1alpha1.InnerObject) (v1alpha1.Phase, error) {
41 gcpchaos, ok := chaos.(*v1alpha1.GCPChaos)
42 if !ok {
43 err := errors.New("chaos is not gcpchaos")
44 impl.Log.Error(err, "chaos is not GCPChaos", "chaos", chaos)
45 return v1alpha1.NotInjected, err
46 }
47 computeService, err := utils.GetComputeService(ctx, impl.Client, gcpchaos)
48 if err != nil {
49 impl.Log.Error(err, "fail to get the compute service")
50 return v1alpha1.NotInjected, err
51 }
52
53 var selected v1alpha1.GCPSelector
54 err = json.Unmarshal([]byte(records[index].Id), &selected)
55 if err != nil {
56 impl.Log.Error(err, "fail to unmarshal the selector")
57 return v1alpha1.NotInjected, err
58 }
59
60 instance, err := computeService.Instances.Get(selected.Project, selected.Zone, selected.Instance).Do()
61 if err != nil {
62 impl.Log.Error(err, "fail to get the instance")
63 return v1alpha1.NotInjected, err
64 }
65 var (
66 bytes []byte
67 notFound []string
68 marshalErr []string
69 )
70 for _, specDeviceName := range selected.DeviceNames {
71 haveDisk := false
72 for _, disk := range instance.Disks {
73 if disk.DeviceName == specDeviceName {
74 haveDisk = true
75 bytes, err = json.Marshal(disk)
76 if err != nil {
77 marshalErr = append(marshalErr, err.Error())
78 }
79 gcpchaos.Status.AttachedDisksStrings = append(gcpchaos.Status.AttachedDisksStrings, string(bytes))
80 break
81 }
82 }
83 if !haveDisk {
84 notFound = append(notFound, specDeviceName)
85 }
86 }
87 if len(notFound) != 0 {
88 err = errors.Errorf("instance (%s) does not have the disk (%s)", selected.Instance, notFound)
89 impl.Log.Error(err, "the instance does not have the disk")
90 return v1alpha1.NotInjected, err
91 }
92 if len(marshalErr) != 0 {
93 err = errors.Errorf("instance (%s), marshal disk info error (%s)", selected.Instance, marshalErr)
94 impl.Log.Error(err, "marshal disk info error")
95 return v1alpha1.NotInjected, err
96 }
97
98 for _, specDeviceName := range selected.DeviceNames {
99 _, err = computeService.Instances.DetachDisk(selected.Project, selected.Zone, selected.Instance, specDeviceName).Do()
100 if err != nil {
101 impl.Log.Error(err, "fail to detach the disk")
102 return v1alpha1.NotInjected, err
103 }
104 }
105
106 return v1alpha1.Injected, nil
107 }
108
109 func (impl *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, chaos v1alpha1.InnerObject) (v1alpha1.Phase, error) {
110 gcpchaos, ok := chaos.(*v1alpha1.GCPChaos)
111 if !ok {
112 err := errors.New("chaos is not gcpchaos")
113 impl.Log.Error(err, "chaos is not GCPChaos", "chaos", chaos)
114 return v1alpha1.Injected, err
115 }
116 computeService, err := utils.GetComputeService(ctx, impl.Client, gcpchaos)
117 if err != nil {
118 impl.Log.Error(err, "fail to get the compute service")
119 return v1alpha1.Injected, err
120 }
121 var disk compute.AttachedDisk
122 var selected v1alpha1.GCPSelector
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 for _, attachedDiskString := range gcpchaos.Status.AttachedDisksStrings {
130 err = json.Unmarshal([]byte(attachedDiskString), &disk)
131 if err != nil {
132 impl.Log.Error(err, "fail to unmarshal the disk info")
133 return v1alpha1.Injected, err
134 }
135 _, err = computeService.Instances.AttachDisk(selected.Project, selected.Zone, selected.Instance, &disk).Do()
136 if err != nil {
137 impl.Log.Error(err, "fail to attach the disk to the instance")
138 return v1alpha1.Injected, err
139 }
140 }
141 return v1alpha1.NotInjected, nil
142 }
143
144 func NewImpl(c client.Client, log logr.Logger) *Impl {
145 return &Impl{
146 Client: c,
147 Log: log.WithName("diskloss"),
148 }
149 }
150