Skip to content

Commit

Permalink
Merge pull request #12996 from smarterclayton/local_template
Browse files Browse the repository at this point in the history
Merged by openshift-bot
  • Loading branch information
OpenShift Bot authored Feb 19, 2017
2 parents 0aa6ba1 + 8ee72b0 commit cf7e336
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 12 deletions.
2 changes: 2 additions & 0 deletions contrib/completions/bash/oc
Original file line number Diff line number Diff line change
Expand Up @@ -12405,6 +12405,8 @@ _oc_process()
flags+=("--labels=")
two_word_flags+=("-l")
local_nonpersistent_flags+=("--labels=")
flags+=("--local")
local_nonpersistent_flags+=("--local")
flags+=("--output=")
two_word_flags+=("-o")
local_nonpersistent_flags+=("--output=")
Expand Down
2 changes: 2 additions & 0 deletions contrib/completions/bash/openshift
Original file line number Diff line number Diff line change
Expand Up @@ -17514,6 +17514,8 @@ _openshift_cli_process()
flags+=("--labels=")
two_word_flags+=("-l")
local_nonpersistent_flags+=("--labels=")
flags+=("--local")
local_nonpersistent_flags+=("--local")
flags+=("--output=")
two_word_flags+=("-o")
local_nonpersistent_flags+=("--output=")
Expand Down
2 changes: 2 additions & 0 deletions contrib/completions/zsh/oc
Original file line number Diff line number Diff line change
Expand Up @@ -12553,6 +12553,8 @@ _oc_process()
flags+=("--labels=")
two_word_flags+=("-l")
local_nonpersistent_flags+=("--labels=")
flags+=("--local")
local_nonpersistent_flags+=("--local")
flags+=("--output=")
two_word_flags+=("-o")
local_nonpersistent_flags+=("--output=")
Expand Down
2 changes: 2 additions & 0 deletions contrib/completions/zsh/openshift
Original file line number Diff line number Diff line change
Expand Up @@ -17662,6 +17662,8 @@ _openshift_cli_process()
flags+=("--labels=")
two_word_flags+=("-l")
local_nonpersistent_flags+=("--labels=")
flags+=("--local")
local_nonpersistent_flags+=("--local")
flags+=("--output=")
two_word_flags+=("-o")
local_nonpersistent_flags+=("--output=")
Expand Down
3 changes: 3 additions & 0 deletions docs/generated/oc_by_example_content.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2122,6 +2122,9 @@ Process a template into list of resources
# Convert template.json file into resource list and pass to create
oc process -f template.json | oc create -f -

# Process a file locally instead of contacting the server
oc process -f template.json --local -o yaml

# Process template while passing a user-defined label
oc process -f template.json -l name=mytemplate

Expand Down
10 changes: 10 additions & 0 deletions docs/man/man1/oc-process.1
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ Templates allow parameterization of resources prior to being sent to the server
.PP
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.

.PP
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.


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

.PP
\fB\-\-local\fP=false
If true process the template locally instead of contacting the server.

.PP
\fB\-o\fP, \fB\-\-output\fP="json"
Output format. One of: describe|json|yaml|name|go\-template=...|go\-template\-file=...|jsonpath=...|jsonpath\-file=...
Expand Down Expand Up @@ -143,6 +150,9 @@ The output of the process command is always a list of one or more resources. You
# Convert template.json file into resource list and pass to create
oc process \-f template.json | oc create \-f \-

# Process a file locally instead of contacting the server
oc process \-f template.json \-\-local \-o yaml

# Process template while passing a user\-defined label
oc process \-f template.json \-l name=mytemplate

Expand Down
10 changes: 10 additions & 0 deletions docs/man/man1/openshift-cli-process.1
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ Templates allow parameterization of resources prior to being sent to the server
.PP
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.

.PP
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.


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

.PP
\fB\-\-local\fP=false
If true process the template locally instead of contacting the server.

.PP
\fB\-o\fP, \fB\-\-output\fP="json"
Output format. One of: describe|json|yaml|name|go\-template=...|go\-template\-file=...|jsonpath=...|jsonpath\-file=...
Expand Down Expand Up @@ -143,6 +150,9 @@ The output of the process command is always a list of one or more resources. You
# Convert template.json file into resource list and pass to create
openshift cli process \-f template.json | openshift cli create \-f \-

# Process a file locally instead of contacting the server
openshift cli process \-f template.json \-\-local \-o yaml

# Process template while passing a user\-defined label
openshift cli process \-f template.json \-l name=mytemplate

Expand Down
76 changes: 64 additions & 12 deletions pkg/cmd/cli/cmd/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,34 @@ package cmd
import (
"fmt"
"io"
"math/rand"
"reflect"
"strings"
"time"

"github.com/spf13/cobra"
kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/kubectl"
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/runtime"
kerrors "k8s.io/kubernetes/pkg/util/errors"
"k8s.io/kubernetes/pkg/util/sets"

"github.com/openshift/origin/pkg/client"
"github.com/openshift/origin/pkg/cmd/cli/describe"
"github.com/openshift/origin/pkg/cmd/templates"
cmdutil "github.com/openshift/origin/pkg/cmd/util"
"github.com/openshift/origin/pkg/cmd/util/clientcmd"
"github.com/openshift/origin/pkg/generate/app"
"github.com/openshift/origin/pkg/template"
templateapi "github.com/openshift/origin/pkg/template/api"
templatevalidation "github.com/openshift/origin/pkg/template/api/validation"
"github.com/openshift/origin/pkg/template/generator"
)

