Move Docker specific function out of the Kubelet

This commit is contained in:
Clayton Coleman 2014-07-15 11:34:48 -04:00
parent 07fafb1252
commit e02ea37d9f
2 changed files with 139 additions and 114 deletions

138
pkg/kubelet/docker.go Normal file
View File

@ -0,0 +1,138 @@
/*
Copyright 2014 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kubelet
import (
"fmt"
"math/rand"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/fsouza/go-dockerclient"
)
// DockerContainerData is the structured representation of the JSON object returned by Docker inspect
type DockerContainerData struct {
state struct {
Running bool
}
}
// DockerInterface is an abstract interface for testability. It abstracts the interface of docker.Client.
type DockerInterface interface {
ListContainers(options docker.ListContainersOptions) ([]docker.APIContainers, error)
InspectContainer(id string) (*docker.Container, error)
CreateContainer(docker.CreateContainerOptions) (*docker.Container, error)
StartContainer(id string, hostConfig *docker.HostConfig) error
StopContainer(id string, timeout uint) error
PullImage(opts docker.PullImageOptions, auth docker.AuthConfiguration) error
}
// DockerID is an ID of docker container. It is a type to make it clear when we're working with docker container Ids
type DockerID string
// DockerPuller is an abstract interface for testability. It abstracts image pull operations.
type DockerPuller interface {
Pull(image string) error
}
// dockerPuller is the default implementation of DockerPuller.
type dockerPuller struct {
client DockerInterface
}
// NewDockerPuller creates a new instance of the default implementation of DockerPuller.
func NewDockerPuller(client DockerInterface) DockerPuller {
return dockerPuller{
client: client,
}
}
func (p dockerPuller) Pull(image string) error {
image, tag := parseImageName(image)
opts := docker.PullImageOptions{
Repository: image,
Tag: tag,
}
return p.client.PullImage(opts, docker.AuthConfiguration{})
}
// Converts "-" to "_-_" and "_" to "___" so that we can use "--" to meaningfully separate parts of a docker name.
func escapeDash(in string) (out string) {
out = strings.Replace(in, "_", "___", -1)
out = strings.Replace(out, "-", "_-_", -1)
return
}
// Reverses the transformation of escapeDash.
func unescapeDash(in string) (out string) {
out = strings.Replace(in, "_-_", "-", -1)
out = strings.Replace(out, "___", "_", -1)
return
}
const containerNamePrefix = "k8s"
// Creates a name which can be reversed to identify both manifest id and container name.
func buildDockerName(manifest *api.ContainerManifest, container *api.Container) string {
// Note, manifest.ID could be blank.
return fmt.Sprintf("%s--%s--%s--%08x", containerNamePrefix, escapeDash(container.Name), escapeDash(manifest.ID), rand.Uint32())
}
// Upacks a container name, returning the manifest id and container name we would have used to
// construct the docker name. If the docker name isn't one we created, we may return empty strings.
func parseDockerName(name string) (manifestID, containerName string) {
// For some reason docker appears to be appending '/' to names.
// If its there, strip it.
if name[0] == '/' {
name = name[1:]
}
parts := strings.Split(name, "--")
if len(parts) == 0 || parts[0] != containerNamePrefix {
return
}
if len(parts) > 1 {
containerName = unescapeDash(parts[1])
}
if len(parts) > 2 {
manifestID = unescapeDash(parts[2])
}
return
}
// Parses image name including an tag and returns image name and tag
// TODO: Future Docker versions can parse the tag on daemon side, see:
// https://github.com/dotcloud/docker/issues/6876
// So this can be deprecated at some point.
func parseImageName(image string) (string, string) {
tag := ""
parts := strings.SplitN(image, "/", 2)
repo := ""
if len(parts) == 2 {
repo = parts[0]
image = parts[1]
}
parts = strings.SplitN(image, ":", 2)
if len(parts) == 2 {
image = parts[0]
tag = parts[1]
}
if repo != "" {
image = fmt.Sprintf("%s/%s", repo, image)
}
return image, tag
}

View File

@ -21,7 +21,6 @@ import (
"errors"
"fmt"
"io/ioutil"
"math/rand"
"net"
"net/http"
"os"
@ -47,31 +46,6 @@ import (
const defaultChanSize = 1024
// DockerContainerData is the structured representation of the JSON object returned by Docker inspect
type DockerContainerData struct {
state struct {
Running bool
}
}
// DockerInterface is an abstract interface for testability. It abstracts the interface of docker.Client.
type DockerInterface interface {
ListContainers(options docker.ListContainersOptions) ([]docker.APIContainers, error)
InspectContainer(id string) (*docker.Container, error)
CreateContainer(docker.CreateContainerOptions) (*docker.Container, error)
StartContainer(id string, hostConfig *docker.HostConfig) error
StopContainer(id string, timeout uint) error
PullImage(opts docker.PullImageOptions, auth docker.AuthConfiguration) error
}
// DockerID is an ID of docker container. It is a type to make it clear when we're working with docker container Ids
type DockerID string
// DockerPuller is an abstract interface for testability. It abstracts image pull operations.
type DockerPuller interface {
Pull(image string) error
}
// CadvisorInterface is an abstract interface for testability. It abstracts the interface of "github.com/google/cadvisor/client".Client.
type CadvisorInterface interface {
ContainerInfo(name string) (*info.ContainerInfo, error)
@ -120,7 +94,7 @@ func (kl *Kubelet) RunKubelet(dockerEndpoint, configPath, manifestURL, etcdServe
}
}
if kl.DockerPuller == nil {
kl.DockerPuller = kl.MakeDockerPuller()
kl.DockerPuller = NewDockerPuller(kl.DockerClient)
}
updateChannel := make(chan manifestUpdate)
if configPath != "" {
@ -237,70 +211,6 @@ func (kl *Kubelet) getContainer(ID DockerID) (*docker.APIContainers, error) {
return nil, nil
}
// MakeDockerPuller creates a new instance of the default implementation of DockerPuller.
func (kl *Kubelet) MakeDockerPuller() DockerPuller {
return dockerPuller{
client: kl.DockerClient,
}
}
// dockerPuller is the default implementation of DockerPuller.
type dockerPuller struct {
client DockerInterface
}
func (p dockerPuller) Pull(image string) error {
image, tag := parseImageName(image)
opts := docker.PullImageOptions{
Repository: image,
Tag: tag,
}
return p.client.PullImage(opts, docker.AuthConfiguration{})
}
// Converts "-" to "_-_" and "_" to "___" so that we can use "--" to meaningfully separate parts of a docker name.
func escapeDash(in string) (out string) {
out = strings.Replace(in, "_", "___", -1)
out = strings.Replace(out, "-", "_-_", -1)
return
}
// Reverses the transformation of escapeDash.
func unescapeDash(in string) (out string) {
out = strings.Replace(in, "_-_", "-", -1)
out = strings.Replace(out, "___", "_", -1)
return
}
const containerNamePrefix = "k8s"
// Creates a name which can be reversed to identify both manifest id and container name.
func buildDockerName(manifest *api.ContainerManifest, container *api.Container) string {
// Note, manifest.ID could be blank.
return fmt.Sprintf("%s--%s--%s--%08x", containerNamePrefix, escapeDash(container.Name), escapeDash(manifest.ID), rand.Uint32())
}
// Upacks a container name, returning the manifest id and container name we would have used to
// construct the docker name. If the docker name isn't one we created, we may return empty strings.
func parseDockerName(name string) (manifestID, containerName string) {
// For some reason docker appears to be appending '/' to names.
// If its there, strip it.
if name[0] == '/' {
name = name[1:]
}
parts := strings.Split(name, "--")
if len(parts) == 0 || parts[0] != containerNamePrefix {
return
}
if len(parts) > 1 {
containerName = unescapeDash(parts[1])
}
if len(parts) > 2 {
manifestID = unescapeDash(parts[2])
}
return
}
func makeEnvironmentVariables(container *api.Container) []string {
var result []string
for _, value := range container.Env {
@ -359,29 +269,6 @@ func makePortsAndBindings(container *api.Container) (map[docker.Port]struct{}, m
return exposedPorts, portBindings
}
// Parses image name including an tag and returns image name and tag
// TODO: Future Docker versions can parse the tag on daemon side, see:
// https://github.com/dotcloud/docker/issues/6876
// So this can be deprecated at some point.
func parseImageName(image string) (string, string) {
tag := ""
parts := strings.SplitN(image, "/", 2)
repo := ""
if len(parts) == 2 {
repo = parts[0]
image = parts[1]
}
parts = strings.SplitN(image, ":", 2)
if len(parts) == 2 {
image = parts[0]
tag = parts[1]
}
if repo != "" {
image = fmt.Sprintf("%s/%s", repo, image)
}
return image, tag
}
// Run a single container from a manifest. Returns the docker container ID
func (kl *Kubelet) runContainer(manifest *api.ContainerManifest, container *api.Container, netMode string) (id DockerID, err error) {
envVariables := makeEnvironmentVariables(container)