github.com/docker/compose-on-kubernetes@v0.5.0/internal/registry/strategy.go (about)

     1  package registry
     2  
     3  import (
     4  	"context"
     5  
     6  	iv "github.com/docker/compose-on-kubernetes/internal/internalversion"
     7  	"github.com/docker/compose-on-kubernetes/internal/requestaddons"
     8  	log "github.com/sirupsen/logrus"
     9  	apiequality "k8s.io/apimachinery/pkg/api/equality"
    10  	"k8s.io/apimachinery/pkg/runtime"
    11  	"k8s.io/apimachinery/pkg/util/validation/field"
    12  	"k8s.io/apiserver/pkg/storage/names"
    13  	appsv1 "k8s.io/client-go/kubernetes/typed/apps/v1"
    14  	corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
    15  )
    16  
    17  // APIVersion describes an API level (has impact on canonicalization logic)
    18  type APIVersion string
    19  
    20  const (
    21  	// APIV1beta1 represents v1beta1 API level
    22  	APIV1beta1 = APIVersion("v1beta1")
    23  	// APIV1beta2 represents v1beta2 API level or later
    24  	APIV1beta2 = APIVersion("v1beta2")
    25  )
    26  
    27  type stackStrategy struct {
    28  	runtime.ObjectTyper
    29  	names.NameGenerator
    30  	coreClient corev1.CoreV1Interface
    31  	appsClient appsv1.AppsV1Interface
    32  	version    APIVersion
    33  }
    34  
    35  func newStackStrategy(apiVersion APIVersion, typer runtime.ObjectTyper, coreClient corev1.CoreV1Interface, appsClient appsv1.AppsV1Interface) *stackStrategy {
    36  	return &stackStrategy{ObjectTyper: typer, NameGenerator: names.SimpleNameGenerator, coreClient: coreClient, appsClient: appsClient, version: apiVersion}
    37  }
    38  
    39  func (s *stackStrategy) NamespaceScoped() bool {
    40  	return true
    41  }
    42  
    43  type prepareStep func(ctx context.Context, oldStack *iv.Stack, newStack *iv.Stack) error
    44  type validateStep func(ctx context.Context, stack *iv.Stack) field.ErrorList
    45  
    46  func (s *stackStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
    47  	stack, ok := obj.(*iv.Stack)
    48  	if !ok {
    49  		log.Error("Unable to cast object to Stack")
    50  		return
    51  	}
    52  
    53  	skipValidation := requestaddons.SkipValidationFrom(ctx)
    54  
    55  	steps := []prepareStep{
    56  		prepareStackOwnership(),
    57  		prepareStackFromComposefile(skipValidation),
    58  	}
    59  
    60  	for _, step := range steps {
    61  		if err := step(ctx, nil, stack); err != nil {
    62  			stack.Status = &iv.StackStatus{
    63  				Phase:   iv.StackFailure,
    64  				Message: err.Error(),
    65  			}
    66  			log.Errorf("PrepareForCreate error (stack: %s/%s): %s", stack.Namespace, stack.Name, err)
    67  			return
    68  		}
    69  	}
    70  	stack.Status = &iv.StackStatus{
    71  		Phase:   iv.StackReconciliationPending,
    72  		Message: "Stack is waiting for reconciliation",
    73  	}
    74  }
    75  
    76  func (s *stackStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
    77  	stack := obj.(*iv.Stack)
    78  
    79  	skipValidation := requestaddons.SkipValidationFrom(ctx)
    80  	if skipValidation {
    81  		return nil
    82  	}
    83  
    84  	steps := []validateStep{
    85  		validateCreationStatus(),
    86  		validateStackNotNil(),
    87  		validateObjectNames(),
    88  		validateDryRun(),
    89  		validateCollisions(s.coreClient, s.appsClient),
    90  	}
    91  
    92  	for _, step := range steps {
    93  		if lst := step(ctx, stack); len(lst) > 0 {
    94  			log.Errorf("Validate error (stack: %s/%s): %s", stack.Namespace, stack.Name, lst.ToAggregate())
    95  			return lst
    96  		}
    97  	}
    98  	return nil
    99  }
   100  
   101  func (s *stackStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
   102  	newStack, ok := obj.(*iv.Stack)
   103  	if !ok {
   104  		log.Error("Unable to cast object to Stack")
   105  		return
   106  	}
   107  
   108  	oldStack, ok := old.(*iv.Stack)
   109  	if !ok {
   110  		log.Error("Unable to cast object to Stack")
   111  		return
   112  	}
   113  	skipValidation := requestaddons.SkipValidationFrom(ctx)
   114  
   115  	steps := []prepareStep{
   116  		prepareStackOwnership(),
   117  		prepareFieldsForUpdate(s.version),
   118  		prepareStackFromComposefile(skipValidation),
   119  	}
   120  
   121  	for _, step := range steps {
   122  		if err := step(ctx, oldStack, newStack); err != nil {
   123  			newStack.Status = &iv.StackStatus{
   124  				Phase:   iv.StackFailure,
   125  				Message: err.Error(),
   126  			}
   127  			log.Errorf("PrepareForUpdate error (stack: %s/%s): %s", newStack.Namespace, newStack.Name, err)
   128  			return
   129  		}
   130  	}
   131  	if !apiequality.Semantic.DeepEqual(oldStack.Spec, newStack.Spec) {
   132  		log.Infof("stack %s/%s spec has changed, marking as waiting for reconciliation", newStack.Namespace, newStack.Name)
   133  		newStack.Status = &iv.StackStatus{
   134  			Phase:   iv.StackReconciliationPending,
   135  			Message: "Stack is waiting for reconciliation",
   136  		}
   137  	}
   138  }
   139  
   140  func (s *stackStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
   141  	stack := obj.(*iv.Stack)
   142  
   143  	skipValidation := requestaddons.SkipValidationFrom(ctx)
   144  	if skipValidation {
   145  		return nil
   146  	}
   147  
   148  	steps := []validateStep{
   149  		validateStackNotNil(),
   150  		validateObjectNames(),
   151  		validateDryRun(),
   152  		validateCollisions(s.coreClient, s.appsClient),
   153  	}
   154  
   155  	for _, step := range steps {
   156  		if lst := step(ctx, stack); len(lst) > 0 {
   157  			log.Errorf("ValidateUpdate error (stack: %s/%s): %s", stack.Namespace, stack.Name, lst.ToAggregate())
   158  			return lst
   159  		}
   160  	}
   161  	return nil
   162  }
   163  
   164  func (s *stackStrategy) AllowCreateOnUpdate() bool {
   165  	return false
   166  }
   167  
   168  func (s *stackStrategy) AllowUnconditionalUpdate() bool {
   169  	return true
   170  }
   171  
   172  func (s *stackStrategy) Canonicalize(obj runtime.Object) {
   173  }