...

Source file src/github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/gcpchaos/diskloss/impl.go

Documentation: github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/gcpchaos/diskloss

     1  // Copyright 2021 Chaos Mesh Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    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