コード例 #1
0
ファイル: volume.go プロジェクト: ChengTiesheng/talk2docker
func removeVolume(ctx *cobra.Command, volume *Volume) error {
	var (
		config     api.Config
		hostConfig api.HostConfig
	)

	config.Cmd = []string{"/bin/sh", "-c", "rm -rf /.docker_volume_config/" + volume.ID}
	config.Image = "busybox:latest"

	hostConfig.Binds = []string{filepath.Dir(volume.configPath) + ":/.docker_volume_config"}

	if !volume.IsBindMount {
		config.Cmd[2] = config.Cmd[2] + (" && rm -rf /.docker_volume/" + volume.ID)

		hostConfig.Binds = append(hostConfig.Binds, filepath.Dir(volume.Path)+":/.docker_volume")
	}

	docker, err := client.NewDockerClient(configPath, hostName, ctx.Out())
	if err != nil {
		return err
	}

	var cid string
	cid, err = docker.CreateContainer("", config, hostConfig)
	if err != nil {
		if apiErr, ok := err.(api.Error); ok && (apiErr.StatusCode == 404) {
			if err := pullImageInSilence(ctx, config.Image); err != nil {
				return err
			}

			cid, err = docker.CreateContainer("", config, hostConfig)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}
	defer docker.RemoveContainer(cid, true)

	if err := docker.StartContainer(cid); err != nil {
		return err
	}

	if _, err := docker.WaitContainer(cid); err != nil {
		return err
	}

	return nil
}
コード例 #2
0
ファイル: volume.go プロジェクト: ChengTiesheng/talk2docker
func exportVolume(ctx *cobra.Command, args []string) {
	if len(args) < 1 {
		ErrorExit(ctx, "Needs an argument <ID|CONTAINER-NAME:PATH> to export")
	}

	volumes, err := getVolumes(ctx)
	if err != nil {
		log.Fatal(err)
	}

	volume := volumes.Find(args[0])
	if volume == nil {
		log.Fatalf("No such volume: %s", args[0])
	}

	var (
		config     api.Config
		hostConfig api.HostConfig
	)

	config.Image = "busybox:latest"

	hostConfig.Binds = []string{volume.Path + ":/" + volume.ID}

	docker, err := client.NewDockerClient(configPath, hostName, ctx.Out())
	if err != nil {
		log.Fatal(err)
	}

	var cid string
	cid, err = docker.CreateContainer("", config, hostConfig)
	if err != nil {
		if apiErr, ok := err.(api.Error); ok && (apiErr.StatusCode == 404) {
			if err := pullImageInSilence(ctx, config.Image); err != nil {
				log.Fatal(err)
			}

			cid, err = docker.CreateContainer("", config, hostConfig)
			if err != nil {
				log.Fatal(err)
			}
		} else {
			log.Fatal(err)
		}
	}
	defer docker.RemoveContainer(cid, true)

	if err := docker.CopyContainer(cid, "/"+volume.ID); err != nil {
		log.Fatal(err)
	}
}
コード例 #3
0
ファイル: compose.go プロジェクト: ChengTiesheng/talk2docker
func composeContainer(ctx *cobra.Command, root string, composer Composer) (string, error) {
	var (
		config     api.Config
		hostConfig api.HostConfig

		localVolumes   = make(map[string]struct{})
		bindVolumes    []string
		exposedPorts   = make(map[string]struct{})
		portBindings   = make(map[string][]api.PortBinding)
		links          []string
		deviceMappings []api.DeviceMapping
	)

	if composer.Image != "" {
		r, n, t, err := client.ParseRepositoryName(composer.Image)
		if err != nil {
			return "", err
		}
		composer.Image = n + ":" + t
		if r != "" {
			composer.Image = r + "/" + composer.Image
		}
	}

	if (composer.WorkingDir != "") && !filepath.IsAbs(composer.WorkingDir) {
		return "", fmt.Errorf("Invalid working directory: it must be absolute.")
	}

	docker, err := client.NewDockerClient(configPath, hostName, ctx.Out())
	if err != nil {
		return "", err
	}

	if composer.Build != "" {
		if !filepath.IsAbs(composer.Build) {
			composer.Build = filepath.Join(root, composer.Build)
		}
		message, err := docker.BuildImage(composer.Build, composer.Image, false)
		if err != nil {
			return "", err
		}
		if composer.Image == "" {
			if _, err := fmt.Sscanf(message, "Successfully built %s", &composer.Image); err != nil {
				return "", err
			}
		}
	}

	for _, port := range composer.Ports {
		var (
			rawPort       = port
			hostIp        = ""
			hostPort      = ""
			containerPort = ""
			proto         = "tcp"
		)

		if i := strings.LastIndex(port, "/"); i != -1 {
			proto = strings.ToLower(port[i+1:])
			port = port[:i]
		}

		parts := strings.Split(port, ":")
		switch len(parts) {
		case 1:
			containerPort = parts[0]
		case 2:
			hostPort = parts[0]
			containerPort = parts[1]
		case 3:
			hostIp = parts[0]
			hostPort = parts[1]
			containerPort = parts[2]
		default:
			return "", fmt.Errorf("Invalid port specification: %s", rawPort)
		}

		port := fmt.Sprintf("%s/%s", containerPort, proto)
		if _, exists := exposedPorts[port]; !exists {
			exposedPorts[port] = struct{}{}
		}

		portBinding := api.PortBinding{
			HostIp:   hostIp,
			HostPort: hostPort,
		}
		bslice, exists := portBindings[port]
		if !exists {
			bslice = []api.PortBinding{}
		}
		portBindings[port] = append(bslice, portBinding)
	}

	for _, port := range composer.ExposedPorts {
		var (
			rawPort       = port
			containerPort = ""
			proto         = "tcp"
		)

		parts := strings.Split(containerPort, "/")
		switch len(parts) {
		case 1:
			containerPort = parts[0]
		case 2:
			containerPort = parts[0]
			proto = strings.ToLower(parts[1])
		default:
			return "", fmt.Errorf("Invalid port specification: %s", rawPort)
		}

		port := fmt.Sprintf("%s/%s", containerPort, proto)
		if _, exists := exposedPorts[port]; !exists {
			exposedPorts[port] = struct{}{}
		}
	}

	for _, volume := range composer.Volumes {
		if arr := strings.Split(volume, ":"); len(arr) > 1 {
			if arr[1] == "/" {
				return "", fmt.Errorf("Invalid bind mount: destination can't be '/'")
			}
			if !filepath.IsAbs(arr[0]) {
				return "", fmt.Errorf("Invalid bind mount: the host path must be absolute.")
			}
			bindVolumes = append(bindVolumes, volume)
		} else if volume == "/" {
			return "", fmt.Errorf("Invalid volume: path can't be '/'")
		} else {
			localVolumes[volume] = struct{}{}
		}
	}

	for _, link := range append(composer.Links, composer.ExternalLinks...) {
		arr := strings.Split(link, ":")
		if len(arr) < 2 {
			links = append(links, arr[0]+":"+arr[0])
		} else {
			links = append(links, link)
		}
	}

	for _, device := range composer.Devices {
		src := ""
		dst := ""
		permissions := "rwm"
		arr := strings.Split(device, ":")
		switch len(arr) {
		case 3:
			permissions = arr[2]
			fallthrough
		case 2:
			dst = arr[1]
			fallthrough
		case 1:
			src = arr[0]
		default:
			return "", fmt.Errorf("Invalid device specification: %s", device)
		}

		if dst == "" {
			dst = src
		}

		deviceMapping := api.DeviceMapping{
			PathOnHost:        src,
			PathInContainer:   dst,
			CgroupPermissions: permissions,
		}
		deviceMappings = append(deviceMappings, deviceMapping)
	}

	parts := strings.Split(composer.RestartPolicy, ":")
	restartPolicy := api.RestartPolicy{}
	restartPolicy.Name = parts[0]
	if (restartPolicy.Name == "on-failure") && (len(parts) == 2) {
		count, err := strconv.Atoi(parts[1])
		if err != nil {
			return "", err
		}
		restartPolicy.MaximumRetryCount = count
	}

	config.Hostname = composer.Hostname
	config.Domainname = composer.Domainname
	config.User = composer.User
	config.Memory = composer.Memory
	config.MemorySwap = composer.MemorySwap
	config.CpuShares = composer.CpuShares
	config.Cpuset = composer.Cpuset
	config.ExposedPorts = exposedPorts
	config.Tty = composer.Tty
	config.OpenStdin = composer.OpenStdin
	config.Env = composer.Env
	config.Cmd = composer.Cmd
	config.Image = composer.Image
	config.Volumes = localVolumes
	config.WorkingDir = composer.WorkingDir
	if composer.Entrypoint != "" {
		config.Entrypoint = []string{composer.Entrypoint}
	}
	config.MacAddress = composer.MacAddress

	hostConfig.Binds = bindVolumes
	hostConfig.Privileged = composer.Privileged
	hostConfig.PortBindings = portBindings
	hostConfig.Links = links
	hostConfig.PublishAllPorts = composer.PublishAllPorts
	hostConfig.Dns = composer.Dns
	hostConfig.DnsSearch = composer.DnsSearch
	hostConfig.ExtraHosts = composer.ExtraHosts
	hostConfig.VolumesFrom = composer.VolumesFrom
	hostConfig.Devices = deviceMappings
	hostConfig.NetworkMode = composer.NetworkMode
	hostConfig.IpcMode = composer.IpcMode
	hostConfig.PidMode = composer.PidMode
	hostConfig.CapAdd = composer.CapAdd
	hostConfig.CapDrop = composer.CapDrop
	hostConfig.RestartPolicy = restartPolicy
	hostConfig.SecurityOpt = composer.SecurityOpt
	hostConfig.ReadonlyRootfs = composer.ReadonlyRootfs

	var cid string
	cid, err = docker.CreateContainer(composer.Name, config, hostConfig)
	if err != nil {
		if apiErr, ok := err.(api.Error); ok && (apiErr.StatusCode == 404) {
			if _, err := docker.PullImage(config.Image); err != nil {
				return "", err
			}

			cid, err = docker.CreateContainer(composer.Name, config, hostConfig)
			if err != nil {
				return "", err
			}
		} else {
			return "", err
		}
	}

	return cid, nil
}
コード例 #4
0
ファイル: upload.go プロジェクト: ChengTiesheng/talk2docker
func uploadToContainer(ctx *cobra.Command, args []string) {
	if len(args) < 2 {
		ErrorExit(ctx, "Needs two arguments <PATH> to upload into <(NAME|ID):PATH>")
	}

	srcPath, err := filepath.Abs(args[0])
	if err != nil {
		log.Fatal(err)
	}

	arr := strings.Split(args[1], ":")
	if len(arr) < 2 || (arr[1] == "") {
		ErrorExit(ctx, fmt.Sprint("Needs <(NAME|ID):PATH> for the second argument"))
	}

	var (
		name = arr[0]
		path = arr[1]
	)

	f, err := os.Open(os.DevNull)
	if err != nil {
		log.Fatal(err)
	}

	docker, err := client.NewDockerClient(configPath, hostName, f)
	if err != nil {
		log.Fatal(err)
	}

	info, err := docker.Info()
	if err != nil {
		log.Fatal(err)
	}

	rootDir := ""

	for _, pair := range info.DriverStatus {
		if pair[0] == "Root Dir" {
			rootDir = pair[1]
		}
	}

	if rootDir == "" {
		if info.DockerRootDir == "" {
			log.Fatal("Can't get the root dir for the container")
		}
		rootDir = filepath.Join(info.DockerRootDir, info.Driver)
	}

	containerInfo, err := docker.InspectContainer(name)
	if err != nil {
		log.Fatal(err)
	}

	switch info.Driver {
	case "aufs":
		rootDir = filepath.Join(rootDir, "mnt", containerInfo.Id)
	case "btrfs":
		rootDir = filepath.Join(rootDir, "subvolumes", containerInfo.Id)
	case "devicemapper":
		rootDir = filepath.Join(rootDir, "mnt", containerInfo.Id, "rootfs")
	case "overlay":
		rootDir = filepath.Join(rootDir, containerInfo.Id, "merged")
	case "vfs":
		rootDir = filepath.Join(rootDir, "dir", containerInfo.Id)
	default:
		log.Fatalf("Unknown driver: %s", info.Driver)
	}

	dstPath := filepath.Join(rootDir, path)
	dstPath = filepath.Clean(dstPath)
	if !strings.HasPrefix(dstPath, rootDir) {
		log.Fatal("Can't upload to outside of the container")
	}

	ctx.Printf("Uploading %s into %s\n", args[0], args[1])

	message, err := docker.Upload(srcPath, true)
	if err != nil {
		log.Fatal(err)
	}

	var (
		config     api.Config
		hostConfig api.HostConfig
	)

	if _, err := fmt.Sscanf(message, "Successfully built %s", &config.Image); err != nil {
		log.Fatal(err)
	}

	defer docker.RemoveImage(config.Image, true, false)

	hostConfig.Binds = []string{dstPath + ":/.destination"}

	cid, err := docker.CreateContainer("", config, hostConfig)
	if err != nil {
		log.Fatal(err)
	}
	defer docker.RemoveContainer(cid, true)

	if err := docker.StartContainer(cid); err != nil {
		log.Fatal(err)
	}

	if _, err := docker.WaitContainer(cid); err != nil {
		log.Fatal(err)
	}

	ctx.Print("Successfully uploaded\n")
}
コード例 #5
0
ファイル: upload.go プロジェクト: ChengTiesheng/talk2docker
func uploadToVolume(ctx *cobra.Command, args []string) {
	if len(args) < 2 {
		ErrorExit(ctx, "Needs two arguments <PATH> to upload into <ID:PATH>")
	}

	srcPath, err := filepath.Abs(args[0])
	if err != nil {
		log.Fatal(err)
	}

	arr := strings.Split(args[1], ":")
	if len(arr) < 2 || (arr[1] == "") {
		ErrorExit(ctx, fmt.Sprint("Needs <ID:PATH> for the second argument"))
	}

	var (
		id   = arr[0]
		path = arr[1]
	)

	volumes, err := getVolumes(ctx)
	if err != nil {
		log.Fatal(err)
	}

	volume := volumes.Find(id)
	if volume == nil {
		log.Fatalf("No such volume: %s", id)
	}

	dstPath := filepath.Join(volume.Path, path)
	dstPath = filepath.Clean(dstPath)
	if !strings.HasPrefix(dstPath, volume.Path) {
		log.Fatal("Can't upload to outside of the volume")
	}

	f, err := os.Open(os.DevNull)
	if err != nil {
		log.Fatal(err)
	}

	docker, err := client.NewDockerClient(configPath, hostName, f)
	if err != nil {
		log.Fatal(err)
	}

	ctx.Printf("Uploading %s into %s\n", args[0], args[1])

	message, err := docker.Upload(srcPath, true)
	if err != nil {
		log.Fatal(err)
	}

	var (
		config     api.Config
		hostConfig api.HostConfig
	)

	if _, err := fmt.Sscanf(message, "Successfully built %s", &config.Image); err != nil {
		log.Fatal(err)
	}

	defer docker.RemoveImage(config.Image, true, false)

	hostConfig.Binds = []string{dstPath + ":/.destination"}

	cid, err := docker.CreateContainer("", config, hostConfig)
	if err != nil {
		log.Fatal(err)
	}
	defer docker.RemoveContainer(cid, true)

	if err := docker.StartContainer(cid); err != nil {
		log.Fatal(err)
	}

	if _, err := docker.WaitContainer(cid); err != nil {
		log.Fatal(err)
	}

	ctx.Print("Successfully uploaded\n")
}
コード例 #6
0
ファイル: volume.go プロジェクト: ChengTiesheng/talk2docker
func getVolumes(ctx *cobra.Command) (Volumes, error) {
	docker, err := client.NewDockerClient(configPath, hostName, ctx.Out())
	if err != nil {
		return nil, err
	}

	info, err := docker.Info()
	if err != nil {
		return nil, err
	}

	rootDir := "/var/lib/docker"

	if info.DockerRootDir != "" {
		rootDir = info.DockerRootDir
	} else {
		for _, pair := range info.DriverStatus {
			if pair[0] == "Root Dir" {
				rootDir = filepath.Dir(pair[1])
			}
		}
	}

	path := filepath.Join(rootDir, "/volumes")

	var (
		config     api.Config
		hostConfig api.HostConfig
	)

	config.Cmd = []string{"/bin/sh", "-c", "awk '{cmd=\"ls -e \" FILENAME; cmd | getline line; close(cmd); split(line,a,\" \"); print $0,a[6],a[7],a[8],a[9],a[10]}' /.docker_volumes/*/config.json"}
	config.Image = "busybox:latest"

	hostConfig.Binds = []string{path + ":/.docker_volumes:ro"}

	var cid string
	cid, err = docker.CreateContainer("", config, hostConfig)
	if err != nil {
		if apiErr, ok := err.(api.Error); ok && (apiErr.StatusCode == 404) {
			if err := pullImageInSilence(ctx, config.Image); err != nil {
				return nil, err
			}

			cid, err = docker.CreateContainer("", config, hostConfig)
			if err != nil {
				return nil, err
			}
		} else {
			return nil, err
		}
	}
	defer docker.RemoveContainer(cid, true)

	if err := docker.StartContainer(cid); err != nil {
		return nil, err
	}

	if _, err := docker.WaitContainer(cid); err != nil {
		return nil, err
	}

	logs, err := docker.GetContainerLogs(cid, false, true, true, false, 0)
	if err != nil {
		return nil, err
	}

	if logs[0] == "" {
		return nil, nil
	}

	vols := strings.Split(strings.TrimSpace(logs[0]), "\n")

	var volumes Volumes
	for _, vol := range vols {
		arr := strings.SplitN(vol, "} ", 2)
		volume := &Volume{}
		if err := json.Unmarshal([]byte(arr[0]+"}"), volume); err != nil {
			log.Debugf("%s: '%s'", err, arr[0])
			return nil, err
		}
		volume.Created, _ = time.Parse(time.ANSIC, arr[1])
		volume.configPath = filepath.Join(path, "/"+volume.ID)
		volumes = append(volumes, volume)
	}

	if err := docker.RemoveContainer(cid, true); err != nil {
		return nil, err
	}

	mounts, err := getMounts(ctx)
	if err != nil {
		return nil, err
	}

	for _, volume := range volumes {
		for _, mount := range mounts {
			if mount.hostPath == volume.Path {
				volume.MountedOn = append(volume.MountedOn, mount)
			}
		}
	}

	return volumes, nil
}