// Create processes a Template and creates a new list of objects func (s *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { tpl, ok := obj.(*api.Template) if !ok { return nil, errors.NewBadRequest("not a template") } if errs := templatevalidation.ValidateProcessedTemplate(tpl); len(errs) > 0 { return nil, errors.NewInvalid(api.Kind("Template"), tpl.Name, errs) } generators := map[string]generator.Generator{ "expression": generator.NewExpressionValueGenerator(rand.New(rand.NewSource(time.Now().UnixNano()))), } processor := template.NewProcessor(generators) if errs := processor.Process(tpl); len(errs) > 0 { glog.V(1).Infof(errs.ToAggregate().Error()) return nil, errors.NewInvalid(api.Kind("Template"), tpl.Name, errs) } // we know that we get back runtime.Unstructured objects from the Process call. We need to encode those // objects using the unstructured codec BEFORE the REST layers gets its shot at encoding to avoid a layered // encode being done. for i := range tpl.Objects { tpl.Objects[i] = runtime.NewEncodable(runtime.UnstructuredJSONScheme, tpl.Objects[i]) } return tpl, nil }
func TestProcessTemplateParameters(t *testing.T) { var template, expectedTemplate api.Template jsonData, _ := ioutil.ReadFile("../../test/templates/testdata/guestbook.json") if err := runtime.DecodeInto(kapi.Codecs.UniversalDecoder(), jsonData, &template); err != nil { t.Fatalf("unexpected error: %v", err) } expectedData, _ := ioutil.ReadFile("../../test/templates/testdata/guestbook_list.json") if err := runtime.DecodeInto(kapi.Codecs.UniversalDecoder(), expectedData, &expectedTemplate); err != nil { t.Fatalf("unexpected error: %v", err) } generators := map[string]generator.Generator{ "expression": generator.NewExpressionValueGenerator(rand.New(rand.NewSource(1337))), } processor := NewProcessor(generators) // Define custom parameter for the transformation: AddParameter(&template, makeParameter("CUSTOM_PARAM1", "1", "", false)) // Transform the template config into the result config errs := processor.Process(&template) if len(errs) > 0 { t.Fatalf("unexpected error: %v", errs) } result, err := runtime.Encode(kapi.Codecs.LegacyCodec(v1.SchemeGroupVersion), &template) if err != nil { t.Fatalf("unexpected error during encoding Config: %#v", err) } exp, _ := runtime.Encode(kapi.Codecs.LegacyCodec(v1.SchemeGroupVersion), &expectedTemplate) if string(result) != string(exp) { t.Errorf("unexpected output: %s", diff.StringDiff(string(exp), string(result))) } }
func processTemplate(tmpl *tapi.Template, domain string, apiserver string) { generators := map[string]generator.Generator{ "expression": generator.NewExpressionValueGenerator(rand.New(rand.NewSource(time.Now().UnixNano()))), } p := template.NewProcessor(generators) tmpl.Parameters = append(tmpl.Parameters, tapi.Parameter{ Name: "DOMAIN", Value: domain, }, tapi.Parameter{ Name: "APISERVER", Value: apiserver, }) errorList := p.Process(tmpl) for _, errInfo := range errorList { util.Errorf("Processing template field %s got error %s\n", errInfo.Field, errInfo.Detail) } }
func TestProcessValueEscape(t *testing.T) { var template api.Template if err := runtime.DecodeInto(kapi.Codecs.UniversalDecoder(), []byte(`{ "kind":"Template", "apiVersion":"v1", "objects": [ { "kind": "Service", "apiVersion": "v1beta3${VALUE}", "metadata": { "labels": { "key1": "${VALUE}", "key2": "$${VALUE}" } } } ] }`), &template); err != nil { t.Fatalf("unexpected error: %v", err) } generators := map[string]generator.Generator{ "expression": generator.NewExpressionValueGenerator(rand.New(rand.NewSource(1337))), } processor := NewProcessor(generators) // Define custom parameter for the transformation: AddParameter(&template, makeParameter("VALUE", "1", "", false)) // Transform the template config into the result config errs := processor.Process(&template) if len(errs) > 0 { t.Fatalf("unexpected error: %v", errs) } result, err := runtime.Encode(kapi.Codecs.LegacyCodec(v1beta3.SchemeGroupVersion), &template) if err != nil { t.Fatalf("unexpected error during encoding Config: %#v", err) } expect := `{"kind":"Template","apiVersion":"v1beta3","metadata":{"creationTimestamp":null},"objects":[{"apiVersion":"v1beta31","kind":"Service","metadata":{"labels":{"key1":"1","key2":"$1"}}}],"parameters":[{"name":"VALUE","value":"1"}]}` stringResult := strings.TrimSpace(string(result)) if expect != stringResult { t.Errorf("unexpected output: %s", diff.StringDiff(expect, stringResult)) } }
// Create processes a Template and creates a new list of objects func (s *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { tpl, ok := obj.(*api.Template) if !ok { return nil, errors.NewBadRequest("not a template") } if errs := templatevalidation.ValidateProcessedTemplate(tpl); len(errs) > 0 { return nil, errors.NewInvalid("template", tpl.Name, errs) } generators := map[string]generator.Generator{ "expression": generator.NewExpressionValueGenerator(rand.New(rand.NewSource(time.Now().UnixNano()))), } processor := template.NewProcessor(generators) if errs := processor.Process(tpl); len(errs) > 0 { glog.V(1).Infof(utilerr.NewAggregate(errs).Error()) return nil, errors.NewInvalid("template", tpl.Name, errs) } return tpl, nil }
func processTemplate(tmpl *tapi.Template, ns string, domain string, apiserver string) { generators := map[string]generator.Generator{ "expression": generator.NewExpressionValueGenerator(rand.New(rand.NewSource(time.Now().UnixNano()))), } p := template.NewProcessor(generators) ip, port, err := net.SplitHostPort(apiserver) if err != nil && !strings.Contains(err.Error(), "missing port in address") { util.Fatalf("%s", err) } namespaceIdx := -1 for i, param := range tmpl.Parameters { if param.Name == "NAMESPACE" { namespaceIdx = i } } if namespaceIdx >= 0 { tmpl.Parameters[namespaceIdx].Value = ns } tmpl.Parameters = append(tmpl.Parameters, tapi.Parameter{ Name: "DOMAIN", Value: ns + "." + domain, }, tapi.Parameter{ Name: "APISERVER", Value: ip, }, tapi.Parameter{ Name: "OAUTH_AUTHORIZE_PORT", Value: port, }) errorList := p.Process(tmpl) for _, errInfo := range errorList { util.Errorf("Processing template field %s got error %s\n", errInfo.Field, errInfo.Detail) } }
func createTemplate(jsonData []byte, templateName string, ns string, domain string, apiserver string, c *k8sclient.Client) { var v1tmpl tapiv1.Template err := json.Unmarshal(jsonData, &v1tmpl) if err != nil { util.Fatalf("Cannot get %s template to deploy. error: %v\ntemplate: %s", templateName, err, string(jsonData)) } var tmpl tapi.Template err = api.Scheme.Convert(&v1tmpl, &tmpl) if err != nil { util.Fatalf("Cannot convert %s template to deploy: %v", templateName, err) } generators := map[string]generator.Generator{ "expression": generator.NewExpressionValueGenerator(rand.New(rand.NewSource(time.Now().UnixNano()))), } p := template.NewProcessor(generators) tmpl.Parameters = append(tmpl.Parameters, tapi.Parameter{ Name: "DOMAIN", Value: domain, }, tapi.Parameter{ Name: "APISERVER", Value: apiserver, }) p.Process(&tmpl) objectCount := len(tmpl.Objects) if objectCount == 0 { // can't be a template so lets try just process it directly var v1List v1.List err = json.Unmarshal(jsonData, &v1List) if err != nil { util.Fatalf("Cannot unmarshal List %s to deploy. error: %v\ntemplate: %s", templateName, err, string(jsonData)) } if len(v1List.Items) == 0 { // lets check if its an RC / ReplicaSet or something _, groupVersionKind, err := api.Codecs.UniversalDeserializer().Decode(jsonData, nil, nil) if err != nil { printResult(templateName, Failure, err) } else { kind := groupVersionKind.Kind util.Infof("Processing resource of kind: %s version: %s\n", kind, groupVersionKind.Version) if len(kind) <= 0 { printResult(templateName, Failure, fmt.Errorf("Could not find kind from json %s", string(jsonData))) } else { processResource(c, jsonData, ns, kind) } } } else { var kubeList api.List err = api.Scheme.Convert(&v1List, &kubeList) if err != nil { util.Fatalf("Cannot convert %s List to deploy: %v", templateName, err) } util.Infof("Converted json to list with %d items with json %s\n", len(kubeList.Items), string(jsonData)) util.Infof("Creating "+templateName+" list resources from %d objects\n", len(kubeList.Items)) for _, o := range kubeList.Items { err = processItem(c, &o, ns) } } } else { util.Infof("Creating "+templateName+" template resources from %d objects\n", objectCount) for _, o := range tmpl.Objects { err = processItem(c, &o, ns) } } if err != nil { printResult(templateName, Failure, err) } else { printResult(templateName, Success, nil) } }
func TestEvaluateLabels(t *testing.T) { testCases := map[string]struct { Input string Output string Labels map[string]string }{ "no labels": { Input: `{ "kind":"Template", "apiVersion":"v1", "objects": [ { "kind": "Service", "apiVersion": "v1", "metadata": {"labels": {"key1": "v1", "key2": "v2"} } } ] }`, Output: `{ "kind":"Template","apiVersion":"v1","metadata":{"creationTimestamp":null}, "objects":[ { "apiVersion":"v1","kind":"Service","metadata":{ "labels":{"key1":"v1","key2":"v2"}} } ] }`, }, "one different label": { Input: `{ "kind":"Template", "apiVersion":"v1", "objects": [ { "kind": "Service", "apiVersion": "v1", "metadata": {"labels": {"key1": "v1", "key2": "v2"} } } ] }`, Output: `{ "kind":"Template","apiVersion":"v1","metadata":{"creationTimestamp":null}, "objects":[ { "apiVersion":"v1","kind":"Service","metadata":{ "labels":{"key1":"v1","key2":"v2","key3":"v3"}} } ], "labels":{"key3":"v3"} }`, Labels: map[string]string{"key3": "v3"}, }, "when the root object has labels and metadata": { Input: `{ "kind":"Template", "apiVersion":"v1", "objects": [ { "kind": "Service", "apiVersion": "v1", "metadata": {}, "labels": { "key1": "v1", "key2": "v2" } } ] }`, Output: `{ "kind":"Template","apiVersion":"v1","metadata":{"creationTimestamp":null}, "objects":[ { "apiVersion":"v1","kind":"Service", "labels":{"key1":"v1","key2":"v2"}, "metadata":{"labels":{"key3":"v3"}} } ], "labels":{"key3":"v3"} }`, Labels: map[string]string{"key3": "v3"}, }, "overwrites label": { Input: `{ "kind":"Template", "apiVersion":"v1", "objects": [ { "kind": "Service", "apiVersion": "v1", "metadata": {"labels": {"key1": "v1", "key2": "v2"} } } ] }`, Output: `{ "kind":"Template","apiVersion":"v1","metadata":{"creationTimestamp":null}, "objects":[ { "apiVersion":"v1","kind":"Service","metadata":{ "labels":{"key1":"v1","key2":"v3"}} } ], "labels":{"key2":"v3"} }`, Labels: map[string]string{"key2": "v3"}, }, } for k, testCase := range testCases { var template api.Template if err := runtime.DecodeInto(kapi.Codecs.UniversalDecoder(), []byte(testCase.Input), &template); err != nil { t.Errorf("%s: unexpected error: %v", k, err) continue } generators := map[string]generator.Generator{ "expression": generator.NewExpressionValueGenerator(rand.New(rand.NewSource(1337))), } processor := NewProcessor(generators) template.ObjectLabels = testCase.Labels // Transform the template config into the result config errs := processor.Process(&template) if len(errs) > 0 { t.Errorf("%s: unexpected error: %v", k, errs) continue } result, err := runtime.Encode(kapi.Codecs.LegacyCodec(v1.SchemeGroupVersion), &template) if err != nil { t.Errorf("%s: unexpected error: %v", k, err) continue } expect := testCase.Output expect = trailingWhitespace.ReplaceAllString(expect, "") stringResult := strings.TrimSpace(string(result)) if expect != stringResult { t.Errorf("%s: unexpected output: %s", k, diff.StringDiff(expect, stringResult)) continue } } }
func TestProcessValue(t *testing.T) { var template api.Template if err := runtime.DecodeInto(kapi.Codecs.UniversalDecoder(), []byte(`{ "kind":"Template", "apiVersion":"v1", "objects": [ { "kind": "Service", "apiVersion": "v${VALUE}", "metadata": { "labels": { "i1": "${{INT_1}}", "invalidjsonmap": "${{INVALID_JSON_MAP}}", "invalidjsonarray": "${{INVALID_JSON_ARRAY}}", "key1": "${VALUE}", "key2": "$${VALUE}", "quoted_string": "${{STRING_1}}", "s1_s1": "${STRING_1}_${STRING_1}", "s1_s2": "${STRING_1}_${STRING_2}", "untouched": "a${{INT_1}}", "untouched2": "${{INT_1}}a", "untouched3": "${{INVALID_PARAMETER}}", "untouched4": "${{INVALID PARAMETER}}", "validjsonmap": "${{VALID_JSON_MAP}}", "validjsonarray": "${{VALID_JSON_ARRAY}}" } } } ] }`), &template); err != nil { t.Fatalf("unexpected error: %v", err) } generators := map[string]generator.Generator{ "expression": generator.NewExpressionValueGenerator(rand.New(rand.NewSource(1337))), } processor := NewProcessor(generators) // Define custom parameter for the transformation: AddParameter(&template, makeParameter("VALUE", "1", "", false)) AddParameter(&template, makeParameter("STRING_1", "string1", "", false)) AddParameter(&template, makeParameter("STRING_2", "string2", "", false)) AddParameter(&template, makeParameter("INT_1", "1", "", false)) AddParameter(&template, makeParameter("VALID_JSON_MAP", "{\"key\":\"value\"}", "", false)) AddParameter(&template, makeParameter("INVALID_JSON_MAP", "{\"key\":\"value\"", "", false)) AddParameter(&template, makeParameter("VALID_JSON_ARRAY", "[\"key\",\"value\"]", "", false)) AddParameter(&template, makeParameter("INVALID_JSON_ARRAY", "[\"key\":\"value\"", "", false)) // Transform the template config into the result config errs := processor.Process(&template) if len(errs) > 0 { t.Fatalf("unexpected error: %v", errs) } result, err := runtime.Encode(kapi.Codecs.LegacyCodec(v1.SchemeGroupVersion), &template) if err != nil { t.Fatalf("unexpected error during encoding Config: %#v", err) } expect := `{"kind":"Template","apiVersion":"v1","metadata":{"creationTimestamp":null},"objects":[{"apiVersion":"v1","kind":"Service","metadata":{"labels":{"i1":1,"invalidjsonarray":"[\"key\":\"value\"","invalidjsonmap":"{\"key\":\"value\"","key1":"1","key2":"$1","quoted_string":"string1","s1_s1":"string1_string1","s1_s2":"string1_string2","untouched":"a${{INT_1}}","untouched2":"${{INT_1}}a","untouched3":"${{INVALID_PARAMETER}}","untouched4":"${{INVALID PARAMETER}}","validjsonarray":["key","value"],"validjsonmap":{"key":"value"}}}}],"parameters":[{"name":"VALUE","value":"1"},{"name":"STRING_1","value":"string1"},{"name":"STRING_2","value":"string2"},{"name":"INT_1","value":"1"},{"name":"VALID_JSON_MAP","value":"{\"key\":\"value\"}"},{"name":"INVALID_JSON_MAP","value":"{\"key\":\"value\""},{"name":"VALID_JSON_ARRAY","value":"[\"key\",\"value\"]"},{"name":"INVALID_JSON_ARRAY","value":"[\"key\":\"value\""}]}` stringResult := strings.TrimSpace(string(result)) if expect != stringResult { //t.Errorf("unexpected output, expected: \n%s\nGot:\n%s\n", expect, stringResult) t.Errorf("unexpected output: %s", diff.StringDiff(expect, stringResult)) } }
func NewCmdDeploy(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "deploy", Short: "Deploy fabric8 to your Kubernetes or OpenShift environment", Long: `deploy fabric8 to your Kubernetes or OpenShift environment`, PreRun: func(cmd *cobra.Command, args []string) { showBanner() }, Run: func(cmd *cobra.Command, args []string) { c, cfg := client.NewClient(f) ns, _, _ := f.DefaultNamespace() util.Info("Deploying fabric8 to your ") util.Success(string(util.TypeOfMaster(c))) util.Info(" installation at ") util.Success(cfg.Host) util.Info(" in namespace ") util.Successf("%s\n\n", ns) if confirmAction(cmd.Flags()) { v := cmd.Flags().Lookup("version").Value.String() typeOfMaster := util.TypeOfMaster(c) v = f8Version(v, typeOfMaster) versioniPaaS := cmd.Flags().Lookup(versioniPaaSFlag).Value.String() versioniPaaS = versionForUrl(versioniPaaS, iPaaSMetadataUrl) util.Warnf("\nStarting deployment of %s...\n\n", v) if typeOfMaster == util.Kubernetes { uri := fmt.Sprintf(baseConsoleKubernetesUrl, v) filenames := []string{uri} createCmd := cobra.Command{} createCmd.Flags().StringSlice("filename", filenames, "") err := kcmd.RunCreate(f, &createCmd, ioutil.Discard) if err != nil { printResult("fabric8 console", Failure, err) } else { printResult("fabric8 console", Success, nil) } } else { oc, _ := client.NewOpenShiftClient(cfg) r, err := verifyRestrictedSecurityContextConstraints(c, f) printResult("SecurityContextConstraints restricted", r, err) r, err = deployFabric8SecurityContextConstraints(c, f, ns) printResult("SecurityContextConstraints fabric8", r, err) printAddClusterRoleToUser(oc, f, "cluster-admin", "system:serviceaccount:"+ns+":fabric8") printAddClusterRoleToUser(oc, f, "cluster-admin", "system:serviceaccount:"+ns+":jenkins") printAddClusterRoleToUser(oc, f, "cluster-reader", "system:serviceaccount:"+ns+":metrics") printAddServiceAccount(c, f, "metrics") printAddServiceAccount(c, f, "router") if cmd.Flags().Lookup(templatesFlag).Value.String() == "true" { uri := fmt.Sprintf(baseConsoleUrl, v) resp, err := http.Get(uri) if err != nil { util.Fatalf("Cannot get fabric8 template to deploy: %v", err) } defer resp.Body.Close() jsonData, err := ioutil.ReadAll(resp.Body) if err != nil { util.Fatalf("Cannot get fabric8 template to deploy: %v", err) } var v1tmpl tapiv1.Template err = json.Unmarshal(jsonData, &v1tmpl) if err != nil { util.Fatalf("Cannot get fabric8 template to deploy: %v", err) } var tmpl tapi.Template err = api.Scheme.Convert(&v1tmpl, &tmpl) if err != nil { util.Fatalf("Cannot get fabric8 template to deploy: %v", err) } generators := map[string]generator.Generator{ "expression": generator.NewExpressionValueGenerator(rand.New(rand.NewSource(time.Now().UnixNano()))), } p := template.NewProcessor(generators) tmpl.Parameters = append(tmpl.Parameters, tapi.Parameter{ Name: "DOMAIN", Value: cmd.Flags().Lookup("domain").Value.String(), }) p.Process(&tmpl) for _, o := range tmpl.Objects { switch o := o.(type) { case *runtime.Unstructured: var b []byte b, err = json.Marshal(o.Object) if err != nil { break } req := c.Post().Body(b) if o.Kind != "OAuthClient" { req.Namespace(ns).Resource(strings.ToLower(o.TypeMeta.Kind + "s")) } else { req.AbsPath("oapi", "v1", strings.ToLower(o.TypeMeta.Kind+"s")) } res := req.Do() if res.Error() != nil { err = res.Error() break } var statusCode int res.StatusCode(&statusCode) if statusCode != http.StatusCreated { err = fmt.Errorf("Failed to create %s: %d", o.TypeMeta.Kind, statusCode) break } } } if err != nil { printResult("fabric8 console", Failure, err) } else { printResult("fabric8 console", Success, nil) } } else { printError("Ignoring the deploy of the fabric8 console", nil) } if cmd.Flags().Lookup(templatesFlag).Value.String() == "true" { printError("Install DevOps templates", installTemplates(oc, f, v, templatesDistroUrl)) printError("Install iPaaS templates", installTemplates(oc, f, versioniPaaS, iPaaSTemplatesDistroUrl)) } else { printError("Ignoring the deploy of templates", nil) } domain := cmd.Flags().Lookup(domainFlag).Value.String() printError("Create routes", createRoutesForDomain(ns, domain, c, oc, f)) } } }, } cmd.PersistentFlags().StringP("domain", "d", defaultDomain(), "The domain name to append to the service name to access web applications") cmd.PersistentFlags().StringP(versioniPaaSFlag, "", "latest", "The version to use for the Fabric8 iPaaS templates") cmd.PersistentFlags().Bool(templatesFlag, true, "Should the standard Fabric8 templates be installed?") cmd.PersistentFlags().Bool(consoleFlag, true, "Should the Fabric8 console be deployed?") return cmd }