func (c *Config) NewClientFromSettingsData() (*Client, error) { config := Config{} err := json.Unmarshal(c.Settings, &config) if err == nil { return config.NewClient() } return nil, err }
func readFileVars(path string) (map[string]string, error) { bytes, err := ioutil.ReadFile(path) if err != nil { return nil, err } vars := make(map[string]string) err = jsonutil.Unmarshal(bytes, &vars) if err != nil { return nil, err } return vars, nil }
// ParseTemplate takes a byte slice and parses a Template from it, returning // the template and possibly errors while loading the template. The error // could potentially be a MultiError, representing multiple errors. Knowing // and checking for this can be useful, if you wish to format it in a certain // way. func ParseTemplate(data []byte) (t *Template, err error) { var rawTplInterface interface{} err = jsonutil.Unmarshal(data, &rawTplInterface) if err != nil { return } // Decode the raw template interface into the actual rawTemplate // structure, checking for any extranneous keys along the way. var md mapstructure.Metadata var rawTpl rawTemplate decoderConfig := &mapstructure.DecoderConfig{ Metadata: &md, Result: &rawTpl, } decoder, err := mapstructure.NewDecoder(decoderConfig) if err != nil { return } err = decoder.Decode(rawTplInterface) if err != nil { return } errors := make([]error, 0) if len(md.Unused) > 0 { sort.Strings(md.Unused) for _, unused := range md.Unused { errors = append( errors, fmt.Errorf("Unknown root level key in template: '%s'", unused)) } } t = &Template{} t.Variables = make(map[string]string) t.Builders = make(map[string]RawBuilderConfig) t.Hooks = rawTpl.Hooks t.PostProcessors = make([][]RawPostProcessorConfig, len(rawTpl.PostProcessors)) t.Provisioners = make([]RawProvisionerConfig, len(rawTpl.Provisioners)) // Gather all the variables for k, v := range rawTpl.Variables { t.Variables[k] = v } // Gather all the builders for i, v := range rawTpl.Builders { var raw RawBuilderConfig if err := mapstructure.Decode(v, &raw); err != nil { if merr, ok := err.(*mapstructure.Error); ok { for _, err := range merr.Errors { errors = append(errors, fmt.Errorf("builder %d: %s", i+1, err)) } } else { errors = append(errors, fmt.Errorf("builder %d: %s", i+1, err)) } continue } if raw.Type == "" { errors = append(errors, fmt.Errorf("builder %d: missing 'type'", i+1)) continue } // Attempt to get the name of the builder. If the "name" key // missing, use the "type" field, which is guaranteed to exist // at this point. if raw.Name == "" { raw.Name = raw.Type } // Check if we already have a builder with this name and error if so if _, ok := t.Builders[raw.Name]; ok { errors = append(errors, fmt.Errorf("builder with name '%s' already exists", raw.Name)) continue } // Now that we have the name, remove it from the config - as the builder // itself doesn't know about, and it will cause a validation error. delete(v, "name") raw.RawConfig = v t.Builders[raw.Name] = raw } // Gather all the post-processors. This is a complicated process since there // are actually three different formats that the user can use to define // a post-processor. for i, rawV := range rawTpl.PostProcessors { rawPP, err := parsePostProcessor(i, rawV) if err != nil { errors = append(errors, err...) continue } t.PostProcessors[i] = make([]RawPostProcessorConfig, len(rawPP)) configs := t.PostProcessors[i] for j, pp := range rawPP { config := &configs[j] if err := mapstructure.Decode(pp, config); err != nil { if merr, ok := err.(*mapstructure.Error); ok { for _, err := range merr.Errors { errors = append(errors, fmt.Errorf("Post-processor #%d.%d: %s", i+1, j+1, err)) } } else { errors = append(errors, fmt.Errorf("Post-processor %d.%d: %s", i+1, j+1, err)) } continue } if config.Type == "" { errors = append(errors, fmt.Errorf("Post-processor %d.%d: missing 'type'", i+1, j+1)) continue } // Remove the input keep_input_artifact option delete(pp, "keep_input_artifact") config.RawConfig = pp } } // Gather all the provisioners for i, v := range rawTpl.Provisioners { raw := &t.Provisioners[i] if err := mapstructure.Decode(v, raw); err != nil { if merr, ok := err.(*mapstructure.Error); ok { for _, err := range merr.Errors { errors = append(errors, fmt.Errorf("provisioner %d: %s", i+1, err)) } } else { errors = append(errors, fmt.Errorf("provisioner %d: %s", i+1, err)) } continue } if raw.Type == "" { errors = append(errors, fmt.Errorf("provisioner %d: missing 'type'", i+1)) continue } // The provisioners not only don't need or want the override settings // (as they are processed as part of the preparation below), but will // actively reject them as invalid configuration. delete(v, "override") // Verify that the override keys exist... for name, _ := range raw.Override { if _, ok := t.Builders[name]; !ok { errors = append( errors, fmt.Errorf("provisioner %d: build '%s' not found for override", i+1, name)) } } raw.RawConfig = v } if len(t.Builders) == 0 { errors = append(errors, fmt.Errorf("No builders are defined in the template.")) } // If there were errors, we put it into a MultiError and return if len(errors) > 0 { err = &MultiError{errors} t = nil return } return }
// ParseTemplate takes a byte slice and parses a Template from it, returning // the template and possibly errors while loading the template. The error // could potentially be a MultiError, representing multiple errors. Knowing // and checking for this can be useful, if you wish to format it in a certain // way. // // The second parameter, vars, are the values for a set of user variables. func ParseTemplate(data []byte, vars map[string]string) (t *Template, err error) { var rawTplInterface interface{} err = jsonutil.Unmarshal(data, &rawTplInterface) if err != nil { return } // Decode the raw template interface into the actual rawTemplate // structure, checking for any extranneous keys along the way. var md mapstructure.Metadata var rawTpl rawTemplate decoderConfig := &mapstructure.DecoderConfig{ Metadata: &md, Result: &rawTpl, } decoder, err := mapstructure.NewDecoder(decoderConfig) if err != nil { return } err = decoder.Decode(rawTplInterface) if err != nil { return } if rawTpl.MinimumPackerVersion != "" { // TODO: NOPE! Replace this Version := "1.0" vCur, err := version.NewVersion(Version) if err != nil { panic(err) } vReq, err := version.NewVersion(rawTpl.MinimumPackerVersion) if err != nil { return nil, fmt.Errorf( "'minimum_packer_version' error: %s", err) } if vCur.LessThan(vReq) { return nil, fmt.Errorf( "Template requires Packer version %s. "+ "Running version is %s.", vReq, vCur) } } errors := make([]error, 0) if len(md.Unused) > 0 { sort.Strings(md.Unused) for _, unused := range md.Unused { errors = append( errors, fmt.Errorf("Unknown root level key in template: '%s'", unused)) } } t = &Template{} t.Description = rawTpl.Description t.Variables = make(map[string]RawVariable) t.Builders = make(map[string]RawBuilderConfig) t.Hooks = rawTpl.Hooks t.PostProcessors = make([][]RawPostProcessorConfig, len(rawTpl.PostProcessors)) t.Provisioners = make([]RawProvisionerConfig, len(rawTpl.Provisioners)) // Gather all the variables for k, v := range rawTpl.Variables { var variable RawVariable variable.Required = v == nil // Create a new mapstructure decoder in order to decode the default // value since this is the only value in the regular template that // can be weakly typed. decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ Result: &variable.Default, WeaklyTypedInput: true, }) if err != nil { // This should never happen. panic(err) } err = decoder.Decode(v) if err != nil { errors = append(errors, fmt.Errorf("Error decoding default value for user var '%s': %s", k, err)) continue } // Set the value of this variable if we have it if val, ok := vars[k]; ok { variable.HasValue = true variable.Value = val delete(vars, k) } t.Variables[k] = variable } // Gather all the builders for i, v := range rawTpl.Builders { var raw RawBuilderConfig if err := mapstructure.Decode(v, &raw); err != nil { if merr, ok := err.(*mapstructure.Error); ok { for _, err := range merr.Errors { errors = append(errors, fmt.Errorf("builder %d: %s", i+1, err)) } } else { errors = append(errors, fmt.Errorf("builder %d: %s", i+1, err)) } continue } if raw.Type == "" { errors = append(errors, fmt.Errorf("builder %d: missing 'type'", i+1)) continue } // Attempt to get the name of the builder. If the "name" key // missing, use the "type" field, which is guaranteed to exist // at this point. if raw.Name == "" { raw.Name = raw.Type } // Check if we already have a builder with this name and error if so if _, ok := t.Builders[raw.Name]; ok { errors = append(errors, fmt.Errorf("builder with name '%s' already exists", raw.Name)) continue } // Now that we have the name, remove it from the config - as the builder // itself doesn't know about, and it will cause a validation error. delete(v, "name") raw.RawConfig = v t.Builders[raw.Name] = raw } // Gather all the post-processors. This is a complicated process since there // are actually three different formats that the user can use to define // a post-processor. for i, rawV := range rawTpl.PostProcessors { rawPP, err := parsePostProcessor(i, rawV) if err != nil { errors = append(errors, err...) continue } configs := make([]RawPostProcessorConfig, 0, len(rawPP)) for j, pp := range rawPP { var config RawPostProcessorConfig if err := mapstructure.Decode(pp, &config); err != nil { if merr, ok := err.(*mapstructure.Error); ok { for _, err := range merr.Errors { errors = append(errors, fmt.Errorf("Post-processor #%d.%d: %s", i+1, j+1, err)) } } else { errors = append(errors, fmt.Errorf("Post-processor %d.%d: %s", i+1, j+1, err)) } continue } if config.Type == "" { errors = append(errors, fmt.Errorf("Post-processor %d.%d: missing 'type'", i+1, j+1)) continue } // Remove the input keep_input_artifact option config.TemplateOnlyExcept.Prune(pp) delete(pp, "keep_input_artifact") // Verify that the only settings are good if errs := config.TemplateOnlyExcept.Validate(t.Builders); len(errs) > 0 { for _, err := range errs { errors = append(errors, fmt.Errorf("Post-processor %d.%d: %s", i+1, j+1, err)) } continue } config.RawConfig = pp // Add it to the list of configs configs = append(configs, config) } t.PostProcessors[i] = configs } // Gather all the provisioners for i, v := range rawTpl.Provisioners { raw := &t.Provisioners[i] if err := mapstructure.Decode(v, raw); err != nil { if merr, ok := err.(*mapstructure.Error); ok { for _, err := range merr.Errors { errors = append(errors, fmt.Errorf("provisioner %d: %s", i+1, err)) } } else { errors = append(errors, fmt.Errorf("provisioner %d: %s", i+1, err)) } continue } if raw.Type == "" { errors = append(errors, fmt.Errorf("provisioner %d: missing 'type'", i+1)) continue } // Delete the keys that we used raw.TemplateOnlyExcept.Prune(v) delete(v, "override") // Verify that the override keys exist... for name, _ := range raw.Override { if _, ok := t.Builders[name]; !ok { errors = append( errors, fmt.Errorf("provisioner %d: build '%s' not found for override", i+1, name)) } } // Verify that the only settings are good if errs := raw.TemplateOnlyExcept.Validate(t.Builders); len(errs) > 0 { for _, err := range errs { errors = append(errors, fmt.Errorf("provisioner %d: %s", i+1, err)) } } // Setup the pause settings if raw.RawPauseBefore != "" { duration, err := time.ParseDuration(raw.RawPauseBefore) if err != nil { errors = append( errors, fmt.Errorf( "provisioner %d: pause_before invalid: %s", i+1, err)) } raw.pauseBefore = duration } // Remove the pause_before setting if it is there so that we don't // get template validation errors later. delete(v, "pause_before") raw.RawConfig = v } if len(t.Builders) == 0 { errors = append(errors, fmt.Errorf("No builders are defined in the template.")) } // Verify that all the variable sets were for real variables. for k, _ := range vars { errors = append(errors, fmt.Errorf("Unknown user variables: %s", k)) } // If there were errors, we put it into a MultiError and return if len(errors) > 0 { err = &MultiError{errors} t = nil return } return }