mirror of https://github.com/kubernetes/kops.git
199 lines
7.1 KiB
Go
199 lines
7.1 KiB
Go
/*
|
|
Copyright 2017 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package api
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/golang/glog"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/kops/pkg/apis/kops"
|
|
"k8s.io/kops/pkg/apis/kops/registry"
|
|
"k8s.io/kops/pkg/apis/kops/validation"
|
|
kopsinternalversion "k8s.io/kops/pkg/client/clientset_generated/clientset/typed/kops/internalversion"
|
|
"k8s.io/kops/pkg/client/simple/vfsclientset"
|
|
"k8s.io/kops/upup/pkg/fi"
|
|
"k8s.io/kops/upup/pkg/fi/secrets"
|
|
"k8s.io/kops/util/pkg/vfs"
|
|
"k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/api/errors"
|
|
)
|
|
|
|
// RESTClientset is an implementation of clientset that uses a "real" generated REST client
|
|
type RESTClientset struct {
|
|
BaseURL *url.URL
|
|
KopsClient kopsinternalversion.KopsInterface
|
|
}
|
|
|
|
// GetCluster implements the GetCluster method of Clientset for a kubernetes-API state store
|
|
func (c *RESTClientset) GetCluster(name string) (*kops.Cluster, error) {
|
|
namespace := restNamespaceForClusterName(name)
|
|
return c.KopsClient.Clusters(namespace).Get(name, metav1.GetOptions{})
|
|
}
|
|
|
|
// CreateCluster implements the CreateCluster method of Clientset for a kubernetes-API state store
|
|
func (c *RESTClientset) CreateCluster(cluster *kops.Cluster) (*kops.Cluster, error) {
|
|
namespace := restNamespaceForClusterName(cluster.Name)
|
|
return c.KopsClient.Clusters(namespace).Create(cluster)
|
|
}
|
|
|
|
// UpdateCluster implements the UpdateCluster method of Clientset for a kubernetes-API state store
|
|
func (c *RESTClientset) UpdateCluster(cluster *kops.Cluster, status *kops.ClusterStatus) (*kops.Cluster, error) {
|
|
glog.Warningf("validating cluster update client side; needs to move to server")
|
|
old, err := c.GetCluster(cluster.Name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := validation.ValidateClusterUpdate(cluster, status, old).ToAggregate(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
namespace := restNamespaceForClusterName(cluster.Name)
|
|
return c.KopsClient.Clusters(namespace).Update(cluster)
|
|
}
|
|
|
|
// ConfigBaseFor implements the ConfigBaseFor method of Clientset for a kubernetes-API state store
|
|
func (c *RESTClientset) ConfigBaseFor(cluster *kops.Cluster) (vfs.Path, error) {
|
|
if cluster.Spec.ConfigBase != "" {
|
|
return vfs.Context.BuildVfsPath(cluster.Spec.ConfigBase)
|
|
}
|
|
// URL for clusters looks like https://<server>/apis/kops/v1alpha2/namespaces/<cluster>/clusters/<cluster>
|
|
// We probably want to add a subresource for full resources
|
|
return vfs.Context.BuildVfsPath(c.BaseURL.String())
|
|
}
|
|
|
|
// ListClusters implements the ListClusters method of Clientset for a kubernetes-API state store
|
|
func (c *RESTClientset) ListClusters(options metav1.ListOptions) (*kops.ClusterList, error) {
|
|
return c.KopsClient.Clusters(metav1.NamespaceAll).List(options)
|
|
}
|
|
|
|
// InstanceGroupsFor implements the InstanceGroupsFor method of Clientset for a kubernetes-API state store
|
|
func (c *RESTClientset) InstanceGroupsFor(cluster *kops.Cluster) kopsinternalversion.InstanceGroupInterface {
|
|
namespace := restNamespaceForClusterName(cluster.Name)
|
|
return c.KopsClient.InstanceGroups(namespace)
|
|
}
|
|
|
|
// FederationsFor implements the FederationsFor method of Clientset for a kubernetes-API state store
|
|
func (c *RESTClientset) FederationsFor(federation *kops.Federation) kopsinternalversion.FederationInterface {
|
|
// Unsure if this should be namespaced or not - probably, so that we can RBAC it...
|
|
panic("Federations are currently not supported by the server API")
|
|
//namespace := restNamespaceForFederationName(federation.Name)
|
|
//return c.KopsClient.Federations(namespace)
|
|
}
|
|
|
|
// ListFederations implements the ListFederations method of Clientset for a kubernetes-API state store
|
|
func (c *RESTClientset) ListFederations(options metav1.ListOptions) (*kops.FederationList, error) {
|
|
return c.KopsClient.Federations(metav1.NamespaceAll).List(options)
|
|
}
|
|
|
|
// GetFederation implements the GetFederation method of Clientset for a kubernetes-API state store
|
|
func (c *RESTClientset) GetFederation(name string) (*kops.Federation, error) {
|
|
namespace := restNamespaceForFederationName(name)
|
|
return c.KopsClient.Federations(namespace).Get(name, metav1.GetOptions{})
|
|
}
|
|
|
|
func (c *RESTClientset) SecretStore(cluster *kops.Cluster) (fi.SecretStore, error) {
|
|
namespace := restNamespaceForClusterName(cluster.Name)
|
|
return secrets.NewClientsetSecretStore(cluster, c.KopsClient, namespace), nil
|
|
}
|
|
|
|
func (c *RESTClientset) KeyStore(cluster *kops.Cluster) (fi.CAStore, error) {
|
|
namespace := restNamespaceForClusterName(cluster.Name)
|
|
return fi.NewClientsetCAStore(cluster, c.KopsClient, namespace), nil
|
|
}
|
|
|
|
func (c *RESTClientset) DeleteCluster(cluster *kops.Cluster) error {
|
|
configBase, err := registry.ConfigBase(cluster)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = vfsclientset.DeleteAllClusterState(configBase)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
name := cluster.Name
|
|
namespace := restNamespaceForClusterName(name)
|
|
|
|
{
|
|
keysets, err := c.KopsClient.Keysets(namespace).List(metav1.ListOptions{})
|
|
if err != nil {
|
|
return fmt.Errorf("error listing Keysets: %v", err)
|
|
}
|
|
|
|
for i := range keysets.Items {
|
|
keyset := &keysets.Items[i]
|
|
err = c.KopsClient.Keysets(namespace).Delete(keyset.Name, &metav1.DeleteOptions{})
|
|
if err != nil {
|
|
if errors.IsNotFound(err) {
|
|
// Unlikely...
|
|
glog.Warningf("Keyset was concurrently deleted")
|
|
} else {
|
|
return fmt.Errorf("error deleting Keyset %q: %v", keyset.Name, err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
igs, err := c.KopsClient.InstanceGroups(namespace).List(metav1.ListOptions{})
|
|
if err != nil {
|
|
return fmt.Errorf("error listing instance groups: %v", err)
|
|
}
|
|
|
|
for i := range igs.Items {
|
|
ig := &igs.Items[i]
|
|
err = c.KopsClient.InstanceGroups(namespace).Delete(ig.Name, &metav1.DeleteOptions{})
|
|
if err != nil {
|
|
if errors.IsNotFound(err) {
|
|
// Unlikely...
|
|
glog.Warningf("instance group was concurrently deleted")
|
|
} else {
|
|
return fmt.Errorf("error deleting instance group %q: %v", ig.Name, err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
err = c.KopsClient.Clusters(namespace).Delete(name, &metav1.DeleteOptions{})
|
|
if err != nil {
|
|
if errors.IsNotFound(err) {
|
|
// Unlikely...
|
|
glog.Warningf("cluster %q was concurrently deleted", name)
|
|
} else {
|
|
return fmt.Errorf("error deleting cluster%q: %v", name, err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func restNamespaceForClusterName(clusterName string) string {
|
|
// We are not allowed dots, so we map them to dashes
|
|
// This can conflict, but this will simply be a limitation that we pass on to the user
|
|
// i.e. it will not be possible to create a.b.example.com and a-b.example.com
|
|
namespace := strings.Replace(clusterName, ".", "-", -1)
|
|
return namespace
|
|
}
|
|
|
|
func restNamespaceForFederationName(clusterName string) string {
|
|
namespace := strings.Replace(clusterName, ".", "-", -1)
|
|
return namespace
|
|
}
|