func (r *Release) resolveLinks(app App, m *manifest.Manifest) (*manifest.Manifest, error) { // HACK: need an app of type structs.App for docker login. // Should be fixed/removed once proper logic is moved over to structs.App // That includes moving Formation() around sa := structs.App{ Name: app.Name, Release: app.Release, Status: app.Status, Outputs: app.Outputs, Parameters: app.Parameters, Tags: app.Tags, } endpoint, err := AppDockerLogin(sa) if err != nil { return m, fmt.Errorf("could not log into %q", endpoint) } for i, entry := range m.Services { var inspect []struct { Config struct { Env []string } } imageName := entry.Image cmd := exec.Command("docker", "pull", imageName) out, err := cmd.CombinedOutput() fmt.Printf("ns=kernel at=release.formation at=entry.pull imageName=%q out=%q err=%q\n", imageName, string(out), err) if err != nil { return m, fmt.Errorf("could not pull %q", imageName) } cmd = exec.Command("docker", "inspect", imageName) out, err = cmd.CombinedOutput() // fmt.Printf("ns=kernel at=release.formation at=entry.inspect imageName=%q out=%q err=%q\n", imageName, string(out), err) if err != nil { return m, fmt.Errorf("could not inspect %q", imageName) } err = json.Unmarshal(out, &inspect) if err != nil { fmt.Printf("ns=kernel at=release.formation at=entry.unmarshal err=%q\n", err) return m, fmt.Errorf("could not inspect %q", imageName) } entry.Exports = make(map[string]string) linkableEnvs := make([]string, len(entry.Environment)) for k, v := range entry.Environment { val := fmt.Sprintf("%s=%s", k, v) linkableEnvs = append(linkableEnvs, val) } if len(inspect) == 1 { linkableEnvs = append(linkableEnvs, inspect[0].Config.Env...) } for _, val := range linkableEnvs { if strings.HasPrefix(val, "LINK_") { parts := strings.SplitN(val, "=", 2) if len(parts) == 2 { entry.Exports[parts[0]] = parts[1] m.Services[i] = entry } } } } for i, entry := range m.Services { entry.LinkVars = make(map[string]template.HTML) for _, link := range entry.Links { other, ok := m.Services[link] if !ok { return m, fmt.Errorf("Cannot find link %q", link) } scheme := other.Exports["LINK_SCHEME"] if scheme == "" { scheme = "tcp" } mb := m.GetBalancer(link) if mb == nil { // commented out to be less strict, just don't create the link //return m, fmt.Errorf("Cannot discover balancer for link %q", link) continue } host := fmt.Sprintf(`{ "Fn::If" : [ "Enabled%s", { "Fn::GetAtt" : [ "%s", "DNSName" ] }, "DISABLED" ] }`, UpperName(other.Name), mb.ResourceName()) if len(other.Ports) == 0 { // commented out to be less strict, just don't create the link // return m, fmt.Errorf("Cannot link to %q because it does not expose ports in the manifest", link) continue } var port manifest.Port linkPort := other.Exports["LINK_PORT"] if linkPort == "" { port = other.Ports[0] } else { i, _ := strconv.Atoi(linkPort) if err != nil { return nil, err } var matchedPort = false for _, p := range other.Ports { if i == p.Container { port = p matchedPort = true } } if !matchedPort { return nil, fmt.Errorf("No Port matching %s found", linkPort) } } path := other.Exports["LINK_PATH"] var userInfo string if other.Exports["LINK_USERNAME"] != "" || other.Exports["LINK_PASSWORD"] != "" { userInfo = fmt.Sprintf("%s:%s@", other.Exports["LINK_USERNAME"], other.Exports["LINK_PASSWORD"]) } html := fmt.Sprintf(`{ "Fn::Join": [ "", [ "%s", "://", "%s", %s, ":", "%s", "%s" ] ] }`, scheme, userInfo, host, port, path) prefix := strings.ToUpper(link) + "_" prefix = strings.Replace(prefix, "-", "_", -1) entry.LinkVars[prefix+"HOST"] = template.HTML(host) entry.LinkVars[prefix+"SCHEME"] = template.HTML(fmt.Sprintf("%q", scheme)) entry.LinkVars[prefix+"PORT"] = template.HTML(fmt.Sprintf("%q", port)) entry.LinkVars[prefix+"PASSWORD"] = template.HTML(fmt.Sprintf("%q", other.Exports["LINK_PASSWORD"])) entry.LinkVars[prefix+"USERNAME"] = template.HTML(fmt.Sprintf("%q", other.Exports["LINK_USERNAME"])) entry.LinkVars[prefix+"PATH"] = template.HTML(fmt.Sprintf("%q", path)) entry.LinkVars[prefix+"URL"] = template.HTML(html) m.Services[i] = entry } } return m, nil }
func (r *Release) resolveLinks(app App, manifest *manifest.Manifest) (*manifest.Manifest, error) { m := *manifest endpoint, err := AppDockerLogin(app) if err != nil { return &m, fmt.Errorf("could not log into %q", endpoint) } for i, entry := range m.Services { var inspect []struct { Config struct { Env []string } } imageName := entry.Image cmd := exec.Command("docker", "pull", imageName) out, err := cmd.CombinedOutput() fmt.Printf("ns=kernel at=release.formation at=entry.pull imageName=%q out=%q err=%q\n", imageName, string(out), err) if err != nil { return &m, fmt.Errorf("could not pull %q", imageName) } cmd = exec.Command("docker", "inspect", imageName) out, err = cmd.CombinedOutput() // fmt.Printf("ns=kernel at=release.formation at=entry.inspect imageName=%q out=%q err=%q\n", imageName, string(out), err) if err != nil { return &m, fmt.Errorf("could not inspect %q", imageName) } err = json.Unmarshal(out, &inspect) if err != nil { fmt.Printf("ns=kernel at=release.formation at=entry.unmarshal err=%q\n", err) return &m, fmt.Errorf("could not inspect %q", imageName) } entry.Exports = make(map[string]string) linkableEnvs := make([]string, len(entry.Environment)) for k, v := range entry.Environment { val := fmt.Sprintf("%s=%s", k, v) linkableEnvs = append(linkableEnvs, val) } if len(inspect) == 1 { linkableEnvs = append(linkableEnvs, inspect[0].Config.Env...) } for _, val := range linkableEnvs { if strings.HasPrefix(val, "LINK_") { parts := strings.SplitN(val, "=", 2) if len(parts) == 2 { entry.Exports[parts[0]] = parts[1] m.Services[i] = entry } } } } for i, entry := range m.Services { entry.LinkVars = make(map[string]template.HTML) for _, link := range entry.Links { other, ok := m.Services[link] if !ok { return &m, fmt.Errorf("Cannot find link %q", link) } scheme := other.Exports["LINK_SCHEME"] if scheme == "" { scheme = "tcp" } mb := manifest.GetBalancer(link) if mb == nil { // commented out to be less strict, just don't create the link //return m, fmt.Errorf("Cannot discover balancer for link %q", link) continue } host := fmt.Sprintf(`{ "Fn::If" : [ "Enabled%s", { "Fn::GetAtt" : [ "%s", "DNSName" ] }, "DISABLED" ] }`, UpperName(other.Name), mb.ResourceName()) if len(other.Ports) == 0 { // commented out to be less strict, just don't create the link // return m, fmt.Errorf("Cannot link to %q because it does not expose ports in the manifest", link) continue } port := other.Ports[0] path := other.Exports["LINK_PATH"] var userInfo string if other.Exports["LINK_USERNAME"] != "" || other.Exports["LINK_PASSWORD"] != "" { userInfo = fmt.Sprintf("%s:%s@", other.Exports["LINK_USERNAME"], other.Exports["LINK_PASSWORD"]) } html := fmt.Sprintf(`{ "Fn::Join": [ "", [ "%s", "://", "%s", %s, ":", "%s", "%s" ] ] }`, scheme, userInfo, host, port, path) prefix := strings.ToUpper(link) + "_" prefix = strings.Replace(prefix, "-", "_", -1) entry.LinkVars[prefix+"HOST"] = template.HTML(host) entry.LinkVars[prefix+"SCHEME"] = template.HTML(fmt.Sprintf("%q", scheme)) entry.LinkVars[prefix+"PORT"] = template.HTML(fmt.Sprintf("%q", port)) entry.LinkVars[prefix+"PASSWORD"] = template.HTML(fmt.Sprintf("%q", other.Exports["LINK_PASSWORD"])) entry.LinkVars[prefix+"USERNAME"] = template.HTML(fmt.Sprintf("%q", other.Exports["LINK_USERNAME"])) entry.LinkVars[prefix+"PATH"] = template.HTML(fmt.Sprintf("%q", path)) entry.LinkVars[prefix+"URL"] = template.HTML(html) m.Services[i] = entry } } return &m, nil }