Skip to content

Commit cf7e336

Browse files
author
OpenShift Bot
authored
Merge pull request #12996 from smarterclayton/local_template
Merged by openshift-bot
2 parents 0aa6ba1 + 8ee72b0 commit cf7e336

File tree

9 files changed

+107
-12
lines changed

9 files changed

+107
-12
lines changed

contrib/completions/bash/oc

+2
Original file line numberDiff line numberDiff line change
@@ -12405,6 +12405,8 @@ _oc_process()
1240512405
flags+=("--labels=")
1240612406
two_word_flags+=("-l")
1240712407
local_nonpersistent_flags+=("--labels=")
12408+
flags+=("--local")
12409+
local_nonpersistent_flags+=("--local")
1240812410
flags+=("--output=")
1240912411
two_word_flags+=("-o")
1241012412
local_nonpersistent_flags+=("--output=")

contrib/completions/bash/openshift

+2
Original file line numberDiff line numberDiff line change
@@ -17514,6 +17514,8 @@ _openshift_cli_process()
1751417514
flags+=("--labels=")
1751517515
two_word_flags+=("-l")
1751617516
local_nonpersistent_flags+=("--labels=")
17517+
flags+=("--local")
17518+
local_nonpersistent_flags+=("--local")
1751717519
flags+=("--output=")
1751817520
two_word_flags+=("-o")
1751917521
local_nonpersistent_flags+=("--output=")

contrib/completions/zsh/oc

+2
Original file line numberDiff line numberDiff line change
@@ -12553,6 +12553,8 @@ _oc_process()
1255312553
flags+=("--labels=")
1255412554
two_word_flags+=("-l")
1255512555
local_nonpersistent_flags+=("--labels=")
12556+
flags+=("--local")
12557+
local_nonpersistent_flags+=("--local")
1255612558
flags+=("--output=")
1255712559
two_word_flags+=("-o")
1255812560
local_nonpersistent_flags+=("--output=")

contrib/completions/zsh/openshift

+2
Original file line numberDiff line numberDiff line change
@@ -17662,6 +17662,8 @@ _openshift_cli_process()
1766217662
flags+=("--labels=")
1766317663
two_word_flags+=("-l")
1766417664
local_nonpersistent_flags+=("--labels=")
17665+
flags+=("--local")
17666+
local_nonpersistent_flags+=("--local")
1766517667
flags+=("--output=")
1766617668
two_word_flags+=("-o")
1766717669
local_nonpersistent_flags+=("--output=")

docs/generated/oc_by_example_content.adoc

+3
Original file line numberDiff line numberDiff line change
@@ -2122,6 +2122,9 @@ Process a template into list of resources
21222122
# Convert template.json file into resource list and pass to create
21232123
oc process -f template.json | oc create -f -
21242124
2125+
# Process a file locally instead of contacting the server
2126+
oc process -f template.json --local -o yaml
2127+
21252128
# Process template while passing a user-defined label
21262129
oc process -f template.json -l name=mytemplate
21272130

docs/man/man1/oc-process.1

+10
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ Templates allow parameterization of resources prior to being sent to the server
2121
.PP
2222
The output of the process command is always a list of one or more resources. You may pipe the output to the create command over STDIN (using the '\-f \-' option) or redirect it to a file.
2323

24+
.PP
25+
Process resolves the template on the server, but you may pass \-\-local to parameterize the template locally. When running locally be aware that the version of your client tools will determine what template transformations are supported, rather than the server.
26+
2427

2528
.SH OPTIONS
2629
.PP
@@ -31,6 +34,10 @@ The output of the process command is always a list of one or more resources. You
3134
\fB\-l\fP, \fB\-\-labels\fP=""
3235
Label to set in all resources for this template
3336

