diff --git a/cluster/kubernetes/resource/resource.go b/cluster/kubernetes/resource/resource.go index 91fffcbc6..63489c59b 100644 --- a/cluster/kubernetes/resource/resource.go +++ b/cluster/kubernetes/resource/resource.go @@ -85,6 +85,12 @@ func unmarshalObject(source string, bytes []byte) (resource.Resource, error) { return nil, err } return &ns, nil + case "StatefulSet": + var ss = StatefulSet{baseObject: base} + if err := yaml.Unmarshal(bytes, &ss); err != nil { + return nil, err + } + return &ss, nil // The remainder are things we have to care about, but not // treat specially default: diff --git a/cluster/kubernetes/resource/statefulset.go b/cluster/kubernetes/resource/statefulset.go new file mode 100644 index 000000000..16ca8ffb6 --- /dev/null +++ b/cluster/kubernetes/resource/statefulset.go @@ -0,0 +1,11 @@ +package resource + +type StatefulSet struct { + baseObject + Spec StatefulSetSpec +} + +type StatefulSetSpec struct { + Replicas int + Template PodTemplate +} diff --git a/cluster/kubernetes/resourcekinds.go b/cluster/kubernetes/resourcekinds.go index b44e31c44..6f7c49e76 100644 --- a/cluster/kubernetes/resourcekinds.go +++ b/cluster/kubernetes/resourcekinds.go @@ -5,6 +5,7 @@ import ( meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" apiv1 "k8s.io/client-go/pkg/api/v1" + apiapps "k8s.io/client-go/pkg/apis/apps/v1beta1" apiext "k8s.io/client-go/pkg/apis/extensions/v1beta1" "github.com/weaveworks/flux" @@ -26,6 +27,7 @@ var ( func init() { resourceKinds["deployment"] = &deploymentKind{} resourceKinds["daemonset"] = &daemonSetKind{} + resourceKinds["statefulset"] = &statefulSetKind{} } type podController struct { @@ -164,5 +166,57 @@ func makeDaemonSetPodController(daemonSet *apiext.DaemonSet) podController { apiObject: daemonSet} } +///////////////////////////////////////////////////////////////////////////// +// apps/v1beta1 StatefulSet + +type statefulSetKind struct{} + +func (dk *statefulSetKind) getPodController(c *Cluster, namespace, name string) (podController, error) { + statefulSet, err := c.client.StatefulSets(namespace).Get(name, meta_v1.GetOptions{}) + if err != nil { + return podController{}, err + } + + return makeStatefulSetPodController(statefulSet), nil +} + +func (dk *statefulSetKind) getPodControllers(c *Cluster, namespace string) ([]podController, error) { + statefulSets, err := c.client.StatefulSets(namespace).List(meta_v1.ListOptions{}) + if err != nil { + return nil, err + } + + var podControllers []podController + for _, statefulSet := range statefulSets.Items { + podControllers = append(podControllers, makeStatefulSetPodController(&statefulSet)) + } + + return podControllers, nil +} + +func makeStatefulSetPodController(statefulSet *apiapps.StatefulSet) podController { + var status string + objectMeta, statefulSetStatus := statefulSet.ObjectMeta, statefulSet.Status + if *statefulSetStatus.ObservedGeneration >= objectMeta.Generation { + // the definition has been updated; now let's see about the replicas + updated, wanted := statefulSetStatus.UpdatedReplicas, *statefulSet.Spec.Replicas + if updated == wanted { + status = StatusReady + } else { + status = fmt.Sprintf("%d out of %d updated", updated, wanted) + } + } else { + status = StatusUpdating + } + + return podController{ + apiVersion: "apps/v1beta1", + kind: "StatefulSet", + name: statefulSet.ObjectMeta.Name, + status: status, + podTemplate: statefulSet.Spec.Template, + apiObject: statefulSet} +} + ///////////////////////////////////////////////////////////////////////////// // diff --git a/remote/rpc/clientV8.go b/remote/rpc/clientV8.go index f36418631..828a781a6 100644 --- a/remote/rpc/clientV8.go +++ b/remote/rpc/clientV8.go @@ -19,7 +19,7 @@ type RPCClientV8 struct { var _ remote.PlatformV6 = &RPCClientV8{} -var supportedKindsV8 = []string{"deployment", "daemonset"} +var supportedKindsV8 = []string{"deployment", "daemonset", "statefulset"} // NewClient creates a new rpc-backed implementation of the platform. func NewClientV8(conn io.ReadWriteCloser) *RPCClientV8 {