/* Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.gnu.org/licenses/agpl-3.0.html Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package settings import ( "crypto/sha1" "fmt" "io" "sort" "strings" "k8s.libre.sh/controller-utils/application/settings/parameters" "k8s.libre.sh/controller-utils/meta" "k8s.libre.sh/controller-utils/objects" ) const ( // Generate settings as env variables in a configMap or Secret GenEnvFile SettingsGenerate = "envFile" ) const ( // Generate settings as env variables in a configMap or Secret SecretSettings SettingsType = "secret" ) type SettingsGenerate string type SettingsType string // +kubebuilder:object:generate=true type Settings struct { CreateOptions *CreateOptions `json:"createOptions,omitempty"` *SettingsSpec `json:",inline"` } // +kubebuilder:object:generate=true type CreateOptions struct { CommonMeta *meta.ObjectMeta `json:"commonMeta,omitempty"` SecretMeta *meta.ObjectMeta `json:"secretMeta,omitempty"` ConfigMeta *meta.ObjectMeta `json:"configMeta,omitempty"` Generate SettingsGenerate `json:"generate,omitempty"` SettingsType SettingsType `json:"type,omitempty"` } // NewSettings returns a Settings struct func NewSettings(co *CreateOptions, srcs *Sources, ps *parameters.Parameters) *Settings { return &Settings{ CreateOptions: co, SettingsSpec: &SettingsSpec{ Sources: srcs, Parameters: ps, }, } } func (opts *CreateOptions) Init() { if opts.CommonMeta == nil { opts.CommonMeta = &meta.ObjectMeta{} } if opts.CommonMeta.Labels == nil { opts.CommonMeta.Labels = make(map[string]string) } if opts.SecretMeta == nil { opts.SecretMeta = &meta.ObjectMeta{} } if opts.SecretMeta.Labels == nil { opts.SecretMeta.Labels = make(map[string]string) } if opts.ConfigMeta == nil { opts.ConfigMeta = &meta.ObjectMeta{} } if opts.ConfigMeta.Labels == nil { opts.SecretMeta.Labels = make(map[string]string) } } // GetCreateOptions return the CreateOptions func (s *Settings) GetCreateOptions() *CreateOptions { return s.CreateOptions } // GetConfig return the SettingsSpec func (s *Settings) GetConfig() Config { return s.SettingsSpec } // GetMeta return the meta.Instance interface func (s *Settings) GetMeta() meta.Instance { return s.CreateOptions.CommonMeta } // GetCreateOptions return the CreateOptions func (s *Settings) GetObjects() map[int]objects.Object { return GetObjects(s) } // SetDefaults sets the defaults from the create options func (s *Settings) SetDefaults() { srcs := &Sources{} secretSrc := Source{ Ref: s.GetCreateOptions().SecretMeta.GetName(), Type: "secret", } configSrc := Source{ Ref: s.GetCreateOptions().ConfigMeta.GetName(), Type: "configmap", } // Reset sources, we do not want to mount orginal resources if s.GetCreateOptions().Generate == GenEnvFile { srcs = &Sources{} } for _, p := range *s.GetParameters() { // TODO IMPROVE if p.MountType == parameters.MountEnvFile || (p.MountType != parameters.MountFile && s.GetCreateOptions().Generate == GenEnvFile) { if p.Type != parameters.ObjectFieldParameter || p.RefType != parameters.ObjectFieldParameter { p.MountType = parameters.MountEnvFile // add newly created resource ref to sources if p.Type == parameters.ConfigParameter { srcs = AppendSourceIfUnique(srcs, configSrc) } else if p.Type == parameters.SecretParameter || p.Type == "" { srcs = AppendSourceIfUnique(srcs, secretSrc) } } } if p.Type != parameters.ObjectFieldParameter || p.RefType != parameters.ObjectFieldParameter { if s.GetCreateOptions().SettingsType == "configmap" { p.Type = parameters.ConfigParameter } else if s.GetCreateOptions().SettingsType == "secret" { p.Type = parameters.SecretParameter } } if p.MountType == parameters.MountFile && len(p.Ref) == 0 { if p.Type == parameters.ConfigParameter { p.Ref = s.GetCreateOptions().ConfigMeta.GetName() } if p.Type == parameters.SecretParameter { p.Ref = s.GetCreateOptions().SecretMeta.GetName() } } } srcs.DeepCopyInto(s.GetSources()) shaParam := ¶meters.Parameter{ Key: s.GetMeta().GetComponent(), Value: GetSHAfromParameters(s.GetParameters()), MountType: parameters.MountLiteral, } for _, p := range *s.GetParameters() { if p.Key == s.GetMeta().GetComponent() { p = shaParam return } } *s.GetParameters() = append(*s.GetParameters(), shaParam) } // Init initialise the settings. // ObjectMeta are set from commons meta. // Parameters are initialised from external resources set in ValueFrom and random values are generated. /* func (s *Settings) Init(c client.Client, owner interfaces.Object, scheme *runtime.Scheme) error { if s.CreateOptions == nil { s.CreateOptions = &CreateOptions{} } s.CreateOptions.Init() meta.SetObjectMeta(s.CreateOptions.CommonMeta, s.CreateOptions.ConfigMeta) meta.SetObjectMeta(s.CreateOptions.CommonMeta, s.CreateOptions.SecretMeta) err := InitParametersValueFrom(s, c, owner, scheme) if err != nil { return err } s.InitRandValues() return nil } */ func GetSHAfromParameters(params *parameters.Parameters) string { values := []string{} for _, p := range *params { if len(p.Key) > 0 && len(p.Value) > 0 { values = append(values, p.Key+"="+p.Value) } } sort.Strings(values) return GenerateSHA(strings.Join(values, ";")) } // GenerateSHA generates SHA from string func GenerateSHA(data string) string { hasher := sha1.New() _, err := io.WriteString(hasher, data) if err != nil { // logrus.Errorf("Unable to write data in hash writer %v", err) } sha := hasher.Sum(nil) return fmt.Sprintf("%x", sha) }