37+
.PP
38+
\fB\-\-local\fP=false
39+
If true process the template locally instead of contacting the server.
40+
3441
.PP
3542
\fB\-o\fP, \fB\-\-output\fP="json"
3643
Output format. One of: describe|json|yaml|name|go\-template=...|go\-template\-file=...|jsonpath=...|jsonpath\-file=...
@@ -143,6 +150,9 @@ The output of the process command is always a list of one or more resources. You
143150
# Convert template.json file into resource list and pass to create
144151
oc process \-f template.json | oc create \-f \-
145152

153+
# Process a file locally instead of contacting the server
154+
oc process \-f template.json \-\-local \-o yaml
155+
146156
# Process template while passing a user\-defined label
147157
oc process \-f template.json \-l name=mytemplate
148158

docs/man/man1/openshift-cli-process.1

+10
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ Templates allow parameterization of resources prior to being sent to the server
2121
.PP
2222
The output of the process command is always a list of one or more resources. You may pipe the output to the create command over STDIN (using the '\-f \-' option) or redirect it to a file.
2323

24+
.PP
25+
Process resolves the template on the server, but you may pass \-\-local to parameterize the template locally. When running locally be aware that the version of your client tools will determine what template transformations are supported, rather than the server.
26+
2427

2528
.SH OPTIONS
2629
.PP
@@ -31,6 +34,10 @@ The output of the process command is always a list of one or more resources. You
3134
\fB\-l\fP, \fB\-\-labels\fP=""
3235
Label to set in all resources for this template
3336

37+
.PP
38+
\fB\-\-local\fP=false
39+
If true process the template locally instead of contacting the server.
40+
3441
.PP
3542
\fB\-o\fP, \fB\-\-output\fP="json"
3643
Output format. One of: describe|json|yaml|name|go\-template=...|go\-template\-file=...|jsonpath=...|jsonpath\-file=...
@@ -143,6 +150,9 @@ The output of the process command is always a list of one or more resources. You
143150
# Convert template.json file into resource list and pass to create
144151
openshift cli process \-f template.json | openshift cli create \-f \-
145152

153+
# Process a file locally instead of contacting the server
154+
openshift cli process \-f template.json \-\-local \-o yaml
155+
146156
# Process template while passing a user\-defined label
147157
openshift cli process \-f template.json \-l name=mytemplate
148158

pkg/cmd/cli/cmd/process.go

+64-12
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,34 @@ package cmd
33
import (
44
"fmt"
55
"io"
6+
"math/rand"
67
"reflect"
78
"strings"
9+
"time"
810

911
"github.com/spf13/cobra"
1012
kapi "k8s.io/kubernetes/pkg/api"
1113
"k8s.io/kubernetes/pkg/api/errors"
1214
"k8s.io/kubernetes/pkg/api/meta"
1315
"k8s.io/kubernetes/pkg/api/unversioned"
16+
"k8s.io/kubernetes/pkg/apimachinery/registered"
1417
"k8s.io/kubernetes/pkg/kubectl"
1518
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
1619
"k8s.io/kubernetes/pkg/kubectl/resource"
1720
"k8s.io/kubernetes/pkg/runtime"
1821
kerrors "k8s.io/kubernetes/pkg/util/errors"
1922
"k8s.io/kubernetes/pkg/util/sets"
2023

24+
"github.com/openshift/origin/pkg/client"
2125
"github.com/openshift/origin/pkg/cmd/cli/describe"
2226
"github.com/openshift/origin/pkg/cmd/templates"
2327
cmdutil "github.com/openshift/origin/pkg/cmd/util"
2428
"github.com/openshift/origin/pkg/cmd/util/clientcmd"
2529
"github.com/openshift/origin/pkg/generate/app"
2630
"github.com/openshift/origin/pkg/template"
2731
templateapi "github.com/openshift/origin/pkg/template/api"
32+
templatevalidation "github.com/openshift/origin/pkg/template/api/validation"
33+
"github.com/openshift/origin/pkg/template/generator"
2834
)
2935

