// MergeServicesV1 merges a v1 compose file into an existing set of service configs func MergeServicesV1(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup, file string, datas RawServiceMap, options *ParseOptions) (map[string]*ServiceConfigV1, error) { if options.Interpolate { if err := Interpolate(environmentLookup, &datas); err != nil { return nil, err } } if options.Preprocess != nil { var err error datas, err = options.Preprocess(datas) if err != nil { return nil, err } } if options.Validate { if err := validate(datas); err != nil { return nil, err } } for name, data := range datas { data, err := parseV1(resourceLookup, environmentLookup, file, data, datas, options) if err != nil { logrus.Errorf("Failed to parse service %s: %v", name, err) return nil, err } if serviceConfig, ok := existingServices.Get(name); ok { var rawExistingService RawService if err := utils.Convert(serviceConfig, &rawExistingService); err != nil { return nil, err } data = mergeConfig(rawExistingService, data) } datas[name] = data } if options.Validate { for name, data := range datas { err := validateServiceConstraints(data, name) if err != nil { return nil, err } } } serviceConfigs := make(map[string]*ServiceConfigV1) if err := utils.Convert(datas, &serviceConfigs); err != nil { return nil, err } return serviceConfigs, nil }
// MergeServices merges a compose file into an existing set of service configs func MergeServices(existingServices *Configs, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup, file string, bytes []byte) (map[string]*ServiceConfig, error) { configs := make(map[string]*ServiceConfig) datas := make(RawServiceMap) if err := yaml.Unmarshal(bytes, &datas); err != nil { return nil, err } if err := Interpolate(environmentLookup, &datas); err != nil { return nil, err } if err := validate(datas); err != nil { return nil, err } for name, data := range datas { data, err := parse(resourceLookup, environmentLookup, file, data, datas) if err != nil { logrus.Errorf("Failed to parse service %s: %v", name, err) return nil, err } if serviceConfig, ok := existingServices.Get(name); ok { var rawExistingService RawService if err := utils.Convert(serviceConfig, &rawExistingService); err != nil { return nil, err } data = mergeConfig(rawExistingService, data) } datas[name] = data } for name, data := range datas { err := validateServiceConstraints(data, name) if err != nil { return nil, err } } if err := utils.Convert(datas, &configs); err != nil { return nil, err } adjustValues(configs) return configs, nil }
// MergeServicesV2 merges a v2 compose file into an existing set of service configs func MergeServicesV2(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup, file string, bytes []byte, options *ParseOptions) (map[string]*ServiceConfig, error) { var config Config if err := yaml.Unmarshal(bytes, &config); err != nil { return nil, err } datas := config.Services if options.Interpolate { if err := Interpolate(environmentLookup, &datas); err != nil { return nil, err } } if options.Preprocess != nil { var err error datas, err = options.Preprocess(datas) if err != nil { return nil, err } } for name, data := range datas { data, err := parseV2(resourceLookup, environmentLookup, file, data, datas, options) if err != nil { logrus.Errorf("Failed to parse service %s: %v", name, err) return nil, err } if serviceConfig, ok := existingServices.Get(name); ok { var rawExistingService RawService if err := utils.Convert(serviceConfig, &rawExistingService); err != nil { return nil, err } data = mergeConfig(rawExistingService, data) } datas[name] = data } serviceConfigs := make(map[string]*ServiceConfig) if err := utils.Convert(datas, &serviceConfigs); err != nil { return nil, err } return serviceConfigs, nil }
func (c *Context) unmarshalBytes(composeBytes, bytes []byte) error { rawServiceMap := project.RawServiceMap{} if composeBytes != nil { if err := yaml.Unmarshal(composeBytes, &rawServiceMap); err != nil { return err } for key := range rawServiceMap { delete(rawServiceMap[key], "hostname") } } if bytes != nil { if err := yaml.Unmarshal(bytes, &rawServiceMap); err != nil { return err } } if err := project.Interpolate(c.EnvironmentLookup, &rawServiceMap); err != nil { return err } if err := utils.Convert(rawServiceMap, &c.RancherConfig); err != nil { return err } for _, v := range c.RancherConfig { rUtils.RemoveInterfaceKeys(v.Metadata) } return nil }
func (q *QuestionLookup) parse(file string) error { contents, err := ioutil.ReadFile(file) if os.IsNotExist(err) { return nil } else if err != nil { return err } data := map[string]map[string]interface{}{} if err := yaml.Unmarshal(contents, &data); err != nil { return err } rawQuestions := data[".catalog"] if rawQuestions != nil { var wrapper questionWrapper if err := utils.Convert(rawQuestions, &wrapper); err != nil { return err } for _, question := range wrapper.Questions { q.questions[question.Variable] = question } } return nil }
func (q *QuestionLookup) parse(file string) error { contents, err := ioutil.ReadFile(file) if os.IsNotExist(err) { return nil } else if err != nil { return err } config, err := config.CreateConfig(contents) if err != nil { return err } data := config.Services rawQuestions := data[".catalog"] if rawQuestions != nil { var wrapper questionWrapper if err := utils.Convert(rawQuestions, &wrapper); err != nil { return err } for _, question := range wrapper.Questions { q.questions[question.Variable] = question } } return nil }
func ParseCatalogConfig(contents []byte) (*model.RancherCompose, error) { cfg, err := config.CreateConfig(contents) if err != nil { return nil, err } var rawCatalogConfig interface{} if cfg.Version == "2" && cfg.Services[".catalog"] != nil { rawCatalogConfig = cfg.Services[".catalog"] } var data map[string]interface{} if err := yaml.Unmarshal(contents, &data); err != nil { return nil, err } if data["catalog"] != nil { rawCatalogConfig = data["catalog"] } else if data[".catalog"] != nil { rawCatalogConfig = data[".catalog"] } if rawCatalogConfig != nil { var catalogConfig model.RancherCompose if err := utils.Convert(rawCatalogConfig, &catalogConfig); err != nil { return nil, err } return &catalogConfig, nil } return &model.RancherCompose{}, nil }
func mergeProject(p *Project, bytes []byte) (map[string]*ServiceConfig, error) { configs := make(map[string]*ServiceConfig) datas := make(rawServiceMap) if err := yaml.Unmarshal(bytes, &datas); err != nil { return nil, err } if err := interpolate(p.context.EnvironmentLookup, &datas); err != nil { return nil, err } for name, data := range datas { data, err := parse(p.context.ConfigLookup, p.context.EnvironmentLookup, p.File, data, datas) if err != nil { logrus.Errorf("Failed to parse service %s: %v", name, err) return nil, err } datas[name] = data } if err := utils.Convert(datas, &configs); err != nil { return nil, err } adjustValues(configs) return configs, nil }
func createLaunchConfigs(r *RancherService) (rancherClient.LaunchConfig, []rancherClient.SecondaryLaunchConfig, error) { secondaryLaunchConfigs := []rancherClient.SecondaryLaunchConfig{} launchConfig, err := createLaunchConfig(r, r.Name(), r.Config()) if err != nil { return launchConfig, nil, err } launchConfig.HealthCheck = r.HealthCheck("") if secondaries, ok := r.Context().SidekickInfo.primariesToSidekicks[r.Name()]; ok { for _, secondaryName := range secondaries { serviceConfig, ok := r.Context().Project.Configs[secondaryName] if !ok { return launchConfig, nil, fmt.Errorf("Failed to find sidekick: %s", secondaryName) } launchConfig, err := createLaunchConfig(r, secondaryName, serviceConfig) if err != nil { return launchConfig, nil, err } launchConfig.HealthCheck = r.HealthCheck(secondaryName) var secondaryLaunchConfig rancherClient.SecondaryLaunchConfig utils.Convert(launchConfig, &secondaryLaunchConfig) secondaryLaunchConfig.Name = secondaryName if secondaryLaunchConfig.Labels == nil { secondaryLaunchConfig.Labels = map[string]interface{}{} } secondaryLaunchConfigs = append(secondaryLaunchConfigs, secondaryLaunchConfig) } } return launchConfig, secondaryLaunchConfigs, nil }
func readEnvFile(configLookup ConfigLookup, inFile string, serviceData rawService) (rawService, error) { var config ServiceConfig if err := utils.Convert(serviceData, &config); err != nil { return nil, err } if len(config.EnvFile.Slice()) == 0 { return serviceData, nil } if configLookup == nil { return nil, fmt.Errorf("Can not use env_file in file %s no mechanism provided to load files", inFile) } vars := config.Environment.Slice() for i := len(config.EnvFile.Slice()) - 1; i >= 0; i-- { envFile := config.EnvFile.Slice()[i] content, _, err := configLookup.Lookup(envFile, inFile) if err != nil { return nil, err } if err != nil { return nil, err } scanner := bufio.NewScanner(bytes.NewBuffer(content)) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) key := strings.SplitAfter(line, "=")[0] found := false for _, v := range vars { if strings.HasPrefix(v, key) { found = true break } } if !found { vars = append(vars, line) } } if scanner.Err() != nil { return nil, scanner.Err() } } serviceData["environment"] = vars delete(serviceData, "env_file") return serviceData, nil }
func (c *Context) unmarshalBytes(bytes []byte) error { rawServiceMap := project.RawServiceMap{} if err := yaml.Unmarshal(bytes, &rawServiceMap); err != nil { return err } if err := project.Interpolate(c.EnvironmentLookup, &rawServiceMap); err != nil { return err } return utils.Convert(rawServiceMap, &c.RancherConfig) }
func hashObj(obj interface{}) (string, error) { hash := sha1.New() mapObj := map[interface{}]interface{}{} if err := utils.Convert(obj, &mapObj); err != nil { return "", err } writeNativeMap(hash, mapObj) return hex.EncodeToString(hash.Sum(nil)), nil }
//ExtractBindings gets bindings from created RawServiceMap func ExtractBindings(yamlContent []byte) (BindingProperty, error) { var rawConfigDocker config.RawServiceMap var bindingsMap map[string]ServiceBinding var bindingPropertyMap BindingProperty var labels libYaml.SliceorMap config, err := config.CreateConfig(yamlContent) if err != nil { return nil, err } rawConfigDocker = config.Services preProcessServiceMap := preprocess.PreprocessServiceMap(nil) rawConfigDocker, err = preProcessServiceMap(rawConfigDocker) if err != nil { log.Errorf("Error during preprocess : %v\n", err) return nil, err } bindingsMap = make(map[string]ServiceBinding) bindingPropertyMap = make(map[string]interface{}) for key := range rawConfigDocker { if _, serviceParsed := bindingsMap[key]; serviceParsed { log.Debugf("Service bindings already provided") continue } newServiceBinding := ServiceBinding{} newServiceBinding.Labels = MapLabel{} newServiceBinding.Ports = PortArray{} if rawConfigDocker[key]["labels"] != nil { err := utils.Convert(rawConfigDocker[key]["labels"], &labels) if err != nil { return nil, err } for k, v := range labels { newServiceBinding.Labels[k] = v } } if rawConfigDocker[key]["ports"] != nil { for _, port := range rawConfigDocker[key]["ports"].([]interface{}) { newServiceBinding.Ports = append(newServiceBinding.Ports, port) } } bindingsMap[key] = newServiceBinding } bindingPropertyMap["services"] = bindingsMap return bindingPropertyMap, nil }
// ParseNetworks parses networks in a compose file func ParseNetworks(bytes []byte) (map[string]*NetworkConfig, error) { networkConfigs := make(map[string]*NetworkConfig) var config Config if err := yaml.Unmarshal(bytes, &config); err != nil { return nil, err } if err := utils.Convert(config.Networks, &networkConfigs); err != nil { return nil, err } return networkConfigs, nil }
// ParseVolumes parses volumes in a compose file func ParseVolumes(bytes []byte) (map[string]*VolumeConfig, error) { volumeConfigs := make(map[string]*VolumeConfig) var config Config if err := yaml.Unmarshal(bytes, &config); err != nil { return nil, err } if err := utils.Convert(config.Volumes, &volumeConfigs); err != nil { return nil, err } return volumeConfigs, nil }
func (c *Context) fillInRancherConfig(rawServiceMap config.RawServiceMap) error { if err := config.Interpolate(c.EnvironmentLookup, &rawServiceMap); err != nil { return err } rawServiceMap, err := preprocess.TryConvertStringsToInts(rawServiceMap, getRancherConfigObjects()) if err != nil { return err } if err := utils.Convert(rawServiceMap, &c.RancherConfig); err != nil { return err } for _, v := range c.RancherConfig { rUtils.RemoveInterfaceKeys(v.Metadata) } return nil }
func LookupHash(service *client.Service) (ServiceHash, bool) { ret := ServiceHash{ SecondaryLaunchConfigs: map[string]string{}, } ret.Service = toString(service.Metadata[ServiceHashKey]) ret.LaunchConfig = toString(service.LaunchConfig.Labels[ServiceHashKey]) for _, rawSecondaryLaunchConfig := range service.SecondaryLaunchConfigs { var secondaryLaunchConfig client.SecondaryLaunchConfig if err := utils.Convert(rawSecondaryLaunchConfig, &secondaryLaunchConfig); err != nil { return ret, false } ret.SecondaryLaunchConfigs[secondaryLaunchConfig.Name] = toString(secondaryLaunchConfig.Labels[ServiceHashKey]) } return ret, ret.Service != "" }
// ParseNetworks parses networks in a compose file func ParseNetworks(bytes []byte) (map[string]*NetworkConfig, error) { networkConfigs := make(map[string]*NetworkConfig) var config Config if err := yaml.Unmarshal(bytes, &config); err != nil { return nil, err } if err := utils.Convert(config.Networks, &networkConfigs); err != nil { return nil, err } for key, value := range networkConfigs { if value == nil { networkConfigs[key] = &NetworkConfig{} } } return networkConfigs, nil }
// Merge read the specified byte array, which is the content of a yaml composefile, // and merge it into the current project. func Merge(p *Project, bytes []byte) (map[string]*ServiceConfig, error) { configs := make(map[string]*ServiceConfig) datas := make(rawServiceMap) err := yaml.Unmarshal(bytes, &datas) if err != nil { logrus.Fatalf("Could not parse config for project %s : %v", p.Name, err) } for name, data := range datas { data, err := parse(p.context.ConfigLookup, p.File, data, datas) if err != nil { logrus.Errorf("Failed to parse service %s: %v", name, err) return nil, err } datas[name] = data } err = utils.Convert(datas, &configs) return configs, err }
func (r *RancherService) createNormalService() (*rancherClient.Service, error) { secondaryLaunchConfigs := []interface{}{} launchConfig, err := r.createLaunchConfig(r.serviceConfig) if err != nil { return nil, err } if secondaries, ok := r.context.SidekickInfo.primariesToSidekicks[r.name]; ok { for _, secondaryName := range secondaries { serviceConfig, ok := r.context.Project.Configs[secondaryName] if !ok { return nil, fmt.Errorf("Failed to find sidekick: %s", secondaryName) } launchConfig, err := r.createLaunchConfig(serviceConfig) if err != nil { return nil, err } var secondaryLaunchConfig rancherClient.SecondaryLaunchConfig utils.Convert(launchConfig, &secondaryLaunchConfig) secondaryLaunchConfig.Name = secondaryName secondaryLaunchConfigs = append(secondaryLaunchConfigs, secondaryLaunchConfig) } } return r.context.Client.Service.Create(&rancherClient.Service{ Name: r.name, Metadata: r.getMetadata(), LaunchConfig: launchConfig, SecondaryLaunchConfigs: secondaryLaunchConfigs, Scale: int64(r.getConfiguredScale()), EnvironmentId: r.context.Environment.Id, SelectorContainer: r.getSelectorContainer(), SelectorLink: r.getSelectorLink(), }) }
// ConvertServices converts a set of v1 service configs to v2 service configs func ConvertServices(v1Services map[string]*ServiceConfigV1) (map[string]*ServiceConfig, error) { v2Services := make(map[string]*ServiceConfig) replacementFields := make(map[string]*ServiceConfig) for name, service := range v1Services { replacementFields[name] = &ServiceConfig{ Build: Build{ Context: service.Build, Dockerfile: service.Dockerfile, }, Logging: Log{ Driver: service.LogDriver, Options: service.LogOpt, }, NetworkMode: service.Net, } v1Services[name].Build = "" v1Services[name].Dockerfile = "" v1Services[name].LogDriver = "" v1Services[name].LogOpt = nil v1Services[name].Net = "" } if err := utils.Convert(v1Services, &v2Services); err != nil { return nil, err } for name := range v2Services { v2Services[name].Build = replacementFields[name].Build v2Services[name].Logging = replacementFields[name].Logging v2Services[name].NetworkMode = replacementFields[name].NetworkMode } return v2Services, nil }
func readEnvFile(resourceLookup ResourceLookup, inFile string, serviceData RawService) (RawService, error) { if _, ok := serviceData["env_file"]; !ok { return serviceData, nil } var envFiles composeYaml.Stringorslice if err := utils.Convert(serviceData["env_file"], &envFiles); err != nil { return nil, err } if len(envFiles) == 0 { return serviceData, nil } if resourceLookup == nil { return nil, fmt.Errorf("Can not use env_file in file %s no mechanism provided to load files", inFile) } var vars composeYaml.MaporEqualSlice if _, ok := serviceData["environment"]; ok { if err := utils.Convert(serviceData["environment"], &vars); err != nil { return nil, err } } for i := len(envFiles) - 1; i >= 0; i-- { envFile := envFiles[i] content, _, err := resourceLookup.Lookup(envFile, inFile) if err != nil { return nil, err } if err != nil { return nil, err } scanner := bufio.NewScanner(bytes.NewBuffer(content)) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if len(line) > 0 && !strings.HasPrefix(line, "#") { key := strings.SplitAfter(line, "=")[0] found := false for _, v := range vars { if strings.HasPrefix(v, key) { found = true break } } if !found { vars = append(vars, line) } } } if scanner.Err() != nil { return nil, scanner.Err() } } serviceData["environment"] = vars delete(serviceData, "env_file") return serviceData, nil }
// Merge merges a compose file into an existing set of service configs func Merge(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup, file string, bytes []byte, options *ParseOptions) (string, map[string]*ServiceConfig, map[string]*VolumeConfig, map[string]*NetworkConfig, error) { if options == nil { options = &defaultParseOptions } config, err := CreateConfig(bytes) if err != nil { return "", nil, nil, nil, err } baseRawServices := config.Services if options.Interpolate { if err := InterpolateRawServiceMap(&baseRawServices, environmentLookup); err != nil { return "", nil, nil, nil, err } for k, v := range config.Volumes { if err := Interpolate(k, &v, environmentLookup); err != nil { return "", nil, nil, nil, err } config.Volumes[k] = v } for k, v := range config.Networks { if err := Interpolate(k, &v, environmentLookup); err != nil { return "", nil, nil, nil, err } config.Networks[k] = v } } if options.Preprocess != nil { var err error baseRawServices, err = options.Preprocess(baseRawServices) if err != nil { return "", nil, nil, nil, err } } var serviceConfigs map[string]*ServiceConfig if config.Version == "2" { var err error serviceConfigs, err = MergeServicesV2(existingServices, environmentLookup, resourceLookup, file, baseRawServices, options) if err != nil { return "", nil, nil, nil, err } } else { serviceConfigsV1, err := MergeServicesV1(existingServices, environmentLookup, resourceLookup, file, baseRawServices, options) if err != nil { return "", nil, nil, nil, err } serviceConfigs, err = ConvertServices(serviceConfigsV1) if err != nil { return "", nil, nil, nil, err } } adjustValues(serviceConfigs) if options.Postprocess != nil { var err error serviceConfigs, err = options.Postprocess(serviceConfigs) if err != nil { return "", nil, nil, nil, err } } var volumes map[string]*VolumeConfig var networks map[string]*NetworkConfig if err := utils.Convert(config.Volumes, &volumes); err != nil { return "", nil, nil, nil, err } if err := utils.Convert(config.Networks, &networks); err != nil { return "", nil, nil, nil, err } return config.Version, serviceConfigs, volumes, networks, nil }
func TestCreateBindings(t *testing.T) { var labelsCompose libYaml.SliceorMap var labels libYaml.SliceorMap var ports PortArray bindingPropertyMap, err := ExtractBindings([]byte(` test_v1: ports: - 9000:9000/tcp labels: label_1: value_1 tty: true image: foo`)) if err != nil { t.Fatal(err) } labelsCompose = make(map[string]string) labelsCompose["label_1"] = "value_1" portsCompose := PortArray{} portsCompose = append(portsCompose, "9000:9000/tcp") if len(bindingPropertyMap) != 1 { t.Fatal("Bindings not created") } if _, ok := bindingPropertyMap["services"]; ok { service := bindingPropertyMap["services"].(map[string]ServiceBinding) err = utils.Convert(service["test_v1"].Labels, &labels) if err != nil { t.Fatal(err) } if !(reflect.DeepEqual(labels, labelsCompose)) { t.Fatal("Bindings labels incorrect") } err = utils.Convert(service["test_v1"].Ports, &ports) if err != nil { t.Fatal(err) } if !(reflect.DeepEqual(ports, portsCompose)) { t.Fatal("Bindings ports incorrect") } } bindingPropertyMap, err = ExtractBindings([]byte(` version: '2' services: test_v2: labels: label_2: value_2 ports: - 9001:9001/tcp `)) if err != nil { t.Fatal(err) } labelsCompose = make(map[string]string) labelsCompose["label_2"] = "value_2" portsCompose = PortArray{} portsCompose = append(portsCompose, "9001:9001/tcp") if len(bindingPropertyMap) != 1 { t.Fatal("Bindings not created") } if _, ok := bindingPropertyMap["services"]; ok { service := bindingPropertyMap["services"].(map[string]ServiceBinding) err = utils.Convert(service["test_v2"].Labels, &labels) if err != nil { t.Fatal(err) } if !(reflect.DeepEqual(labels, labelsCompose)) { t.Fatal("Bindings labels incorrect") } err = utils.Convert(service["test_v2"].Ports, &ports) if err != nil { t.Fatal(err) } if !(reflect.DeepEqual(ports, portsCompose)) { t.Fatal("Bindings ports incorrect") } } }