github.com/jlmeeker/kismatic@v1.10.1-0.20180612190640-57f9005a1f1a/pkg/data/kubernetes.go (about) 1 package data 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "strings" 7 8 "github.com/apprenda/kismatic/pkg/ssh" 9 ) 10 11 // PodLister lists pods on a Kubernetes cluster 12 type PodLister interface { 13 ListPods() (*PodList, error) 14 } 15 16 // PVLister lists persistent volumes that exist on a Kubernetes cluster 17 type PVLister interface { 18 ListPersistentVolumes() (*PersistentVolumeList, error) 19 } 20 21 // PersistentVolumeGetter gets a persistent volume 22 type PersistentVolumeGetter interface { 23 GetPersistentVolume(name string) (*PersistentVolume, error) 24 } 25 26 // PersistentVolumeClaimGetter gets a persistent volume claim 27 type PersistentVolumeClaimGetter interface { 28 GetPersistentVolumeClaim(namespace, name string) (*PersistentVolumeClaim, error) 29 } 30 31 // DaemonSetGetter gets a given daemonset 32 type DaemonSetGetter interface { 33 GetDaemonSet(namespace, name string) (*DaemonSet, error) 34 } 35 36 // ReplicationControllerGetter gets a replication controller 37 type ReplicationControllerGetter interface { 38 GetReplicationController(namespace, name string) (*ReplicationController, error) 39 } 40 41 // ReplicaSetGetter gets a replica set 42 type ReplicaSetGetter interface { 43 GetReplicaSet(namespace, name string) (*ReplicaSet, error) 44 } 45 46 // StatefulSetGetter gets a stateful set 47 type StatefulSetGetter interface { 48 GetStatefulSet(namespace, name string) (*StatefulSet, error) 49 } 50 51 type KubernetesClient interface { 52 PodLister 53 PVLister 54 } 55 56 // RemoteKubectl is a kubectl client that uses an underlying SSH connection 57 // to connect to a node that has the kubectl binary. It is expected that this 58 // node has access to a kubernetes cluster via kubectl. 59 type RemoteKubectl struct { 60 SSHClient ssh.Client 61 } 62 63 // ListPersistentVolumes returns PersistentVolume data 64 func (k RemoteKubectl) ListPersistentVolumes() (*PersistentVolumeList, error) { 65 pvRaw, err := k.SSHClient.Output(true, "sudo kubectl --kubeconfig /root/.kube/config get pv -o json") 66 if err != nil { 67 return nil, fmt.Errorf("error getting persistent volume data: %v", err) 68 } 69 return UnmarshalPVs(pvRaw) 70 } 71 72 func UnmarshalPVs(raw string) (*PersistentVolumeList, error) { 73 if isNoResourcesResponse(raw) { 74 return nil, nil 75 } 76 var pvs PersistentVolumeList 77 err := json.Unmarshal([]byte(raw), &pvs) 78 if err != nil { 79 return nil, fmt.Errorf("error unmarshalling persistent volume data: %v", err) 80 } 81 return &pvs, nil 82 } 83 84 // ListPods returns Pods data with --all-namespaces=true flag 85 func (k RemoteKubectl) ListPods() (*PodList, error) { 86 podsRaw, err := k.SSHClient.Output(true, "sudo kubectl --kubeconfig /root/.kube/config get pods --all-namespaces=true -o json") 87 if err != nil { 88 return nil, fmt.Errorf("error getting pod data: %v", err) 89 } 90 return UnmarshalPods(podsRaw) 91 } 92 93 func UnmarshalPods(raw string) (*PodList, error) { 94 if isNoResourcesResponse(raw) { 95 return nil, nil 96 } 97 var pods PodList 98 err := json.Unmarshal([]byte(raw), &pods) 99 if err != nil { 100 return nil, fmt.Errorf("error unmarshalling pod data: %v", err) 101 } 102 return &pods, nil 103 } 104 105 // GetDaemonSet returns the DaemonSet with the given namespace and name. If not found, 106 // returns an error. 107 func (k RemoteKubectl) GetDaemonSet(namespace, name string) (*DaemonSet, error) { 108 cmd := fmt.Sprintf("sudo kubectl --kubeconfig /root/.kube/config get ds --namespace=%s -o json %s", namespace, name) 109 dsRaw, err := k.SSHClient.Output(true, cmd) 110 if err != nil { 111 return nil, fmt.Errorf("error getting daemon sets: %v", err) 112 } 113 if isNoResourcesResponse(dsRaw) { 114 return nil, fmt.Errorf("DaemonSet %s/%s was not found", namespace, name) 115 } 116 var d DaemonSet 117 if err := json.Unmarshal([]byte(dsRaw), &d); err != nil { 118 return nil, fmt.Errorf("error unmarshalling daemonset: %v", err) 119 } 120 return &d, nil 121 } 122 123 // GetReplicationController returns the ReplicationController with the given name in the given namespace. 124 // If not found, returns an error. 125 func (k RemoteKubectl) GetReplicationController(namespace, name string) (*ReplicationController, error) { 126 cmd := fmt.Sprintf("sudo kubectl --kubeconfig /root/.kube/config get replicationcontroller --namespace=%s -o json %s", namespace, name) 127 rcRaw, err := k.SSHClient.Output(true, cmd) 128 if err != nil { 129 return nil, fmt.Errorf("error getting replication controller: %v", err) 130 } 131 if isNoResourcesResponse(rcRaw) { 132 return nil, fmt.Errorf("ReplicationController %s/%s was not found", namespace, name) 133 } 134 var r ReplicationController 135 if err := json.Unmarshal([]byte(rcRaw), &r); err != nil { 136 return nil, fmt.Errorf("error unmarshalling replication controller: %v", err) 137 } 138 return &r, nil 139 } 140 141 // GetReplicaSet returns the ReplicaSet with the given name in the given namespace. 142 // If not found, returns an error. 143 func (k RemoteKubectl) GetReplicaSet(namespace, name string) (*ReplicaSet, error) { 144 cmd := fmt.Sprintf("sudo kubectl --kubeconfig /root/.kube/config get replicaset --namespace=%s -o json %s", namespace, name) 145 raw, err := k.SSHClient.Output(true, cmd) 146 if err != nil { 147 return nil, fmt.Errorf("error getting ReplicaSet: %v", err) 148 } 149 if isNoResourcesResponse(raw) { 150 return nil, fmt.Errorf("ReplicaSet %s/%s was not found", namespace, name) 151 } 152 var r ReplicaSet 153 if err := json.Unmarshal([]byte(raw), &r); err != nil { 154 return nil, fmt.Errorf("error unmarshalling ReplicaSet: %v", err) 155 } 156 return &r, nil 157 } 158 159 // GetPersistentVolume returns the persistent volume with the given name. 160 // If not found, returns an error. 161 func (k RemoteKubectl) GetPersistentVolume(name string) (*PersistentVolume, error) { 162 cmd := fmt.Sprintf("sudo kubectl --kubeconfig /root/.kube/config get pv -o json %s", name) 163 raw, err := k.SSHClient.Output(true, cmd) 164 if err != nil { 165 return nil, fmt.Errorf("error getting PersistentVolume: %v", err) 166 } 167 if isNoResourcesResponse(raw) { 168 return nil, fmt.Errorf("PersistentVolume %s was not found", name) 169 } 170 var p PersistentVolume 171 if err := json.Unmarshal([]byte(raw), &p); err != nil { 172 return nil, fmt.Errorf("error unmarshalling PersistentVolume: %v", err) 173 } 174 return &p, nil 175 } 176 177 // GetPersistentVolumeClaim returns the persistent volume claim with the given name and namespace. 178 // If not found, returns an error. 179 func (k RemoteKubectl) GetPersistentVolumeClaim(namespace, name string) (*PersistentVolumeClaim, error) { 180 cmd := fmt.Sprintf("sudo kubectl --kubeconfig /root/.kube/config get pvc --namespace %s -o json %s", namespace, name) 181 raw, err := k.SSHClient.Output(true, cmd) 182 if err != nil { 183 return nil, fmt.Errorf("error getting PersistentVolumeClaim: %v", err) 184 } 185 if isNoResourcesResponse(raw) { 186 return nil, fmt.Errorf("PersistentVolumeClaim %s was not found", name) 187 } 188 var p PersistentVolumeClaim 189 if err := json.Unmarshal([]byte(raw), &p); err != nil { 190 return nil, fmt.Errorf("error unmarshalling PersistentVolumeClaim: %v", err) 191 } 192 return &p, nil 193 } 194 195 // GetStatefulSet returns the stateful set with the given name in the given namespace. 196 // If not found, returns an error. 197 func (k RemoteKubectl) GetStatefulSet(namespace, name string) (*StatefulSet, error) { 198 cmd := fmt.Sprintf("sudo kubectl --kubeconfig /root/.kube/config get statefulset --namespace %s -o json %s", namespace, name) 199 raw, err := k.SSHClient.Output(true, cmd) 200 if err != nil { 201 return nil, fmt.Errorf("error getting StatefulSet: %v", err) 202 } 203 if isNoResourcesResponse(raw) { 204 return nil, fmt.Errorf("StatefulSet %s/%s was not found", namespace, name) 205 } 206 var s StatefulSet 207 if err := json.Unmarshal([]byte(raw), &s); err != nil { 208 return nil, fmt.Errorf("error unmarshalling StatefulSet: %v", err) 209 } 210 return &s, nil 211 } 212 213 // kubectl will print this message when no resources are returned 214 func isNoResourcesResponse(s string) bool { 215 if strings.Contains(strings.TrimSpace(s), "No resources found") { 216 return true 217 } 218 return false 219 }