var (
Expand All @@ -36,12 +42,19 @@ var (
as well as metadata describing the template.

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.`)
output to the create command over STDIN (using the '-f -' option) or redirect it to a file.

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.`)

processExample = templates.Examples(`
# Convert template.json file into resource list and pass to create
%[1]s process -f template.json | %[1]s create -f -

# Process a file locally instead of contacting the server
%[1]s process -f template.json --local -o yaml

# Process template while passing a user-defined label
%[1]s process -f template.json -l name=mytemplate

Expand Down Expand Up @@ -78,6 +91,7 @@ func NewCmdProcess(fullName string, f *clientcmd.Factory, in io.Reader, out, err
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.")
cmd.Flags().StringArray("param-file", []string{}, "File containing template parameter values to set/override in the template.")
cmd.MarkFlagFilename("param-file")
cmd.Flags().BoolP("local", "", false, "If true process the template locally instead of contacting the server.")
cmd.Flags().BoolP("parameters", "", false, "If true, do not process but only print available parameters")
cmd.Flags().StringP("labels", "l", "", "Label to set in all resources for this template")

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

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

mapper, typer := f.Object()

client, _, err := f.Clients()
if err != nil {
return err
}

var (
objects []runtime.Object
infos []*resource.Info

mapper meta.RESTMapper
typer runtime.ObjectTyper

client *client.Client
clientMappingFn resource.ClientMapperFunc
)

if local {
// TODO: Change f.Object() so that it can fall back to local RESTMapper safely (currently glog.Fatals)
mapper = registered.RESTMapper()
typer = kapi.Scheme
clientMappingFn = func(*meta.RESTMapping) (resource.RESTClient, error) { return nil, nil }
// client is deliberately left nil
} else {
client, _, err = f.Clients()
if err != nil {
return err
}

mapper, typer = f.Object()
clientMappingFn = f.ClientForMapping
}
mapping, err := mapper.RESTMapping(templateapi.Kind("Template"))
if err != nil {
return err
Expand All @@ -184,6 +213,7 @@ func RunProcess(f *clientcmd.Factory, in io.Reader, out, errout io.Writer, cmd *
if len(storedTemplate) == 0 {
return fmt.Errorf("invalid value syntax %q", templateName)
}

templateObj, err := client.Templates(sourceNamespace).Get(storedTemplate)
if err != nil {
if errors.IsNotFound(err) {
Expand All @@ -194,7 +224,7 @@ func RunProcess(f *clientcmd.Factory, in io.Reader, out, errout io.Writer, cmd *
templateObj.CreationTimestamp = unversioned.Now()
infos = append(infos, &resource.Info{Object: templateObj})
} else {
infos, err = resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()).
infos, err = resource.NewBuilder(mapper, typer, clientMappingFn, kapi.Codecs.UniversalDecoder()).
NamespaceParam(namespace).RequireNamespace().
FilenameParam(explicit, &resource.FilenameOptions{Recursive: false, Filenames: []string{filename}}).
Do().
Expand Down Expand Up @@ -249,9 +279,16 @@ func RunProcess(f *clientcmd.Factory, in io.Reader, out, errout io.Writer, cmd *
return kerrors.NewAggregate(errs)
}

resultObj, err := client.TemplateConfigs(namespace).Create(obj)
if err != nil {
return fmt.Errorf("error processing the template %q: %v\n", obj.Name, err)
resultObj := obj
if local {
if err := processTemplateLocally(obj); err != nil {
return err
}
} else {
resultObj, err = client.TemplateConfigs(namespace).Create(obj)
if err != nil {
return fmt.Errorf("error processing the template %q: %v\n", obj.Name, err)
}
}

outputFormat := kcmdutil.GetFlagString(cmd, "output")
Expand Down Expand Up @@ -307,3 +344,18 @@ func injectUserVars(values app.Environment, t *templateapi.Template) []error {
}
return errors
}

// processTemplateLocally applies the same logic that a remote call would make but makes no
// connection to the server.
func processTemplateLocally(tpl *templateapi.Template) error {
if errs := templatevalidation.ValidateProcessedTemplate(tpl); len(errs) > 0 {
return errors.NewInvalid(templateapi.Kind("Template"), tpl.Name, errs)
}
processor := template.NewProcessor(map[string]generator.Generator{
"expression": generator.NewExpressionValueGenerator(rand.New(rand.NewSource(time.Now().UnixNano()))),
})
if errs := processor.Process(tpl); len(errs) > 0 {
return errors.NewInvalid(templateapi.Kind("Template"), tpl.Name, errs)
}
return nil
}
12 changes: 12 additions & 0 deletions test/cmd/templates.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ guestbook_template="${OS_ROOT}/test/templates/testdata/guestbook.json"
os::cmd::expect_success "oc process -f '${guestbook_template}' -l app=guestbook | oc create -f -"
os::cmd::expect_success_and_text 'oc status' 'frontend-service'
echo "template+config: ok"

os::test::junit::declare_suite_start "cmd/templates/local-config"
# Processes the template locally
os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --local -l app=guestbook -o yaml" "app: guestbook"
# Processes the template locally and get the same output in YAML
new="$(mktemp -d)"
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"'
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"'
os::cmd::expect_success 'diff "${new}/localtemplate" "${new}/remotetemplate"'
# Does not even try to hit the server
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"
echo "template+config+local: ok"
os::test::junit::declare_suite_end

os::test::junit::declare_suite_start "cmd/templates/parameters"
Expand Down

0 comments on commit cf7e336

Please sign in to comment.