Merge pull request #7465 from yifan-gu/split_rkt

kubelet/rkt: Add basic rkt runtime routines.
pull/6/head
Victor Marmol 2015-04-30 08:37:24 -07:00
commit 946dac4f7c
3 changed files with 343 additions and 0 deletions

50
pkg/kubelet/rkt/config.go Normal file
View File

@ -0,0 +1,50 @@
/*
Copyright 2015 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 rkt
import "fmt"
// Config stores the global configuration for the rkt runtime.
// Run 'rkt' for more details.
type Config struct {
// The debug flag for rkt.
Debug bool
// The rkt data directory.
Dir string
// This flag controls whether we skip image or key verification.
InsecureSkipVerify bool
// The local config directory.
LocalConfigDir string
}
// buildGlobalOptions returns an array of global command line options.
func (c *Config) buildGlobalOptions() []string {
var result []string
if c == nil {
return result
}
result = append(result, fmt.Sprintf("--debug=%v", c.Debug))
result = append(result, fmt.Sprintf("--insecure-skip-verify=%v", c.InsecureSkipVerify))
if c.LocalConfigDir != "" {
result = append(result, fmt.Sprintf("--local-config=%s", c.LocalConfigDir))
}
if c.Dir != "" {
result = append(result, fmt.Sprintf("--dir=%s", c.Dir))
}
return result
}

144
pkg/kubelet/rkt/rkt.go Normal file
View File

@ -0,0 +1,144 @@
/*
Copyright 2015 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 rkt
import (
"fmt"
"os/exec"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/credentialprovider"
"github.com/coreos/go-systemd/dbus"
"github.com/golang/glog"
)
const (
acversion = "0.5.1"
rktMinimumVersion = "0.5.4"
systemdMinimumVersion = "215"
systemdServiceDir = "/run/systemd/system"
rktDataDir = "/var/lib/rkt"
rktLocalConfigDir = "/etc/rkt"
rktMetadataServiceFile = "rkt-metadata.service"
rktMetadataSocketFile = "rkt-metadata.socket"
kubernetesUnitPrefix = "k8s"
unitKubernetesSection = "X-Kubernetes"
unitPodName = "POD"
unitRktID = "RktID"
dockerPrefix = "docker://"
)
const (
rktBinName = "rkt"
Embryo = "embryo"
Preparing = "preparing"
AbortedPrepare = "aborted prepare"
Prepared = "prepared"
Running = "running"
Deleting = "deleting" // This covers pod.isExitedDeleting and pod.isDeleting.
Exited = "exited" // This covers pod.isExited and pod.isExitedGarbage.
Garbage = "garbage"
)
const (
dockerAuthTemplate = `{"rktKind":"dockerAuth","rktVersion":"v1","registries":[%q],"credentials":{"user":%q,"password":%q}}`
)
// Runtime implements the ContainerRuntime for rkt. The implementation
// uses systemd, so in order to run this runtime, systemd must be installed
// on the machine.
type Runtime struct {
systemd *dbus.Conn
absPath string
config *Config
// TODO(yifan): Refactor this to be generic keyring.
dockerKeyring credentialprovider.DockerKeyring
}
// New creates the rkt container runtime which implements the container runtime interface.
// It will test if the rkt binary is in the $PATH, and whether we can get the
// version of it. If so, creates the rkt container runtime, otherwise returns an error.
func New(config *Config) (*Runtime, error) {
systemdVersion, err := getSystemdVersion()
if err != nil {
return nil, err
}
result, err := systemdVersion.Compare(systemdMinimumVersion)
if err != nil {
return nil, err
}
if result < 0 {
return nil, fmt.Errorf("rkt: systemd version is too old, requires at least %v", systemdMinimumVersion)
}
systemd, err := dbus.New()
if err != nil {
glog.Errorf("rkt: Cannot connect to dbus: %v", err)
return nil, err
}
// Test if rkt binary is in $PATH.
absPath, err := exec.LookPath(rktBinName)
if err != nil {
glog.Errorf("rkt: Cannot find rkt binary: %v", err)
return nil, err
}
rkt := &Runtime{
systemd: systemd,
absPath: absPath,
config: config,
dockerKeyring: credentialprovider.NewDockerKeyring(),
}
// Test the rkt version.
version, err := rkt.Version()
if err != nil {
return nil, err
}
result, err = version.Compare(rktMinimumVersion)
if err != nil {
return nil, err
}
if result < 0 {
return nil, fmt.Errorf("rkt: Version is too old, requires at least %v", rktMinimumVersion)
}
return rkt, nil
}
func (r *Runtime) buildCommand(args ...string) *exec.Cmd {
cmd := exec.Command(rktBinName)
cmd.Args = append(cmd.Args, r.config.buildGlobalOptions()...)
cmd.Args = append(cmd.Args, args...)
return cmd
}
// runCommand invokes rkt binary with arguments and returns the result
// from stdout in a list of strings.
func (r *Runtime) runCommand(args ...string) ([]string, error) {
glog.V(4).Info("rkt: Run command:", args)
output, err := r.buildCommand(args...).Output()
if err != nil {
return nil, err
}
return strings.Split(strings.TrimSpace(string(output)), "\n"), nil
}

149
pkg/kubelet/rkt/version.go Normal file
View File

@ -0,0 +1,149 @@
/*
Copyright 2015 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 rkt
import (
"fmt"
"os/exec"
"strconv"
"strings"
kubecontainer "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/container"
"github.com/golang/glog"
)
type rktVersion []int
func parseVersion(input string) (rktVersion, error) {
tail := strings.Index(input, "+")
if tail > 0 {
input = input[:tail]
}
var result rktVersion
tuples := strings.Split(input, ".")
for _, t := range tuples {
n, err := strconv.Atoi(t)
if err != nil {
return nil, err
}
result = append(result, n)
}
return result, nil
}
func (r rktVersion) Compare(other string) (int, error) {
v, err := parseVersion(other)
if err != nil {
return -1, err
}
for i := range r {
if i > len(v)-1 {
return 1, nil
}
if r[i] < v[i] {
return -1, nil
}
if r[i] > v[i] {
return 1, nil
}
}
// When loop ends, len(r) is <= len(v).
if len(r) < len(v) {
return -1, nil
}
return 0, nil
}
func (r rktVersion) String() string {
var version []string
for _, v := range r {
version = append(version, fmt.Sprintf("%d", v))
}
return strings.Join(version, ".")
}
// Version invokes 'rkt version' to get the version information of the rkt
// runtime on the machine.
// The return values are an int array containers the version number.
//
// Example:
// rkt:0.3.2+git --> []int{0, 3, 2}.
//
func (r *Runtime) Version() (kubecontainer.Version, error) {
output, err := r.runCommand("version")
if err != nil {
return nil, err
}
// Example output for 'rkt version':
// rkt version 0.3.2+git
// appc version 0.3.0+git
for _, line := range output {
tuples := strings.Split(strings.TrimSpace(line), " ")
if len(tuples) != 3 {
glog.Warningf("rkt: cannot parse the output: %q.", line)
continue
}
if tuples[0] == "rkt" {
return parseVersion(tuples[2])
}
}
return nil, fmt.Errorf("rkt: cannot determine the version")
}
type systemdVersion int
func (s systemdVersion) String() string {
return fmt.Sprintf("%d", s)
}
func (s systemdVersion) Compare(other string) (int, error) {
v, err := strconv.Atoi(other)
if err != nil {
return -1, err
}
if int(s) < v {
return -1, nil
} else if int(s) > v {
return 1, nil
}
return 0, nil
}
func getSystemdVersion() (systemdVersion, error) {
output, err := exec.Command("systemctl", "--version").Output()
if err != nil {
return -1, err
}
// Example output of 'systemctl --version':
//
// systemd 215
// +PAM +AUDIT +SELINUX +IMA +SYSVINIT +LIBCRYPTSETUP +GCRYPT +ACL +XZ -SECCOMP -APPARMOR
//
lines := strings.Split(string(output), "\n")
tuples := strings.Split(lines[0], " ")
if len(tuples) != 2 {
return -1, fmt.Errorf("rkt: Failed to parse version %v", lines)
}
result, err := strconv.Atoi(string(tuples[1]))
if err != nil {
return -1, err
}
return systemdVersion(result), nil
}