...

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