3036
var (
@@ -36,12 +42,19 @@ var (
3642
as well as metadata describing the template.
3743
3844
The output of the process command is always a list of one or more resources. You may pipe the
39-
output to the create command over STDIN (using the '-f -' option) or redirect it to a file.`)
45+
output to the create command over STDIN (using the '-f -' option) or redirect it to a file.
46+
47+
Process resolves the template on the server, but you may pass --local to parameterize the template
48+
locally. When running locally be aware that the version of your client tools will determine what
49+
template transformations are supported, rather than the server.`)
4050

4151
processExample = templates.Examples(`
4252
# Convert template.json file into resource list and pass to create
4353
%[1]s process -f template.json | %[1]s create -f -
4454
55+
# Process a file locally instead of contacting the server
56+
%[1]s process -f template.json --local -o yaml
57+
4558
# Process template while passing a user-defined label
4659
%[1]s process -f template.json -l name=mytemplate
4760
@@ -78,6 +91,7 @@ func NewCmdProcess(fullName string, f *clientcmd.Factory, in io.Reader, out, err
7891
cmd.Flags().StringArrayVarP(params, "param", "p", nil, "Specify a key-value pair (eg. -p FOO=BAR) to set/override a parameter value in the template.")
7992
cmd.Flags().StringArray("param-file", []string{}, "File containing template parameter values to set/override in the template.")
8093
cmd.MarkFlagFilename("param-file")
94+
cmd.Flags().BoolP("local", "", false, "If true process the template locally instead of contacting the server.")
8195
cmd.Flags().BoolP("parameters", "", false, "If true, do not process but only print available parameters")
8296
cmd.Flags().StringP("labels", "l", "", "Label to set in all resources for this template")
8397

@@ -112,6 +126,7 @@ func RunProcess(f *clientcmd.Factory, in io.Reader, out, errout io.Writer, cmd *
112126
}
113127
}
114128

129+
local := kcmdutil.GetFlagBool(cmd, "local")
115130
if cmd.Flag("value").Changed || cmd.Flag("param").Changed {
116131
flagValues := getFlagStringArray(cmd, "param")
117132
cmdutil.WarnAboutCommaSeparation(errout, flagValues, "--param")
@@ -149,18 +164,32 @@ func RunProcess(f *clientcmd.Factory, in io.Reader, out, errout io.Writer, cmd *
149164
return err
150165
}
151166

152-
mapper, typer := f.Object()
153-
154-
client, _, err := f.Clients()
155-
if err != nil {
156-
return err
157-
}
158-
159167
var (
160168
objects []runtime.Object
161169
infos []*resource.Info
170+
171+
mapper meta.RESTMapper
172+
typer runtime.ObjectTyper
173+
174+
client *client.Client
175+
clientMappingFn resource.ClientMapperFunc
162176
)
163177

178+
if local {
179+
// TODO: Change f.Object() so that it can fall back to local RESTMapper safely (currently glog.Fatals)
180+
mapper = registered.RESTMapper()
181+
typer = kapi.Scheme
182+
clientMappingFn = func(*meta.RESTMapping) (resource.RESTClient, error) { return nil, nil }
183+
// client is deliberately left nil
184+
} else {
185+
client, _, err = f.Clients()
186+
if err != nil {
187+
return err
188+
}
189+
190+
mapper, typer = f.Object()
191+
clientMappingFn = f.ClientForMapping
192+
}
164193
mapping, err := mapper.RESTMapping(templateapi.Kind("Template"))
165194
if err != nil {
166195
return err
@@ -184,6 +213,7 @@ func RunProcess(f *clientcmd.Factory, in io.Reader, out, errout io.Writer, cmd *
184213
if len(storedTemplate) == 0 {
185214
return fmt.Errorf("invalid value syntax %q", templateName)
186215
}
216+
187217
templateObj, err := client.Templates(sourceNamespace).Get(storedTemplate)
188218
if err != nil {
189219
if errors.IsNotFound(err) {
@@ -194,7 +224,7 @@ func RunProcess(f *clientcmd.Factory, in io.Reader, out, errout io.Writer, cmd *
194224
templateObj.CreationTimestamp = unversioned.Now()
195225
infos = append(infos, &resource.Info{Object: templateObj})
196226
} else {
197-
infos, err = resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()).
227+
infos, err = resource.NewBuilder(mapper, typer, clientMappingFn, kapi.Codecs.UniversalDecoder()).
198228
NamespaceParam(namespace).RequireNamespace().
199229
FilenameParam(explicit, &resource.FilenameOptions{Recursive: false, Filenames: []string{filename}}).
200230
Do().
@@ -249,9 +279,16 @@ func RunProcess(f *clientcmd.Factory, in io.Reader, out, errout io.Writer, cmd *
249279
return kerrors.NewAggregate(errs)
250280
}
251281

252-
resultObj, err := client.TemplateConfigs(namespace).Create(obj)
253-
if err != nil {
254-
return fmt.Errorf("error processing the template %q: %v\n", obj.Name, err)
282+
resultObj := obj
283+
if local {
284+
if err := processTemplateLocally(obj); err != nil {
285+
return err
286+
}
287+
} else {
288+
resultObj, err = client.TemplateConfigs(namespace).Create(obj)
289+
if err != nil {
290+
return fmt.Errorf("error processing the template %q: %v\n", obj.Name, err)
291+
}
255292
}
256293

257294
outputFormat := kcmdutil.GetFlagString(cmd, "output")
@@ -307,3 +344,18 @@ func injectUserVars(values app.Environment, t *templateapi.Template) []error {
307344
}
308345
return errors
309346
}
347+
348+
// processTemplateLocally applies the same logic that a remote call would make but makes no
349+
// connection to the server.
350+
func processTemplateLocally(tpl *templateapi.Template) error {
351+
if errs := templatevalidation.ValidateProcessedTemplate(tpl); len(errs) > 0 {
352+
return errors.NewInvalid(templateapi.Kind("Template"), tpl.Name, errs)
353+
}
354+
processor := template.NewProcessor(map[string]generator.Generator{
355+
"expression": generator.NewExpressionValueGenerator(rand.New(rand.NewSource(time.Now().UnixNano()))),
356+
})
357+
if errs := processor.Process(tpl); len(errs) > 0 {
358+
return errors.NewInvalid(templateapi.Kind("Template"), tpl.Name, errs)
359+
}
360+
return nil
361+
}

test/cmd/templates.sh

+12
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,18 @@ guestbook_template="${OS_ROOT}/test/templates/testdata/guestbook.json"
4646
os::cmd::expect_success "oc process -f '${guestbook_template}' -l app=guestbook | oc create -f -"
4747
os::cmd::expect_success_and_text 'oc status' 'frontend-service'
4848
echo "template+config: ok"
49+
50+
os::test::junit::declare_suite_start "cmd/templates/local-config"
51+
# Processes the template locally
52+
os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --local -l app=guestbook -o yaml" "app: guestbook"
53+
# Processes the template locally and get the same output in YAML
54+
new="$(mktemp -d)"
55+
os::cmd::expect_success 'oc process -f "${guestbook_template}" --local -l app=guestbook -o yaml ADMIN_USERNAME=au ADMIN_PASSWORD=ap REDIS_PASSWORD=rp > "${new}/localtemplate"'
56+
os::cmd::expect_success 'oc process -f "${guestbook_template}" -l app=guestbook -o yaml ADMIN_USERNAME=au ADMIN_PASSWORD=ap REDIS_PASSWORD=rp > "${new}/remotetemplate"'
57+
os::cmd::expect_success 'diff "${new}/localtemplate" "${new}/remotetemplate"'
58+
# Does not even try to hit the server
59+
os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --local -l app=guestbook -o yaml --server 0.0.0.0:1" "app: guestbook"
60+
echo "template+config+local: ok"
4961
os::test::junit::declare_suite_end
5062

5163
os::test::junit::declare_suite_start "cmd/templates/parameters"

0 commit comments

Comments
 (0)