Skip to content

Commit 019446a

Browse files
authored
Merge pull request #1 from kaloom/ocp
Add Crio support
2 parents 6aca363 + c3f1322 commit 019446a

File tree

9 files changed

+378
-13
lines changed

9 files changed

+378
-13
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,10 @@ see [kactus cni-plugin repo](https://github.com/kaloom/kubernetes-kactus-cni-plu
9797

9898
> $ `kubectl apply -f manifests/podagent-serviceaccount-and-rbac.yaml`
9999
100-
3. delopy the podagent as a daemon set:
100+
3. deploy the podagent as a daemon set:
101101

102-
> $ `kubectl apply -f manifests/podagent-ds.yaml`
102+
> $ `kubectl apply -f manifests/podagent-ds.yaml` for docker
103+
> $ `kubectl apply -f manifests/podagent-cs.yaml` for crio
103104
104105

105106
### Note

controller/controller.go

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ package controller
1818

1919
import (
2020
"context"
21+
"fmt"
2122
"time"
2223

2324
"github.com/kaloom/kubernetes-podagent/controller/cni"
25+
ccri "github.com/kaloom/kubernetes-podagent/controller/crio-runtime"
2426
dcri "github.com/kaloom/kubernetes-podagent/controller/docker-runtime"
2527

2628
"github.com/golang/glog"
@@ -29,10 +31,33 @@ import (
2931
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
3032
)
3133

34+
// ContainerType defines the type if continer used to support the pods
35+
type ContainerType int
36+
37+
const (
38+
// Docker type container
39+
Docker ContainerType = iota
40+
41+
// Crio type container
42+
Crio
43+
)
44+
45+
func (ct ContainerType) String() string {
46+
switch ct {
47+
case Docker:
48+
return "Docker"
49+
case Crio:
50+
return "Crio"
51+
default:
52+
glog.Errorf("Invalid ContainerType: %v", ct)
53+
return fmt.Sprintf("%d", int(ct))
54+
}
55+
}
56+
3257
// Controller the controller object
3358
type Controller struct {
3459
kubeClient *kubernetes.Clientset
35-
runtime *dcri.DockerRuntime
60+
runtime Runtime
3661
cniPlugin *cni.NetworkPlugin
3762
}
3863

@@ -57,17 +82,27 @@ func (c *Controller) Run(ctx context.Context, nodeName string) error {
5782
return ctx.Err()
5883
}
5984

60-
// NewController instantiate a controller object
61-
func NewController(kubeClient *kubernetes.Clientset, dockerEndpoint, cniBinPath, cniConfPath, cniVendor string) (*Controller, error) {
85+
// NewController instantiate a docker controller object
86+
func NewController(kubeClient *kubernetes.Clientset, endpoint, cniBinPath, cniConfPath, cniVendor string, containerType ContainerType) (*Controller, error) {
6287
runtimeRequestTimeout := 2 * time.Minute
6388
imagePullProgressDeadline := time.Minute
64-
dockerClient := libdocker.ConnectToDockerOrDie(dockerEndpoint,
65-
runtimeRequestTimeout,
66-
imagePullProgressDeadline)
67-
runTime, err := dcri.NewDockerRuntime(dockerClient)
89+
90+
var runTime Runtime
91+
var err error
92+
switch containerType {
93+
case Crio:
94+
runTime, err = ccri.NewCrioRuntime(endpoint, runtimeRequestTimeout)
95+
96+
default:
97+
dockerClient := libdocker.ConnectToDockerOrDie(endpoint,
98+
runtimeRequestTimeout,
99+
imagePullProgressDeadline)
100+
runTime, err = dcri.NewDockerRuntime(dockerClient)
101+
}
68102
if err != nil {
69103
return nil, err
70104
}
105+
71106
cniPlugin, err := cni.NewCNIPlugin(cniBinPath, cniConfPath, cniVendor)
72107
if err != nil {
73108
return nil, err

controller/crio-runtime/runtime.go

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
// /*
2+
// Copyright 2020 Kaloom Inc.
3+
// Copyright 2014 The Kubernetes Authors.
4+
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
// */
17+
18+
package crioruntime
19+
20+
import (
21+
"context"
22+
"encoding/json"
23+
"fmt"
24+
"strings"
25+
"time"
26+
27+
"github.com/golang/glog"
28+
"github.com/pkg/errors"
29+
"google.golang.org/grpc"
30+
pb "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
31+
"k8s.io/kubernetes/pkg/kubelet/util"
32+
)
33+
34+
const (
35+
crioNetNSFmt = "/var/run/netns/%s"
36+
)
37+
38+
// CrioRuntime runtime object
39+
type CrioRuntime struct {
40+
client pb.RuntimeServiceClient
41+
}
42+
43+
type PodStatusResponseInfo struct {
44+
SandboxId string
45+
RunTimeSpec RuneTimeSpecInfo
46+
}
47+
48+
type RuneTimeSpecInfo struct {
49+
Linux NamespacesInfo
50+
}
51+
52+
type NamespacesInfo struct {
53+
NameSpaces []NameSpaceInfo
54+
}
55+
56+
type NameSpaceInfo struct {
57+
Type string
58+
Path string
59+
}
60+
61+
// GetNetNS returns the network namespace of the given containerID. The ID
62+
// supplied is typically the ID of a pod sandbox. This getter doesn't try
63+
// to map non-sandbox IDs to their respective sandboxes.
64+
func (cr *CrioRuntime) GetNetNS(podSandboxID string) (string, error) {
65+
66+
glog.V(4).Infof("GetNetNS:podSandboxID:%s", podSandboxID)
67+
if podSandboxID == "" {
68+
return "", fmt.Errorf("ID cannot be empty")
69+
}
70+
71+
request := &pb.PodSandboxStatusRequest{
72+
PodSandboxId: podSandboxID,
73+
Verbose: true, // TODO see with non verbose if all info is there
74+
}
75+
glog.V(5).Infof("PodSandboxStatusRequest: %v", request)
76+
r, err := cr.client.PodSandboxStatus(context.Background(), request)
77+
glog.V(5).Infof("PodSandboxStatusResponse: %v", r)
78+
if err != nil {
79+
return "", err
80+
}
81+
82+
mapInfo := r.GetInfo()
83+
glog.V(5).Infof("GetNetNS:GetInfo():%s", mapInfo)
84+
var podStatusResponseInfo PodStatusResponseInfo
85+
info := mapInfo["info"]
86+
glog.V(5).Infof("GetNetNS:info:%s", info)
87+
err = json.Unmarshal([]byte(info), &podStatusResponseInfo)
88+
if err != nil {
89+
glog.Errorf("GetNetNS:error decoding response:", err)
90+
if e, ok := err.(*json.SyntaxError); ok {
91+
glog.Errorf("GetNetNS:syntax error at byte offset ", e.Offset)
92+
}
93+
return "", err
94+
}
95+
96+
namespaces := podStatusResponseInfo.RunTimeSpec.Linux.NameSpaces
97+
glog.V(5).Infof("GetNetNS:RunTimeSpec.Linux.NameSpaces:", namespaces)
98+
for _, namespace := range namespaces {
99+
if namespace.Type == "network" {
100+
ss := strings.Split(namespace.Path, "/")
101+
netNS := ss[len(ss)-1]
102+
glog.V(5).Infof("GetNetNS:NetNS:%s", netNS)
103+
return fmt.Sprintf(crioNetNSFmt, netNS), nil
104+
}
105+
}
106+
return "", nil
107+
}
108+
109+
// GetSandboxID returns kubernete's crio sandbox container ID
110+
func (cr *CrioRuntime) GetSandboxID(containerID string) (string, error) {
111+
glog.V(5).Infof("GetSandboxID:containerID:%s", containerID)
112+
if containerID == "" {
113+
return "", fmt.Errorf("ID cannot be empty")
114+
}
115+
116+
filter := &pb.ContainerFilter{
117+
Id: containerID,
118+
}
119+
120+
request := &pb.ListContainersRequest{
121+
Filter: filter,
122+
}
123+
124+
glog.V(5).Infof("ListContainerRequest: %v", request)
125+
r, err := cr.client.ListContainers(context.Background(), request)
126+
glog.V(5).Infof("ListContainerResponse: %v", r)
127+
if err != nil {
128+
return "", err
129+
}
130+
131+
containerslist := r.GetContainers()
132+
if len(containerslist) == 0 {
133+
return "", fmt.Errorf("Didn't find any container with containerID:%s", containerID)
134+
} else if len(containerslist) != 1 {
135+
return "", fmt.Errorf("Found more then one container with containerID:%s", containerID)
136+
}
137+
138+
sandboxID := containerslist[0].PodSandboxId
139+
glog.V(5).Infof("ContainerStatusResponse:SandboxId %s", sandboxID)
140+
return sandboxID, nil
141+
}
142+
143+
func getConnection(endPoints []string, timeOut time.Duration) (*grpc.ClientConn, error) {
144+
if endPoints == nil || len(endPoints) == 0 {
145+
return nil, fmt.Errorf("endpoint is not set")
146+
}
147+
endPointsLen := len(endPoints)
148+
var conn *grpc.ClientConn
149+
for indx, endPoint := range endPoints {
150+
glog.Infof("connect using endpoint '%s' with '%s' timeout", endPoint, timeOut)
151+
addr, dialer, err := util.GetAddressAndDialer(endPoint)
152+
if err != nil {
153+
if indx == endPointsLen-1 {
154+
return nil, err
155+
}
156+
glog.Error(err)
157+
continue
158+
}
159+
conn, err = grpc.Dial(addr, grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(timeOut), grpc.WithContextDialer(dialer))
160+
if err != nil {
161+
errMsg := errors.Wrapf(err, "connect endpoint '%s', make sure you are running as root and the endpoint has been started", endPoint)
162+
if indx == endPointsLen-1 {
163+
return nil, errMsg
164+
}
165+
glog.Error(errMsg)
166+
} else {
167+
glog.Infof("connected successfully using endpoint: %s", endPoint)
168+
break
169+
}
170+
}
171+
return conn, nil
172+
}
173+
174+
// NewCrioRuntime instantiate a crio runtime object
175+
func NewCrioRuntime(endpoint string, timeOut time.Duration) (*CrioRuntime, error) {
176+
177+
if endpoint == "" {
178+
return nil, fmt.Errorf("--runtime-endpoint is not set")
179+
}
180+
clientConnection, err := getConnection([]string{endpoint}, timeOut)
181+
if err != nil {
182+
return nil, errors.Wrap(err, "connect")
183+
}
184+
runtimeClient := pb.NewRuntimeServiceClient(clientConnection)
185+
186+
cr := &CrioRuntime{
187+
client: runtimeClient,
188+
}
189+
190+
return cr, nil
191+
}

controller/docker-runtime/runtime.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ func (dr *DockerRuntime) GetNetNS(podSandboxID string) (string, error) {
5858
if err != nil {
5959
return "", err
6060
}
61-
return getNetworkNamespace(c)
61+
62+
ns, err := getNetworkNamespace(c)
63+
glog.V(5).Infof("GetNetNS:%s %v", ns, err)
64+
return ns, err
6265
}
6366

6467
// GetSandboxID returns kubernete's docker "pause" container ID
@@ -73,6 +76,7 @@ func (dr *DockerRuntime) GetSandboxID(containerID string) (string, error) {
7376
return val, nil
7477
}
7578
}
79+
glog.V(5).Infof("GetSandboxID:SandboxId %s", kubernetesSandboxID)
7680
return "", fmt.Errorf("Cannot find label %s in container %q", kubernetesSandboxID, c.ID)
7781
}
7882

controller/runtime.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
Copyright 2020 Kaloom Inc.
3+
Copyright 2014 The Kubernetes Authors.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
18+
package controller
19+
20+
// Runtime interface
21+
type Runtime interface {
22+
// GetNetNS returns the network namespace of the given containerID. The ID
23+
// supplied is typically the ID of a pod sandbox. This getter doesn't try
24+
// to map non-sandbox IDs to their respective sandboxes.
25+
GetNetNS(podSandboxID string) (string, error)
26+
27+
// GetSandboxID returns kubernete's docker "pause" container ID
28+
GetSandboxID(containerID string) (string, error)
29+
}

0 commit comments

Comments
 (0)