GitOps for k8s
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

resourcekinds.go 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. package kubernetes
  2. import (
  3. "fmt"
  4. apiapps "k8s.io/api/apps/v1beta1"
  5. apibatch "k8s.io/api/batch/v1beta1"
  6. apiv1 "k8s.io/api/core/v1"
  7. apiext "k8s.io/api/extensions/v1beta1"
  8. meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  9. "github.com/weaveworks/flux"
  10. "github.com/weaveworks/flux/cluster"
  11. "github.com/weaveworks/flux/image"
  12. "github.com/weaveworks/flux/resource"
  13. )
  14. /////////////////////////////////////////////////////////////////////////////
  15. // Kind registry
  16. type resourceKind interface {
  17. getPodController(c *Cluster, namespace, name string) (podController, error)
  18. getPodControllers(c *Cluster, namespace string) ([]podController, error)
  19. }
  20. var (
  21. resourceKinds = make(map[string]resourceKind)
  22. )
  23. func init() {
  24. resourceKinds["cronjob"] = &cronJobKind{}
  25. resourceKinds["daemonset"] = &daemonSetKind{}
  26. resourceKinds["deployment"] = &deploymentKind{}
  27. resourceKinds["statefulset"] = &statefulSetKind{}
  28. }
  29. type podController struct {
  30. apiVersion string
  31. kind string
  32. name string
  33. status string
  34. podTemplate apiv1.PodTemplateSpec
  35. apiObject interface{}
  36. }
  37. func (pc podController) toClusterController(resourceID flux.ResourceID) cluster.Controller {
  38. var clusterContainers []resource.Container
  39. var excuse string
  40. for _, container := range pc.podTemplate.Spec.Containers {
  41. ref, err := image.ParseRef(container.Image)
  42. if err != nil {
  43. clusterContainers = nil
  44. excuse = err.Error()
  45. break
  46. }
  47. clusterContainers = append(clusterContainers, resource.Container{Name: container.Name, Image: ref})
  48. }
  49. return cluster.Controller{
  50. ID: resourceID,
  51. Status: pc.status,
  52. Containers: cluster.ContainersOrExcuse{Containers: clusterContainers, Excuse: excuse},
  53. }
  54. }
  55. func (pc podController) GetNamespace() string {
  56. objectMeta := pc.apiObject.(namespacedLabeled)
  57. return objectMeta.GetNamespace()
  58. }
  59. func (pc podController) GetLabels() map[string]string {
  60. objectMeta := pc.apiObject.(namespacedLabeled)
  61. return objectMeta.GetLabels()
  62. }
  63. /////////////////////////////////////////////////////////////////////////////
  64. // extensions/v1beta1 Deployment
  65. type deploymentKind struct{}
  66. func (dk *deploymentKind) getPodController(c *Cluster, namespace, name string) (podController, error) {
  67. deployment, err := c.client.Deployments(namespace).Get(name, meta_v1.GetOptions{})
  68. if err != nil {
  69. return podController{}, err
  70. }
  71. return makeDeploymentPodController(deployment), nil
  72. }
  73. func (dk *deploymentKind) getPodControllers(c *Cluster, namespace string) ([]podController, error) {
  74. deployments, err := c.client.Deployments(namespace).List(meta_v1.ListOptions{})
  75. if err != nil {
  76. return nil, err
  77. }
  78. var podControllers []podController
  79. for i := range deployments.Items {
  80. podControllers = append(podControllers, makeDeploymentPodController(&deployments.Items[i]))
  81. }
  82. return podControllers, nil
  83. }
  84. func makeDeploymentPodController(deployment *apiext.Deployment) podController {
  85. var status string
  86. objectMeta, deploymentStatus := deployment.ObjectMeta, deployment.Status
  87. if deploymentStatus.ObservedGeneration >= objectMeta.Generation {
  88. // the definition has been updated; now let's see about the replicas
  89. updated, wanted := deploymentStatus.UpdatedReplicas, *deployment.Spec.Replicas
  90. if updated == wanted {
  91. status = StatusReady
  92. } else {
  93. status = fmt.Sprintf("%d out of %d updated", updated, wanted)
  94. }
  95. } else {
  96. status = StatusUpdating
  97. }
  98. return podController{
  99. apiVersion: "extensions/v1beta1",
  100. kind: "Deployment",
  101. name: deployment.ObjectMeta.Name,
  102. status: status,
  103. podTemplate: deployment.Spec.Template,
  104. apiObject: deployment}
  105. }
  106. /////////////////////////////////////////////////////////////////////////////
  107. // extensions/v1beta daemonset
  108. type daemonSetKind struct{}
  109. func (dk *daemonSetKind) getPodController(c *Cluster, namespace, name string) (podController, error) {
  110. daemonSet, err := c.client.DaemonSets(namespace).Get(name, meta_v1.GetOptions{})
  111. if err != nil {
  112. return podController{}, err
  113. }
  114. return makeDaemonSetPodController(daemonSet), nil
  115. }
  116. func (dk *daemonSetKind) getPodControllers(c *Cluster, namespace string) ([]podController, error) {
  117. daemonSets, err := c.client.DaemonSets(namespace).List(meta_v1.ListOptions{})
  118. if err != nil {
  119. return nil, err
  120. }
  121. var podControllers []podController
  122. for i, _ := range daemonSets.Items {
  123. podControllers = append(podControllers, makeDaemonSetPodController(&daemonSets.Items[i]))
  124. }
  125. return podControllers, nil
  126. }
  127. func makeDaemonSetPodController(daemonSet *apiext.DaemonSet) podController {
  128. var status string
  129. objectMeta, daemonSetStatus := daemonSet.ObjectMeta, daemonSet.Status
  130. if daemonSetStatus.ObservedGeneration >= objectMeta.Generation {
  131. // the definition has been updated; now let's see about the replicas
  132. updated, wanted := daemonSetStatus.UpdatedNumberScheduled, daemonSetStatus.DesiredNumberScheduled
  133. if updated == wanted {
  134. status = StatusReady
  135. } else {
  136. status = fmt.Sprintf("%d out of %d updated", updated, wanted)
  137. }
  138. } else {
  139. status = StatusUpdating
  140. }
  141. return podController{
  142. apiVersion: "extensions/v1beta1",
  143. kind: "DaemonSet",
  144. name: daemonSet.ObjectMeta.Name,
  145. status: status,
  146. podTemplate: daemonSet.Spec.Template,
  147. apiObject: daemonSet}
  148. }
  149. /////////////////////////////////////////////////////////////////////////////
  150. // apps/v1beta1 StatefulSet
  151. type statefulSetKind struct{}
  152. func (dk *statefulSetKind) getPodController(c *Cluster, namespace, name string) (podController, error) {
  153. statefulSet, err := c.client.StatefulSets(namespace).Get(name, meta_v1.GetOptions{})
  154. if err != nil {
  155. return podController{}, err
  156. }
  157. return makeStatefulSetPodController(statefulSet), nil
  158. }
  159. func (dk *statefulSetKind) getPodControllers(c *Cluster, namespace string) ([]podController, error) {
  160. statefulSets, err := c.client.StatefulSets(namespace).List(meta_v1.ListOptions{})
  161. if err != nil {
  162. return nil, err
  163. }
  164. var podControllers []podController
  165. for i, _ := range statefulSets.Items {
  166. podControllers = append(podControllers, makeStatefulSetPodController(&statefulSets.Items[i]))
  167. }
  168. return podControllers, nil
  169. }
  170. func makeStatefulSetPodController(statefulSet *apiapps.StatefulSet) podController {
  171. var status string
  172. objectMeta, statefulSetStatus := statefulSet.ObjectMeta, statefulSet.Status
  173. if *statefulSetStatus.ObservedGeneration >= objectMeta.Generation {
  174. // the definition has been updated; now let's see about the replicas
  175. updated, wanted := statefulSetStatus.UpdatedReplicas, *statefulSet.Spec.Replicas
  176. if updated == wanted {
  177. status = StatusReady
  178. } else {
  179. status = fmt.Sprintf("%d out of %d updated", updated, wanted)
  180. }
  181. } else {
  182. status = StatusUpdating
  183. }
  184. return podController{
  185. apiVersion: "apps/v1beta1",
  186. kind: "StatefulSet",
  187. name: statefulSet.ObjectMeta.Name,
  188. status: status,
  189. podTemplate: statefulSet.Spec.Template,
  190. apiObject: statefulSet}
  191. }
  192. /////////////////////////////////////////////////////////////////////////////
  193. // batch/v1beta1 CronJob
  194. type cronJobKind struct{}
  195. func (dk *cronJobKind) getPodController(c *Cluster, namespace, name string) (podController, error) {
  196. cronJob, err := c.client.CronJobs(namespace).Get(name, meta_v1.GetOptions{})
  197. if err != nil {
  198. return podController{}, err
  199. }
  200. return makeCronJobPodController(cronJob), nil
  201. }
  202. func (dk *cronJobKind) getPodControllers(c *Cluster, namespace string) ([]podController, error) {
  203. cronJobs, err := c.client.CronJobs(namespace).List(meta_v1.ListOptions{})
  204. if err != nil {
  205. return nil, err
  206. }
  207. var podControllers []podController
  208. for i, _ := range cronJobs.Items {
  209. podControllers = append(podControllers, makeCronJobPodController(&cronJobs.Items[i]))
  210. }
  211. return podControllers, nil
  212. }
  213. func makeCronJobPodController(cronJob *apibatch.CronJob) podController {
  214. return podController{
  215. apiVersion: "batch/v1beta1",
  216. kind: "CronJob",
  217. name: cronJob.ObjectMeta.Name,
  218. status: StatusReady,
  219. podTemplate: cronJob.Spec.JobTemplate.Spec.Template,
  220. apiObject: cronJob}
  221. }
  222. /////////////////////////////////////////////////////////////////////////////
  223. //