...

Source file src/github.com/chaos-mesh/chaos-mesh/cmd/chaos-builder/impl.go

Documentation: github.com/chaos-mesh/chaos-mesh/cmd/chaos-builder

     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 main
    17  
    18  import (
    19  	"bytes"
    20  	"text/template"
    21  )
    22  
    23  const implImport = `
    24  import (
    25  	"encoding/json"
    26  	"reflect"
    27  	"time"
    28  	"fmt"
    29  
    30  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	"sigs.k8s.io/controller-runtime/pkg/webhook"
    32  	logf "sigs.k8s.io/controller-runtime/pkg/log"
    33  	"k8s.io/apimachinery/pkg/runtime"
    34  
    35  	gw "github.com/chaos-mesh/chaos-mesh/api/v1alpha1/genericwebhook"
    36  )
    37  
    38  // updating spec of a chaos will have no effect, we'd better reject it
    39  var ErrCanNotUpdateChaos = fmt.Errorf("Cannot update chaos spec")
    40  `
    41  
    42  const implTemplate = `
    43  const Kind{{.Type}} = "{{.Type}}"
    44  {{if .IsExperiment}}
    45  // IsDeleted returns whether this resource has been deleted
    46  func (in *{{.Type}}) IsDeleted() bool {
    47  	return !in.DeletionTimestamp.IsZero()
    48  }
    49  
    50  // IsPaused returns whether this resource has been paused
    51  func (in *{{.Type}}) IsPaused() bool {
    52  	if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" {
    53  		return false
    54  	}
    55  	return true
    56  }
    57  
    58  // GetObjectMeta would return the ObjectMeta for chaos
    59  func (in *{{.Type}}) GetObjectMeta() *metav1.ObjectMeta {
    60  	return &in.ObjectMeta
    61  }
    62  
    63  // GetDuration would return the duration for chaos
    64  func (in *{{.Type}}Spec) GetDuration() (*time.Duration, error) {
    65  	if in.Duration == nil {
    66  		return nil, nil
    67  	}
    68  	duration, err := time.ParseDuration(string(*in.Duration))
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  	return &duration, nil
    73  }
    74  
    75  // GetStatus returns the status
    76  func (in *{{.Type}}) GetStatus() *ChaosStatus {
    77  	return &in.Status.ChaosStatus
    78  }
    79  
    80  // GetSpecAndMetaString returns a string including the meta and spec field of this chaos object.
    81  func (in *{{.Type}}) GetSpecAndMetaString() (string, error) {
    82  	spec, err := json.Marshal(in.Spec)
    83  	if err != nil {
    84  		return "", err
    85  	}
    86  
    87  	meta := in.ObjectMeta.DeepCopy()
    88  	meta.SetResourceVersion("")
    89  	meta.SetGeneration(0)
    90  
    91  	return string(spec) + meta.String(), nil
    92  }
    93  
    94  // +kubebuilder:object:root=true
    95  
    96  // {{.Type}}List contains a list of {{.Type}}
    97  type {{.Type}}List struct {
    98  	metav1.TypeMeta ` + "`" + `json:",inline"` + "`" + `
    99  	metav1.ListMeta ` + "`" + `json:"metadata,omitempty"` + "`" + `
   100  	Items           []{{.Type}} ` + "`" + `json:"items"` + "`" + `
   101  }
   102  
   103  func (in *{{.Type}}List) DeepCopyList() GenericChaosList {
   104  	return in.DeepCopy()
   105  }
   106  
   107  // ListChaos returns a list of chaos
   108  func (in *{{.Type}}List) ListChaos() []GenericChaos {
   109  	var result []GenericChaos
   110  	for _, item := range in.Items {
   111  		item := item
   112  		result = append(result, &item)
   113  	}
   114  	return result
   115  }
   116  
   117  func (in *{{.Type}}) DurationExceeded(now time.Time) (bool, time.Duration, error) {
   118  	duration, err := in.Spec.GetDuration()
   119  	if err != nil {
   120  		return false, 0, err
   121  	}
   122  
   123  	if duration != nil {
   124  		stopTime := in.GetCreationTimestamp().Add(*duration)
   125  		if stopTime.Before(now) {
   126  			return true, 0, nil
   127  		}
   128  
   129  		return false, stopTime.Sub(now), nil
   130  	}
   131  
   132  	return false, 0, nil
   133  }
   134  
   135  func (in *{{.Type}}) IsOneShot() bool {
   136  	{{- if .OneShotExp}}
   137  	if {{.OneShotExp}} {
   138  		return true
   139  	}
   140  
   141  	return false
   142  	{{- else}}
   143  	return false
   144  	{{- end}}
   145  }
   146  {{end}}
   147  var {{.Type}}WebhookLog = logf.Log.WithName("{{.Type}}-resource")
   148  
   149  func (in *{{.Type}}) ValidateCreate() error {
   150  	{{.Type}}WebhookLog.Info("validate create", "name", in.Name)
   151  	return in.Validate()
   152  }
   153  
   154  // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
   155  func (in *{{.Type}}) ValidateUpdate(old runtime.Object) error {
   156  	{{.Type}}WebhookLog.Info("validate update", "name", in.Name)
   157  	{{- if not .EnableUpdate}}
   158  	if !reflect.DeepEqual(in.Spec, old.(*{{.Type}}).Spec) {
   159  		return ErrCanNotUpdateChaos
   160  	}
   161  	{{- end}}
   162  	return in.Validate()
   163  }
   164  
   165  // ValidateDelete implements webhook.Validator so a webhook will be registered for the type
   166  func (in *{{.Type}}) ValidateDelete() error {
   167  	{{.Type}}WebhookLog.Info("validate delete", "name", in.Name)
   168  
   169  	// Nothing to do?
   170  	return nil
   171  }
   172  
   173  var _ webhook.Validator = &{{.Type}}{}
   174  
   175  func (in *{{.Type}}) Validate() error {
   176  	errs := gw.Validate(in)
   177  	return gw.Aggregate(errs)
   178  }
   179  
   180  var _ webhook.Defaulter = &{{.Type}}{}
   181  
   182  func (in *{{.Type}}) Default() {
   183  	gw.Default(in)
   184  }
   185  `
   186  
   187  func generateImpl(name string, oneShotExp string, isExperiment, enableUpdate bool) string {
   188  	tmpl, err := template.New("impl").Parse(implTemplate)
   189  	if err != nil {
   190  		log.Error(err, "fail to build template")
   191  		return ""
   192  	}
   193  
   194  	buf := new(bytes.Buffer)
   195  	err = tmpl.Execute(buf, &metadata{
   196  		Type:         name,
   197  		OneShotExp:   oneShotExp,
   198  		IsExperiment: isExperiment,
   199  		EnableUpdate: enableUpdate,
   200  	})
   201  	if err != nil {
   202  		log.Error(err, "fail to execute template")
   203  		return ""
   204  	}
   205  
   206  	return buf.String()
   207  }
   208