func (p *Pod) Push() { log.Get().Info("Push POD", p.manifest.Name) p.Build() for _, e := range p.manifest.Pod.Apps { aci, err := NewAciWithManifest(p.path+"/"+e.Name, p.args, p.toAciManifest(e)) if err != nil { log.Get().Panic(err) } aci.PodName = &p.manifest.Name aci.Push() } utils.ExecCmd("curl", "-i", "-F", "r=releases", "-F", "hasPom=false", "-F", "e=pod", "-F", "g=com.blablacar.aci.linux.amd64", "-F", "p=pod", "-F", "v="+p.manifest.Name.Version(), "-F", "a="+p.manifest.Name.ShortName(), "-F", "file=@"+p.target+POD_TARGET_MANIFEST, "-u", config.GetConfig().Push.Username+":"+config.GetConfig().Push.Password, config.GetConfig().Push.Url+"/service/local/artifact/maven/content") }
func (cnt *Img) Test() { log.Get().Info("Testing " + cnt.manifest.NameAndVersion) if _, err := os.Stat(cnt.target + "/image.aci"); os.IsNotExist(err) { if err := cnt.Build(); err != nil { log.Get().Panic("Cannot Install since build failed") } } // prepare runner in target // run contauner with mout mpoint // run real service in background // run tests // // BATS os.MkdirAll(cnt.target+"/test", 0777) bats.WriteBats(cnt.target + "/test") // if err := utils.ExecCmd("systemd-nspawn", "--directory=" + cnt.rootfs, "--capability=all", // "--bind=" + cnt.target + "/:/target", "--share-system", "target/build.sh"); err != nil { // log.Get().Panic("Build step did not succeed", err) // // // utils.ExecCmd("rkt", "--insecure-skip-verify=true", "run", cnt.target + "/image.aci") // TODO missing command override that will arrive in next RKT version // } }
func discoverAndRunUpdateType(path string, args builder.BuildArgs) { if cnt, err := builder.NewAci(path, args); err == nil { cnt.UpdateConf() } else if _, err := builder.OpenPod(path, args); err == nil { log.Get().Panic("Not Yet implemented for pods") } else { log.Get().Panic("Cannot find cnt-manifest.yml") } }
func (cnt *Img) copyRunlevelsPrestart() { if err := os.MkdirAll(cnt.rootfs+"/etc/prestart/late-prestart.d", 0755); err != nil { log.Get().Panic(err) } if err := os.MkdirAll(cnt.rootfs+"/etc/prestart/early-prestart.d", 0755); err != nil { log.Get().Panic(err) } utils.CopyDir(cnt.path+RUNLEVELS_PRESTART, cnt.rootfs+"/etc/prestart/early-prestart.d") utils.CopyDir(cnt.path+RUNLEVELS_LATESTART, cnt.rootfs+"/etc/prestart/late-prestart.d") }
func WritePodManifest(im *schema.PodManifest, targetFile string) { buff, err := im.MarshalJSON() if err != nil { log.Get().Panic(err) } err = ioutil.WriteFile(targetFile, []byte(buff), 0644) if err != nil { log.Get().Panic(err) } }
func (p *Pod) Test() { log.Get().Info("Testing POD", p.manifest.Name) for _, e := range p.manifest.Pod.Apps { aci, err := NewAciWithManifest(p.path+"/"+e.Name, p.args, p.toAciManifest(e)) if err != nil { log.Get().Panic(err) } aci.PodName = &p.manifest.Name aci.Test() } }
func (n *ACFullname) UnmarshalJSON(data []byte) error { var s string if err := json.Unmarshal(data, &s); err != nil { log.Get().Panic(err) return err } nn, err := NewACFullName(s) if err != nil { log.Get().Panic(err) return err } *n = *nn return nil }
func (cnt *Img) copyConfd() { if err := os.MkdirAll(cnt.rootfs+"/etc/prestart/", 0755); err != nil { log.Get().Panic(err) } utils.CopyDir(cnt.path+CONFD_CONFIG, cnt.rootfs+"/etc/prestart/conf.d") utils.CopyDir(cnt.path+CONFD_TEMPLATE, cnt.rootfs+"/etc/prestart/templates") }
func (p *Pod) Clean() { log.Get().Info("Cleaning POD", p.manifest.Name) if err := os.RemoveAll(p.target + "/"); err != nil { log.Get().Panic("Cannot clean", p.manifest.Name, err) } for _, e := range p.manifest.Pod.Apps { aci, err := NewAciWithManifest(p.path+"/"+e.Name, p.args, p.toAciManifest(e)) if err != nil { log.Get().Panic(err) } aci.PodName = &p.manifest.Name aci.Clean() } }
func ExecCmd(head string, parts ...string) error { log.Get().Debug("Exec > ", head, " ", strings.Join(parts, " ")) cmd := exec.Command(head, parts...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr return cmd.Run() }
func UserHomeOrFatal() string { usr, err := homedir.Dir() if err != nil { log.Get().Panic(err) } return usr }
func (i *Img) checkBuilt() { if _, err := os.Stat(i.target + "/image.aci"); os.IsNotExist(err) { if err := i.Build(); err != nil { log.Get().Panic("Cannot Install since build failed") } } }
func NewAci(path string, args BuildArgs) (*Img, error) { manifest, err := readManifest(path + IMG_MANIFEST) if err != nil { log.Get().Debug(path, IMG_MANIFEST+" does not exists") return nil, err } return NewAciWithManifest(path, args, *manifest) }
func (cnt *Img) writeImgManifest() { log.Get().Debug("Writing aci manifest") version := cnt.manifest.NameAndVersion.Version() if version == "" { version = utils.GenerateVersion() } utils.WriteImageManifest(&cnt.manifest, cnt.target+"/manifest", cnt.manifest.NameAndVersion.Name(), version) }
func (cnt *Img) runlevelBuildSetup() { files, err := ioutil.ReadDir(cnt.path + RUNLEVELS_BUILD_SETUP) if err != nil { return } os.Setenv("BASEDIR", cnt.path) os.Setenv("TARGET", cnt.target) for _, f := range files { if !f.IsDir() { log.Get().Info("Running Build setup level : ", f.Name()) if err := utils.ExecCmd(cnt.path + RUNLEVELS_BUILD_SETUP + "/" + f.Name()); err != nil { log.Get().Panic(err) } } } }
func NewAciWithManifest(path string, args BuildArgs, manifest spec.AciManifest) (*Img, error) { log.Get().Debug("New aci", path, args, manifest) cnt, err := PrepAci(path, args) if err != nil { return nil, err } cnt.manifest = manifest return cnt, nil }
func Execute() { log.Set(logger.NewLogger()) currentAbsDir, err := filepath.Abs("") if err != nil { log.Get().Panic("Cannot find current absolute directory") } var rootCmd = &cobra.Command{Use: "cnt"} buildCmd.Flags().BoolVarP(&buildArgs.Zip, "nozip", "z", false, "Zip final image or not") rootCmd.PersistentFlags().BoolVarP(&buildArgs.Clean, "clean", "c", false, "Clean before doing anything") rootCmd.PersistentFlags().StringVarP(&buildArgs.TargetPath, "target-path", "t", currentAbsDir, "Set target path") rootCmd.AddCommand(buildCmd, cleanCmd, pushCmd, installCmd, testCmd, versionCmd, initCmd, updateCmd) config.GetConfig().Load() rootCmd.Execute() log.Get().Info("Victory !") }
func (cnt *Img) tarAci() { dir, _ := os.Getwd() log.Get().Debug("chdir to", cnt.target) os.Chdir(cnt.target) args := []string{"manifest", "rootfs/"} if _, err := os.Stat(cnt.path + RUNLEVELS_BUILD_INHERIT_EARLY); err == nil { args = append(args, strings.TrimPrefix(RUNLEVELS_BUILD_INHERIT_EARLY, "/")) } if _, err := os.Stat(cnt.path + RUNLEVELS_BUILD_INHERIT_LATE); err == nil { args = append(args, strings.TrimPrefix(RUNLEVELS_BUILD_INHERIT_LATE, "/")) } utils.Tar(cnt.args.Zip, "image.aci", args...) log.Get().Debug("chdir to", dir) os.Chdir(dir) }
func discoverAndRunTestType(path string, args builder.BuildArgs) { if cnt, err := builder.NewAci(path, args); err == nil { cnt.Test() } else if pod, err := builder.OpenPod(path, args); err == nil { pod.Test() } else { log.Get().Panic("Cannot find cnt-manifest.yml") } }
func (p *Pod) Build() { log.Get().Info("Building POD : ", p.manifest.Name) os.MkdirAll(p.target, 0777) os.Remove(p.target + POD_TARGET_MANIFEST) apps := p.processAci() p.writePodManifest(apps) }
func ExecCmdGetOutput(head string, parts ...string) (string, error) { var stdout bytes.Buffer log.Get().Debug("Exec > ", head, " ", strings.Join(parts, " ")) cmd := exec.Command(head, parts...) cmd.Stdout = &stdout cmd.Stderr = os.Stderr cmd.Start() err := cmd.Wait() return strings.TrimSpace(stdout.String()), err }
func (p *Pod) readManifest(manifestPath string) { source, err := ioutil.ReadFile(manifestPath) if err != nil { log.Get().Panic(err) } err = yaml.Unmarshal([]byte(source), &p.manifest) if err != nil { log.Get().Panic(err) } for i, app := range p.manifest.Pod.Apps { if app.Name == "" { p.manifest.Pod.Apps[i].Name = app.Dependencies[0].ShortName() } } //TODO check that there is no app name conflict log.Get().Trace("Pod manifest : ", p.manifest.Name, p.manifest) }
func (p *Pod) buildAciIfNeeded(e spec.RuntimeApp) *spec.ACFullname { if dir, err := os.Stat(p.path + "/" + e.Name); err == nil && dir.IsDir() { aci, err := NewAciWithManifest(p.path+"/"+e.Name, p.args, p.toAciManifest(e)) if err != nil { log.Get().Panic(err) } aci.PodName = &p.manifest.Name aci.Build() return &aci.manifest.NameAndVersion } return nil }
func (cnt *Img) Init() { initPath := cnt.path if cnt.args.Path != "" { initPath = cnt.args.Path } log.Get().Info("Setting up files three") uid := "0" gid := "0" if os.Getenv("SUDO_UID") != "" { uid = os.Getenv("SUDO_UID") gid = os.Getenv("SUDO_GID") } uidInt, err := strconv.Atoi(uid) gidInt, err := strconv.Atoi(gid) if err != nil { log.Get().Panic(err) } folderList := []string{ RUNLEVELS, RUNLEVELS_PRESTART, RUNLEVELS_LATESTART, RUNLEVELS_BUILD, RUNLEVELS_BUILD_SETUP, RUNLEVELS_BUILD_INHERIT_EARLY, RUNLEVELS_BUILD_INHERIT_LATE, CONFD, CONFD_TEMPLATE, CONFD_CONFIG, ATTRIBUTES, FILES_PATH, } for _, folder := range folderList { fpath := initPath + "/" + folder os.MkdirAll(fpath, 0777) os.Lchown(fpath, uidInt, gidInt) } }
func (cnt *Img) processFrom() { if cnt.manifest.From != "" { log.Get().Info("Prepare rootfs from " + cnt.manifest.From) app, err := discovery.NewAppFromString(string(cnt.manifest.From)) if app.Labels["os"] == "" { app.Labels["os"] = "linux" } if app.Labels["arch"] == "" { app.Labels["arch"] = "amd64" } endpoint, _, err := discovery.DiscoverEndpoints(*app, false) if err != nil { panic(err) } url := endpoint.ACIEndpoints[0].ACI aciPath := config.GetConfig().AciPath + "/" + string(cnt.manifest.From) if _, err := os.Stat(aciPath + "/image.aci"); cnt.args.ForceUpdate || os.IsNotExist(err) { if err := os.MkdirAll(aciPath, 0755); err != nil { log.Get().Panic(err) } if err = utils.ExecCmd("wget", "-O", aciPath+"/image.aci", url); err != nil { os.Remove(aciPath + "/image.aci") log.Get().Panic("Cannot download from image", err) } } else { log.Get().Info("Image " + cnt.manifest.From + " Already exists locally, will not be downloaded") } utils.ExecCmd("tar", "xpf", aciPath+"/image.aci", "-C", cnt.target) // utils.ExecCmd("rkt", "--insecure-skip-verify=true", "fetch", cnt.manifest.From) // utils.ExecCmd("rkt", "image", "export", "--overwrite", cnt.manifest.From, cnt.target + "/from.aci") // utils.ExecCmd("tar", "xf", cnt.target + "/from.aci", "-C", cnt.target) // os.Remove(cnt.target + "/from.aci") } }
func (p *Pod) processAci() []schema.RuntimeApp { apps := []schema.RuntimeApp{} for _, e := range p.manifest.Pod.Apps { aciName := p.buildAciIfNeeded(e) // TODO: support not FS override by only storing info pod manifest // if aciName == nil { // aciName = &e.Image // } name, _ := types.NewACName(e.Name) sum, err := utils.Sha512sum(p.path + "/" + e.Name + "/target/image.aci") if err != nil { log.Get().Panic(err) } tmp, _ := types.NewHash("sha512-" + sum) labels := types.Labels{} labels = append(labels, types.Label{Name: "version", Value: aciName.Version()}) identifier, _ := types.NewACIdentifier(aciName.Name()) ttmp := schema.RuntimeImage{Name: identifier, ID: *tmp, Labels: labels} if e.App.User == "" { e.App.User = "******" } if e.App.Group == "" { e.App.Group = "0" } apps = append(apps, schema.RuntimeApp{ Name: *name, Image: ttmp, App: &types.App{ Exec: e.App.Exec, EventHandlers: e.App.EventHandlers, User: e.App.User, Group: e.App.Group, WorkingDirectory: e.App.WorkingDirectory, Environment: e.App.Environment, MountPoints: e.App.MountPoints, Ports: e.App.Ports, Isolators: e.App.Isolators, }, Mounts: e.Mounts, Annotations: e.Annotations}) } return apps }
func WriteImageManifest(m *spec.AciManifest, targetFile string, projectName string, version string) { name, _ := types.NewACIdentifier(m.NameAndVersion.Name()) labels := types.Labels{} labels = append(labels, types.Label{Name: "version", Value: m.NameAndVersion.Version()}) if m.Aci.App.User == "" { m.Aci.App.User = "******" } if m.Aci.App.Group == "" { m.Aci.App.Group = "0" } im := schema.BlankImageManifest() im.Annotations = m.Aci.Annotations im.Dependencies = toAppcDependencies(m.Aci.Dependencies) im.Name = *name im.Labels = labels im.App = &types.App{ Exec: m.Aci.App.Exec, EventHandlers: m.Aci.App.EventHandlers, User: m.Aci.App.User, Group: m.Aci.App.Group, WorkingDirectory: m.Aci.App.WorkingDirectory, Environment: m.Aci.App.Environment, MountPoints: m.Aci.App.MountPoints, Ports: m.Aci.App.Ports, Isolators: m.Aci.App.Isolators, } buff, err := im.MarshalJSON() if err != nil { log.Get().Panic(err) } err = ioutil.WriteFile(targetFile, buff, 0644) if err != nil { log.Get().Panic(err) } }
func PrepAci(aciPath string, args BuildArgs) (*Img, error) { cnt := new(Img) cnt.args = args if fullPath, err := filepath.Abs(aciPath); err != nil { log.Get().Panic("Cannot get fullpath of project", err) } else { cnt.path = fullPath cnt.target = path.Join(args.TargetPath, "target") cnt.rootfs = cnt.target + "/rootfs" } return cnt, nil }
func OpenPod(path string, args BuildArgs) (*Pod, error) { pod := new(Pod) if fullPath, err := filepath.Abs(path); err != nil { log.Get().Panic("Cannot get fullpath of project", err) } else { pod.path = fullPath } pod.args = args pod.target = pod.path + "/target" pod.readManifest(pod.path + POD_MANIFEST) return pod, nil }
func readManifest(manifestPath string) (*spec.AciManifest, error) { manifest := spec.AciManifest{Aci: spec.AciDefinition{}} source, err := ioutil.ReadFile(manifestPath) if err != nil { return nil, err } err = yaml.Unmarshal([]byte(source), &manifest) if err != nil { log.Get().Panic(err) } return &manifest, nil }