Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions modules/common/util/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,8 @@ var (
ErrNoPodSubdomain = errors.New("no subdomain or hostname")
// ErrPodsInterfaces indicates that pod interfaces aren't configured
ErrPodsInterfaces = errors.New("not all pods have interfaces")
// ErrTemplateSubdirUnset indicates no template subdir for a non-none template type
ErrTemplateSubdirUnset = errors.New("template subdir not set")
// ErrInstanceTypeUnsetWithMultiTemplateDir indicates InstanceType is empty while MultiTemplateDir is set
ErrInstanceTypeUnsetWithMultiTemplateDir = errors.New("instance type not set")
)
32 changes: 25 additions & 7 deletions modules/common/util/template_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ type Template struct {
ConfigOptions map[string]interface{} // map of parameters as input data to render the templates
SkipSetOwner bool // skip setting ownership on the associated configmap
Version string // optional version string to separate templates inside the InstanceType/Type directory. E.g. placementapi/config/18.0
MultiTemplateDir string // templates dir for multi-group operators, e.g. nova/api; requires InstanceType to be set
Comment thread
gibizer marked this conversation as resolved.
}

// GetTemplatesPath get path to templates, either running local or deployed as container
Expand All @@ -83,20 +84,21 @@ func GetTemplatesPath() (string, error) {

// GetAllTemplates - get all template files
//
// The structur of the folder is, base path, the kind (CRD in lower case),
// The structure of the folder is, base path, subdir, templateType, version
// - path - base path of the templates folder
// - kind - sub folder for the CRDs templates
// - subdir - directory under that root: one segment (legacy InstanceType, e.g. NovaAPI) or
// multi-segment (e.g. nova/api from MultiTemplateDir)
// - templateType - TType of the templates. When the templates got rendered and added to a CM
// this information is e.g. used for the permissions they get mounted into the pod
// - version - if there need to be templates for different versions, they can be stored in a version subdir
//
// Sub directories inside the specified directory with the above parameters get ignored.
func GetAllTemplates(path string, kind string, templateType string, version string) []string {
func GetAllTemplates(path string, subdir string, templateType string, version string) []string {
Comment thread
gibizer marked this conversation as resolved.

templatePath := filepath.Join(path, strings.ToLower(kind), templateType, "*")
templatePath := filepath.Join(path, subdir, templateType, "*")

if version != "" {
templatePath = filepath.Join(path, strings.ToLower(kind), templateType, version, "*")
templatePath = filepath.Join(path, subdir, templateType, version, "*")
}

templatesFiles, err := filepath.Glob(templatePath)
Expand Down Expand Up @@ -293,8 +295,24 @@ func GetTemplateData(t Template) (map[string]string, error) {
data := make(map[string]string)

if t.Type != TemplateTypeNone {
// get all scripts templates which are in ../templesPath/cr.Kind/CMType/<OSPVersion - optional>
templatesFiles := GetAllTemplates(templatesPath, t.InstanceType, string(t.Type), string(t.Version))
// If MultiTemplateDir is set but InstanceType is not, return an error
// though we do not use InstanceType here, but it is used in secret.go
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I see it in https://github.com/openstack-k8s-operators/lib-common/blame/3e1007da0cbd673047305e423866c8c50b1e3167/modules/common/secret/secret.go#L272

I'm wondering why we are setting an owner label on a Secret this way instead of using the owner reference way. Also it is strange that we only do that on Secret but not on ConfigMap.
@stuggi Are we still supporting cross namespace Secrets? (That is the most I could extract from the code why we are labelling)
Also it is strange that we only enforce InstanceType if the template is not TemplateTypeNone. So I guess a template with TemplateTypeNone and without a InstanceType cannot be outside of our namespace as secret creation would fail due to the missing InstanceType.

  • If we don't need to support Secrets outside of the namespace the I suggest to clean that code up and remove this dependency and checks
  • if we do need to support Secrets outside of the namespace then I suggest
    • to make the InstanceType mandatory in all template types to avoid surprises
    • consider supporting the same thing for ConfigMaps as well.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, the owner label is coming from creating/tracking object in different namespaces. There is one use case I know of where we create secret in a different namespace and this is for BMH provisioning, where userdata and networkdata secret needs to be created in the bmh namespaces , https://github.com/openstack-k8s-operators/openstack-baremetal-operator/blob/main/internal/openstackbaremetalset/baremetalhost.go#L83 ,

Just from a quick search it is not using the labels, for delete its using name https://github.com/openstack-k8s-operators/openstack-baremetal-operator/blob/main/internal/openstackbaremetalset/baremetalhost.go#L318, but I think its still good to see from the labels who the owner is, if someone checks the env and wonders who created those secrets in the bmh namespace. Therefore I don't think we should remove it. We can consider supporting it for CMs as well in a follow up. I wanted to spend more time on lib-common to cleanup/align things, but got other prios. Maybe after FR6 I can spend some time on this.

if t.MultiTemplateDir != "" && t.InstanceType == "" {
return nil, ErrInstanceTypeUnsetWithMultiTemplateDir
}

var templateSubdir string
// if MultiTemplateDir is set, it will take precedence over InstanceType
// otherwise, InstanceType is used to create the template subdir based on CRD name
if t.MultiTemplateDir != "" {
Comment thread
gibizer marked this conversation as resolved.
templateSubdir = t.MultiTemplateDir
} else {
templateSubdir = strings.ToLower(t.InstanceType)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good, we are doing the ToLower here, was wondering above

}
if templateSubdir == "" {
return nil, fmt.Errorf("%w: type is %q", ErrTemplateSubdirUnset, t.Type)
}
templatesFiles := GetAllTemplates(templatesPath, templateSubdir, string(t.Type), string(t.Version))

// render all template files
for _, file := range templatesFiles {
Expand Down
79 changes: 74 additions & 5 deletions modules/common/util/template_util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,14 +300,14 @@ func TestGetAllTemplates(t *testing.T) {

tests := []struct {
name string
kind string
subdir string
tmplType TType
version string
want []string
}{
{
name: "Get TemplateTypeConfig templates with no version",
kind: "testservice",
subdir: "testservice",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we should use TestService in one of them to check the ToLower situation? something we did not have right now.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used TestService at L369.

tmplType: TemplateTypeConfig,
version: "",
want: []string{
Expand All @@ -318,7 +318,7 @@ func TestGetAllTemplates(t *testing.T) {
},
{
name: "Get TemplateTypeScripts templates with version",
kind: "testservice",
subdir: "testservice",
tmplType: TemplateTypeScripts,
version: "1.0",
want: []string{
Expand All @@ -334,7 +334,7 @@ func TestGetAllTemplates(t *testing.T) {
p, _ := GetTemplatesPath()
g.Expect(p).To(BeADirectory())

templatesFiles := GetAllTemplates(p, tt.kind, string(tt.tmplType), tt.version)
templatesFiles := GetAllTemplates(p, tt.subdir, string(tt.tmplType), tt.version)

g.Expect(templatesFiles).To(HaveLen(len(tt.want)))
g.Expect(templatesFiles).Should(HaveEach(BeARegularFile()))
Expand Down Expand Up @@ -366,7 +366,7 @@ func TestGetTemplateData(t *testing.T) {
Name: "testservice",
Namespace: "somenamespace",
Type: TemplateTypeConfig,
InstanceType: "testservice",
InstanceType: "TestService",
Version: "",
ConfigOptions: map[string]interface{}{
"ServiceUser": "foo",
Expand All @@ -382,6 +382,75 @@ func TestGetTemplateData(t *testing.T) {
},
error: false,
},
{
name: "Render TemplateTypeConfig using MultiTemplateDir with InstanceType",
tmpl: Template{
Name: "testservice",
Namespace: "somenamespace",
Type: TemplateTypeConfig,
InstanceType: "wrong-unused",
MultiTemplateDir: "testservice",
Comment thread
bogdando marked this conversation as resolved.
Version: "",
ConfigOptions: map[string]interface{}{
"ServiceUser": "foo",
"Count": 1,
"Upper": "BAR",
},
AdditionalTemplate: map[string]string{},
},
want: map[string]string{
"bar.conf": "[DEFAULT]\nstate_path = /var/lib/nova\ndebug=true\nsome_parameter_with_brackets=[test]\ncompute_driver = libvirt.LibvirtDriver\n\n[oslo_concurrency]\nlock_path = /var/lib/nova/tmp\n",
"config.json": "{\n \"command\": \"/usr/sbin/httpd -DFOREGROUND\",\n}\n",
"foo.conf": "username = foo\ncount = 1\nadd = 3\nlower = bar\n",
},
error: false,
},
{
name: "Render TemplateTypeConfig using MultiTemplateDir test/service with InstanceType",
tmpl: Template{
Name: "testservice",
Namespace: "somenamespace",
Type: TemplateTypeConfig,
InstanceType: "wrong-unused",
MultiTemplateDir: "test/service",
Version: "",
ConfigOptions: map[string]interface{}{
"ServiceUser": "foo",
"Count": 1,
"Upper": "BAR",
},
AdditionalTemplate: map[string]string{},
},
want: map[string]string{
"bar.conf": "[DEFAULT]\nstate_path = /var/lib/nova\ndebug=true\nsome_parameter_with_brackets=[test]\ncompute_driver = libvirt.LibvirtDriver\n\n[oslo_concurrency]\nlock_path = /var/lib/nova/tmp\n",
"config.json": "{\n \"command\": \"/usr/sbin/httpd -DFOREGROUND\",\n}\n",
"foo.conf": "username = foo\ncount = 1\nadd = 3\nlower = bar\n",
},
error: false,
},
{
name: "TemplateTypeConfig with MultiTemplateDir and empty InstanceType errors",
tmpl: Template{
Name: "testservice",
Namespace: "somenamespace",
Type: TemplateTypeConfig,
MultiTemplateDir: "testservice",
ConfigOptions: map[string]interface{}{"ServiceUser": "foo"},
},
want: map[string]string{},
error: true,
},
{
name: "TemplateTypeConfig with empty InstanceType and MultiTemplateDir errors",
tmpl: Template{
Name: "testservice",
Namespace: "somenamespace",
Type: TemplateTypeConfig,
ConfigOptions: map[string]interface{}{"ServiceUser": "foo"},
},
want: map[string]string{},
error: true,
},
{
name: "Render TemplateTypeScripts templates with version",
tmpl: Template{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{{define "bar-template"}}
[DEFAULT]
state_path = /var/lib/nova


debug=true

some_parameter_with_brackets=[test]
compute_driver = libvirt.LibvirtDriver




[oslo_concurrency]
lock_path = /var/lib/nova/tmp
{{end}}
{{- $var := execTempl "bar-template" . | removeNewLinesInSections -}}
{{$var -}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"command": "/usr/sbin/httpd -DFOREGROUND",
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
username = {{ .ServiceUser }}
count = {{ .Count }}
add = {{ (add 1 2) }}
lower = {{ (lower .Upper) }}
Loading