mirror of https://github.com/k3s-io/k3s
commit
df8490f52f
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
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"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// containerID defines the ID of rkt containers, it will
|
||||
// be returned to kubelet, and kubelet will use this for
|
||||
// container level operations.
|
||||
type containerID struct {
|
||||
uuid string // uuid of the pod.
|
||||
appName string // name of the app in that pod.
|
||||
imageID string // id of the image. TODO(yifan): Depreciate this.
|
||||
}
|
||||
|
||||
// buildContainerID constructs the containers's ID using containerID,
|
||||
// which containers the pod uuid and the container name.
|
||||
// The result can be used to globally identify a container.
|
||||
func buildContainerID(c *containerID) string {
|
||||
return fmt.Sprintf("%s:%s:%s", c.uuid, c.appName, c.imageID)
|
||||
}
|
||||
|
||||
// parseContainerID parses the containerID into pod uuid and the container name. The
|
||||
// results can be used to get more information of the container.
|
||||
func parseContainerID(id string) (*containerID, error) {
|
||||
tuples := strings.Split(id, ":")
|
||||
if len(tuples) != 3 {
|
||||
return nil, fmt.Errorf("rkt: cannot parse container ID for: %v", id)
|
||||
}
|
||||
return &containerID{
|
||||
uuid: tuples[0],
|
||||
appName: tuples[1],
|
||||
imageID: tuples[2],
|
||||
}, nil
|
||||
}
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
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"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
kubecontainer "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/container"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// rkt pod state.
|
||||
// TODO(yifan): Use exported definition in rkt.
|
||||
const (
|
||||
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"
|
||||
)
|
||||
|
||||
// podInfo is the internal type that represents the state of
|
||||
// the rkt pod.
|
||||
type podInfo struct {
|
||||
// The state of the pod, e.g. Embryo, Preparing.
|
||||
state string
|
||||
// The ip of the pod. IPv4 for now.
|
||||
ip string
|
||||
// The pid of the init process in the pod.
|
||||
pid int
|
||||
// A map from image hashes to exit codes.
|
||||
// TODO(yifan): Should be appName to exit code in the future.
|
||||
exitCodes map[string]int
|
||||
}
|
||||
|
||||
// parsePodInfo parses the result of 'rkt status' into podInfo.
|
||||
func parsePodInfo(status []string) (*podInfo, error) {
|
||||
p := &podInfo{
|
||||
pid: -1,
|
||||
exitCodes: make(map[string]int),
|
||||
}
|
||||
|
||||
for _, line := range status {
|
||||
tuples := strings.SplitN(line, "=", 2)
|
||||
if len(tuples) != 2 {
|
||||
return nil, fmt.Errorf("invalid status line: %q", line)
|
||||
}
|
||||
switch tuples[0] {
|
||||
case "state":
|
||||
// TODO(yifan): Parse the status here. This requires more details in
|
||||
// the rkt status, (e.g. started time, image name, etc).
|
||||
p.state = tuples[1]
|
||||
case "networks":
|
||||
p.ip = getIPFromNetworkInfo(tuples[1])
|
||||
case "pid":
|
||||
pid, err := strconv.Atoi(tuples[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse pid from %s: %v", tuples[1], err)
|
||||
}
|
||||
p.pid = pid
|
||||
}
|
||||
if strings.HasPrefix(tuples[0], "sha512") {
|
||||
exitcode, err := strconv.Atoi(tuples[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse exit code from %s : %v", tuples[1], err)
|
||||
}
|
||||
p.exitCodes[tuples[0]] = exitcode
|
||||
}
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// getIPFromNetworkInfo returns the IP of a pod by parsing the network info.
|
||||
// The network info looks like this:
|
||||
//
|
||||
// default:ip4=172.16.28.3, database:ip4=172.16.28.42
|
||||
//
|
||||
func getIPFromNetworkInfo(networkInfo string) string {
|
||||
parts := strings.Split(networkInfo, ",")
|
||||
|
||||
for _, part := range parts {
|
||||
if strings.HasPrefix(part, "default:") {
|
||||
tuples := strings.Split(part, "=")
|
||||
if len(tuples) == 2 {
|
||||
return tuples[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// getContainerStatus creates the api.containerStatus of a container from the podInfo.
|
||||
// TODO(yifan): Get more detailed info such as Image, ImageID, etc.
|
||||
func (p *podInfo) getContainerStatus(container *kubecontainer.Container) api.ContainerStatus {
|
||||
var status api.ContainerStatus
|
||||
status.Name = container.Name
|
||||
status.Image = container.Image
|
||||
containerID, _ := parseContainerID(string(container.ID))
|
||||
status.ImageID = containerID.imageID
|
||||
|
||||
switch p.state {
|
||||
case Running:
|
||||
// TODO(yifan): Get StartedAt.
|
||||
status.State = api.ContainerState{
|
||||
Running: &api.ContainerStateRunning{
|
||||
StartedAt: util.Unix(container.Created, 0),
|
||||
},
|
||||
}
|
||||
case Embryo, Preparing, Prepared:
|
||||
status.State = api.ContainerState{Waiting: &api.ContainerStateWaiting{}}
|
||||
case AbortedPrepare, Deleting, Exited, Garbage:
|
||||
exitCode, ok := p.exitCodes[status.ImageID]
|
||||
if !ok {
|
||||
glog.Warningf("rkt: Cannot get exit code for container %v", container)
|
||||
}
|
||||
exitCode = -1
|
||||
status.State = api.ContainerState{
|
||||
Termination: &api.ContainerStateTerminated{
|
||||
ExitCode: exitCode,
|
||||
StartedAt: util.Unix(container.Created, 0),
|
||||
},
|
||||
}
|
||||
default:
|
||||
glog.Warningf("rkt: Unknown pod state: %q", p.state)
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
// toPodStatus converts a podInfo type into an api.PodStatus type.
|
||||
func (p *podInfo) toPodStatus(pod *kubecontainer.Pod) api.PodStatus {
|
||||
var status api.PodStatus
|
||||
status.PodIP = p.ip
|
||||
// For now just make every container's state the same as the pod.
|
||||
for _, container := range pod.Containers {
|
||||
status.ContainerStatuses = append(status.ContainerStatuses, p.getContainerStatus(container))
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
// splitLineByTab breaks a line by tabs, and trims the leading and tailing spaces.
|
||||
func splitLineByTab(line string) []string {
|
||||
var result []string
|
||||
tuples := strings.Split(strings.TrimSpace(line), "\t")
|
||||
for _, t := range tuples {
|
||||
if t != "" {
|
||||
result = append(result, t)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// getPodInfos returns a map of [pod-uuid]:*podInfo
|
||||
func (r *Runtime) getPodInfos() (map[string]*podInfo, error) {
|
||||
result := make(map[string]*podInfo)
|
||||
|
||||
output, err := r.runCommand("list", "--no-legend", "--full")
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
if len(output) == 0 {
|
||||
// No pods are running.
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Example output of current 'rkt list --full' (version == 0.4.2):
|
||||
// UUID ACI STATE NETWORKS
|
||||
// 2372bc17-47cb-43fb-8d78-20b31729feda foo running default:ip4=172.16.28.3
|
||||
// bar
|
||||
// 40e2813b-9d5d-4146-a817-0de92646da96 foo exited
|
||||
// 40e2813b-9d5d-4146-a817-0de92646da96 bar exited
|
||||
//
|
||||
// With '--no-legend', the first line is eliminated.
|
||||
for _, line := range output {
|
||||
tuples := splitLineByTab(line)
|
||||
if len(tuples) < 3 { // At least it should have 3 entries.
|
||||
glog.Warningf("rkt: Unrecognized line: %q", line)
|
||||
continue
|
||||
}
|
||||
id := tuples[0]
|
||||
|
||||
status, err := r.runCommand("status", id)
|
||||
if err != nil {
|
||||
glog.Errorf("rkt: Cannot get status for pod (uuid=%q): %v", id, err)
|
||||
continue
|
||||
}
|
||||
info, err := parsePodInfo(status)
|
||||
if err != nil {
|
||||
glog.Errorf("rkt: Cannot parse status for pod (uuid=%q): %v", id, err)
|
||||
continue
|
||||
}
|
||||
result[id] = info
|
||||
}
|
||||
return result, nil
|
||||
}
|
|
@ -28,6 +28,8 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
rktBinName = "rkt"
|
||||
|
||||
acversion = "0.5.1"
|
||||
rktMinimumVersion = "0.5.4"
|
||||
systemdMinimumVersion = "215"
|
||||
|
@ -46,19 +48,6 @@ const (
|
|||
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"
|
||||
)
|
||||
|
||||
// Runtime implements the ContainerRuntime for rkt. The implementation
|
||||
// uses systemd, so in order to run this runtime, systemd must be installed
|
||||
// on the machine.
|
||||
|
|
Loading…
Reference in New Issue