Just leaving a comment here since between #6376 and this issue, this is the one that’s more obviously related to the Chart Template Guide / getting started example, and as of Helm 3.5.2 and today’s guide, the guide has the same issue. I ran through all the suggestions in #6376 and this issue to understand what works and what doesn’t, a good learning experience for a Helm newbie like myself. FWIW:
Variations that work in Helm 3.5.2 (personally I think the first variation is easiest to understand):
{{if eq (.Values.favorite.drink | default "") "coffee"}}mug: "true"{{ end }}
{{ if eq (default "" .Values.favorite.drink) "coffee" }}mug: "true"{{ end }}
{{if eq (.Values.favorite.drink | toString) "coffee"}}mug: "true"{{ end }}
{{- if .Values.favorite.drink }}
{{- if eq .Values.favorite.drink "coffee" }}
mug: "true"
{{- end }}
{{- end }}
Variations with error calling eq: incompatible types for comparison
(the first variation is the one from the Chart Template Guide):
{{ if eq .Values.favorite.drink "coffee" }}mug: "true"{{ end }}
{{ if eq (default .Values.favorite.drink "") "coffee" }}mug: "true"{{ end }}
{{- if and (.Values.favorite.drink) (eq .Values.favorite.drink "coffee") }}mug: "true"{{ end }}
Variation with drink is not a method but has arguments
:
{{ if .Values.favorite.drink and eq .Values.favorite.drink "coffee" }}mug: "true"{{ end }}
Variation with can't give argument to non-function .Values.favorite.drink
:
{{ if ( .Values.favorite.drink ) and eq .Values.favorite.drink "coffee" }}mug: "true"{{ end }}
I have to check if my application container in a replication controller runs on a certain port. Here is the command with the go template string that I’m using.
kubectl get rc my-rc --namespace=nightly --template='{{range .spec.template.spec.containers}}{{if .ports}}{{range .ports}}{{if .containerPort}}{{if eq .containerPort 5445}}{{end}}{{end}}{{end}}{{end}}{{end}}'
I think it is not a string comparison since it is a port. even string comparison throws an error «error calling eq: incompatible types for comparison'»
I could just fetch an array of container ports and do the comparison outside but want to get it done inside the go template.
I am new to Go lang. Appreciate any suggestions to accomplish this using template string or using a template file.. Thanks
asked Mar 5, 2016 at 18:34
Inspecting the .containerPort with printf "%T" .containerPort
shows that it’s a float64. if you compare your port with a trailing 5445.0
it should work.
You also have some unnecessary if statements.
--template='{{range .spec.template.spec.containers}}{{range .ports}}{{if eq .containerPort 5445.0}}True{{end}}{{end}}{{end}}'
Your example was also missing the -o="go-template"
flag to specify the output as a Go template.
answered Mar 5, 2016 at 18:47
jmaloneyjmaloney
11.2k2 gold badges36 silver badges29 bronze badges
2
У меня есть шаблон диаграммы, содержащий эту строку
{{- if eq $.Values.global.environment "dev" }}
При запуске helm lint
это не удается:
> helm lint my-services/
==> Linting my-services/
[INFO] Chart.yaml: icon is recommended
[ERROR] templates/: render error in "my-services/templates/istio-gateway.yaml": template: acquiring-services/templates/istio-gateway.yaml:64:9: executing "my-services/templates/istio-gateway.yaml" at <eq $.Values.global.e...>: error calling eq: invalid type for comparison
Интересно, что у меня такое же сравнение — только с другой строкой — в строке 8, что совсем не проблема. Удаление ошибочной линии способствует успешному прохождению ворса
helm lint my-services/
==> Linting my-services/
[INFO] Chart.yaml: icon is recommended
1 chart(s) linted, no failures
Вот соответствующий yaml
-файл:
kind: VirtualService
metadata:
name: acquiring-gateway-virtualservice
namespace: {{ default $.Release.Namespace }}
spec:
hosts:
{{- if eq $.Release.Namespace $.Values.global.defaultNamespace }}
{{- if eq $.Values.global.environment "prd" }}
- {{ $.Values.global.ingressName }}.{{$.Values.global.environment}}.sc.intra
{{- else }}
- {{ $.Values.global.ingressName }}.svc.{{$.Values.global.environment}}.sc.intra
{{- end }}
{{- else }}
- {{ $.Values.global.ingressName }}-{{ default $.Release.Namespace }}.svc.{{$.Values.global.environment}}.sc.intra
{{- end }}
gateways:
- acquiring-gateway
http:
- match:
- uri:
prefix: /uaa
prefix: /uaa/
route:
- destination:
port:
number: 80
host: auth-server.{{ $.Release.Namespace }}.svc.cluster.local
corsPolicy:
allowOrigin:
- '*'
allowMethods:
- OPTIONS
- GET
- PUT
- POST
- PATCH
allowHeaders:
- authorization
{{- if eq $.Values.global.environment "dev" }}
- match:
Также следование предложению под # 2979 не помогает
Вывод helm version
:
Client: &version.Version{SemVer:"v2.12.3", GitCommit:"eecf22f77df5f65c823aacd2dbd30ae6c65f186e", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.12.3", GitCommit:"eecf22f77df5f65c823aacd2dbd30ae6c65f186e", GitTreeState:"clean"}
Вывод kubectl version
:
N / A
Облачный провайдер / платформа (AKS, GKE, Minikube и т. Д.):
На месте
Все 11 Комментарий
Когда global.environment
не задано, устанавливается значение nil
. Строка и значение nil
являются несовместимыми типами, поэтому их нельзя сравнивать на равенство.
Вероятно, вам нужно следующее:
{{- if eq (default $.Values.global.environment "prod") "dev" }}
Таким образом, если global.environment
не задано, оно все равно сравнивается со строковым значением.
Если значения считаются «необязательными», диаграмма должна сначала проверить и определить, не установлено ли значение.
Это поможет?
Я предполагаю, что логика оценки текста / шаблона будет заключаться в том, что если первый оператор if
оценивается как ложный, то ветвь закорачивается. Первый оператор if
мог никогда не выполняться.
Хорошо, если я сделаю это
#{{- if eq $.Release.Namespace $.Values.global.defaultNamespace }}
{{- if eq $.Values.global.environment "prd" }}
- {{ $.Values.global.ingressName }}.{{$.Values.global.environment}}.sc.intra
{{- else }}
- {{ $.Values.global.ingressName }}.svc.{{$.Values.global.environment}}.intra
{{- end }}
#{{- else }}
#- {{ $.Values.global.ingressName }}-{{ default $.Release.Namespace }}.svc.{{$.Values.global.environment}}.intra
#{{- end }}
lint не жалуется.
helm template
тоже жаловался? Мне также любопытно, можно ли это воспроизвести сейчас, когда мы компилируем с Go 1.14, поскольку это почти на 100% проблема с методом Go text/template
оценки условного оператора.
Если мы сможем свести это к минимально воспроизводимому случаю, я, возможно, смогу проследить его дальше. И это гораздо интереснее, если lint
терпит неудачу, а template
— нет.
Для чего это стоит. Я вижу, как мне кажется, ту же проблему:
Error: UPGRADE FAILED: template: ota-tdx/templates/kong-consumers.yaml:30:44: executing "ota-tdx/templates/kong-consumers.yaml" at <eq .Values.app.configMap.DEMO_MODE "1">: error calling eq: incompatible types for comparison
Мой шаблон шлема
{{- if and (.Values.app.configMap.DEMO_MODE) (eq .Values.app.configMap.DEMO_MODE "1") }}
Версия Helm
version.BuildInfo{Version:"v3.3.0", GitCommit:"8a4aeec08d67a7b84472007529e8097ec3742105", GitTreeState:"dirty", GoVersion:"go1.14.7"}
Обходной путь (СУПЕР УЖАСНО ВСТАВЛЕННЫЙ !!!!: sob:)
-{{- if (.Values.app.configMap.DEMO_MODE) and eq .Values.app.configMap.DEMO_MODE "1" }}
+{{- if .Values.app.configMap.DEMO_MODE }}
+{{- if eq .Values.app.configMap.DEMO_MODE "1" }}
...
-{{- end }}
+{{- end }}
+{{- end }}
@bclouser Я if
оператор and
будет работать на большинстве языков, но я не уверен, виноват ли здесь Helm или Go.
Это будет ограничение, установленное с помощью text/template
, который является языком шаблонов, используемым Helm для визуализации шаблонов. Так что это ограничение, установленное разработчиками Go.
https://golang.org/pkg/text/template/
Заключение, поскольку это то, что мы не можем изменить … Скорее это дизайнерское решение, принятое авторами Go. Я предложил обходной путь, который представляет собой все, что мы можем сделать на данный момент. Если другие нашли другие решения, опубликуйте их здесь. Спасибо!
Спасибо за ссылку @bacongobbler.
Действительно, отрывок из документации для and
гласит:
Returns the boolean AND of its arguments by returning the
first empty argument or the last argument, that is,
"and x y" behaves as "if x then y else x". All the
arguments are evaluated.
Я могу подтвердить, что обходной путь if eq (default <.variable> <fallback_value>) <comparison_value>
работает.
Насколько я могу судить, рекомендуемый обходной путь неверен. default
принимает резервное значение в качестве первого аргумента, а не второго:
В шаблонах часто используется функция
default
function:default DEFAULT_VALUE GIVEN_VALUE
.
https://helm.sh/docs/chart_template_guide/functions_and_pipelines/#using -the-default-function
Т.е. должно быть:
{{- if eq (default "prod" $.Values.global.environment) "dev" }}
и нет:
{{- if eq (default $.Values.global.environment "prod") "dev" }}
Другой (более интуитивный) синтаксис:
{{- if eq ($.Values.global.environment | default "prod") "dev" }}
PS Я не понимаю, как опция if eq (default <.variable> <fallback_value>) <comparison_value>
могла работать в тесте @phillycheeze .
Была ли эта страница полезной?
0 / 5 — 0 рейтинги
Article ID:360035987652
1 minute readKnowledge base
Issue
-
I have an issue when installing / upgrading CloudBees Core from the
cloudbees/cloudbees-core
helm chart:
Error: render error in "cloudbees-core/templates/cjoc-statefulset.yaml": template: cloudbees-core/templates/cjoc-statefulset.yaml:119:24: executing "cloudbees-core/templates/cjoc-statefulset.yaml" at <eq .Values.OperationsCenter.RunAsUser 0.0>: error calling eq: incompatible types for comparison
Environment
-
CloudBees CI (CloudBees Core) on Modern Cloud Platforms
-
Helm 2.15.0
Related Issue(s)
-
helm/helm issue #6708
-
helm/helm PR #6010 (Regression)
-
helm/helm PR #6749 (Fix)
Resolution
There is a known issue helm issue #6708 introduced in Helm / Tiller 2.15.0 that causes template generation to fail when comparing numeric value types.
This issue has been fixed in Helm / Tiller 2.15.1.
The solution is to:
-
Upgrade helm (client) to version 2.15.1 or later (the method depends on how it is installed)
-
Upgrade tiller (server) with
helm init --upgrade
I have a chart template which contains this line
{{- if eq $.Values.global.environment "dev" }}
When running helm lint
this fails:
> helm lint my-services/ ==> Linting my-services/ [INFO] Chart.yaml: icon is recommended [ERROR] templates/: render error in "my-services/templates/istio-gateway.yaml": template: acquiring-services/templates/istio-gateway.yaml:64:9: executing "my-services/templates/istio-gateway.yaml" at <eq $.Values.global.e...>: error calling eq: invalid type for comparison
Interestingly I have the same comparison — just with another string — in line 8, which is not a problem at all. Removing the erronous line makes lint passing successfully
helm lint my-services/
==> Linting my-services/
[INFO] Chart.yaml: icon is recommended
1 chart(s) linted, no failures
Here the relevant yaml
-file:
kind: VirtualService metadata: name: acquiring-gateway-virtualservice namespace: {{ default $.Release.Namespace }} spec: hosts: {{- if eq $.Release.Namespace $.Values.global.defaultNamespace }} {{- if eq $.Values.global.environment "prd" }} - {{ $.Values.global.ingressName }}.{{$.Values.global.environment}}.sc.intra {{- else }} - {{ $.Values.global.ingressName }}.svc.{{$.Values.global.environment}}.sc.intra {{- end }} {{- else }} - {{ $.Values.global.ingressName }}-{{ default $.Release.Namespace }}.svc.{{$.Values.global.environment}}.sc.intra {{- end }} gateways: - acquiring-gateway http: - match: - uri: prefix: /uaa prefix: /uaa/ route: - destination: port: number: 80 host: auth-server.{{ $.Release.Namespace }}.svc.cluster.local corsPolicy: allowOrigin: - '*' allowMethods: - OPTIONS - GET - PUT - POST - PATCH allowHeaders: - authorization {{- if eq $.Values.global.environment "dev" }} - match:
Also following the suggestion under #2979 does not help
Output of helm version
:
Client: &version.Version{SemVer:"v2.12.3", GitCommit:"eecf22f77df5f65c823aacd2dbd30ae6c65f186e", GitTreeState:"clean"} Server: &version.Version{SemVer:"v2.12.3", GitCommit:"eecf22f77df5f65c823aacd2dbd30ae6c65f186e", GitTreeState:"clean"}
Output of kubectl version
:
N/A
Cloud Provider/Platform (AKS, GKE, Minikube etc.):
On-Premise
News
March 23, 2015
11 minutes Read
Most Docker users are aware of the docker inspect command which is used to get metadata on a container or image, and may have used the -f argument to pull out some specific data, for example using docker inspect -f to get a container’s IP Address. However, a lot of users seem confused by the syntax of this feature and very few people take full advantage of it (most people seem to pipe the output through grep, which is effective but messy). In this post, I’ll look into how the -f argument works and show some examples of how to use it.
Put simply, the -f argument takes a Go template as input and runs it against the metadata for the given containers or images. The first problem is the phrase «Go template» is rather nebulous, at least to anyone inexperienced in Go — my first feeling was atavistic fear from the memory of C++ templates. Thankfully, Go templates has nothing in common with C++ templates or generics, and is in fact a template engine that takes a data source and a template pattern and combines the two to produce an output document. This idea should be very familiar to most web developers and common examples of template engines include Jinga2 (commonly used with Python and Flask), Mustache and JavaServer Pages. The concept is perhaps best explained by a simple example:
docker inspect -f 'Hello from container ' jenkins
(out) Hello from container /jenkins
As we can see, the argument to -f is a simple pattern (or template) that we want to apply to the metadata of container. In fact, we don’t even have to do anything with the metadata:
docker inspect -f "This is a bit pointless" jenkins
(out) This is a bit pointless
But, if we learn a bit of Go templating magic, things that were once tricky become much simpler. For example, to find the names of all containers with a non-zero exit code:
docker inspect -f ' ' $(docker ps -aq)
(out) /tender_colden 1
(out) /clever_mcclintock 126
(out) # <- empty line
(out) /grave_bartik 1
(Unfortunately Docker prints a new-line for each container, whether it matches the if or not).
Or to find the host directory for the volume /var/jenkins_home in my jenkins-data container:
docker inspect -f '' jenkins-data
(out) /var/lib/docker/vfs/dir/5a6f7b306b96af38723fc4d31def1cc515a0d75c785f3462482f60b730533b1a
At the moment, both of these examples are probably a little hard to parse. There are a few basics you need to understand before you can get started with your own templates.
Directives
The syntax is used for processing directives. Anything outside of the curly brackets will be output literally.
The . Context
A «.» stands for the «current context». Most of the time this is the whole data structure for the metadata of the container, but it can be rebound in certain cirumstances, including using the with action:
docker inspect -f '' jenkins
(out) 6331
docker inspect -f ' ' jenkins
(out) 6331
You can always get the root context by using $. e.g.
docker inspect -f ' has pid ' jenkins
(out) /jenkins has pid 6331
Note that it is perfectly valid to use a «.» by itself, the following will just output the full data completely unformatted:
docker inspect -f '' jenkins
(out) ...
Data Types
The inspect data seems to consist of floats, strings and booleans. These can be tested and compared using various functions. At the moment, it seems that all numbers are floats, although Go templates do support integers, which would seem to be more appropriate in most cases (I’ve submitted an issue about this). Use double quotes when working with strings.
Values which appear as «null» appear to be not present in the data at all, and can’t be compared:
docker inspect -f '' jenkins
(out) NO VALUE HERE!
docker inspect -f '' jenkins
(out) FATA[0000] template: :1:2: executing "" at eq .ExecIDs .ExecIDs: error calling eq: invalid type for comparison
Data Structures
The inspect data uses maps and arrays. Maps are normally easy, you can just chain stuff together to access inner maps as we’ve seen already:
docker inspect -f '' jenkins
(out) 0
However, this isn’t possible if the key for the map isn’t in a suitable format (for example, if it uses a non alphanumeric character). If that’s the case, you can use the index function as we did in the volumes example:
docker inspect -f '' jenkins-data
(out) /var/lib/docker/vfs/dir/5a6f7b306b96af38723fc4d31def1cc515a0d75c785f3462482f60b730533b1a
You can also use index to get an array entry by number:
docker inspect -f '' jenkins
(out) [/var/run/docker.sock:/var/run/docker.sock /usr/bin/docker:/usr/bin/docker]
docker inspect -f '' jenkins
(out) /usr/bin/docker:/usr/bin/docker
Functions
Apart from index, there are a few more functions that are likely to be useful. The logical functions and, or and not are available and operate largely as expected, returning a boolean result. Note that as they are functions, they cannot be used infix i.e:
docker inspect -f '' jenkins
(out) true
Not:
docker inspect -f 'true' jenkins
(out) FATA[0000] template: :1:2: executing "" at <true>: can't give argument to non-function true
The following comparison functions are available:
- eq (equals)
- ne (not equal)
- lt (less than)
- le (less than or equal to)
- gt (greater than)
- ge (greater than or equal to)
They can compare strings, floats or integers:
docker inspect -f '' jenkins
(out) true
docker inspect -f '' jenkins
(out) true
docker inspect -f '' jenkins
(out) true
$ docker inspect -f '' jenkins
(out) false
But note that output types have to match, and numbers in Docker seem to be all floats, despite how they are printed:
docker inspect -f '' jenkins
(out) FATA[0000] template: :1:2: executing "" at <eq "4.5" 4.5>: error calling eq: incompatible types for comparison
docker inspect -f '' jenkins
(out) FATA[0000] template: :1:2: executing "" at <gt .State.Pid 1>: error calling gt: incompatible types for comparison
docker inspect -f '' jenkins
(out) true
UPDATE: This seems to have been fixed; now both integers and floats will work correctly e.g:
docker inspect -f '' redis
(out) true
docker inspect -f '' redis
(out) true
(This was tested in Docker 1.7).
There is also a json function for generating JSON:
docker inspect -f '' jenkins
(out) {"50000/tcp":null,"8080/tcp":[{"HostIp":"0.0.0.0","HostPort":"8080"}]}
So you can combine templates with the jq tool, which you may be more familiar with:
docker inspect -f json .State}}' jenkins-data | jq '.StartedAt'
(out) "2015-03-15T20:26:30.526796706Z"
Of course, the default output of docker inspect is also JSON, so this also works:
docker inspect jenkins-data | jq '.[] | .State.StartedAt'
(out) "2015-03-15T20:26:30.526796706Z"
There are a few more functions listed in the official Go documentation, but it weirdly seems to be missing the json function (which I learnt from Nathan LeClaire’s blog) — if someone knows the reason for this, please let me know!
If Statements
Conditional statements can be handled with an if statement and normally use one of the previous comparison functions:
docker inspect -f '
Normal Exit
Not a Normal Exit
Still Not a Normal Exit
' jenkins
(out) Normal Exit
Note the statement is required to terminate the if. The else if and else parts are optional.
Conclusion
I think this covers most of the stuff you are likely to need when using templates with docker inspect, but there are more features available, such as using range to iterate over data, defining your own functions and using pipes.
I have yet to find a good, complete reference to using Go templates. The best I have found so far is a chapter from a the free e-book «Network programming with Go» by Jan Newmarch.
There is also the official Go documentation, but it is little terse and hard to follow, especially if you’re not a Go programmer.