Skip to content

Commit

Permalink
Parameter set controller (#101)
Browse files Browse the repository at this point in the history
* chore: scaffolding for parameterset crd

Signed-off-by: Steven Gettys <[email protected]>

* basic paramset reconciler with existing tests passing

Signed-off-by: Brian DeGeeter <[email protected]>

* initial passing paramset integration test

Signed-off-by: Brian DeGeeter <[email protected]>

* add paramset installation test

Signed-off-by: Brian DeGeeter <[email protected]>

* chore: Updated docs and added some test coverage

Signed-off-by: Steven Gettys <[email protected]>

* chore: Added parameter for helm chart version configuration

Signed-off-by: Steven Gettys <[email protected]>

* docs: Fixed docs references

Signed-off-by: Steven Gettys <[email protected]>

Co-authored-by: Brian DeGeeter <[email protected]>
  • Loading branch information
sgettys and Brian DeGeeter authored Jun 3, 2022
1 parent 337a3f9 commit 38f717f
Show file tree
Hide file tree
Showing 23 changed files with 1,569 additions and 4 deletions.
8 changes: 8 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,12 @@ resources:
kind: CredentialSet
path: get.porter.sh/operator/api/v1
version: v1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: porter.sh
kind: ParameterSet
path: get.porter.sh/operator/api/v1
version: v1
version: "3"
114 changes: 114 additions & 0 deletions api/v1/parameterset_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package v1

import (
"github.com/pkg/errors"
"gopkg.in/yaml.v3"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// SERIALIZATION NOTE:
// * json tags are required for Kubernetes. Any new fields you add must have json tags for the fields to be serialized.
// * yaml tags are required for Porter. Any new fields you add must have yaml tags for the fields to be serialized.

// Parameter defines an element in a ParameterSet
type Parameter struct {
// Name is the bundle parameter name
Name string `json:"name" yaml:"name"`

//Source is the bundle parameter source
//supported: secret, value
//unsupported: file path(via configMap), env var, shell cmd
Source ParameterSource `json:"source" yaml:"source"`
}

type ParameterSource struct {
// Secret is a parameter source using a secret plugin
Secret string `json:"secret,omitempty" yaml:"secret,omitempty"`
// Value is a paremeter source using plaintext value
Value string `json:"value,omitempty" yaml:"value,omitempty"`
}

// ParameterSetSpec defines the desired state of ParameterSet
type ParameterSetSpec struct {
// AgentConfig is the name of an AgentConfig to use instead of the AgentConfig defined at the namespace or system level.
// +optional
AgentConfig *corev1.LocalObjectReference `json:"agentConfig,omitempty" yaml:"-"`

// PorterConfig is the name of a PorterConfig to use instead of the PorterConfig defined at the namespace or system level.
PorterConfig *corev1.LocalObjectReference `json:"porterConfig,omitempty" yaml:"-"`
//
// These are fields from the Porter parameter set resource.
// Your goal is that someone can copy/paste a resource from Porter into the
// spec and have it work. So be consistent!
//

// SchemaVersion is the version of the parameter set state schema.
SchemaVersion string `json:"schemaVersion" yaml:"schemaVersion"`

// Name is the name of the parameter set in Porter. Immutable.
Name string `json:"name" yaml:"name"`

// Namespace (in Porter) where the parameter set is defined.
Namespace string `json:"namespace" yaml:"namespace"`
// Parameters list of bundle parameters in the parameter set.
Parameters []Parameter `json:"parameters" yaml:"parameters"`
}

func (ps ParameterSetSpec) ToPorterDocument() ([]byte, error) {
b, err := yaml.Marshal(ps)
return b, errors.Wrap(err, "error converting the ParameterSet spec into its Porter resource representation")
}

// ParameterSetStatus defines the observed state of ParameterSet
type ParameterSetStatus struct {
PorterResourceStatus `json:",inline"`
}

//+kubebuilder:object:root=true
//+kubebuilder:subresource:status

// ParameterSet is the Schema for the parametersets API
type ParameterSet struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec ParameterSetSpec `json:"spec,omitempty"`
Status ParameterSetStatus `json:"status,omitempty"`
}

func (ps *ParameterSet) GetStatus() PorterResourceStatus {
return ps.Status.PorterResourceStatus
}

func (ps *ParameterSet) SetStatus(value PorterResourceStatus) {
ps.Status.PorterResourceStatus = value
}

// GetRetryLabelValue returns a value that is safe to use
// as a label value and represents the retry annotation used
// to trigger reconciliation.
func (ps *ParameterSet) GetRetryLabelValue() string {
return getRetryLabelValue(ps.Annotations)
}

// SetRetryAnnotation flags the resource to retry its last operation.
func (ps *ParameterSet) SetRetryAnnotation(retry string) {
if ps.Annotations == nil {
ps.Annotations = make(map[string]string, 1)
}
ps.Annotations[AnnotationRetry] = retry
}

//+kubebuilder:object:root=true

// ParameterSetList contains a list of ParameterSet
type ParameterSetList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []ParameterSet `json:"items"`
}

func init() {
SchemeBuilder.Register(&ParameterSet{}, &ParameterSetList{})
}
110 changes: 110 additions & 0 deletions api/v1/parameterset_types_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package v1

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

portertest "get.porter.sh/porter/pkg/test"
portertests "get.porter.sh/porter/tests"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestParameterSetSpec_ToPorterDocument(t *testing.T) {
wantGoldenFile := "testdata/parameter-set.yaml"
type fields struct {
AgentConfig *corev1.LocalObjectReference
PorterConfig *corev1.LocalObjectReference
SchemaVersion string
Name string
Namespace string
Parameters []Parameter
}
tests := []struct {
name string
fields fields
wantFile string
wantErrMsg string
}{
{
name: "golden file test",
fields: fields{SchemaVersion: "1.0.1",
Name: "porter-test-me",
Namespace: "dev",
Parameters: []Parameter{
{
Name: "param1",
Source: ParameterSource{Value: "test-param"},
},
{
Name: "param2",
Source: ParameterSource{Secret: "test-secret"},
},
},
},
wantFile: wantGoldenFile,
wantErrMsg: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cs := ParameterSetSpec{
AgentConfig: tt.fields.AgentConfig,
PorterConfig: tt.fields.PorterConfig,
SchemaVersion: tt.fields.SchemaVersion,
Name: tt.fields.Name,
Namespace: tt.fields.Namespace,
Parameters: tt.fields.Parameters,
}
got, err := cs.ToPorterDocument()
if tt.wantErrMsg == "" {
require.NoError(t, err)
portertest.CompareGoldenFile(t, tt.wantFile, string(got))
} else {
portertests.RequireErrorContains(t, err, tt.wantErrMsg)
}
})
}
}

func TestParameterSet_SetRetryAnnotation(t *testing.T) {
type fields struct {
TypeMeta metav1.TypeMeta
ObjectMeta metav1.ObjectMeta
Spec ParameterSetSpec
Status ParameterSetStatus
}
type args struct {
retry string
}
tests := []struct {
name string
fields fields
args args
}{
{
name: "set retry 1",
fields: fields{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{},
Spec: ParameterSetSpec{},
Status: ParameterSetStatus{},
},
args: args{retry: "1"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ps := &ParameterSet{
TypeMeta: tt.fields.TypeMeta,
ObjectMeta: tt.fields.ObjectMeta,
Spec: tt.fields.Spec,
Status: tt.fields.Status,
}
ps.SetRetryAnnotation(tt.args.retry)
assert.Equal(t, tt.args.retry, ps.Annotations[AnnotationRetry])
})
}
}
10 changes: 10 additions & 0 deletions api/v1/testdata/parameter-set.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
schemaVersion: 1.0.1
name: porter-test-me
namespace: dev
parameters:
- name: param1
source:
value: test-param
- name: param2
source:
secret: test-secret
136 changes: 136 additions & 0 deletions api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 38f717f

Please sign in to comment.