forked from Azure/aks-engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
kubeclient.go
183 lines (162 loc) · 6.49 KB
/
kubeclient.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
package azurestack
import (
"time"
"github.com/Azure/aks-engine/pkg/armhelpers"
log "github.com/sirupsen/logrus"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
policy "k8s.io/api/policy/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)
const (
evictionKind = "Eviction"
evictionSubresource = "pods/eviction"
)
//KubernetesClientSetClient is a Kubernetes client hooked up to a live api server.
type KubernetesClientSetClient struct {
clientset *kubernetes.Clientset
interval, timeout time.Duration
}
//GetKubernetesClient returns a KubernetesClient hooked up to the api server at the apiserverURL.
func (az *AzureClient) GetKubernetesClient(apiserverURL, kubeConfig string, interval, timeout time.Duration) (armhelpers.KubernetesClient, error) {
// creates the clientset
config, err := clientcmd.BuildConfigFromKubeconfigGetter(apiserverURL, func() (*clientcmdapi.Config, error) { return clientcmd.Load([]byte(kubeConfig)) })
if err != nil {
return nil, err
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, err
}
return &KubernetesClientSetClient{clientset: clientset, interval: interval, timeout: timeout}, nil
}
// ListPods returns all Pods running on the passed in node.
func (c *KubernetesClientSetClient) ListPods(node *v1.Node) (*v1.PodList, error) {
return c.clientset.CoreV1().Pods(metav1.NamespaceAll).List(metav1.ListOptions{
FieldSelector: fields.SelectorFromSet(fields.Set{"spec.nodeName": node.Name}).String()})
}
// ListAllPods returns all Pods running.
func (c *KubernetesClientSetClient) ListAllPods() (*v1.PodList, error) {
return c.clientset.CoreV1().Pods(metav1.NamespaceAll).List(metav1.ListOptions{})
}
// ListNodes returns a list of Nodes registered in the api server.
func (c *KubernetesClientSetClient) ListNodes() (*v1.NodeList, error) {
return c.clientset.CoreV1().Nodes().List(metav1.ListOptions{})
}
// ListServiceAccounts returns a list of Service Accounts in the provided namespace.
func (c *KubernetesClientSetClient) ListServiceAccounts(namespace string) (*v1.ServiceAccountList, error) {
return c.clientset.CoreV1().ServiceAccounts(namespace).List(metav1.ListOptions{})
}
// GetNode returns details about node with passed in name.
func (c *KubernetesClientSetClient) GetNode(name string) (*v1.Node, error) {
return c.clientset.CoreV1().Nodes().Get(name, metav1.GetOptions{})
}
// UpdateNode updates the node in the api server with the passed in info.
func (c *KubernetesClientSetClient) UpdateNode(node *v1.Node) (*v1.Node, error) {
return c.clientset.CoreV1().Nodes().Update(node)
}
// DeleteNode deregisters the node in the api server.
func (c *KubernetesClientSetClient) DeleteNode(name string) error {
return c.clientset.CoreV1().Nodes().Delete(name, &metav1.DeleteOptions{})
}
// DeleteServiceAccount deletes the passed in service account.
func (c *KubernetesClientSetClient) DeleteServiceAccount(sa *v1.ServiceAccount) error {
return c.clientset.CoreV1().ServiceAccounts(sa.Namespace).Delete(sa.Name, &metav1.DeleteOptions{})
}
// SupportEviction queries the api server to discover if it supports eviction, and returns supported type if it is supported.
func (c *KubernetesClientSetClient) SupportEviction() (string, error) {
discoveryClient := c.clientset.Discovery()
groupList, err := discoveryClient.ServerGroups()
if err != nil {
return "", err
}
foundPolicyGroup := false
var policyGroupVersion string
for _, group := range groupList.Groups {
if group.Name == "policy" {
foundPolicyGroup = true
policyGroupVersion = group.PreferredVersion.GroupVersion
break
}
}
if !foundPolicyGroup {
return "", nil
}
resourceList, err := discoveryClient.ServerResourcesForGroupVersion("v1")
if err != nil {
return "", err
}
for _, resource := range resourceList.APIResources {
if resource.Name == evictionSubresource && resource.Kind == evictionKind {
return policyGroupVersion, nil
}
}
return "", nil
}
// DeletePod deletes the passed in pod.
func (c *KubernetesClientSetClient) DeletePod(pod *v1.Pod) error {
return c.clientset.CoreV1().Pods(pod.Namespace).Delete(pod.Name, &metav1.DeleteOptions{})
}
// EvictPod evicts the passed in pod using the passed in api version.
func (c *KubernetesClientSetClient) EvictPod(pod *v1.Pod, policyGroupVersion string) error {
eviction := &policy.Eviction{
TypeMeta: metav1.TypeMeta{
APIVersion: policyGroupVersion,
Kind: evictionKind,
},
ObjectMeta: metav1.ObjectMeta{
Name: pod.Name,
Namespace: pod.Namespace,
},
}
return c.clientset.PolicyV1beta1().Evictions(eviction.Namespace).Evict(eviction)
}
// GetPod returns the pod with the provided name and namespace.
func (c *KubernetesClientSetClient) getPod(namespace, name string) (*v1.Pod, error) {
return c.clientset.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{})
}
// WaitForDelete waits until all pods are deleted. Returns all pods not deleted and an error on failure.
func (c *KubernetesClientSetClient) WaitForDelete(logger *log.Entry, pods []v1.Pod, usingEviction bool) ([]v1.Pod, error) {
var verbStr string
if usingEviction {
verbStr = "evicted"
} else {
verbStr = "deleted"
}
err := wait.PollImmediate(c.interval, c.timeout, func() (bool, error) {
pendingPods := []v1.Pod{}
for i, pod := range pods {
p, err := c.getPod(pod.Namespace, pod.Name)
if apierrors.IsNotFound(err) || (p != nil && p.ObjectMeta.UID != pod.ObjectMeta.UID) {
logger.Infof("%s pod successfully %s", pod.Name, verbStr)
continue
} else if err != nil {
return false, err
} else {
pendingPods = append(pendingPods, pods[i])
}
}
pods = pendingPods
if len(pendingPods) > 0 {
return false, nil
}
return true, nil
})
return pods, err
}
// GetDeployment returns a given deployment in a namespace.
func (c *KubernetesClientSetClient) GetDeployment(namespace, name string) (*appsv1.Deployment, error) {
return c.clientset.AppsV1().Deployments(namespace).Get(name, metav1.GetOptions{})
}
// UpdateDeployment updates a deployment to match the given specification.
func (c *KubernetesClientSetClient) UpdateDeployment(namespace string, deployment *appsv1.Deployment) (*appsv1.Deployment, error) {
return c.clientset.AppsV1().Deployments(namespace).Update(deployment)
}