get.porter.sh/porter@v1.3.0/pkg/storage/parameterset.go (about) 1 package storage 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 "time" 8 9 "get.porter.sh/porter/pkg/cnab" 10 "get.porter.sh/porter/pkg/schema" 11 "get.porter.sh/porter/pkg/secrets" 12 "get.porter.sh/porter/pkg/tracing" 13 "github.com/cnabio/cnab-go/bundle" 14 "go.opentelemetry.io/otel/attribute" 15 ) 16 17 const ( 18 INTERNAL_PARAMETERER_SET = "internal-parameter-set" 19 ) 20 21 var _ Document = ParameterSet{} 22 23 // ParameterSet represents a collection of parameters and their 24 // sources/strategies for value resolution 25 type ParameterSet struct { 26 ParameterSetSpec `yaml:",inline"` 27 Status ParameterSetStatus `json:"status" yaml:"status" toml:"status"` 28 } 29 30 // ParameterSetSpec represents the set of user-modifiable fields on a ParameterSet. 31 type ParameterSetSpec struct { 32 // SchemaType helps when we export the definition so editors can detect the type of document, it's not used by porter. 33 SchemaType string `json:"schemaType,omitempty" yaml:"schemaType,omitempty"` 34 35 // SchemaVersion is the version of the parameter-set schema. 36 SchemaVersion cnab.SchemaVersion `json:"schemaVersion" yaml:"schemaVersion" toml:"schemaVersion"` 37 38 // Namespace to which the credential set is scoped. 39 Namespace string `json:"namespace" yaml:"namespace" toml:"namespace"` 40 41 // Name is the name of the parameter set. 42 Name string `json:"name" yaml:"name" toml:"name"` 43 44 // Labels applied to the parameter set. 45 Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty" toml:"labels,omitempty"` 46 47 // Parameters is a list of parameter specs. 48 Parameters secrets.StrategyList `json:"parameters" yaml:"parameters" toml:"parameters"` 49 } 50 51 // ParameterSetStatus contains additional status metadata that has been set by Porter. 52 type ParameterSetStatus struct { 53 // Created timestamp of the parameter set. 54 Created time.Time `json:"created" yaml:"created" toml:"created"` 55 56 // Modified timestamp of the parameter set. 57 Modified time.Time `json:"modified" yaml:"modified" toml:"modified"` 58 } 59 60 // NewParameterSet creates a new ParameterSet with the required fields initialized. 61 func NewParameterSet(namespace string, name string, params ...secrets.SourceMap) ParameterSet { 62 now := time.Now() 63 ps := ParameterSet{ 64 ParameterSetSpec: ParameterSetSpec{ 65 SchemaType: SchemaTypeParameterSet, 66 SchemaVersion: DefaultParameterSetSchemaVersion, 67 Namespace: namespace, 68 Name: name, 69 Parameters: params, 70 }, 71 Status: ParameterSetStatus{ 72 Created: now, 73 Modified: now, 74 }, 75 } 76 77 return ps 78 } 79 80 // NewInternalParameterSet creates a new internal ParameterSet with the required fields initialized. 81 func NewInternalParameterSet(namespace string, name string, params ...secrets.SourceMap) ParameterSet { 82 return NewParameterSet(namespace, INTERNAL_PARAMETERER_SET+"-"+name, params...) 83 } 84 85 func (s ParameterSet) DefaultDocumentFilter() map[string]interface{} { 86 return map[string]interface{}{"namespace": s.Namespace, "name": s.Name} 87 } 88 89 func (s *ParameterSet) Validate(ctx context.Context, strategy schema.CheckStrategy) error { 90 _, span := tracing.StartSpan(ctx, 91 attribute.String("parameterSet", s.String()), 92 attribute.String("schemaVersion", string(s.SchemaVersion)), 93 attribute.String("defaultSchemaVersion", string(DefaultParameterSetSchemaVersion))) 94 defer span.EndSpan() 95 96 // Before we can validate, get our resource in a consistent state 97 // 1. Check if we know what to do with this version of the resource 98 if warnOnly, err := schema.ValidateSchemaVersion(strategy, SupportedParameterSetSchemaVersions, string(s.SchemaVersion), DefaultParameterSetSemverSchemaVersion); err != nil { 99 if warnOnly { 100 span.Warn(err.Error()) 101 } else { 102 return span.Error(err) 103 } 104 } 105 106 // 2. Check if they passed in the right resource type 107 if s.SchemaType != "" && !strings.EqualFold(s.SchemaType, SchemaTypeParameterSet) { 108 return span.Errorf("invalid schemaType %s, expected %s", s.SchemaType, SchemaTypeParameterSet) 109 } 110 111 // Default the schemaType before importing into the database if it's not set already 112 // SchemaType isn't really used by our code, it's a type hint for editors, but this will ensure we are consistent in our persisted documents 113 if s.SchemaType == "" { 114 s.SchemaType = SchemaTypeParameterSet 115 } 116 117 // OK! Now we can do resource specific validations 118 return nil 119 } 120 121 func (s ParameterSet) String() string { 122 return fmt.Sprintf("%s/%s", s.Namespace, s.Name) 123 } 124 125 // HasParameter determines if the specified parameter is defined in the set. 126 func (s ParameterSet) HasParameter(name string) bool { 127 for _, param := range s.Parameters { 128 if param.Name == name { 129 return true 130 } 131 } 132 133 return false 134 } 135 136 // ValidateBundle compares the given parameters with the spec in the bundle. 137 // 138 // This will result in an error only when the following conditions are true: 139 // - a parameter in the spec is not present in the given set 140 // - the parameters is required 141 // - the parameter applies to the specified action 142 // 143 // It is allowed for spec to specify both an env var and a file. In such case, if 144 // the given set provides either, it will be considered valid. 145 func (s ParameterSet) ValidateBundle(spec map[string]bundle.Parameter, action string) error { 146 for name, param := range spec { 147 if !param.AppliesTo(action) { 148 continue 149 } 150 151 if !s.HasParameter(name) && param.Required { 152 return fmt.Errorf(`parameter "%s" is required`, name) 153 } 154 } 155 return nil 156 } 157 158 // Keys returns the names of all the parameters in the set. 159 func (s ParameterSet) Keys() []string { 160 keys := make([]string, len(s.Parameters)) 161 for _, param := range s.Parameters { 162 keys = append(keys, param.Name) 163 } 164 return keys 165 }