// cloudHandler returns a handler that responds with the cloud config for the // requester. func cloudHandler(srv server.Server) ContextHandler { fn := func(ctx context.Context, w http.ResponseWriter, req *http.Request) { group, err := groupFromContext(ctx) if err != nil || group.Profile == "" { http.NotFound(w, req) return } profile, err := srv.ProfileGet(ctx, &pb.ProfileGetRequest{Id: group.Profile}) if err != nil || profile.CloudId == "" { http.NotFound(w, req) return } contents, err := srv.CloudGet(ctx, profile.CloudId) if err != nil { http.NotFound(w, req) return } // collect data for rendering data := make(map[string]interface{}) if group.Metadata != nil { err = json.Unmarshal(group.Metadata, &data) if err != nil { log.Errorf("error unmarshalling metadata: %v", err) http.NotFound(w, req) return } } for key, value := range group.Selector { data[strings.ToLower(key)] = value } // render the template of a cloud config with data var buf bytes.Buffer err = renderTemplate(&buf, data, contents) if err != nil { http.NotFound(w, req) return } config := buf.String() if !cloudinit.IsCloudConfig(config) && !cloudinit.IsScript(config) { log.Error("error parsing user-data") http.NotFound(w, req) return } if cloudinit.IsCloudConfig(config) { if _, err = cloudinit.NewCloudConfig(config); err != nil { log.Errorf("error parsing cloud config: %v", err) http.NotFound(w, req) return } } http.ServeContent(w, req, "", time.Time{}, strings.NewReader(config)) } return ContextHandlerFunc(fn) }
// cloudHandler returns a handler that responds with the cloud config for the // requester. func cloudHandler(store Store) ContextHandler { fn := func(ctx context.Context, w http.ResponseWriter, req *http.Request) { group, err := groupFromContext(ctx) if err != nil || group.Spec == "" { http.NotFound(w, req) return } spec, err := store.Spec(group.Spec) if err != nil || spec.CloudConfig == "" { http.NotFound(w, req) return } contents, err := store.CloudConfig(spec.CloudConfig) if err != nil { http.NotFound(w, req) return } // collect data for rendering data := make(map[string]interface{}) for k := range group.Metadata { data[k] = group.Metadata[k] } // render the template of a cloud config with data var buf bytes.Buffer err = renderTemplate(&buf, data, contents) if err != nil { http.NotFound(w, req) return } config := buf.String() if !cloudinit.IsCloudConfig(config) && !cloudinit.IsScript(config) { log.Errorf("error parsing user-data") http.NotFound(w, req) return } if cloudinit.IsCloudConfig(config) { if _, err = cloudinit.NewCloudConfig(config); err != nil { log.Errorf("error parsing cloud config: %v", err) http.NotFound(w, req) return } } http.ServeContent(w, req, "", time.Time{}, strings.NewReader(config)) } return ContextHandlerFunc(fn) }
func saveCloudConfig() error { userDataBytes, metadata, err := fetchUserData() if err != nil { return err } userData := string(userDataBytes) scriptBytes := []byte{} if config.IsScript(userData) { scriptBytes = userDataBytes userDataBytes = []byte{} } else if isCompose(userData) { if userDataBytes, err = composeToCloudConfig(userDataBytes); err != nil { log.Errorf("Failed to convert compose to cloud-config syntax: %v", err) return err } } else if config.IsCloudConfig(userData) { if _, err := rancherConfig.ReadConfig(userDataBytes, false); err != nil { log.WithFields(log.Fields{"cloud-config": userData, "err": err}).Warn("Failed to parse cloud-config, not saving.") userDataBytes = []byte{} } } else { log.Errorf("Unrecognized user-data\n%s", userData) userDataBytes = []byte{} } if _, err := rancherConfig.ReadConfig(userDataBytes, false); err != nil { log.WithFields(log.Fields{"cloud-config": userData, "err": err}).Warn("Failed to parse cloud-config") return errors.New("Failed to parse cloud-config") } return saveFiles(userDataBytes, scriptBytes, metadata) }
func ParseUserData(contents string) (interface{}, error) { if len(contents) == 0 { return nil, nil } switch { case config.IsScript(contents): log.Printf("Parsing user-data as script") return config.NewScript(contents) case config.IsCloudConfig(contents): log.Printf("Parsing user-data as cloud-config") cc, err := config.NewCloudConfig(contents) if err != nil { return nil, err } if err := cc.Decode(); err != nil { return nil, err } return cc, nil case config.IsIgnitionConfig(contents): return nil, ErrIgnitionConfig default: return nil, errors.New("Unrecognized user-data format") } }
func saveCloudConfig() error { var userDataBytes []byte var metadata datasource.Metadata ds, err := currentDatasource() if err != nil { log.Errorf("Failed to select datasource: %v", err) return err } if ds != nil { log.Infof("Fetching user-data from datasource %v", ds.Type()) userDataBytes, err = ds.FetchUserdata() if err != nil { log.Errorf("Failed fetching user-data from datasource: %v", err) return err } log.Infof("Fetching meta-data from datasource of type %v", ds.Type()) metadata, err = ds.FetchMetadata() if err != nil { log.Errorf("Failed fetching meta-data from datasource: %v", err) return err } } userDataBytes = substituteUserDataVars(userDataBytes, metadata) userData := string(userDataBytes) scriptBytes := []byte{} if config.IsScript(userData) { scriptBytes = userDataBytes userDataBytes = []byte{} } else if isCompose(userData) { if userDataBytes, err = toCompose(userDataBytes); err != nil { log.Errorf("Failed to convert to compose syntax: %v", err) return err } } else if config.IsCloudConfig(userData) { if rancherConfig.ReadConfig(userDataBytes) == nil { log.WithFields(log.Fields{"cloud-config": userData}).Warn("Failed to parse cloud-config, not saving.") userDataBytes = []byte{} } } else { log.Errorf("Unrecognized cloud-init\n%s", userData) userDataBytes = []byte{} } userDataBytesMerged, scriptBytes, err := mergeBaseConfig(userDataBytes, scriptBytes) if err != nil { log.Errorf("Failed to merge base config: %v", err) } else if rancherConfig.ReadConfig(userDataBytesMerged) == nil { log.WithFields(log.Fields{"cloud-config": userData}).Warn("Failed to parse merged cloud-config, not merging.") } else { userDataBytes = userDataBytesMerged } return saveFiles(userDataBytes, scriptBytes, metadata) }
func saveCloudConfig() error { var userDataBytes []byte var metadata datasource.Metadata ds, err := currentDatasource() if err != nil { log.Errorf("Failed to select datasource: %v", err) return err } if ds != nil { log.Infof("Fetching user-data from datasource %v", ds.Type()) userDataBytes, err = ds.FetchUserdata() if err != nil { log.Errorf("Failed fetching user-data from datasource: %v", err) return err } log.Infof("Fetching meta-data from datasource of type %v", ds.Type()) metadata, err = ds.FetchMetadata() if err != nil { log.Errorf("Failed fetching meta-data from datasource: %v", err) return err } } userDataBytes = substituteUserDataVars(userDataBytes, metadata) userData := string(userDataBytes) scriptBytes := []byte{} if config.IsScript(userData) { scriptBytes = userDataBytes userDataBytes = []byte{} } else if isCompose(userData) { if userDataBytes, err = toCompose(userDataBytes); err != nil { log.Errorf("Failed to convert to compose syntax: %v", err) return err } } else if config.IsCloudConfig(userData) { // nothing to do } else { log.Errorf("Unrecognized cloud-init\n%s", userData) userDataBytes = []byte{} } if userDataBytes, scriptBytes, err = mergeBaseConfig(userDataBytes, scriptBytes); err != nil { log.Errorf("Failed to merge base config: %v", err) return err } return saveFiles(userDataBytes, scriptBytes, metadata) }
// Validate runs a series of validation tests against the given userdata and // returns a report detailing all of the issues. Presently, only cloud-configs // can be validated. func Validate(userdataBytes []byte) (Report, error) { switch { case len(userdataBytes) == 0: return Report{}, nil case config.IsScript(string(userdataBytes)): return Report{}, nil case config.IsCloudConfig(string(userdataBytes)): return validateCloudConfig(userdataBytes, Rules) default: return Report{entries: []Entry{ Entry{kind: entryError, message: `must be "#cloud-config" or begin with "#!"`, line: 1}, }}, nil } }
func ParseUserData(contents string) (interface{}, error) { if len(contents) == 0 { return nil, nil } switch { case config.IsScript(contents): log.Printf("Parsing user-data as script") return config.NewScript(contents) case config.IsCloudConfig(contents): log.Printf("Parsing user-data as cloud-config") return config.NewCloudConfig(contents) default: return nil, errors.New("Unrecognized user-data format") } }
// cloudHandler returns a handler that responds with the cloud config for the // requester. func (s *Server) cloudHandler(core server.Server) ContextHandler { fn := func(ctx context.Context, w http.ResponseWriter, req *http.Request) { group, err := groupFromContext(ctx) if err != nil { s.logger.WithFields(logrus.Fields{ "labels": labelsFromRequest(nil, req), }).Infof("No matching group") http.NotFound(w, req) return } profile, err := core.ProfileGet(ctx, &pb.ProfileGetRequest{Id: group.Profile}) if err != nil { s.logger.WithFields(logrus.Fields{ "labels": labelsFromRequest(nil, req), "group": group.Id, "group_name": group.Name, }).Infof("No profile named: %s", group.Profile) http.NotFound(w, req) return } contents, err := core.CloudGet(ctx, profile.CloudId) if err != nil { s.logger.WithFields(logrus.Fields{ "labels": labelsFromRequest(nil, req), "group": group.Id, "group_name": group.Name, "profile": group.Profile, }).Infof("No cloud-config template named: %s", profile.CloudId) http.NotFound(w, req) return } // match was successful s.logger.WithFields(logrus.Fields{ "labels": labelsFromRequest(nil, req), "group": group.Id, "profile": profile.Id, }).Debug("Matched a cloud-config template") // collect data for rendering data := make(map[string]interface{}) if group.Metadata != nil { err = json.Unmarshal(group.Metadata, &data) if err != nil { s.logger.Errorf("error unmarshalling metadata: %v", err) http.NotFound(w, req) return } } for key, value := range group.Selector { data[strings.ToLower(key)] = value } // render the template of a cloud config with data var buf bytes.Buffer err = s.renderTemplate(&buf, data, contents) if err != nil { http.NotFound(w, req) return } config := buf.String() if !cloudinit.IsCloudConfig(config) && !cloudinit.IsScript(config) { s.logger.Error("error parsing user-data") http.NotFound(w, req) return } if cloudinit.IsCloudConfig(config) { if _, err = cloudinit.NewCloudConfig(config); err != nil { s.logger.Errorf("error parsing cloud config: %v", err) http.NotFound(w, req) return } } http.ServeContent(w, req, "", time.Time{}, strings.NewReader(config)) } return ContextHandlerFunc(fn) }