Documentation ¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var Manager = schema.ModuleManager{ Name: "docker", ModulePrototype: &Docker{}, StatePrototype: &state{}, GobRegister: func() { snobgob.Register(&startDockerRegistryAndSSHTunnelCommand{}) snobgob.Register(&dockerTagPushCommand{}) snobgob.Register(&containerCommand{}) snobgob.Register(&removeImagesCommand{}) snobgob.Register(&installDockerCommand{}) snobgob.Register(&writeCronCommand{}) }, GetState: func(query interface{}) (interface{}, error) { state := &state{Installed: true} client, err := getClient() if err != nil { if err == notInstalledErr { state.Installed = false return state, nil } return nil, fmt.Errorf("Could not get docker client from environment. Details: %v", err.Error()) } ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() containers, err := client.ContainerList(ctx, types.ContainerListOptions{All: true}) if err != nil { return nil, fmt.Errorf("Could not list Docker Containers. Error: %v", err) } state.Containers = containers images, err := client.ImageList(context.Background(), types.ImageListOptions{All: true}) if err != nil { return nil, fmt.Errorf("Could not list Docker Images. Error: %v", err.Error()) } state.Images = images state.Cron = []byte{} if _, err := os.Stat(cronFile); err == nil { cronfileBytes, err := ioutil.ReadFile(cronFile) if err != nil { return nil, fmt.Errorf("Could not read cron file (%v). Error: %v", cronFile, err.Error()) } state.Cron = cronfileBytes } else if !os.IsNotExist(err) { return nil, fmt.Errorf("Could not read cron file (%v). Error: %v", cronFile, err.Error()) } return state, nil }, CalculateCommands: func(c *schema.CalculateCommandsArgs) error { remoteState := c.State.(*state) modules := c.Modules.([]*Docker) cronCommands := make([]string, 0) if len(modules) == 0 && !remoteState.Installed { return nil } if len(modules) == 0 { return nil } remoteRoot := c.RemoteCommands.AsCommand() if !remoteState.Installed { remoteRoot = remoteRoot.Add("Install Docker", &installDockerCommand{}).AsCommand() } client, err := getClient() var localImages []types.ImageSummary func() { defer func() { if r := recover(); r != nil { err = fmt.Errorf("Could not communicate with docker deamon. (details: panic: %v)", r) } }() localImages, err = client.ImageList(context.Background(), types.ImageListOptions{All: true}) }() if err != nil { return neaterror.New(map[string]interface{}{ "error message": err.Error(), }, "Could not list local Docker images. Is Docker installed and running?") } localImageMap := make(map[string]types.ImageSummary) localImageUsage := make(map[string]bool) for _, img := range localImages { localImageMap[img.ID] = img localImageUsage[img.ID] = false } remoteImageMap := make(map[string]types.ImageSummary) for _, img := range remoteState.Images { remoteImageMap[img.ID] = img } rootPushCommand := &startDockerRegistryAndSSHTunnelCommand{connection: c.RemoteConnection} pushCommands := make(map[string]*commandtree.Command) containerNames := make(map[string]bool) for _, module := range modules { tag, err := module.Image.Render(nil) if err != nil { return err } containerName, err := module.Name.Render(nil) if err != nil { return err } folder, err := module.Folder.Render(nil) if err != nil { return err } if folder != "" { tag = filepath.Base(folder) + ":latest" } cron, err := module.Cron.Render(nil) if err != nil { return err } cronUser, err := module.CronUser.Render(nil) if err != nil { return err } // find the corresponding image currently on the local machine. var localImage types.ImageSummary found := false for _, image := range localImages { for _, imageTag := range image.RepoTags { if imageTag == tag { localImage = image found = true break } } } if !found { list := make([]string, 0) for _, image := range localImages { for _, imageTag := range image.RepoTags { if imageTag != "<none>:<none>" { list = append(list, imageTag) } } } return fmt.Errorf("Could not locate image tag '%v' on this machine. Are you sure it's built? Images found: %v", tag, list) } l := localImage for true { localImageUsage[l.ID] = true if l.ParentID != "" { if parent, found := localImageMap[l.ParentID]; !found { return fmt.Errorf("Could not find image %v locally. This shouldn't ever happpen", l.ParentID) } else { l = parent } } else { break } } _, alreadyInRemote := remoteImageMap[localImage.ID] _, markedForPush := pushCommands[tag] if !alreadyInRemote && !markedForPush { pushCommands[tag] = rootPushCommand.AsCommand().Add("Push "+tag, &dockerTagPushCommand{ client: client, imageID: localImage.ID, tag: tag, }).AsCommand() if len(pushCommands) == 1 { c.LocalCommands.Add("Push Docker Images", rootPushCommand) } } command, err := module.Command.Render(nil) if err != nil { return err } options := make([]string, 0, len(module.Options)) for _, t := range module.Options { opt, err := t.Render(nil) if err != nil { return err } options = append(options, opt) } if cron != "" { if containerName != "" { return fmt.Errorf("Containers running under Cron should not have a name defined") } pullTag := "" if !alreadyInRemote { pullTag = fmt.Sprintf("127.0.0.1:%v/%v", registryPort, tag) } if pullTag != "" { remoteRoot.Add("Docker Image: "+pullTag, &containerCommand{ PullTag: pullTag, }) } if cronUser == "" { cronUser = "root" } cmd := bytes.NewBuffer(nil) cmd.WriteString(cron) cmd.WriteString("\t") cmd.WriteString(cronUser) cmd.WriteString("\t") cmd.WriteString("docker run") cmd.WriteString(" --rm") for _, opt := range options { cmd.WriteString(" ") cmd.WriteString(opt) } cmd.WriteString(" " + localImage.ID) cmd.WriteString(" " + command) cronCommands = append(cronCommands, cmd.String()) } else { h := sha1.New() h.Write([]byte(command)) h.Write([]byte(localImage.ID)) h.Write([]byte(folder)) for _, option := range options { h.Write([]byte(option)) } containerVersion := fmt.Sprintf("%x", h.Sum(nil)) if containerName == "" { return fmt.Errorf("Container must have a name. ") } if _, found := containerNames[containerName]; found { return fmt.Errorf("the container name '%v' is used more than once", containerName) } containerNames[containerName] = true startContainer := true stopID := "" for _, container := range remoteState.Containers { for _, n := range container.Names { if n == "/"+containerName { stopID = container.ID if value, found := container.Labels["dogo"]; found { if value == containerVersion { if container.State == "running" { startContainer = false } else { c.Logf("will start %v because its state is '%v'", containerName, container.State) } } } } } } if startContainer { pullTag := "" if !alreadyInRemote { pullTag = fmt.Sprintf("127.0.0.1:%v/%v", registryPort, tag) } cmd := bytes.NewBuffer(nil) cmd.WriteString("docker run") cmd.WriteString(" --detach") cmd.WriteString(" --label dogo=" + containerVersion) cmd.WriteString(" --name " + containerName) for _, opt := range options { cmd.WriteString(" ") cmd.WriteString(opt) } cmd.WriteString(" " + localImage.ID) cmd.WriteString(" " + command) remoteRoot.Add("Docker Container: "+containerName, &containerCommand{ PullTag: pullTag, StopContainerID: stopID, StartCommand: cmd.String(), }) } } } for _, img := range remoteState.Images { if used, found := localImageUsage[img.ID]; !found || !used { usedInContainer := false for _, container := range remoteState.Containers { if container.ImageID == img.ID { usedInContainer = true break } } if !usedInContainer { } } } buf := bytes.NewBuffer(nil) for _, command := range cronCommands { buf.WriteString(command) buf.WriteString("\n") } arr := buf.Bytes() if !bytes.Equal(arr, remoteState.Cron) { if len(arr) == 0 { remoteRoot.Add("Remove "+cronFile, &writeCronCommand{Content: arr}) } else { remoteRoot.Add("Update "+cronFile, &writeCronCommand{Content: arr}) } } return nil }, }
Manager is the main entry point to this Dogo Module
Functions ¶
func StartDockerRegistry ¶
Types ¶
type Docker ¶
type Docker struct { // which image to run Folder schema.Template Image schema.Template // If running as a cron job Cron schema.Template CronUser schema.Template // how the container should be configured. Name schema.Template `required:"yes" description:"The container name to use."` Command schema.Template Options []schema.Template }
Click to show internal directories.
Click to hide internal directories.