func TestState_ClusterExists(t *testing.T) { t.Parallel() testPrefix := "TestState_ClusterExists" testutil.ResetEtcd(t, testPrefix) logger := testutil.NewTestLogger(testPrefix, t) state, err := NewStateEtcdWithPrefix(testutil.LocalEtcdConfig, testPrefix, logger) if err != nil { t.Fatalf("Could not create state", err) } clusterID := structs.ClusterID(uuid.New()) planID := uuid.New() clusterState := structs.ClusterState{ InstanceID: clusterID, OrganizationGUID: "OrganizationGUID", PlanID: planID, ServiceID: "ServiceID", SpaceGUID: "SpaceGUID", } err = state.SaveCluster(clusterState) if err != nil { t.Fatalf("SaveCluster failed %s", err) } if !state.ClusterExists(clusterID) { t.Fatalf("Cluster %s should exist", clusterID) } if state.ClusterExists("fakeID") { t.Fatalf("Cluster %s should not exist", "fakeID") } }
func TestState_LoadCluster(t *testing.T) { t.Parallel() testPrefix := "TestState_LoadClusterState" testutil.ResetEtcd(t, testPrefix) logger := testutil.NewTestLogger(testPrefix, t) state, err := NewStateEtcdWithPrefix(testutil.LocalEtcdConfig, testPrefix, logger) if err != nil { t.Fatalf("Could not create state", err) } instanceID := structs.ClusterID(uuid.New()) planID := uuid.New() clusterState := structs.ClusterState{ InstanceID: instanceID, OrganizationGUID: "OrganizationGUID", PlanID: planID, ServiceID: "ServiceID", SpaceGUID: "SpaceGUID", } err = state.SaveCluster(clusterState) if err != nil { t.Fatalf("SaveCluster failed %s", err) } loadedState, err := state.LoadCluster(instanceID) if !reflect.DeepEqual(clusterState, loadedState) { t.Fatalf("Failed to load ClusterState") } }
func TestRouter_RemoveClusterAssignement(t *testing.T) { t.Parallel() testPrefix := "TestRouter_RemoveClusterAssignement" etcdApi := resetEtcd(t, testPrefix) logger := testutil.NewTestLogger(testPrefix, t) clusterID := structs.ClusterID("clusterID") port := 30000 key := fmt.Sprintf("%s/routing/allocation/%s", testPrefix, clusterID) _, err := etcdApi.Set(context.Background(), key, fmt.Sprintf("%d", port), &etcd.SetOptions{}) router, err := NewRouterWithPrefix(testutil.LocalEtcdConfig, testPrefix, logger) if err != nil { t.Fatalf("Could not create a new router", err) } err = router.RemoveClusterAssignment(clusterID) if err != nil { t.Fatalf("Could not remove the assignment %s", err) } _, err = etcdApi.Get(context.Background(), fmt.Sprintf("%s/routing/allocation/%s", testPrefix, clusterID), &etcd.GetOptions{}) if err == nil { t.Fatalf("port wasn't deleted %s", err) } }
func TestRouter_AssignPortToCluster(t *testing.T) { t.Parallel() testPrefix := "TestRouter_AssignPortToCluster" etcdApi := resetEtcd(t, testPrefix) logger := testutil.NewTestLogger(testPrefix, t) router, err := NewRouterWithPrefix(testutil.LocalEtcdConfig, testPrefix, logger) if err != nil { t.Fatalf("Could not create a new router", err) } clusterID := structs.ClusterID("clusterID") port := 30000 err = router.AssignPortToCluster(clusterID, port) if err != nil { t.Fatalf("Assigning port failed") } key := fmt.Sprintf("%s/routing/allocation/%s", testPrefix, clusterID) resp, err := etcdApi.Get(context.Background(), key, &etcd.GetOptions{}) if err != nil { t.Fatalf("Could not read port from etcd") } retrievedPort, err := strconv.Atoi(resp.Node.Value) if want, got := port, retrievedPort; want != got { t.Fatalf("Routing was not initialized. Expected %d, got %d", want, got) } }
// LoadAllRunningClusters fetches the /state information for all running clusters func (s *StateEtcd) LoadAllRunningClusters() (clusters []*structs.ClusterState, err error) { ctx := context.Background() servicesKey := fmt.Sprintf("%s/service", s.prefix) services, err := s.etcdApi.Get(ctx, servicesKey, &etcd.GetOptions{Recursive: false}) if err != nil { return } instanceIDRegExp, _ := regexp.Compile("/service/(.*)") for _, service := range services.Node.Nodes { instanceID := instanceIDRegExp.FindStringSubmatch(service.Key)[1] cluster, _ := s.LoadCluster(structs.ClusterID(instanceID)) clusters = append(clusters, &cluster) } return }
func adminServiceInstances(bkr *Broker, router httpRouter, logger lager.Logger) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { vars := router.Vars(req) instanceID := structs.ClusterID(vars["instance_id"]) logger := bkr.newLoggingSession("admin.service-instances", lager.Data{"instance-id": instanceID}) defer logger.Info("done") cluster, err := bkr.state.LoadCluster(instanceID) if err != nil { logger.Error("load-cluster.error", err) respond(w, http.StatusInternalServerError, err.Error()) } respond(w, http.StatusOK, cluster) } }
func TestState_DeleteCluster(t *testing.T) { t.Parallel() testPrefix := "TestState_DeleteClusterState" etcdApi := testutil.ResetEtcd(t, testPrefix) logger := testutil.NewTestLogger(testPrefix, t) state, err := NewStateEtcdWithPrefix(testutil.LocalEtcdConfig, testPrefix, logger) if err != nil { t.Fatalf("Could not create state", err) } instanceID := structs.ClusterID(uuid.New()) planID := uuid.New() clusterState := structs.ClusterState{ InstanceID: instanceID, OrganizationGUID: "OrganizationGUID", PlanID: planID, ServiceID: "ServiceID", SpaceGUID: "SpaceGUID", } err = state.SaveCluster(clusterState) if err != nil { t.Fatalf("SaveCluster failed %s", err) } err = state.DeleteCluster(instanceID) if err != nil { t.Fatalf("DeleteClusterState failed %s", err) } key := fmt.Sprintf("%s/service/%s/state", testPrefix, instanceID) _, err = etcdApi.Get(context.Background(), key, &etcd.GetOptions{}) if err == nil { t.Fatalf("Was expecting error 'Key not found'") } else { notFoundRegExp, _ := regexp.Compile("Key not found") if notFoundRegExp.FindString(err.Error()) != "Key not found" { t.Fatalf("An error other than 'Key not found' occured %s", err) } } }
func TestState_LoadCluster(t *testing.T) { t.Parallel() testPrefix := "TestState_LoadClusterState" etcdApi := testutil.ResetEtcd(t, testPrefix) logger := testutil.NewTestLogger(testPrefix, t) state, err := NewStateEtcdWithPrefix(testutil.LocalEtcdConfig, testPrefix, logger) if err != nil { t.Fatalf("Could not create state", err) } instanceID := structs.ClusterID(uuid.New()) planID := uuid.New() node := structs.Node{ID: "node_id", CellGUID: "cell_guid"} clusterState := structs.ClusterState{ InstanceID: instanceID, OrganizationGUID: "OrganizationGUID", PlanID: planID, ServiceID: "ServiceID", SpaceGUID: "SpaceGUID", SchedulingInfo: structs.SchedulingInfo{ Status: structs.SchedulingStatusInProgress, }, } clusterState.Nodes = []*structs.Node{&node} err = state.SaveCluster(clusterState) if err != nil { t.Fatalf("SaveCluster failed %s", err) } data, err := json.Marshal(node) key := fmt.Sprintf( "/%s/service/%s/nodes/%s", testPrefix, clusterState.InstanceID, node.ID) etcdApi.Set(context.Background(), key, string(data), &etcd.SetOptions{}) loadedState, err := state.LoadCluster(instanceID) if !reflect.DeepEqual(clusterState, loadedState) { t.Fatalf("Failed to load ClusterState. Expected: %v, actual: %v", clusterState, loadedState) } }
func TestState_SaveCluster(t *testing.T) { t.Parallel() testPrefix := "TestState_SaveCluster" etcdApi := testutil.ResetEtcd(t, testPrefix) logger := testutil.NewTestLogger(testPrefix, t) state, err := NewStateEtcdWithPrefix(testutil.LocalEtcdConfig, testPrefix, logger) if err != nil { t.Fatalf("Could not create state", err) } clusterID := structs.ClusterID(uuid.New()) planID := uuid.New() clusterState := structs.ClusterState{ InstanceID: clusterID, OrganizationGUID: "OrganizationGUID", PlanID: planID, ServiceID: "ServiceID", SpaceGUID: "SpaceGUID", } err = state.SaveCluster(clusterState) if err != nil { t.Fatalf("SaveCluster failed %s", err) } resp, err := etcdApi.Get(context.Background(), fmt.Sprintf("%s/service/%s/state", testPrefix, clusterID), &etcd.GetOptions{}) if err != nil { t.Fatalf("Could not load state from etcd %s", err) } retrievedState := structs.ClusterState{} json.Unmarshal([]byte(resp.Node.Value), &retrievedState) if !reflect.DeepEqual(clusterState, retrievedState) { t.Fatalf("Retrieved State does not match. Want %v, Got %v", clusterState, retrievedState) } }
func TestCallbacks_RestoreRecreationData(t *testing.T) { t.Parallel() testPrefix := "TestCallbacks_WriteRecreationData" logger := testutil.NewTestLogger(testPrefix, t) testDir, err := ioutil.TempDir("", testPrefix) if err != nil { t.Fatalf("err: %v", err) } defer os.Remove(testDir) fileName := fmt.Sprintf("%s/%s", testDir, testPrefix) instanceID := structs.ClusterID(uuid.New()) recreationData := &structs.ClusterRecreationData{ InstanceID: instanceID, OrganizationGUID: "OrganizationGUID", PlanID: "PlanID", ServiceID: "ServiceID", SpaceGUID: "SpaceGUID", AdminCredentials: structs.PostgresCredentials{ Username: "******", Password: "******", }, AllocatedPort: 1234, } dataRaw, _ := json.Marshal(recreationData) err = ioutil.WriteFile(fileName, dataRaw, os.ModePerm) if err != nil { t.Fatalf("Could not write file") } cfg := config.Callbacks{ ClusterDataRestore: &config.CallbackCommand{ Command: "cat", Arguments: []string{fileName}, }, } // test that it retrieves the data from stdout callbacks := NewCallbacks(cfg, logger) restoredData, err := callbacks.RestoreRecreationData(instanceID) if err != nil { t.Fatalf("Could not open file %s, Err: %s", fileName, err) } if !reflect.DeepEqual(recreationData, restoredData) { t.Fatalf("Retrieved Data doesn't equal original. %v != %v", restoredData, recreationData) } // test that it passes instanceID to stdin cfg = config.Callbacks{ ClusterDataRestore: &config.CallbackCommand{ Command: "tee", Arguments: []string{fileName}, }, } callbacks = NewCallbacks(cfg, logger) _, err = callbacks.RestoreRecreationData(instanceID) fileContent, err := ioutil.ReadFile(fileName) if err != nil { t.Fatalf("Could not open file %s, Err: %s", fileName, err) } if structs.ClusterID(fileContent) != instanceID { t.Fatalf("InstanceID %s was not passed via stdin", instanceID) } }
// Bind returns access credentials for a service instance func (bkr *Broker) Bind(instanceID string, bindingID string, details brokerapi.BindDetails) (brokerapi.BindingResponse, error) { return bkr.bind(structs.ClusterID(instanceID), bindingID, details) }
// Provision a new service instance func (bkr *Broker) Provision(instanceID string, details brokerapi.ProvisionDetails, acceptsIncomplete bool) (resp brokerapi.ProvisioningResponse, async bool, err error) { return bkr.provision(structs.ClusterID(instanceID), details, acceptsIncomplete) }
// LastOperation returns the status of the last operation on a service instance // TODO: Plan needs to progressively store the state/description/error message; then // LastOperation fetches it and returns it (rather than doing any calculations of its own) // TODO: AddNode, AddNode, WaitForAllMembersRunning func (bkr *Broker) LastOperation(instanceID string) (resp brokerapi.LastOperationResponse, err error) { return bkr.lastOperation(structs.ClusterID(instanceID)) }
// Deprovision service instance func (bkr *Broker) Deprovision(instanceID string, details brokerapi.DeprovisionDetails, acceptsIncomplete bool) (async bool, err error) { return bkr.deprovision(structs.ClusterID(instanceID), details, acceptsIncomplete) }
// Update service instance func (bkr *Broker) Update(instanceID string, updateDetails brokerapi.UpdateDetails, acceptsIncomplete bool) (async bool, err error) { return bkr.update(structs.ClusterID(instanceID), updateDetails, acceptsIncomplete) }