diff --git a/pkg/api/store/cluster/cluster_store.go b/pkg/api/store/cluster/cluster_store.go index 4dbfdf96ff9..0f32d35b126 100644 --- a/pkg/api/store/cluster/cluster_store.go +++ b/pkg/api/store/cluster/cluster_store.go @@ -1,12 +1,21 @@ package cluster import ( + "sync" + + "strings" + + "github.com/rancher/norman/api/access" + "github.com/rancher/norman/httperror" "github.com/rancher/norman/types" + "github.com/rancher/norman/types/convert" + managementv3 "github.com/rancher/types/client/management/v3" ) type Store struct { types.Store ShellHandler types.RequestHandler + mu sync.Mutex } func (r *Store) ByID(apiContext *types.APIContext, schema *types.Schema, id string) (map[string]interface{}, error) { @@ -17,3 +26,65 @@ func (r *Store) ByID(apiContext *types.APIContext, schema *types.Schema, id stri } return r.Store.ByID(apiContext, schema, id) } + +func (r *Store) Create(apiContext *types.APIContext, schema *types.Schema, data map[string]interface{}) (map[string]interface{}, error) { + + name := convert.ToString(data["name"]) + if name == "" { + return nil, httperror.NewFieldAPIError(httperror.MissingRequired, "Cluster name", "") + } + + r.mu.Lock() + defer r.mu.Unlock() + + if err := canUseClusterName(apiContext, name); err != nil { + return nil, err + } + + return r.Store.Create(apiContext, schema, data) +} + +func (r *Store) Update(apiContext *types.APIContext, schema *types.Schema, data map[string]interface{}, id string) (map[string]interface{}, error) { + + updatedName := convert.ToString(data["name"]) + if updatedName == "" { + return nil, httperror.NewFieldAPIError(httperror.MissingRequired, "Cluster name", "") + } + + existingCluster, err := r.ByID(apiContext, schema, id) + if err != nil { + return nil, err + } + + clusterName, ok := existingCluster["name"].(string) + if !ok { + clusterName = "" + } + + if !strings.EqualFold(updatedName, clusterName) { + r.mu.Lock() + defer r.mu.Unlock() + + if err := canUseClusterName(apiContext, updatedName); err != nil { + return nil, err + } + } + return r.Store.Update(apiContext, schema, data, id) +} + +func canUseClusterName(apiContext *types.APIContext, requestedName string) error { + var clusters []managementv3.Cluster + + if err := access.List(apiContext, apiContext.Version, managementv3.ClusterType, &types.QueryOptions{}, &clusters); err != nil { + return err + } + + for _, c := range clusters { + if c.Removed == "" && strings.EqualFold(c.Name, requestedName) { + //cluster exists by this name + return httperror.NewFieldAPIError(httperror.NotUnique, "Cluster name", "") + } + } + + return nil +} diff --git a/vendor.conf b/vendor.conf index e2a814cf84d..7682f137b61 100644 --- a/vendor.conf +++ b/vendor.conf @@ -28,8 +28,7 @@ github.com/aws/aws-sdk-go 6755a29e78026d7435884fe490e08cc250 github.com/heptio/authenticator d282f87a19728018b67d80754bcb3e9b0457403f github.com/smartystreets/go-aws-auth 8ef1316913ee4f44bc48c2456e44a5c1c68ea53b github.com/rancher/rdns-server de2b06e01b956b30aa078609bd6efa65081fae0e - -github.com/rancher/types 815e59af8a674e01a4963bf6787036a637ef6dce +github.com/rancher/types fdb95a1ac6c93f633224f165eae9d1ba86977a93 github.com/rancher/norman 79b91ea33c9ce18094018b26e86fa2577cac2bdd github.com/rancher/kontainer-engine 032917c69ba22ff22031caa50a6eedbca4439d09 github.com/rancher/rke d909253640f2f524fbe234f60085ccafa2b716a4 diff --git a/vendor/github.com/rancher/types/apis/management.cattle.io/v3/cluster_types.go b/vendor/github.com/rancher/types/apis/management.cattle.io/v3/cluster_types.go index fc1e0f57d7e..12ddb720f32 100644 --- a/vendor/github.com/rancher/types/apis/management.cattle.io/v3/cluster_types.go +++ b/vendor/github.com/rancher/types/apis/management.cattle.io/v3/cluster_types.go @@ -56,7 +56,7 @@ type Cluster struct { } type ClusterSpec struct { - DisplayName string `json:"displayName"` + DisplayName string `json:"displayName" norman:"required"` Description string `json:"description"` Internal bool `json:"internal" norman:"nocreate,noupdate"` DesiredAgentImage string `json:"desiredAgentImage"`