Skip to content

Commit

Permalink
Add options for a resource in a delivery (#623)
Browse files Browse the repository at this point in the history
Co-authored-by: Emily Johnson <emjohnson@vmware.com>
Co-authored-by: Marty Spiewak <mspiewak@vmware.com>
  • Loading branch information
3 people authored Feb 16, 2022
1 parent ec1315d commit 2952afa
Show file tree
Hide file tree
Showing 42 changed files with 1,772 additions and 625 deletions.
63 changes: 62 additions & 1 deletion config/crd/bases/carto.run_clusterdeliveries.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,70 @@ spec:
description: Name of the template to apply
minLength: 1
type: string
options:
description: Options is a list of template names and Selectors.
The templates must all be of type Kind. A template will
be selected if the deliverable matches the specified Selector.
Only one template can be selected. Only one of Name and
Options can be specified.
items:
properties:
name:
description: Name of the template to apply
minLength: 1
type: string
selector:
description: Selector is a field query over a workload
or deliverable resource.
properties:
matchFields:
description: MatchFields is a list of field selector
requirements. The requirements are ANDed.
items:
properties:
key:
description: 'Key is the JSON path in the
workload to match against. e.g. for workload:
"workload.spec.source.git.url", e.g. for
deliverable: "deliverable.spec.source.git.url"'
minLength: 1
type: string
operator:
description: Operator represents a key's
relationship to a set of values. Valid
operators are In, NotIn, Exists and DoesNotExist.
enum:
- In
- NotIn
- Exists
- DoesNotExist
type: string
values:
description: Values is an array of string
values. If the operator is In or NotIn,
the values array must be non-empty. If
the operator is Exists or DoesNotExist,
the values array must be empty.
items:
type: string
type: array
required:
- key
- operator
type: object
minItems: 1
type: array
required:
- matchFields
type: object
required:
- name
- selector
type: object
minItems: 2
type: array
required:
- kind
- name
type: object
required:
- name
Expand Down
8 changes: 5 additions & 3 deletions config/crd/bases/carto.run_clustersupplychains.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -185,16 +185,18 @@ spec:
type: string
selector:
description: Selector is a field query over a workload
resource.
or deliverable resource.
properties:
matchFields:
description: MatchFields is a list of field selector
requirements. The requirements are ANDed.
items:
properties:
key:
description: Key is the JSON path in the
workload to match against. e.g. "workload.spec.source.git.url"
description: 'Key is the JSON path in the
workload to match against. e.g. for workload:
"workload.spec.source.git.url", e.g. for
deliverable: "deliverable.spec.source.git.url"'
minLength: 1
type: string
operator:
Expand Down
111 changes: 28 additions & 83 deletions pkg/apis/v1alpha1/cluster_delivery.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ const (
NotFoundDeliveryTemplatesReadyReason = "TemplatesNotFound"
)

var ValidDeliveryTemplates = []client.Object{
&ClusterSourceTemplate{},
&ClusterDeploymentTemplate{},
&ClusterTemplate{},
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:scope=Cluster
Expand All @@ -53,10 +59,6 @@ type ClusterDelivery struct {
Status DeliveryStatus `json:"status,omitempty"`
}

func (c *ClusterDelivery) GetSelector() map[string]string {
return c.Spec.Selector
}

type DeliverySpec struct {
// Resources that are responsible for deploying and validating
// the deliverable
Expand Down Expand Up @@ -131,23 +133,24 @@ type DeliveryResource struct {
Configs []ResourceReference `json:"configs,omitempty"`
}

type DeploymentReference struct {
Resource string `json:"resource"`
}

var ValidDeliveryTemplates = []client.Object{
&ClusterSourceTemplate{},
&ClusterDeploymentTemplate{},
&ClusterTemplate{},
}

type DeliveryTemplateReference struct {
// Kind of the template to apply
// +kubebuilder:validation:Enum=ClusterSourceTemplate;ClusterDeploymentTemplate;ClusterTemplate
Kind string `json:"kind"`
// Name of the template to apply
// +kubebuilder:validation:MinLength=1
Name string `json:"name"`
Name string `json:"name,omitempty"`

// Options is a list of template names and Selectors. The templates must all be of type Kind.
// A template will be selected if the deliverable matches the specified Selector.
// Only one template can be selected.
// Only one of Name and Options can be specified.
// +kubebuilder:validation:MinItems=2
Options []TemplateOption `json:"options,omitempty"`
}

type DeploymentReference struct {
Resource string `json:"resource"`
}

// +kubebuilder:object:root=true
Expand All @@ -159,85 +162,27 @@ type ClusterDeliveryList struct {
}

func (c *ClusterDelivery) ValidateCreate() error {
return c.validateNewState()
}

func (c *ClusterDelivery) ValidateUpdate(_ runtime.Object) error {
return c.validateNewState()
}

func (c *ClusterDelivery) ValidateDelete() error {
return nil
}

func (c *ClusterDelivery) validateNewState() error {
if err := c.validateParams(); err != nil {
return err
}

if err := c.validateResourceNamesUnique(); err != nil {
return err
}

if err := c.validateDeploymentPassedToProperReceivers(); err != nil {
return err
}

return c.validateDeploymentTemplateDidNotReceiveConfig()
}

func (c *ClusterDelivery) validateDeploymentPassedToProperReceivers() error {
for _, resource := range c.Spec.Resources {
if resource.TemplateRef.Kind == "ClusterDeploymentTemplate" && resource.Deployment == nil {
return fmt.Errorf("spec.resources[%s] is a ClusterDeploymentTemplate and must receive a deployment", resource.Name)
}

if resource.Deployment != nil && resource.TemplateRef.Kind != "ClusterDeploymentTemplate" {
return fmt.Errorf("spec.resources[%s] receives a deployment but is not a ClusterDeploymentTemplate", resource.Name)
}
err := c.validateNewState()
if err != nil {
return fmt.Errorf("error validating clusterdelivery [%s]: %w", c.Name, err)
}
return nil
}

func (c *ClusterDelivery) validateResourceNamesUnique() error {
names := map[string]bool{}

for idx, resource := range c.Spec.Resources {
if names[resource.Name] {
return fmt.Errorf("spec.resources[%d].name \"%s\" cannot appear twice", idx, resource.Name)
}
names[resource.Name] = true
func (c *ClusterDelivery) ValidateUpdate(_ runtime.Object) error {
err := c.validateNewState()
if err != nil {
return fmt.Errorf("error validating clusterdelivery [%s]: %w", c.Name, err)
}
return nil
}

func (c *ClusterDelivery) validateDeploymentTemplateDidNotReceiveConfig() error {
for _, resource := range c.Spec.Resources {
if resource.TemplateRef.Kind == "ClusterDeploymentTemplate" && resource.Configs != nil {
return fmt.Errorf("spec.resources[%s] is a ClusterDeploymentTemplate and must not receive config", resource.Name)
}
}
func (c *ClusterDelivery) ValidateDelete() error {
return nil
}

func (c *ClusterDelivery) validateParams() error {
for _, param := range c.Spec.Params {
err := param.validate()
if err != nil {
return err
}
}

for _, resource := range c.Spec.Resources {
for _, param := range resource.Params {
err := param.validate()
if err != nil {
return fmt.Errorf("resource [%s] is invalid: %w", resource.Name, err)
}
}
}

return nil
func (c *ClusterDelivery) GetSelector() map[string]string {
return c.Spec.Selector
}

func init() {
Expand Down
Loading

0 comments on commit 2952afa

Please sign in to comment.