Support generated clientset as alternative to vfs clientset

We modelled our VFS clientset (for API objects backed by a VFS path)
after the "real" clientsets, so now it is relatively easy to add a
second implementation that will be backed by a real clientset.

The snafu here is that we weren't really using namespaces previously.
Namespaces do seem to be the primary RBAC scoping mechanism though, so
we start using them with the real clientset.

The namespace is currently inferred from the cluster name.  We map dots
to dashes, because of namespace limitations, which could yield
collisions, but we'll deal with this by simply preventing users from
creating conflicting cluster names - i.e. you simply won't be able to
create a.b.example.com and a-b.example.com
This commit is contained in:
Justin Santa Barbara 2017-05-22 10:34:00 -04:00
parent 98ae12a152
commit e945322cab
56 changed files with 542 additions and 200 deletions

View File

@ -481,6 +481,8 @@ apimachinery:
#cd pkg/apis/kops/v1alpha2/ && ~/k8s/bin/codecgen -d 1234 -o types.generated.go instancegroup.go cluster.go federation.go
#cd pkg/apis/kops/v1alpha1/ && ~/k8s/bin/codecgen -d 1234 -o types.generated.go instancegroup.go cluster.go federation.go
#cd pkg/apis/kops/ && ~/k8s/bin/codecgen -d 1234 -o types.generated.go instancegroup.go cluster.go federation.go
${GOPATH}/bin/client-gen --input-base k8s.io/kops/pkg/apis/ --input="kops/,kops/v1alpha1,kops/v1alpha2" --clientset-path k8s.io/kops/pkg/client/clientset_generated/
${GOPATH}/bin/client-gen --clientset-name="clientset" --input-base k8s.io/kops/pkg/apis/ --input="kops/,kops/v1alpha1,kops/v1alpha2" --clientset-path k8s.io/kops/pkg/client/clientset_generated/
# -----------------------------------------------------

View File

@ -17,11 +17,10 @@ limitations under the License.
package main
import (
"bytes"
"fmt"
"io"
"bytes"
"github.com/golang/glog"
"github.com/spf13/cobra"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@ -140,7 +139,7 @@ func RunCreate(f *util.Factory, out io.Writer, c *CreateOptions) error {
switch v := o.(type) {
case *kopsapi.Federation:
_, err = clientset.Federations().Create(v)
_, err = clientset.FederationsFor(v).Create(v)
if err != nil {
if apierrors.IsAlreadyExists(err) {
return fmt.Errorf("federation %q already exists", v.ObjectMeta.Name)
@ -156,7 +155,7 @@ func RunCreate(f *util.Factory, out io.Writer, c *CreateOptions) error {
if err != nil {
return fmt.Errorf("error populating configuration: %v", err)
}
_, err = clientset.Clusters().Create(v)
_, err = clientset.ClustersFor(v).Create(v)
if err != nil {
if apierrors.IsAlreadyExists(err) {
return fmt.Errorf("cluster %q already exists", v.ObjectMeta.Name)
@ -172,7 +171,12 @@ func RunCreate(f *util.Factory, out io.Writer, c *CreateOptions) error {
if clusterName == "" {
return fmt.Errorf("must specify %q label with cluster name to create instanceGroup", kopsapi.LabelClusterName)
}
_, err = clientset.InstanceGroups(clusterName).Create(v)
cluster, err := clientset.GetCluster(clusterName)
if err != nil {
return fmt.Errorf("error querying cluster %q: %v", clusterName, err)
}
_, err = clientset.InstanceGroupsFor(cluster).Create(v)
if err != nil {
if apierrors.IsAlreadyExists(err) {
return fmt.Errorf("instanceGroup %q already exists", v.ObjectMeta.Name)

View File

@ -27,13 +27,13 @@ import (
"github.com/golang/glog"
"github.com/spf13/cobra"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kops"
"k8s.io/kops/cmd/kops/util"
api "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/apis/kops/registry"
"k8s.io/kops/pkg/apis/kops/validation"
"k8s.io/kops/pkg/client/simple/vfsclientset"
"k8s.io/kops/pkg/dns"
"k8s.io/kops/pkg/featureflag"
"k8s.io/kops/upup/pkg/fi"
@ -328,9 +328,13 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e
return err
}
cluster, err := clientset.Clusters().Get(clusterName)
cluster, err := clientset.GetCluster(clusterName)
if err != nil {
return err
if apierrors.IsNotFound(err) {
cluster = nil
} else {
return err
}
}
if cluster != nil {
@ -338,6 +342,7 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e
}
cluster = &api.Cluster{}
cluster.ObjectMeta.Name = clusterName
channel, err := api.LoadChannel(c.Channel)
if err != nil {
@ -354,7 +359,7 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e
}
cluster.Spec.Channel = c.Channel
configBase, err := clientset.Clusters().(*vfsclientset.ClusterVFS).ConfigBase(clusterName)
configBase, err := clientset.ConfigBaseFor(cluster)
if err != nil {
return fmt.Errorf("error building ConfigBase for cluster: %v", err)
}
@ -640,10 +645,6 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e
cluster.Spec.Project = c.Project
}
if clusterName != "" {
cluster.ObjectMeta.Name = clusterName
}
if c.KubernetesVersion != "" {
cluster.Spec.KubernetesVersion = c.KubernetesVersion
}

View File

@ -120,7 +120,7 @@ func runCreateClusterIntegrationTest(t *testing.T, srcDir string, version string
}
// Compare cluster
clusters, err := clientset.Clusters().List(metav1.ListOptions{})
clusters, err := clientset.ListClusters(metav1.ListOptions{})
if err != nil {
t.Fatalf("error listing clusters: %v", err)
}
@ -144,7 +144,7 @@ func runCreateClusterIntegrationTest(t *testing.T, srcDir string, version string
// Compare instance groups
instanceGroups, err := clientset.InstanceGroups(clusters.Items[0].ObjectMeta.Name).List(metav1.ListOptions{})
instanceGroups, err := clientset.InstanceGroupsFor(&clusters.Items[0]).List(metav1.ListOptions{})
if err != nil {
t.Fatalf("error listing instance groups: %v", err)
}

View File

@ -25,6 +25,7 @@ import (
"strings"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kops/cmd/kops/util"
api "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/apis/kops/validation"
@ -111,7 +112,7 @@ func RunCreateInstanceGroup(f *util.Factory, cmd *cobra.Command, args []string,
return err
}
existing, err := clientset.InstanceGroups(cluster.ObjectMeta.Name).Get(groupName)
existing, err := clientset.InstanceGroupsFor(cluster).Get(groupName, metav1.GetOptions{})
if err != nil {
return err
}
@ -175,7 +176,7 @@ func RunCreateInstanceGroup(f *util.Factory, cmd *cobra.Command, args []string,
return err
}
_, err = clientset.InstanceGroups(cluster.ObjectMeta.Name).Create(group)
_, err = clientset.InstanceGroupsFor(cluster).Create(group)
if err != nil {
return fmt.Errorf("error storing InstanceGroup: %v", err)
}

View File

@ -23,6 +23,7 @@ import (
"os"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kops/cmd/kops/util"
"k8s.io/kops/pkg/instancegroups"
"k8s.io/kops/upup/pkg/fi/cloudup"
@ -129,7 +130,7 @@ func RunDeleteInstanceGroup(f *util.Factory, out io.Writer, options *DeleteInsta
return err
}
group, err := clientset.InstanceGroups(cluster.ObjectMeta.Name).Get(groupName)
group, err := clientset.InstanceGroupsFor(cluster).Get(groupName, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("error reading InstanceGroup %q: %v", groupName, err)
}

View File

@ -97,7 +97,7 @@ func RunEditCluster(f *util.Factory, cmd *cobra.Command, args []string, out io.W
return err
}
list, err := clientset.InstanceGroups(oldCluster.ObjectMeta.Name).List(metav1.ListOptions{})
list, err := clientset.InstanceGroupsFor(oldCluster).List(metav1.ListOptions{})
if err != nil {
return err
}
@ -235,7 +235,7 @@ func RunEditCluster(f *util.Factory, cmd *cobra.Command, args []string, out io.W
}
// Note we perform as much validation as we can, before writing a bad config
_, err = clientset.Clusters().Update(newCluster)
_, err = clientset.ClustersFor(newCluster).Update(newCluster)
if err != nil {
return preservedFile(err, file, out)
}

View File

@ -93,7 +93,7 @@ func RunEditFederation(f *util.Factory, cmd *cobra.Command, args []string, out i
return fmt.Errorf("name is required")
}
old, err := clientset.Federations().Get(name)
old, err := clientset.GetFederation(name)
if err != nil {
return fmt.Errorf("error reading Federation %q: %v", name, err)
}
@ -144,7 +144,7 @@ func RunEditFederation(f *util.Factory, cmd *cobra.Command, args []string, out i
}
// Note we perform as much validation as we can, before writing a bad config
_, err = clientset.Federations().Update(newFed)
_, err = clientset.FederationsFor(newFed).Update(newFed)
if err != nil {
return err
}

View File

@ -19,12 +19,12 @@ package main
import (
"bytes"
"fmt"
"io"
"os"
"path/filepath"
"io"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kops/cmd/kops/util"
api "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/apis/kops/validation"
@ -105,7 +105,7 @@ func RunEditInstanceGroup(f *util.Factory, cmd *cobra.Command, args []string, ou
return fmt.Errorf("name is required")
}
oldGroup, err := clientset.InstanceGroups(cluster.ObjectMeta.Name).Get(groupName)
oldGroup, err := clientset.InstanceGroupsFor(cluster).Get(groupName, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("error reading InstanceGroup %q: %v", groupName, err)
}
@ -177,7 +177,7 @@ func RunEditInstanceGroup(f *util.Factory, cmd *cobra.Command, args []string, ou
}
// Note we perform as much validation as we can, before writing a bad config
_, err = clientset.InstanceGroups(cluster.ObjectMeta.Name).Update(fullGroup)
_, err = clientset.InstanceGroupsFor(cluster).Update(fullGroup)
if err != nil {
return err
}

View File

@ -121,7 +121,7 @@ func RunGet(context Factory, out io.Writer, options *GetOptions) error {
return err
}
cluster, err := client.Clusters().Get(options.clusterName)
cluster, err := client.GetCluster(options.clusterName)
if err != nil {
return err
}
@ -139,7 +139,7 @@ func RunGet(context Factory, out io.Writer, options *GetOptions) error {
clusters, err := buildClusters(args, clusterList)
ig, err := client.InstanceGroups(options.clusterName).List(metav1.ListOptions{})
ig, err := client.InstanceGroupsFor(cluster).List(metav1.ListOptions{})
if err != nil {
return err
}

View File

@ -100,7 +100,7 @@ func RunGetClusters(context Factory, out io.Writer, options *GetClusterOptions)
return err
}
clusterList, err := client.Clusters().List(metav1.ListOptions{})
clusterList, err := client.ListClusters(metav1.ListOptions{})
if err != nil {
return err
}

View File

@ -73,7 +73,7 @@ func RunGetFederations(context Factory, out io.Writer, options *GetFederationOpt
return err
}
list, err := client.Federations().List(metav1.ListOptions{})
list, err := client.ListFederations(metav1.ListOptions{})
if err != nil {
return err
}

View File

@ -85,7 +85,12 @@ func RunGetInstanceGroups(options *GetInstanceGroupsOptions, args []string) erro
return err
}
list, err := clientset.InstanceGroups(clusterName).List(metav1.ListOptions{})
cluster, err := clientset.GetCluster(clusterName)
if err != nil {
return fmt.Errorf("error fetching cluster %q: %v", cluster, err)
}
list, err := clientset.InstanceGroupsFor(cluster).List(metav1.ListOptions{})
if err != nil {
return err
}

View File

@ -69,7 +69,7 @@ func (c *ImportClusterCmd) Run() error {
return err
}
cluster, err := clientset.Clusters().Get(clusterName)
cluster, err := clientset.GetCluster(clusterName)
if err != nil {
return err
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package main
import (
"bytes"
"fmt"
"io"
@ -25,8 +26,6 @@ import (
"k8s.io/kops/cmd/kops/util"
"k8s.io/kops/util/pkg/vfs"
"bytes"
kopsapi "k8s.io/kops/pkg/apis/kops"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@ -101,13 +100,13 @@ func RunReplace(f *util.Factory, cmd *cobra.Command, out io.Writer, c *ReplaceOp
switch v := o.(type) {
case *kopsapi.Federation:
_, err = clientset.Federations().Update(v)
_, err = clientset.FederationsFor(v).Update(v)
if err != nil {
return fmt.Errorf("error replacing federation: %v", err)
}
case *kopsapi.Cluster:
_, err = clientset.Clusters().Update(v)
_, err = clientset.ClustersFor(v).Update(v)
if err != nil {
return fmt.Errorf("error replacing cluster: %v", err)
}
@ -117,7 +116,11 @@ func RunReplace(f *util.Factory, cmd *cobra.Command, out io.Writer, c *ReplaceOp
if clusterName == "" {
return fmt.Errorf("must specify %q label with cluster name to replace instanceGroup", kopsapi.LabelClusterName)
}
_, err = clientset.InstanceGroups(clusterName).Update(v)
cluster, err := clientset.GetCluster(clusterName)
if err != nil {
return fmt.Errorf("error fetching cluster %q: %v", clusterName, err)
}
_, err = clientset.InstanceGroupsFor(cluster).Update(v)
if err != nil {
return fmt.Errorf("error replacing instanceGroup: %v", err)
}

View File

@ -225,7 +225,7 @@ func RunRollingUpdateCluster(f *util.Factory, out io.Writer, options *RollingUpd
}
}
list, err := clientset.InstanceGroups(cluster.ObjectMeta.Name).List(metav1.ListOptions{})
list, err := clientset.InstanceGroupsFor(cluster).List(metav1.ListOptions{})
if err != nil {
return err
}

View File

@ -277,7 +277,7 @@ func GetCluster(factory *util.Factory, clusterName string) (*kopsapi.Cluster, er
return nil, err
}
cluster, err := clientset.Clusters().Get(clusterName)
cluster, err := clientset.GetCluster(clusterName)
if err != nil {
return nil, fmt.Errorf("error reading cluster configuration: %v", err)
}

View File

@ -99,12 +99,12 @@ func RunToolboxConvertImported(f *util.Factory, out io.Writer, options *ToolboxC
return fmt.Errorf("ClusterName is required")
}
cluster, err := clientset.Clusters().Get(options.ClusterName)
cluster, err := clientset.GetCluster(options.ClusterName)
if err != nil {
return err
}
list, err := clientset.InstanceGroups(cluster.ObjectMeta.Name).List(metav1.ListOptions{})
list, err := clientset.InstanceGroupsFor(cluster).List(metav1.ListOptions{})
if err != nil {
return err
}

View File

@ -93,7 +93,7 @@ func RunToolboxDump(f *util.Factory, out io.Writer, options *ToolboxDumpOptions)
return fmt.Errorf("ClusterName is required")
}
cluster, err := clientset.Clusters().Get(options.ClusterName)
cluster, err := clientset.GetCluster(options.ClusterName)
if err != nil {
return err
}

View File

@ -174,7 +174,7 @@ func RunUpdateCluster(f *util.Factory, clusterName string, out io.Writer, c *Upd
var instanceGroups []*kops.InstanceGroup
{
list, err := clientset.InstanceGroups(cluster.ObjectMeta.Name).List(metav1.ListOptions{})
list, err := clientset.InstanceGroupsFor(cluster).List(metav1.ListOptions{})
if err != nil {
return err
}

View File

@ -77,7 +77,7 @@ func RunUpdateFederation(factory *util.Factory, cmd *cobra.Command, args []strin
return err
}
f, err := clientset.Federations().Get(name)
f, err := clientset.GetFederation(name)
if err != nil {
return fmt.Errorf("error reading federation %q: %v", name, err)
}

View File

@ -86,7 +86,7 @@ func (c *UpgradeClusterCmd) Run(args []string) error {
return err
}
list, err := clientset.InstanceGroups(cluster.ObjectMeta.Name).List(metav1.ListOptions{})
list, err := clientset.InstanceGroupsFor(cluster).List(metav1.ListOptions{})
if err != nil {
return err
}
@ -294,13 +294,13 @@ func (c *UpgradeClusterCmd) Run(args []string) error {
}
// Note we perform as much validation as we can, before writing a bad config
_, err = clientset.Clusters().Update(cluster)
_, err = clientset.ClustersFor(cluster).Update(cluster)
if err != nil {
return err
}
for _, g := range instanceGroups {
_, err := clientset.InstanceGroups(cluster.ObjectMeta.Name).Update(g)
_, err := clientset.InstanceGroupsFor(cluster).Update(g)
if err != nil {
return fmt.Errorf("error writing InstanceGroup %q: %v", g.ObjectMeta.Name, err)
}

View File

@ -23,8 +23,14 @@ import (
"k8s.io/kops/pkg/client/simple/vfsclientset"
"k8s.io/kops/util/pkg/vfs"
"k8s.io/client-go/rest"
kopsclient "k8s.io/kops/pkg/client/clientset_generated/clientset"
// Register our APIs
"github.com/golang/glog"
_ "k8s.io/kops/pkg/apis/kops/install"
"net/url"
"strings"
)
type FactoryOptions struct {
@ -59,16 +65,46 @@ func (f *Factory) Clientset() (simple.Clientset, error) {
if registryPath == "" {
return nil, field.Required(field.NewPath("State Store"), STATE_ERROR)
}
basePath, err := vfs.Context.BuildVfsPath(registryPath)
if err != nil {
return nil, fmt.Errorf("error building path for %q: %v", registryPath, err)
}
if !vfs.IsClusterReadable(basePath) {
return nil, field.Invalid(field.NewPath("State Store"), registryPath, INVALID_STATE_ERROR)
}
// We recognize a `k8s` scheme; this might change in future so we won't document it yet
// In practice nobody is going to hit this accidentally, so I don't think we need a feature flag.
if strings.HasPrefix(registryPath, "k8s://") {
u, err := url.Parse(registryPath)
if err != nil {
return nil, fmt.Errorf("Invalid kops server url: %q", registryPath)
}
f.clientset = vfsclientset.NewVFSClientset(basePath)
config := &rest.Config{
Host: u.Scheme + "://" + u.Host,
}
glog.Warning("Using insecure TLS")
config.Insecure = true
kopsClient, err := kopsclient.NewForConfig(config)
if err != nil {
return nil, fmt.Errorf("error building kops API client: %v", err)
}
f.clientset = &simple.RESTClientset{
BaseURL: &url.URL{
Scheme: "k8s",
Host: u.Host,
},
KopsClient: kopsClient.Kops(),
}
} else {
basePath, err := vfs.Context.BuildVfsPath(registryPath)
if err != nil {
return nil, fmt.Errorf("error building path for %q: %v", registryPath, err)
}
if !vfs.IsClusterReadable(basePath) {
return nil, field.Invalid(field.NewPath("State Store"), registryPath, INVALID_STATE_ERROR)
}
f.clientset = vfsclientset.NewVFSClientset(basePath)
}
}
return f.clientset, nil

View File

@ -74,7 +74,7 @@ func RunValidateCluster(f *util.Factory, cmd *cobra.Command, args []string, out
return err
}
list, err := clientSet.InstanceGroups(cluster.ObjectMeta.Name).List(metav1.ListOptions{})
list, err := clientSet.InstanceGroupsFor(cluster).List(metav1.ListOptions{})
if err != nil {
return fmt.Errorf("cannot get InstanceGroups for %q: %v", cluster.ObjectMeta.Name, err)
}

View File

@ -24,7 +24,7 @@ import (
func apply() error {
clientset := vfsclientset.NewVFSClientset(registryBase)
cluster, err := clientset.Clusters().Get(clusterName)
cluster, err := clientset.GetCluster(clusterName)
if err != nil {
return err
}

View File

@ -67,7 +67,7 @@ func up() error {
return err
}
_, err := clientset.Clusters().Create(cluster)
_, err := clientset.ClustersFor(cluster).Create(cluster)
if err != nil {
return err
}
@ -80,7 +80,7 @@ func up() error {
Role: api.InstanceGroupRoleMaster,
Subnets: masterZones,
}
_, err := clientset.InstanceGroups(cluster.ObjectMeta.Name).Create(ig)
_, err := clientset.InstanceGroupsFor(cluster).Create(ig)
if err != nil {
return err
}
@ -95,7 +95,7 @@ func up() error {
Subnets: nodeZones,
}
_, err := clientset.InstanceGroups(cluster.ObjectMeta.Name).Create(ig)
_, err := clientset.InstanceGroupsFor(cluster).Create(ig)
if err != nil {
return err
}

View File

@ -67,7 +67,7 @@ func (o *ApplyFederationOperation) FindKubecfg() (*kubeconfig.KubeconfigBuilder,
// Loop through looking for a configured cluster
for _, controller := range o.Federation.Spec.Controllers {
cluster, err := o.KopsClient.Clusters().Get(controller)
cluster, err := o.KopsClient.GetCluster(controller)
if err != nil {
return nil, fmt.Errorf("error reading cluster %q: %v", controller, err)
}
@ -116,7 +116,7 @@ func (o *ApplyFederationOperation) Run() error {
var controllerKubernetesClients []kubernetes.Interface
for _, controller := range o.Federation.Spec.Controllers {
cluster, err := o.KopsClient.Clusters().Get(controller)
cluster, err := o.KopsClient.GetCluster(controller)
if err != nil {
return fmt.Errorf("error reading cluster %q: %v", controller, err)
}
@ -150,7 +150,7 @@ func (o *ApplyFederationOperation) Run() error {
for _, member := range o.Federation.Spec.Members {
glog.V(2).Infof("configuring member cluster %q", member)
cluster, err := o.KopsClient.Clusters().Get(member)
cluster, err := o.KopsClient.GetCluster(member)
if err != nil {
return fmt.Errorf("error reading cluster %q: %v", member, err)
}

View File

@ -34,6 +34,24 @@ k8s.io/kops/pkg/apis/nodeup
k8s.io/kops/pkg/apiserver
k8s.io/kops/pkg/apiserver/cmd/server
k8s.io/kops/pkg/apiserver/registry/cluster
k8s.io/kops/pkg/client/clientset_generated/clientset
k8s.io/kops/pkg/client/clientset_generated/clientset/fake
k8s.io/kops/pkg/client/clientset_generated/clientset/scheme
k8s.io/kops/pkg/client/clientset_generated/clientset/typed/kops/internalversion
k8s.io/kops/pkg/client/clientset_generated/clientset/typed/kops/internalversion/fake
k8s.io/kops/pkg/client/clientset_generated/clientset/typed/kops/v1alpha1
k8s.io/kops/pkg/client/clientset_generated/clientset/typed/kops/v1alpha1/fake
k8s.io/kops/pkg/client/clientset_generated/clientset/typed/kops/v1alpha2
k8s.io/kops/pkg/client/clientset_generated/clientset/typed/kops/v1alpha2/fake
k8s.io/kops/pkg/client/clientset_generated/internalclientset
k8s.io/kops/pkg/client/clientset_generated/internalclientset/fake
k8s.io/kops/pkg/client/clientset_generated/internalclientset/scheme
k8s.io/kops/pkg/client/clientset_generated/internalclientset/typed/kops/internalversion
k8s.io/kops/pkg/client/clientset_generated/internalclientset/typed/kops/internalversion/fake
k8s.io/kops/pkg/client/clientset_generated/internalclientset/typed/kops/v1alpha1
k8s.io/kops/pkg/client/clientset_generated/internalclientset/typed/kops/v1alpha1/fake
k8s.io/kops/pkg/client/clientset_generated/internalclientset/typed/kops/v1alpha2
k8s.io/kops/pkg/client/clientset_generated/internalclientset/typed/kops/v1alpha2/fake
k8s.io/kops/pkg/client/simple
k8s.io/kops/pkg/client/simple/vfsclientset
k8s.io/kops/pkg/diff

View File

@ -33,3 +33,7 @@ cp ${WORK_DIR}/go/bin/conversion-gen ${GOPATH}/bin/
GOPATH=${WORK_DIR}/go/ go install k8s.io/kubernetes/cmd/libs/go2idl/defaulter-gen
cp ${WORK_DIR}/go/bin/defaulter-gen ${GOPATH}/bin/
GOPATH=${WORK_DIR}/go/ go install k8s.io/kubernetes/cmd/libs/go2idl/client-gen
cp ${WORK_DIR}/go/bin/client-gen ${GOPATH}/bin/

View File

@ -22,6 +22,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient=true
type Cluster struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

View File

@ -14,4 +14,5 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// +groupName=kops
package kops // import "k8s.io/kops/pkg/apis/kops"

View File

@ -20,6 +20,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient=true
// Federation represents a federated set of kubernetes clusters
type Federation struct {
metav1.TypeMeta `json:",inline"`

View File

@ -28,6 +28,8 @@ const LabelClusterName = "kops.k8s.io/cluster"
// Deprecated - use the new labels & taints node-role.kubernetes.io/master and node-role.kubernetes.io/node
const TaintNoScheduleMaster15 = "dedicated=master:NoSchedule"
// +genclient=true
// InstanceGroup represents a group of instances (either nodes or masters) with the same configuration
type InstanceGroup struct {
metav1.TypeMeta `json:",inline"`

View File

@ -37,13 +37,13 @@ func CreateClusterConfig(clientset simple.Clientset, cluster *api.Cluster, group
}
}
_, err := clientset.Clusters().Create(cluster)
_, err := clientset.ClustersFor(cluster).Create(cluster)
if err != nil {
return err
}
for _, ig := range groups {
_, err = clientset.InstanceGroups(cluster.ObjectMeta.Name).Create(ig)
_, err = clientset.InstanceGroupsFor(cluster).Create(ig)
if err != nil {
return fmt.Errorf("error writing updated instancegroup configuration: %v", err)
}

View File

@ -20,6 +20,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient=true
type Cluster struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

View File

@ -20,6 +20,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient=true
type Federation struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

View File

@ -20,6 +20,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient=true
// InstanceGroup represents a group of instances (either nodes or masters) with the same configuration
type InstanceGroup struct {
metav1.TypeMeta `json:",inline"`

View File

@ -20,6 +20,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient=true
type Cluster struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

View File

@ -20,6 +20,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient=true
// Federation represents a federated set of kubernetes clusters
type Federation struct {
metav1.TypeMeta `json:",inline"`

View File

@ -20,6 +20,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient=true
// InstanceGroup represents a group of instances (either nodes or masters) with the same configuration
type InstanceGroup struct {
metav1.TypeMeta `json:",inline"`

View File

@ -16,8 +16,97 @@ limitations under the License.
package simple
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kops/pkg/apis/kops"
kopsinternalversion "k8s.io/kops/pkg/client/clientset_generated/clientset/typed/kops/internalversion"
"k8s.io/kops/util/pkg/vfs"
"net/url"
"strings"
)
type Clientset interface {
Clusters() ClusterInterface
InstanceGroups(cluster string) InstanceGroupInterface
Federations() FederationInterface
// ClustersFor returns the ClusterInterface bound to the namespace for a particular Cluster
ClustersFor(cluster *kops.Cluster) kopsinternalversion.ClusterInterface
// GetCluster reads a cluster by name
GetCluster(name string) (*kops.Cluster, error)
// ListClusters returns all clusters
ListClusters(options metav1.ListOptions) (*kops.ClusterList, error)
// ConfigBaseFor returns the vfs path where we will read configuration information from
ConfigBaseFor(cluster *kops.Cluster) (vfs.Path, error)
// InstanceGroupsFor returns the InstanceGroupInterface bounds to the namespace for a particular Cluster
InstanceGroupsFor(cluster *kops.Cluster) kopsinternalversion.InstanceGroupInterface
// FederationsFor returns the FederationInterface bounds to the namespace for a particular Federation
FederationsFor(federation *kops.Federation) kopsinternalversion.FederationInterface
// GetFederation reads a federation by name
GetFederation(name string) (*kops.Federation, error)
// ListFederations returns all federations
ListFederations(options metav1.ListOptions) (*kops.FederationList, error)
}
// RESTClientset is an implementation of clientset that uses a "real" generated REST client
type RESTClientset struct {
BaseURL *url.URL
KopsClient kopsinternalversion.KopsInterface
}
func (c *RESTClientset) ClustersFor(cluster *kops.Cluster) kopsinternalversion.ClusterInterface {
namespace := restNamespaceForClusterName(cluster.Name)
return c.KopsClient.Clusters(namespace)
}
func (c *RESTClientset) GetCluster(name string) (*kops.Cluster, error) {
namespace := restNamespaceForClusterName(name)
return c.KopsClient.Clusters(namespace).Get(name, metav1.GetOptions{})
}
func (c *RESTClientset) ConfigBaseFor(cluster *kops.Cluster) (vfs.Path, error) {
// 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())
}
func (c *RESTClientset) ListClusters(options metav1.ListOptions) (*kops.ClusterList, error) {
return c.KopsClient.Clusters(metav1.NamespaceAll).List(options)
}
func (c *RESTClientset) InstanceGroupsFor(cluster *kops.Cluster) kopsinternalversion.InstanceGroupInterface {
namespace := restNamespaceForClusterName(cluster.Name)
return c.KopsClient.InstanceGroups(namespace)
}
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 curently not supported by the server API")
//namespace := restNamespaceForFederationName(federation.Name)
//return c.KopsClient.Federations(namespace)
}
func (c *RESTClientset) ListFederations(options metav1.ListOptions) (*kops.FederationList, error) {
return c.KopsClient.Federations(metav1.NamespaceAll).List(options)
}
func (c *RESTClientset) GetFederation(name string) (*kops.Federation, error) {
namespace := restNamespaceForFederationName(name)
return c.KopsClient.Federations(namespace).Get(name, metav1.GetOptions{})
}
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
}

View File

@ -1,36 +0,0 @@
/*
Copyright 2016 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 simple
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
api "k8s.io/kops/pkg/apis/kops"
)
// ClusterInterface has methods to work with Cluster resources.
type ClusterInterface interface {
Create(*api.Cluster) (*api.Cluster, error)
Update(*api.Cluster) (*api.Cluster, error)
//UpdateStatus(*api.Cluster) (*api.Cluster, error)
//Delete(name string, options *api.DeleteOptions) error
//DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error
Get(name string) (*api.Cluster, error)
List(opts metav1.ListOptions) (*api.ClusterList, error)
//Watch(opts k8sapi.ListOptions) (watch.Interface, error)
//Patch(name string, pt api.PatchType, data []byte, subresources ...string) (result *api.Cluster, err error)
//ClusterExpansion
}

View File

@ -1,36 +0,0 @@
/*
Copyright 2016 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 simple
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
api "k8s.io/kops/pkg/apis/kops"
)
// FederationInterface has methods to work with Federation resources.
type FederationInterface interface {
Create(*api.Federation) (*api.Federation, error)
Update(*api.Federation) (*api.Federation, error)
//UpdateStatus(*api.Federation) (*api.Federation, error)
Delete(name string, options *metav1.DeleteOptions) error
//DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error
Get(name string) (*api.Federation, error)
List(opts metav1.ListOptions) (*api.FederationList, error)
//Watch(opts k8sapi.ListOptions) (watch.Interface, error)
//Patch(name string, pt api.PatchType, data []byte, subresources ...string) (result *api.Federation, err error)
//FederationExpansion
}

View File

@ -1,36 +0,0 @@
/*
Copyright 2016 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 simple
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
api "k8s.io/kops/pkg/apis/kops"
)
// InstanceGroupInterface has methods to work with InstanceGroup resources.
type InstanceGroupInterface interface {
Create(*api.InstanceGroup) (*api.InstanceGroup, error)
Update(*api.InstanceGroup) (*api.InstanceGroup, error)
//UpdateStatus(*api.InstanceGroup) (*api.InstanceGroup, error)
Delete(name string, options *metav1.DeleteOptions) error
//DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error
Get(name string) (*api.InstanceGroup, error)
List(opts metav1.ListOptions) (*api.InstanceGroupList, error)
//Watch(opts k8sapi.ListOptions) (watch.Interface, error)
//Patch(name string, pt api.PatchType, data []byte, subresources ...string) (result *api.InstanceGroup, err error)
//InstanceGroupExpansion
}

View File

@ -17,6 +17,9 @@ limitations under the License.
package vfsclientset
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kops/pkg/apis/kops"
kopsinternalversion "k8s.io/kops/pkg/client/clientset_generated/clientset/typed/kops/internalversion"
"k8s.io/kops/pkg/client/simple"
"k8s.io/kops/util/pkg/vfs"
)
@ -27,21 +30,50 @@ type VFSClientset struct {
var _ simple.Clientset = &VFSClientset{}
func (c *VFSClientset) Clusters() simple.ClusterInterface {
func (c *VFSClientset) ClustersFor(cluster *kops.Cluster) kopsinternalversion.ClusterInterface {
return c.clusters()
}
func (c *VFSClientset) clusters() *ClusterVFS {
return newClusterVFS(c.basePath)
}
func (c *VFSClientset) InstanceGroups(clusterName string) simple.InstanceGroupInterface {
func (c *VFSClientset) GetCluster(name string) (*kops.Cluster, error) {
return c.clusters().Get(name, metav1.GetOptions{})
}
func (c *VFSClientset) ListClusters(options metav1.ListOptions) (*kops.ClusterList, error) {
return c.clusters().List(options)
}
func (c *VFSClientset) ConfigBaseFor(cluster *kops.Cluster) (vfs.Path, error) {
return c.clusters().configBase(cluster.Name)
}
func (c *VFSClientset) InstanceGroupsFor(cluster *kops.Cluster) kopsinternalversion.InstanceGroupInterface {
clusterName := cluster.Name
return newInstanceGroupVFS(c, clusterName)
}
func (c *VFSClientset) Federations() simple.FederationInterface {
func (c *VFSClientset) federations() kopsinternalversion.FederationInterface {
return newFederationVFS(c)
}
func (c *VFSClientset) FederationsFor(federation *kops.Federation) kopsinternalversion.FederationInterface {
return c.federations()
}
func (c *VFSClientset) ListFederations(options metav1.ListOptions) (*kops.FederationList, error) {
return c.federations().List(options)
}
func (c *VFSClientset) GetFederation(name string) (*kops.Federation, error) {
return c.federations().Get(name, metav1.GetOptions{})
}
func NewVFSClientset(basePath vfs.Path) simple.Clientset {
clientset := &VFSClientset{
vfsClientset := &VFSClientset{
basePath: basePath,
}
return clientset
return vfsClientset
}

View File

@ -20,11 +20,13 @@ import (
"fmt"
"github.com/golang/glog"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/watch"
api "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/apis/kops/registry"
"k8s.io/kops/pkg/apis/kops/v1alpha1"
"k8s.io/kops/pkg/apis/kops/validation"
"k8s.io/kops/pkg/client/simple"
kopsinternalversion "k8s.io/kops/pkg/client/clientset_generated/clientset/typed/kops/internalversion"
"k8s.io/kops/util/pkg/vfs"
"os"
"strings"
@ -43,14 +45,17 @@ func newClusterVFS(basePath vfs.Path) *ClusterVFS {
return c
}
var _ simple.ClusterInterface = &ClusterVFS{}
var _ kopsinternalversion.ClusterInterface = &ClusterVFS{}
func (c *ClusterVFS) Get(name string) (*api.Cluster, error) {
func (c *ClusterVFS) Get(name string, options metav1.GetOptions) (*api.Cluster, error) {
if options.ResourceVersion != "" {
return nil, fmt.Errorf("ResourceVersion not supported in ClusterVFS::Get")
}
return c.find(name)
}
// Deprecated, but we need this for now..
func (c *ClusterVFS) ConfigBase(clusterName string) (vfs.Path, error) {
func (c *ClusterVFS) configBase(clusterName string) (vfs.Path, error) {
if clusterName == "" {
return nil, fmt.Errorf("clusterName is required")
}
@ -180,7 +185,7 @@ func (r *ClusterVFS) find(clusterName string) (*api.Cluster, error) {
// TODO: Split this out into real version updates / schema changes
if c.Spec.ConfigBase == "" {
configBase, err := r.ConfigBase(clusterName)
configBase, err := r.configBase(clusterName)
if err != nil {
return nil, fmt.Errorf("error building ConfigBase for cluster: %v", err)
}
@ -189,3 +194,19 @@ func (r *ClusterVFS) find(clusterName string) (*api.Cluster, error) {
return c, nil
}
func (r *ClusterVFS) Delete(name string, options *metav1.DeleteOptions) error {
return fmt.Errorf("cluster Delete not implemented for vfs store")
}
func (r *ClusterVFS) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
return fmt.Errorf("cluster DeleteCollection not implemented for vfs store")
}
func (r *ClusterVFS) Watch(opts metav1.ListOptions) (watch.Interface, error) {
return nil, fmt.Errorf("cluster Watch not implemented for vfs store")
}
func (r *ClusterVFS) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *api.Cluster, err error) {
return nil, fmt.Errorf("cluster Patch not implemented for vfs store")
}

View File

@ -17,12 +17,15 @@ limitations under the License.
package vfsclientset
import (
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/watch"
api "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/apis/kops/v1alpha1"
"k8s.io/kops/pkg/apis/kops/validation"
"k8s.io/kops/pkg/client/simple"
kopsinternalversion "k8s.io/kops/pkg/client/clientset_generated/clientset/typed/kops/internalversion"
)
type FederationVFS struct {
@ -42,9 +45,12 @@ func newFederationVFS(c *VFSClientset) *FederationVFS {
return r
}
var _ simple.FederationInterface = &FederationVFS{}
var _ kopsinternalversion.FederationInterface = &FederationVFS{}
func (c *FederationVFS) Get(name string) (*api.Federation, error) {
func (c *FederationVFS) Get(name string, options metav1.GetOptions) (*api.Federation, error) {
if options.ResourceVersion != "" {
return nil, fmt.Errorf("ResourceVersion not supported in FederationVFS::Get")
}
o, err := c.get(name)
if err != nil {
return nil, err
@ -84,3 +90,15 @@ func (c *FederationVFS) Update(g *api.Federation) (*api.Federation, error) {
func (c *FederationVFS) Delete(name string, options *metav1.DeleteOptions) error {
return c.delete(name, options)
}
func (r *FederationVFS) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
return fmt.Errorf("FederationVFS DeleteCollection not implemented for vfs store")
}
func (r *FederationVFS) Watch(opts metav1.ListOptions) (watch.Interface, error) {
return nil, fmt.Errorf("FederationVFS Watch not implemented for vfs store")
}
func (r *FederationVFS) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *api.Federation, err error) {
return nil, fmt.Errorf("FederationVFS Patch not implemented for vfs store")
}

View File

@ -17,14 +17,17 @@ limitations under the License.
package vfsclientset
import (
"fmt"
"github.com/golang/glog"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/kops/pkg/apis/kops"
api "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/apis/kops/v1alpha1"
"k8s.io/kops/pkg/apis/kops/validation"
"k8s.io/kops/pkg/client/simple"
kopsinternalversion "k8s.io/kops/pkg/client/clientset_generated/clientset/typed/kops/internalversion"
)
type InstanceGroupVFS struct {
@ -52,9 +55,13 @@ func newInstanceGroupVFS(c *VFSClientset, clusterName string) *InstanceGroupVFS
return r
}
var _ simple.InstanceGroupInterface = &InstanceGroupVFS{}
var _ kopsinternalversion.InstanceGroupInterface = &InstanceGroupVFS{}
func (c *InstanceGroupVFS) Get(name string, options metav1.GetOptions) (*api.InstanceGroup, error) {
if options.ResourceVersion != "" {
return nil, fmt.Errorf("ResourceVersion not supported in InstanceGroupVFS::Get")
}
func (c *InstanceGroupVFS) Get(name string) (*api.InstanceGroup, error) {
o, err := c.get(name)
if err != nil {
return nil, err
@ -108,3 +115,15 @@ func (c *InstanceGroupVFS) Update(g *api.InstanceGroup) (*api.InstanceGroup, err
func (c *InstanceGroupVFS) Delete(name string, options *metav1.DeleteOptions) error {
return c.delete(name, options)
}
func (r *InstanceGroupVFS) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
return fmt.Errorf("InstanceGroupVFS DeleteCollection not implemented for vfs store")
}
func (r *InstanceGroupVFS) Watch(opts metav1.ListOptions) (watch.Interface, error) {
return nil, fmt.Errorf("InstanceGroupVFS Watch not implemented for vfs store")
}
func (r *InstanceGroupVFS) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *api.InstanceGroup, err error) {
return nil, fmt.Errorf("InstanceGroupVFS Patch not implemented for vfs store")
}

View File

@ -119,7 +119,7 @@ func (c *DeleteInstanceGroup) DeleteInstanceGroup(group *api.InstanceGroup) erro
}
}
err = c.Clientset.InstanceGroups(c.Cluster.ObjectMeta.Name).Delete(group.ObjectMeta.Name, nil)
err = c.Clientset.InstanceGroupsFor(c.Cluster).Delete(group.ObjectMeta.Name, nil)
if err != nil {
return err
}

View File

@ -108,7 +108,7 @@ func (c *ApplyClusterCmd) Run() error {
}
if c.InstanceGroups == nil {
list, err := c.Clientset.InstanceGroups(c.Cluster.ObjectMeta.Name).List(metav1.ListOptions{})
list, err := c.Clientset.InstanceGroupsFor(c.Cluster).List(metav1.ListOptions{})
if err != nil {
return err
}
@ -709,7 +709,7 @@ func (c *ApplyClusterCmd) Run() error {
}
for _, g := range c.InstanceGroups {
_, err := c.Clientset.InstanceGroups(c.Cluster.ObjectMeta.Name).Update(g)
_, err := c.Clientset.InstanceGroupsFor(c.Cluster).Update(g)
if err != nil {
return fmt.Errorf("error writing InstanceGroup %q to registry: %v", g.ObjectMeta.Name, err)
}

View File

@ -28,7 +28,6 @@ import (
api "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/apis/kops/registry"
"k8s.io/kops/pkg/client/simple"
"k8s.io/kops/pkg/client/simple/vfsclientset"
"k8s.io/kops/pkg/resources"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup"
@ -77,7 +76,7 @@ func (x *ConvertKubeupCluster) Upgrade() error {
// Build completed cluster (force errors asap)
cluster.ObjectMeta.Name = newClusterName
newConfigBase, err := x.Clientset.Clusters().(*vfsclientset.ClusterVFS).ConfigBase(newClusterName)
newConfigBase, err := x.Clientset.ConfigBaseFor(cluster)
if err != nil {
return fmt.Errorf("error building ConfigBase for cluster: %v", err)
}

View File

@ -31,7 +31,6 @@ import (
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/apis/kops/registry"
"k8s.io/kops/pkg/client/simple"
"k8s.io/kops/pkg/client/simple/vfsclientset"
"k8s.io/kops/pkg/resources"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup"
@ -72,7 +71,7 @@ func (x *ImportCluster) ImportAWSCluster() error {
cluster.Spec.KubernetesAPIAccess = []string{"0.0.0.0/0"}
cluster.Spec.SSHAccess = []string{"0.0.0.0/0"}
configBase, err := x.Clientset.Clusters().(*vfsclientset.ClusterVFS).ConfigBase(clusterName)
configBase, err := x.Clientset.ConfigBaseFor(cluster)
if err != nil {
return fmt.Errorf("error building ConfigBase for cluster: %v", err)
}

View File

@ -36,6 +36,7 @@ import (
// but allows us to configure S3 credentials, for example
type VFSContext struct {
s3Context *S3Context
k8sContext *KubernetesContext
memfsContext *MemFSContext
// mutex guards gcsClient
mutex sync.Mutex
@ -44,7 +45,8 @@ type VFSContext struct {
}
var Context = VFSContext{
s3Context: NewS3Context(),
s3Context: NewS3Context(),
k8sContext: NewKubernetesContext(),
}
// ReadLocation reads a file from a vfs URL
@ -106,6 +108,10 @@ func (c *VFSContext) BuildVfsPath(p string) (Path, error) {
return c.buildGCSPath(p)
}
if strings.HasPrefix(p, "k8s://") {
return c.buildKubernetesPath(p)
}
return nil, fmt.Errorf("unknown / unhandled path type: %q", p)
}
@ -219,6 +225,24 @@ func (c *VFSContext) buildS3Path(p string) (*S3Path, error) {
return s3path, nil
}
func (c *VFSContext) buildKubernetesPath(p string) (*KubernetesPath, error) {
u, err := url.Parse(p)
if err != nil {
return nil, fmt.Errorf("invalid kubernetes vfs path: %q", p)
}
if u.Scheme != "k8s" {
return nil, fmt.Errorf("invalid kubernetes vfs path: %q", p)
}
bucket := strings.TrimSuffix(u.Host, "/")
if bucket == "" {
return nil, fmt.Errorf("invalid kubernetes vfs path: %q", p)
}
k8sPath := newKubernetesPath(c.k8sContext, bucket, u.Path)
return k8sPath, nil
}
func (c *VFSContext) buildMemFSPath(p string) (*MemFSPath, error) {
if !strings.HasPrefix(p, "memfs://") {
return nil, fmt.Errorf("memfs path not recognized: %q", p)

View File

@ -0,0 +1,43 @@
/*
Copyright 2016 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.
*/
/*
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 vfs
// KubernetesContext is the context for a Kubernetes VFS implementation
type KubernetesContext struct {
}
// NewKubernetesContext builds a KubernetesContext
// This will likely take a kubernetes rest client object (or similar) once the implementation is more complete
func NewKubernetesContext() *KubernetesContext {
return &KubernetesContext{}
}

109
util/pkg/vfs/k8sfs.go Normal file
View File

@ -0,0 +1,109 @@
/*
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 vfs
import (
"fmt"
"k8s.io/kops/util/pkg/hashing"
"path"
"strings"
)
// KubernetesPath is a path for a VFS backed by the kubernetes API
// Currently all operations are no-ops
type KubernetesPath struct {
k8sContext *KubernetesContext
host string
key string
}
var _ Path = &KubernetesPath{}
var _ HasHash = &KubernetesPath{}
func newKubernetesPath(k8sContext *KubernetesContext, host string, key string) *KubernetesPath {
host = strings.TrimSuffix(host, "/")
key = strings.TrimPrefix(key, "/")
return &KubernetesPath{
k8sContext: k8sContext,
host: host,
key: key,
}
}
func (p *KubernetesPath) Path() string {
return "k8s://" + p.host + "/" + p.key
}
func (p *KubernetesPath) Host() string {
return p.host
}
func (p *KubernetesPath) Key() string {
return p.key
}
func (p *KubernetesPath) String() string {
return p.Path()
}
func (p *KubernetesPath) Remove() error {
return fmt.Errorf("KubernetesPath::Remove not supported")
}
func (p *KubernetesPath) Join(relativePath ...string) Path {
args := []string{p.key}
args = append(args, relativePath...)
joined := path.Join(args...)
return &KubernetesPath{
k8sContext: p.k8sContext,
host: p.host,
key: joined,
}
}
func (p *KubernetesPath) WriteFile(data []byte) error {
return fmt.Errorf("KubernetesPath::WriteFile not supported")
}
func (p *KubernetesPath) CreateFile(data []byte) error {
return fmt.Errorf("KubernetesPath::CreateFile not supported")
}
func (p *KubernetesPath) ReadFile() ([]byte, error) {
return nil, fmt.Errorf("KubernetesPath::ReadFile not supported")
}
func (p *KubernetesPath) ReadDir() ([]Path, error) {
return nil, fmt.Errorf("KubernetesPath::ReadDir not supported")
}
func (p *KubernetesPath) ReadTree() ([]Path, error) {
return nil, fmt.Errorf("KubernetesPath::ReadTree not supported")
}
func (p *KubernetesPath) Base() string {
return path.Base(p.key)
}
func (p *KubernetesPath) PreferredHash() (*hashing.Hash, error) {
return p.Hash(hashing.HashAlgorithmMD5)
}
func (p *KubernetesPath) Hash(a hashing.HashAlgorithm) (*hashing.Hash, error) {
return nil, fmt.Errorf("KubernetesPath::Hash not supported")
}

View File

@ -90,6 +90,9 @@ func IsClusterReadable(p Path) bool {
case *S3Path, *GSPath:
return true
case *KubernetesPath:
return true
case *SSHPath:
return false