Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
H
helm3
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
helm3
Commits
81ac98ad
Commit
81ac98ad
authored
Jun 23, 2016
by
Miguel Martinez
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Adding support for associated templates
Fixing unit test
parent
03d27779
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
73 additions
and
32 deletions
+73
-32
configmap.yaml
docs/examples/nginx/templates/configmap.yaml
+3
-3
deployment.yaml
docs/examples/nginx/templates/deployment.yaml
+5
-5
svc.yaml
docs/examples/nginx/templates/svc.yaml
+4
-4
template.go
pkg/lint/rules/template.go
+40
-14
template_test.go
pkg/lint/rules/template_test.go
+17
-0
message.go
pkg/lint/support/message.go
+3
-5
message_test.go
pkg/lint/support/message_test.go
+1
-1
No files found.
docs/examples/nginx/templates/configmap.yaml
View file @
81ac98ad
...
@@ -5,11 +5,11 @@ kind: ConfigMap
...
@@ -5,11 +5,11 @@ kind: ConfigMap
metadata
:
metadata
:
name
:
{{
template "fullname" .
}}
name
:
{{
template "fullname" .
}}
labels
:
labels
:
release
:
{{
.Release.Name
}}
release
:
{{
.Release.Name | quote
}}
app
:
{{
template "fullname" .
}}
app
:
{{
template "fullname" .
}}
heritage
:
{{
.Release.Service
}}
heritage
:
{{
.Release.Service
| quote
}}
data
:
data
:
# When the config map is mounted as a volume, these will be created as
# When the config map is mounted as a volume, these will be created as
# files.
# files.
index.html
:
{{
default "Hello" .index | squote
}}
index.html
:
{{
default "Hello" .index | quote
}}
test.txt
:
test
test.txt
:
test
docs/examples/nginx/templates/deployment.yaml
View file @
81ac98ad
...
@@ -9,18 +9,18 @@ metadata:
...
@@ -9,18 +9,18 @@ metadata:
# The "heritage" label is used to track which tool deployed a given chart.
# The "heritage" label is used to track which tool deployed a given chart.
# It is useful for admins who want to see what releases a particular tool
# It is useful for admins who want to see what releases a particular tool
# is responsible for.
# is responsible for.
heritage
:
{{
.Release.Service
}}
heritage
:
{{
.Release.Service | quote
}}
# This makes it easy to search for all components of a release using kubectl.
# This makes it easy to search for all components of a release using kubectl.
release
:
{{
.Release.Name
}}
release
:
{{
.Release.Name | quote
}}
# This makes it easy to audit chart usage.
# This makes it easy to audit chart usage.
chart
:
{{
.Chart.Name
}}
-{{.Chart.Version}}
chart
:
"
{{.Chart.Name}}-{{.Chart.Version}}"
spec
:
spec
:
replicas
:
{{
default 1 .replicaCount
}}
replicas
:
{{
default 1 .replicaCount | quote
}}
template
:
template
:
metadata
:
metadata
:
labels
:
labels
:
app
:
{{
template "fullname" .
}}
app
:
{{
template "fullname" .
}}
release
:
{{
.Release.Name
}}
release
:
{{
.Release.Name
| quote
}}
spec
:
spec
:
containers
:
containers
:
-
name
:
{{
template "fullname" .
}}
-
name
:
{{
template "fullname" .
}}
...
...
docs/examples/nginx/templates/svc.yaml
View file @
81ac98ad
...
@@ -5,12 +5,12 @@ kind: Service
...
@@ -5,12 +5,12 @@ kind: Service
metadata
:
metadata
:
name
:
{{
template "fullname" .
}}
name
:
{{
template "fullname" .
}}
labels
:
labels
:
heritage
:
{{
.Release.Service
}}
heritage
:
{{
.Release.Service | quote
}}
release
:
{{
.Release.Name
}}
release
:
{{
.Release.Name | quote
}}
chart
:
{{
.Chart.Name
}}
-{{.Chart.Version}}
chart
:
"
{{.Chart.Name}}-{{.Chart.Version}}"
spec
:
spec
:
ports
:
ports
:
-
port
:
{{
default 80 .httpPort
}}
-
port
:
{{
default 80 .httpPort | quote
}}
targetPort
:
80
targetPort
:
80
protocol
:
TCP
protocol
:
TCP
name
:
http
name
:
http
...
...
pkg/lint/rules/template.go
View file @
81ac98ad
...
@@ -35,7 +35,7 @@ import (
...
@@ -35,7 +35,7 @@ import (
func
Templates
(
linter
*
support
.
Linter
)
{
func
Templates
(
linter
*
support
.
Linter
)
{
templatesPath
:=
filepath
.
Join
(
linter
.
ChartDir
,
"templates"
)
templatesPath
:=
filepath
.
Join
(
linter
.
ChartDir
,
"templates"
)
templatesDirExist
:=
linter
.
RunLinterRule
(
support
.
WarningSev
,
validateTemplatesDir
(
linter
,
templatesPath
))
templatesDirExist
:=
linter
.
RunLinterRule
(
support
.
WarningSev
,
validateTemplatesDir
(
templatesPath
))
// Templates directory is optional for now
// Templates directory is optional for now
if
!
templatesDirExist
{
if
!
templatesDirExist
{
...
@@ -80,14 +80,15 @@ func Templates(linter *support.Linter) {
...
@@ -80,14 +80,15 @@ func Templates(linter *support.Linter) {
for
_
,
template
:=
range
chart
.
Templates
{
for
_
,
template
:=
range
chart
.
Templates
{
fileName
,
preExecutedTemplate
:=
template
.
Name
,
template
.
Data
fileName
,
preExecutedTemplate
:=
template
.
Name
,
template
.
Data
yamlFile
:=
linter
.
RunLinterRule
(
support
.
ErrorSev
,
validateYamlExtension
(
linter
,
fileName
))
linter
.
RunLinterRule
(
support
.
ErrorSev
,
validateAllowedExtension
(
fileName
))
if
!
yamlFile
{
// We only apply the following lint rules to yaml files
return
if
filepath
.
Ext
(
fileName
)
!=
".yaml"
{
continue
}
}
// Check that all the templates have a matching value
// Check that all the templates have a matching value
linter
.
RunLinterRule
(
support
.
WarningSev
,
validateNonMissingValues
(
fileName
,
chartValues
,
preExecutedTemplate
))
linter
.
RunLinterRule
(
support
.
WarningSev
,
validateNonMissingValues
(
fileName
,
templatesPath
,
chartValues
,
preExecutedTemplate
))
linter
.
RunLinterRule
(
support
.
WarningSev
,
validateQuotes
(
fileName
,
string
(
preExecutedTemplate
)))
linter
.
RunLinterRule
(
support
.
WarningSev
,
validateQuotes
(
fileName
,
string
(
preExecutedTemplate
)))
...
@@ -100,7 +101,7 @@ func Templates(linter *support.Linter) {
...
@@ -100,7 +101,7 @@ func Templates(linter *support.Linter) {
validYaml
:=
linter
.
RunLinterRule
(
support
.
ErrorSev
,
validateYamlContent
(
fileName
,
err
))
validYaml
:=
linter
.
RunLinterRule
(
support
.
ErrorSev
,
validateYamlContent
(
fileName
,
err
))
if
!
validYaml
{
if
!
validYaml
{
return
continue
}
}
linter
.
RunLinterRule
(
support
.
ErrorSev
,
validateNoNamespace
(
fileName
,
yamlStruct
))
linter
.
RunLinterRule
(
support
.
ErrorSev
,
validateNoNamespace
(
fileName
,
yamlStruct
))
...
@@ -108,7 +109,7 @@ func Templates(linter *support.Linter) {
...
@@ -108,7 +109,7 @@ func Templates(linter *support.Linter) {
}
}
// Validation functions
// Validation functions
func
validateTemplatesDir
(
linter
*
support
.
Linter
,
templatesPath
string
)
(
lintError
support
.
LintError
)
{
func
validateTemplatesDir
(
templatesPath
string
)
(
lintError
support
.
LintError
)
{
if
fi
,
err
:=
os
.
Stat
(
templatesPath
);
err
!=
nil
{
if
fi
,
err
:=
os
.
Stat
(
templatesPath
);
err
!=
nil
{
lintError
=
fmt
.
Errorf
(
"Templates directory not found"
)
lintError
=
fmt
.
Errorf
(
"Templates directory not found"
)
}
else
if
err
==
nil
&&
!
fi
.
IsDir
()
{
}
else
if
err
==
nil
&&
!
fi
.
IsDir
()
{
...
@@ -145,22 +146,42 @@ func validateQuotes(templateName string, templateContent string) (lintError supp
...
@@ -145,22 +146,42 @@ func validateQuotes(templateName string, templateContent string) (lintError supp
return
return
}
}
func
validateYamlExtension
(
linter
*
support
.
Linter
,
fileName
string
)
(
lintError
support
.
LintError
)
{
func
validateAllowedExtension
(
fileName
string
)
(
lintError
support
.
LintError
)
{
if
filepath
.
Ext
(
fileName
)
!=
".yaml"
{
ext
:=
filepath
.
Ext
(
fileName
)
lintError
=
fmt
.
Errorf
(
"templates:
\"
%s
\"
needs to use the .yaml extension"
,
fileName
)
validExtensions
:=
[]
string
{
".yaml"
,
".tpl"
}
for
_
,
b
:=
range
validExtensions
{
if
b
==
ext
{
return
}
}
}
lintError
=
fmt
.
Errorf
(
"templates:
\"
%s
\"
needs to use .yaml or .tpl extensions"
,
fileName
)
return
return
}
}
// validateNonMissingValues checks that all the {{}} functions returns a non empty value (<no value> or "")
// validateNonMissingValues checks that all the {{}} functions returns a non empty value (<no value> or "")
// and return an error otherwise.
// and return an error otherwise.
func
validateNonMissingValues
(
fileName
string
,
chartValues
chartutil
.
Values
,
templateContent
[]
byte
)
(
lintError
support
.
LintError
)
{
func
validateNonMissingValues
(
fileName
string
,
templatesPath
string
,
chartValues
chartutil
.
Values
,
templateContent
[]
byte
)
(
lintError
support
.
LintError
)
{
// 1 - Load Main and associated templates
// Main template that we will parse dynamically
tmpl
:=
template
.
New
(
"tpl"
)
.
Funcs
(
sprig
.
TxtFuncMap
())
tmpl
:=
template
.
New
(
"tpl"
)
.
Funcs
(
sprig
.
TxtFuncMap
())
// If the templatesPath includes any *.tpl files we will parse and import them as associated templates
associatedTemplates
,
err
:=
filepath
.
Glob
(
filepath
.
Join
(
templatesPath
,
"*.tpl"
))
if
len
(
associatedTemplates
)
>
0
{
tmpl
,
err
=
tmpl
.
ParseFiles
(
associatedTemplates
...
)
if
err
!=
nil
{
return
err
}
}
var
buf
bytes
.
Buffer
var
buf
bytes
.
Buffer
var
emptyValues
[]
string
var
emptyValues
[]
string
// 2 - Extract every function and execute them agains the loaded values
// Supported {{ .Chart.Name }}, {{ .Chart.Name | quote }}
// Supported {{ .Chart.Name }}, {{ .Chart.Name | quote }}
r
,
_
:=
regexp
.
Compile
(
`{{
([\w]|\.*|\s|\|)
+}}`
)
r
,
_
:=
regexp
.
Compile
(
`{{
[\w|\.|\s|\|\"|\']
+}}`
)
functions
:=
r
.
FindAllString
(
string
(
templateContent
),
-
1
)
functions
:=
r
.
FindAllString
(
string
(
templateContent
),
-
1
)
// Iterate over the {{ FOO }} templates, executing them against the chartValues
// Iterate over the {{ FOO }} templates, executing them against the chartValues
...
@@ -172,7 +193,12 @@ func validateNonMissingValues(fileName string, chartValues chartutil.Values, tem
...
@@ -172,7 +193,12 @@ func validateNonMissingValues(fileName string, chartValues chartutil.Values, tem
return
return
}
}
err
=
newtmpl
.
Execute
(
&
buf
,
chartValues
)
err
=
newtmpl
.
ExecuteTemplate
(
&
buf
,
"tpl"
,
chartValues
)
if
err
!=
nil
{
return
err
}
renderedValue
:=
buf
.
String
()
renderedValue
:=
buf
.
String
()
if
renderedValue
==
"<no value>"
||
renderedValue
==
""
{
if
renderedValue
==
"<no value>"
||
renderedValue
==
""
{
...
@@ -182,7 +208,7 @@ func validateNonMissingValues(fileName string, chartValues chartutil.Values, tem
...
@@ -182,7 +208,7 @@ func validateNonMissingValues(fileName string, chartValues chartutil.Values, tem
}
}
if
len
(
emptyValues
)
>
0
{
if
len
(
emptyValues
)
>
0
{
lintError
=
fmt
.
Errorf
(
"templates: %s: The following functions are not returning
e
ny value %v"
,
fileName
,
emptyValues
)
lintError
=
fmt
.
Errorf
(
"templates: %s: The following functions are not returning
a
ny value %v"
,
fileName
,
emptyValues
)
}
}
return
return
}
}
...
...
pkg/lint/rules/template_test.go
View file @
81ac98ad
...
@@ -24,6 +24,23 @@ import (
...
@@ -24,6 +24,23 @@ import (
const
templateTestBasedir
=
"./testdata/albatross"
const
templateTestBasedir
=
"./testdata/albatross"
func
TestValidateAllowedExtension
(
t
*
testing
.
T
)
{
var
failTest
=
[]
string
{
"/foo"
,
"/test.yml"
,
"/test.toml"
,
"test.yml"
}
for
_
,
test
:=
range
failTest
{
err
:=
validateAllowedExtension
(
test
)
if
err
==
nil
||
!
strings
.
Contains
(
err
.
Error
(),
"needs to use .yaml or .tpl extension"
)
{
t
.
Errorf
(
"validateAllowedExtension('%s') to return
\"
needs to use .yaml or .tpl extension
\"
, got no error"
,
test
)
}
}
var
successTest
=
[]
string
{
"/foo.yaml"
,
"foo.yaml"
,
"foo.tpl"
,
"/foo/bar/baz.yaml"
}
for
_
,
test
:=
range
successTest
{
err
:=
validateAllowedExtension
(
test
)
if
err
!=
nil
{
t
.
Errorf
(
"validateAllowedExtension('%s') to return no error but got
\"
%s
\"
"
,
test
,
err
.
Error
())
}
}
}
func
TestValidateQuotes
(
t
*
testing
.
T
)
{
func
TestValidateQuotes
(
t
*
testing
.
T
)
{
// add `| quote` lint error
// add `| quote` lint error
var
failTest
=
[]
string
{
"foo: {{.Release.Service }}"
,
"foo: {{.Release.Service }}"
,
"- {{.Release.Service }}"
,
"foo: {{default 'Never' .restart_policy}}"
,
"- {{.Release.Service }} "
}
var
failTest
=
[]
string
{
"foo: {{.Release.Service }}"
,
"foo: {{.Release.Service }}"
,
"- {{.Release.Service }}"
,
"foo: {{default 'Never' .restart_policy}}"
,
"- {{.Release.Service }} "
}
...
...
pkg/lint/support/message.go
View file @
81ac98ad
...
@@ -19,8 +19,6 @@ package support
...
@@ -19,8 +19,6 @@ package support
import
"fmt"
import
"fmt"
// Severity indicatest the severity of a Message.
// Severity indicatest the severity of a Message.
type
Severity
int
const
(
const
(
// UnknownSev indicates that the severity of the error is unknown, and should not stop processing.
// UnknownSev indicates that the severity of the error is unknown, and should not stop processing.
UnknownSev
=
iota
UnknownSev
=
iota
...
@@ -38,7 +36,7 @@ var sev = []string{"UNKNOWN", "INFO", "WARNING", "ERROR"}
...
@@ -38,7 +36,7 @@ var sev = []string{"UNKNOWN", "INFO", "WARNING", "ERROR"}
// Message is a linting output message
// Message is a linting output message
type
Message
struct
{
type
Message
struct
{
// Severity is one of the *Sev constants
// Severity is one of the *Sev constants
Severity
Severity
Severity
int
// Text contains the message text
// Text contains the message text
Text
string
Text
string
}
}
...
@@ -60,9 +58,9 @@ func (m Message) String() string {
...
@@ -60,9 +58,9 @@ func (m Message) String() string {
}
}
// Returns true if the validation passed
// Returns true if the validation passed
func
(
l
*
Linter
)
RunLinterRule
(
severity
Severity
,
lintError
LintError
)
bool
{
func
(
l
*
Linter
)
RunLinterRule
(
severity
int
,
lintError
LintError
)
bool
{
// severity is out of bound
// severity is out of bound
if
severity
<
0
||
int
(
severity
)
>=
len
(
sev
)
{
if
severity
<
0
||
severity
>=
len
(
sev
)
{
return
false
return
false
}
}
...
...
pkg/lint/support/message_test.go
View file @
81ac98ad
...
@@ -26,7 +26,7 @@ var lintError LintError = fmt.Errorf("Foobar")
...
@@ -26,7 +26,7 @@ var lintError LintError = fmt.Errorf("Foobar")
func
TestRunLinterRule
(
t
*
testing
.
T
)
{
func
TestRunLinterRule
(
t
*
testing
.
T
)
{
var
tests
=
[]
struct
{
var
tests
=
[]
struct
{
Severity
Severity
Severity
int
LintError
error
LintError
error
ExpectedMessages
int
ExpectedMessages
int
ExpectedReturn
bool
ExpectedReturn
bool
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment