mirror of https://github.com/kubernetes/kops.git
Merge pull request #54 from justinsb/fix_tests
Update & get tests working again
This commit is contained in:
commit
fa3157e512
1
Makefile
1
Makefile
|
@ -14,7 +14,6 @@ codegen:
|
|||
GO15VENDOREXPERIMENT=1 go generate k8s.io/kops/upup/pkg/fi/fitasks
|
||||
|
||||
test:
|
||||
GO15VENDOREXPERIMENT=1 go test k8s.io/kops/cmd/...
|
||||
GO15VENDOREXPERIMENT=1 go test k8s.io/kops/upup/pkg/...
|
||||
|
||||
godeps:
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup"
|
||||
"k8s.io/kops/upup/pkg/fi/vfs"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TODO: Refactor CreateClusterCmd into pkg/fi/cloudup
|
||||
|
||||
func buildDefaultCreateCluster() *CreateClusterCmd {
|
||||
var err error
|
||||
|
||||
c := &CreateClusterCmd{}
|
||||
|
||||
c.ClusterConfig = &cloudup.CloudConfig{}
|
||||
c.ClusterConfig.ClusterName = "testcluster.mydomain.com"
|
||||
c.ClusterConfig.NodeZones = []string{"us-east-1a", "us-east-1b", "us-east-1c"}
|
||||
c.ClusterConfig.MasterZones = c.ClusterConfig.NodeZones
|
||||
c.SSHPublicKey = "~/.ssh/id_rsa.pub"
|
||||
|
||||
c.ClusterConfig.CloudProvider = "aws"
|
||||
|
||||
dryrun := false
|
||||
c.StateStore, err = fi.NewVFSStateStore(vfs.NewFSPath("test-state"), dryrun)
|
||||
if err != nil {
|
||||
glog.Fatalf("error building state store: %v", err)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func expectErrorFromRun(t *testing.T, c *CreateClusterCmd, message string) {
|
||||
err := c.Run()
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error from run")
|
||||
}
|
||||
actualMessage := fmt.Sprintf("%v", err)
|
||||
if actualMessage != message {
|
||||
t.Fatalf("Expected error %q, got %q", message, actualMessage)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateCluster_DuplicateZones(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.ClusterConfig.NodeZones = []string{"us-east-1a", "us-east-1b", "us-east-1b"}
|
||||
c.ClusterConfig.MasterZones = []string{"us-east-1a"}
|
||||
expectErrorFromRun(t, c, "NodeZones contained a duplicate value: us-east-1b")
|
||||
}
|
||||
|
||||
func TestCreateCluster_NoClusterName(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.ClusterConfig.ClusterName = ""
|
||||
expectErrorFromRun(t, c, "-name is required (e.g. mycluster.myzone.com)")
|
||||
}
|
||||
|
||||
func TestCreateCluster_NoCloud(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.ClusterConfig.CloudProvider = ""
|
||||
expectErrorFromRun(t, c, "-cloud is required (e.g. aws, gce)")
|
||||
}
|
||||
|
||||
func TestCreateCluster_ExtraMasterZone(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.ClusterConfig.NodeZones = []string{"us-east-1a", "us-east-1c"}
|
||||
c.ClusterConfig.MasterZones = []string{"us-east-1a", "us-east-1b", "us-east-1c"}
|
||||
expectErrorFromRun(t, c, "All MasterZones must (currently) also be NodeZones")
|
||||
}
|
||||
|
||||
func TestCreateCluster_NoMasterZones(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.ClusterConfig.MasterZones = []string{}
|
||||
expectErrorFromRun(t, c, "must specify at least one MasterZone")
|
||||
}
|
||||
|
||||
func TestCreateCluster_NoNodeZones(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.ClusterConfig.NodeZones = []string{}
|
||||
expectErrorFromRun(t, c, "must specify at least one NodeZone")
|
||||
}
|
||||
|
||||
func TestCreateCluster_RegionAsZone(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.ClusterConfig.NodeZones = []string{"us-east-1"}
|
||||
c.ClusterConfig.MasterZones = c.ClusterConfig.NodeZones
|
||||
expectErrorFromRun(t, c, "Region is not a recognized EC2 region: \"us-east-\" (check you have specified valid zones?)")
|
||||
}
|
||||
|
||||
func TestCreateCluster_BadZone(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.ClusterConfig.NodeZones = []string{"us-east-1z"}
|
||||
c.ClusterConfig.MasterZones = c.ClusterConfig.NodeZones
|
||||
expectErrorFromRun(t, c, "Zone is not a recognized AZ: \"us-east-1z\" (check you have specified a valid zone?)")
|
||||
}
|
||||
|
||||
func TestCreateCluster_MixedRegion(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.ClusterConfig.NodeZones = []string{"us-west-1a", "us-west-2b", "us-west-2c"}
|
||||
c.ClusterConfig.MasterZones = c.ClusterConfig.NodeZones
|
||||
expectErrorFromRun(t, c, "Clusters cannot span multiple regions")
|
||||
}
|
||||
|
||||
func TestCreateCluster_EvenEtcdClusterSize(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.ClusterConfig.NodeZones = []string{"us-east-1a", "us-east-1b", "us-east-1c", "us-east-1d"}
|
||||
c.ClusterConfig.MasterZones = c.ClusterConfig.NodeZones
|
||||
expectErrorFromRun(t, c, "There should be an odd number of master-zones, for etcd's quorum. Hint: Use -zones and -master-zones to declare node zones and master zones separately.")
|
||||
}
|
|
@ -138,7 +138,7 @@ func (c *Cluster) Validate() error {
|
|||
return fmt.Errorf("MasterKubelet CloudProvider did not match cluster CloudProvider")
|
||||
}
|
||||
if c.Spec.KubeAPIServer.CloudProvider != c.Spec.CloudProvider {
|
||||
return fmt.Errorf("Errorf CloudProvider did not match cluster CloudProvider")
|
||||
return fmt.Errorf("KubeAPIServer CloudProvider did not match cluster CloudProvider")
|
||||
}
|
||||
if c.Spec.KubeControllerManager.CloudProvider != c.Spec.CloudProvider {
|
||||
return fmt.Errorf("KubeControllerManager CloudProvider did not match cluster CloudProvider")
|
||||
|
|
|
@ -112,7 +112,7 @@ func (c *CreateClusterCmd) Run() error {
|
|||
|
||||
if len(c.Cluster.Spec.Zones) == 0 {
|
||||
// TODO: Auto choose zones from region?
|
||||
return fmt.Errorf("must configuration at least one Zone (use --zones)")
|
||||
return fmt.Errorf("must configure at least one Zone (use --zones)")
|
||||
}
|
||||
|
||||
if len(c.InstanceGroups) == 0 {
|
||||
|
@ -208,7 +208,7 @@ func (c *CreateClusterCmd) Run() error {
|
|||
|
||||
if (len(etcdZones) % 2) == 0 {
|
||||
// Not technically a requirement, but doesn't really make sense to allow
|
||||
return fmt.Errorf("There should be an odd number of master-zones, for etcd's quorum. Hint: Use --zone and --master-zone to declare node zones and master zones separately.")
|
||||
return fmt.Errorf("There should be an odd number of master-zones, for etcd's quorum. Hint: Use --zones and --master-zones to declare node zones and master zones separately.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
package cloudup
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kops/upup/pkg/api"
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/upup/pkg/fi/vfs"
|
||||
k8sapi "k8s.io/kubernetes/pkg/api"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func buildDefaultCreateCluster() *CreateClusterCmd {
|
||||
var err error
|
||||
|
||||
memfs := vfs.NewMemFSContext()
|
||||
memfs.MarkClusterReadable()
|
||||
|
||||
c := &CreateClusterCmd{}
|
||||
|
||||
// TODO: We should actually just specify the minimums here, and run in though the default logic
|
||||
c.Cluster = &api.Cluster{}
|
||||
c.Cluster.Name = "testcluster.mydomain.com"
|
||||
c.Cluster.Spec.Zones = []*api.ClusterZoneSpec{
|
||||
{Name: "us-east-1a", CIDR: "172.20.1.0/24"},
|
||||
{Name: "us-east-1b", CIDR: "172.20.2.0/24"},
|
||||
{Name: "us-east-1c", CIDR: "172.20.3.0/24"},
|
||||
{Name: "us-east-1d", CIDR: "172.20.4.0/24"},
|
||||
}
|
||||
c.InstanceGroups = append(c.InstanceGroups, buildNodeInstanceGroup("us-east-1a"))
|
||||
c.InstanceGroups = append(c.InstanceGroups, buildMasterInstanceGroup("us-east-1a"))
|
||||
c.SSHPublicKey = path.Join(os.Getenv("HOME"), ".ssh", "id_rsa.pub")
|
||||
|
||||
c.Cluster.Spec.Kubelet = &api.KubeletConfig{}
|
||||
c.Cluster.Spec.KubeControllerManager = &api.KubeControllerManagerConfig{}
|
||||
c.Cluster.Spec.KubeDNS = &api.KubeDNSConfig{}
|
||||
c.Cluster.Spec.KubeAPIServer = &api.KubeAPIServerConfig{}
|
||||
c.Cluster.Spec.KubeProxy = &api.KubeProxyConfig{}
|
||||
c.Cluster.Spec.Docker = &api.DockerConfig{}
|
||||
|
||||
c.Cluster.Spec.NetworkCIDR = "172.20.0.0/16"
|
||||
|
||||
c.Cluster.Spec.NonMasqueradeCIDR = "100.64.0.0/10"
|
||||
c.Cluster.Spec.Kubelet.NonMasqueradeCIDR = c.Cluster.Spec.NonMasqueradeCIDR
|
||||
|
||||
c.Cluster.Spec.ServiceClusterIPRange = "100.64.1.0/24"
|
||||
c.Cluster.Spec.KubeAPIServer.ServiceClusterIPRange = c.Cluster.Spec.ServiceClusterIPRange
|
||||
|
||||
c.Cluster.Spec.KubeDNS.ServerIP = "100.64.1.10"
|
||||
c.Cluster.Spec.Kubelet.ClusterDNS = c.Cluster.Spec.KubeDNS.ServerIP
|
||||
|
||||
c.Cluster.Spec.CloudProvider = "aws"
|
||||
c.Cluster.Spec.Kubelet.CloudProvider = c.Cluster.Spec.CloudProvider
|
||||
c.Cluster.Spec.KubeAPIServer.CloudProvider = c.Cluster.Spec.CloudProvider
|
||||
c.Cluster.Spec.KubeControllerManager.CloudProvider = c.Cluster.Spec.CloudProvider
|
||||
|
||||
c.Target = "dryrun"
|
||||
|
||||
dryrun := false
|
||||
c.StateStore, err = fi.NewVFSStateStore(vfs.NewMemFSPath(memfs, "test-statestore"), c.Cluster.Name, dryrun)
|
||||
if err != nil {
|
||||
glog.Fatalf("error building state store: %v", err)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func buildNodeInstanceGroup(zones ...string) *api.InstanceGroup {
|
||||
g := &api.InstanceGroup{
|
||||
ObjectMeta: k8sapi.ObjectMeta{Name: "nodes-" + strings.Join(zones, "-")},
|
||||
Spec: api.InstanceGroupSpec{
|
||||
Role: api.InstanceGroupRoleNode,
|
||||
Zones: zones,
|
||||
},
|
||||
}
|
||||
return g
|
||||
}
|
||||
|
||||
func buildMasterInstanceGroup(zones ...string) *api.InstanceGroup {
|
||||
g := &api.InstanceGroup{
|
||||
ObjectMeta: k8sapi.ObjectMeta{Name: "master-" + strings.Join(zones, "-")},
|
||||
Spec: api.InstanceGroupSpec{
|
||||
Role: api.InstanceGroupRoleMaster,
|
||||
Zones: zones,
|
||||
},
|
||||
}
|
||||
return g
|
||||
}
|
||||
|
||||
func expectErrorFromRun(t *testing.T, c *CreateClusterCmd, message string) {
|
||||
err := c.Run()
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error from run")
|
||||
}
|
||||
actualMessage := fmt.Sprintf("%v", err)
|
||||
if !strings.Contains(actualMessage, message) {
|
||||
t.Fatalf("Expected error %q, got %q", message, actualMessage)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateCluster_DuplicateZones(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.Cluster.Spec.Zones = []*api.ClusterZoneSpec{
|
||||
{Name: "us-east-1a", CIDR: "172.20.1.0/24"},
|
||||
{Name: "us-east-1a", CIDR: "172.20.2.0/24"},
|
||||
}
|
||||
expectErrorFromRun(t, c, "Zones contained a duplicate value: us-east-1a")
|
||||
}
|
||||
|
||||
func TestCreateCluster_NoClusterName(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.Cluster.Name = ""
|
||||
expectErrorFromRun(t, c, "ClusterName is required")
|
||||
}
|
||||
|
||||
func TestCreateCluster_NoCloud(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.Cluster.Spec.CloudProvider = ""
|
||||
expectErrorFromRun(t, c, "-cloud is required (e.g. aws, gce)")
|
||||
}
|
||||
|
||||
func TestCreateCluster_ExtraMasterZone(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.Cluster.Spec.Zones = []*api.ClusterZoneSpec{
|
||||
{Name: "us-east-1a", CIDR: "172.20.1.0/24"},
|
||||
{Name: "us-east-1b", CIDR: "172.20.2.0/24"},
|
||||
}
|
||||
c.InstanceGroups = []*api.InstanceGroup{}
|
||||
c.InstanceGroups = append(c.InstanceGroups, buildNodeInstanceGroup("us-east-1a", "us-east-1b"))
|
||||
c.InstanceGroups = append(c.InstanceGroups, buildMasterInstanceGroup("us-east-1a", "us-east-1b", "us-east-1c"))
|
||||
expectErrorFromRun(t, c, "is not configured as a Zone in the cluster")
|
||||
}
|
||||
|
||||
func TestCreateCluster_NoMasterZones(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.InstanceGroups = []*api.InstanceGroup{}
|
||||
c.InstanceGroups = append(c.InstanceGroups, buildNodeInstanceGroup("us-east-1a"))
|
||||
expectErrorFromRun(t, c, "must configure at least one Master InstanceGroup")
|
||||
}
|
||||
|
||||
func TestCreateCluster_NoNodeZones(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.InstanceGroups = []*api.InstanceGroup{}
|
||||
c.InstanceGroups = append(c.InstanceGroups, buildMasterInstanceGroup("us-east-1a"))
|
||||
expectErrorFromRun(t, c, "must configure at least one Node InstanceGroup")
|
||||
}
|
||||
|
||||
func TestCreateCluster_RegionAsZone(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.Cluster.Spec.Zones = []*api.ClusterZoneSpec{
|
||||
{Name: "us-east-1", CIDR: "172.20.1.0/24"},
|
||||
}
|
||||
c.InstanceGroups = []*api.InstanceGroup{
|
||||
buildNodeInstanceGroup("us-east-1"),
|
||||
buildMasterInstanceGroup("us-east-1"),
|
||||
}
|
||||
expectErrorFromRun(t, c, "Region is not a recognized EC2 region: \"us-east-\" (check you have specified valid zones?)")
|
||||
}
|
||||
|
||||
func TestCreateCluster_NotIncludedZone(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.InstanceGroups = []*api.InstanceGroup{
|
||||
buildNodeInstanceGroup("us-east-1e"),
|
||||
buildMasterInstanceGroup("us-east-1a"),
|
||||
}
|
||||
expectErrorFromRun(t, c, "not configured as a Zone in the cluster")
|
||||
}
|
||||
|
||||
func TestCreateCluster_BadZone(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.Cluster.Spec.Zones = []*api.ClusterZoneSpec{
|
||||
{Name: "us-east-1z", CIDR: "172.20.1.0/24"},
|
||||
}
|
||||
c.InstanceGroups = []*api.InstanceGroup{
|
||||
buildNodeInstanceGroup("us-east-1z"),
|
||||
buildMasterInstanceGroup("us-east-1z"),
|
||||
}
|
||||
expectErrorFromRun(t, c, "Zone is not a recognized AZ: \"us-east-1z\" (check you have specified a valid zone?)")
|
||||
}
|
||||
|
||||
func TestCreateCluster_MixedRegion(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.Cluster.Spec.Zones = []*api.ClusterZoneSpec{
|
||||
{Name: "us-east-1a", CIDR: "172.20.1.0/24"},
|
||||
{Name: "us-west-1b", CIDR: "172.20.2.0/24"},
|
||||
}
|
||||
c.InstanceGroups = []*api.InstanceGroup{
|
||||
buildNodeInstanceGroup("us-east-1a", "us-west-1b"),
|
||||
buildMasterInstanceGroup("us-east-1a"),
|
||||
}
|
||||
expectErrorFromRun(t, c, "Clusters cannot span multiple regions")
|
||||
}
|
||||
|
||||
func TestCreateCluster_EvenEtcdClusterSize(t *testing.T) {
|
||||
c := buildDefaultCreateCluster()
|
||||
c.InstanceGroups = []*api.InstanceGroup{}
|
||||
c.InstanceGroups = append(c.InstanceGroups, buildNodeInstanceGroup("us-east-1a"))
|
||||
c.InstanceGroups = append(c.InstanceGroups, buildMasterInstanceGroup("us-east-1a", "us-east-1b", "us-east-1c", "us-east-1d"))
|
||||
c.Cluster.Spec.EtcdClusters = []*api.EtcdClusterSpec{
|
||||
{
|
||||
Name: "main",
|
||||
Members: []*api.EtcdMemberSpec{
|
||||
{Name: "us-east-1a", Zone: "us-east-1a"},
|
||||
{Name: "us-east-1b", Zone: "us-east-1b"},
|
||||
},
|
||||
},
|
||||
}
|
||||
expectErrorFromRun(t, c, "There should be an odd number of master-zones, for etcd's quorum. Hint: Use --zones and --master-zones to declare node zones and master zones separately.")
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
package vfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type MemFSPath struct {
|
||||
context *MemFSContext
|
||||
location string
|
||||
|
||||
contents []byte
|
||||
children map[string]*MemFSPath
|
||||
}
|
||||
|
||||
var _ Path = &MemFSPath{}
|
||||
|
||||
type MemFSContext struct {
|
||||
clusterReadable bool
|
||||
root *MemFSPath
|
||||
}
|
||||
|
||||
func NewMemFSContext() *MemFSContext {
|
||||
c := &MemFSContext{}
|
||||
c.root = &MemFSPath{
|
||||
context: c,
|
||||
location: "",
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// MarkClusterReadable pretends the current memfscontext is cluster readable; this is useful for tests
|
||||
func (c *MemFSContext) MarkClusterReadable() {
|
||||
c.clusterReadable = true
|
||||
}
|
||||
|
||||
func (c *MemFSPath) IsClusterReadable() bool {
|
||||
return c.context.clusterReadable
|
||||
}
|
||||
|
||||
var _ HasClusterReadable = &MemFSPath{}
|
||||
|
||||
func NewMemFSPath(context *MemFSContext, location string) *MemFSPath {
|
||||
return context.root.Join(location).(*MemFSPath)
|
||||
}
|
||||
|
||||
func (p *MemFSPath) Join(relativePath ...string) Path {
|
||||
joined := path.Join(relativePath...)
|
||||
tokens := strings.Split(joined, "/")
|
||||
current := p
|
||||
for _, token := range tokens {
|
||||
if current.children == nil {
|
||||
current.children = make(map[string]*MemFSPath)
|
||||
}
|
||||
child := current.children[token]
|
||||
if child == nil {
|
||||
child = &MemFSPath{
|
||||
context: p.context,
|
||||
location: path.Join(current.location, token),
|
||||
}
|
||||
current.children[token] = child
|
||||
}
|
||||
current = child
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
func (p *MemFSPath) WriteFile(data []byte) error {
|
||||
p.contents = data
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *MemFSPath) CreateFile(data []byte) error {
|
||||
// Check if exists
|
||||
if p.contents != nil {
|
||||
return os.ErrExist
|
||||
}
|
||||
|
||||
return p.WriteFile(data)
|
||||
}
|
||||
|
||||
func (p *MemFSPath) ReadFile() ([]byte, error) {
|
||||
if p.contents == nil {
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
// TODO: Copy?
|
||||
return p.contents, nil
|
||||
}
|
||||
|
||||
func (p *MemFSPath) ReadDir() ([]Path, error) {
|
||||
var paths []Path
|
||||
for _, f := range p.children {
|
||||
paths = append(paths, f)
|
||||
}
|
||||
return paths, nil
|
||||
}
|
||||
|
||||
func (p *MemFSPath) ReadTree() ([]Path, error) {
|
||||
var paths []Path
|
||||
p.readTree(&paths)
|
||||
return paths, nil
|
||||
}
|
||||
|
||||
func (p *MemFSPath) readTree(dest *[]Path) {
|
||||
for _, f := range p.children {
|
||||
*dest = append(*dest, f)
|
||||
f.readTree(dest)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *MemFSPath) Base() string {
|
||||
return path.Base(p.location)
|
||||
}
|
||||
|
||||
func (p *MemFSPath) Path() string {
|
||||
return p.location
|
||||
}
|
||||
|
||||
func (p *MemFSPath) String() string {
|
||||
return p.Path()
|
||||
}
|
||||
|
||||
func (p *MemFSPath) Remove() error {
|
||||
p.contents = nil
|
||||
return nil
|
||||
}
|
|
@ -61,6 +61,10 @@ func RelativePath(base Path, child Path) (string, error) {
|
|||
}
|
||||
|
||||
func IsClusterReadable(p Path) bool {
|
||||
if hcr, ok := p.(HasClusterReadable); ok {
|
||||
return hcr.IsClusterReadable()
|
||||
}
|
||||
|
||||
switch p.(type) {
|
||||
case *S3Path:
|
||||
return true
|
||||
|
@ -76,3 +80,7 @@ func IsClusterReadable(p Path) bool {
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
type HasClusterReadable interface {
|
||||
IsClusterReadable() bool
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue