From a46f8d0e29f2afb51ffbf80e4dc52adb7fb71ebf Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Thu, 13 May 2021 17:05:48 -0700 Subject: [PATCH] Rename machine to target. Remove core services. --- .../singleprocess/service_core_environment.go | 55 --- .../singleprocess/service_core_machine.go | 225 ------------ .../server/singleprocess/service_machine.go | 59 --- .../server/singleprocess/service_target.go | 59 +++ .../server/singleprocess/state/machine.go | 338 ------------------ internal/server/singleprocess/state/target.go | 338 ++++++++++++++++++ 6 files changed, 397 insertions(+), 677 deletions(-) delete mode 100644 internal/server/singleprocess/service_core_environment.go delete mode 100644 internal/server/singleprocess/service_core_machine.go delete mode 100644 internal/server/singleprocess/service_machine.go create mode 100644 internal/server/singleprocess/service_target.go delete mode 100644 internal/server/singleprocess/state/machine.go create mode 100644 internal/server/singleprocess/state/target.go diff --git a/internal/server/singleprocess/service_core_environment.go b/internal/server/singleprocess/service_core_environment.go deleted file mode 100644 index b344e43bf..000000000 --- a/internal/server/singleprocess/service_core_environment.go +++ /dev/null @@ -1,55 +0,0 @@ -package singleprocess - -import ( - "context" - "strings" - - "github.com/golang/protobuf/ptypes/empty" - "github.com/hashicorp/vagrant-plugin-sdk/proto/vagrant_plugin_sdk" - - "github.com/hashicorp/vagrant/internal/server/proto/vagrant_server" - serverptypes "github.com/hashicorp/vagrant/internal/server/ptypes" -) - -func (s *service) MachineNames( - ctx context.Context, - in *empty.Empty, -) (result *vagrant_plugin_sdk.Project_MachineNamesResponse, err error) { - machines, err := s.state.MachineList() - if err != nil { - return nil, err - } - - machineNames := []string{} - for _, m := range machines { - sanatizedName := strings.Split(m.Name, "+")[1] - machineNames = append(machineNames, sanatizedName) - } - return &vagrant_plugin_sdk.Project_MachineNamesResponse{ - Names: machineNames, - }, nil -} - -func (s *service) ActiveMachines( - ctx context.Context, - in *vagrant_plugin_sdk.Project_ActiveMachinesRequest, -) (result *vagrant_plugin_sdk.Project_ActiveMachinesResponse, err error) { - machines := []*vagrant_plugin_sdk.Project_MachineAndProvider{} - - p, err := s.state.ProjectGet(&vagrant_server.Ref_Project{ - ResourceId: in.Env.ProjectId, - }) - pp := serverptypes.Project{Project: p} - for _, m := range pp.Project.Machines { - machine, err := s.state.MachineGet(m) - if err != nil { - // Machine not found - } - machines = append(machines, - &vagrant_plugin_sdk.Project_MachineAndProvider{Name: machine.Name, Provider: machine.Provider}) - } - - return &vagrant_plugin_sdk.Project_ActiveMachinesResponse{ - Machines: machines, - }, nil -} diff --git a/internal/server/singleprocess/service_core_machine.go b/internal/server/singleprocess/service_core_machine.go deleted file mode 100644 index 74c1abc4c..000000000 --- a/internal/server/singleprocess/service_core_machine.go +++ /dev/null @@ -1,225 +0,0 @@ -package singleprocess - -import ( - "context" - - "github.com/hashicorp/vagrant-plugin-sdk/helper/paths" - "github.com/hashicorp/vagrant-plugin-sdk/proto/vagrant_plugin_sdk" - "github.com/hashicorp/vagrant/internal/server/proto/vagrant_server" -) - -func (s *service) Box( - ctx context.Context, - in *vagrant_plugin_sdk.Machine_BoxRequest, -) (result *vagrant_plugin_sdk.Machine_BoxResponse, err error) { - // TODO: actually get the box! - - // m, err := s.state.MachineGet( - // &vagrant_server.Ref_Machine{ - // ResourceId: in.Machine.ResourceId, - // }, - // ) - // if err != nil { - // return - // } - - dataPath, _ := paths.VagrantHome() - - fakeBox := &vagrant_plugin_sdk.Args_Box{ - Name: "hashicorp/bionic64", - Provider: "virtualbox", - Version: "1.0.282", - Directory: dataPath.String() + "/boxes/hashicorp-VAGRANTSLASH-bionic64/1.0.282/virtualbox", - Metadata: map[string]string{}, - MetadataUrl: "https://vagrantcloud.com/hashicorp/bionic64", - } - - return &vagrant_plugin_sdk.Machine_BoxResponse{ - // Box: m.Box, - Box: fakeBox, - }, nil -} - -func (s *service) SetName( - ctx context.Context, - in *vagrant_plugin_sdk.Machine_SetNameRequest, -) (result *vagrant_plugin_sdk.Machine_SetNameResponse, err error) { - return -} - -func (s *service) GetName( - ctx context.Context, - in *vagrant_plugin_sdk.Machine_GetNameRequest, -) (result *vagrant_plugin_sdk.Machine_GetNameResponse, err error) { - m, err := s.state.MachineGet( - &vagrant_server.Ref_Machine{ - ResourceId: in.Machine.ResourceId, - }, - ) - if err != nil { - return - } - - return &vagrant_plugin_sdk.Machine_GetNameResponse{ - Name: m.Name, - }, nil -} - -func (s *service) SetID( - ctx context.Context, - in *vagrant_plugin_sdk.Machine_SetIDRequest, -) (result *vagrant_plugin_sdk.Machine_SetIDResponse, err error) { - m, err := s.state.MachineGet( - &vagrant_server.Ref_Machine{ - ResourceId: in.Machine.ResourceId, - }, - ) - if err != nil { - return - } - m.Id = in.Id - _, err = s.state.MachinePut(m) - return &vagrant_plugin_sdk.Machine_SetIDResponse{}, err -} - -func (s *service) GetID( - ctx context.Context, - in *vagrant_plugin_sdk.Machine_GetIDRequest, -) (result *vagrant_plugin_sdk.Machine_GetIDResponse, err error) { - m, err := s.state.MachineGet( - &vagrant_server.Ref_Machine{ - ResourceId: in.Machine.ResourceId, - }, - ) - if err != nil { - return - } - - return &vagrant_plugin_sdk.Machine_GetIDResponse{ - Id: m.Id, - }, nil -} - -func (s *service) Datadir( - ctx context.Context, - in *vagrant_plugin_sdk.Machine_DatadirRequest, -) (result *vagrant_plugin_sdk.Machine_DatadirResponse, err error) { - m, err := s.state.MachineGet( - &vagrant_server.Ref_Machine{ - ResourceId: in.Machine.ResourceId, - }, - ) - if err != nil { - return - } - - return &vagrant_plugin_sdk.Machine_DatadirResponse{ - Datadir: m.Datadir, - }, nil -} - -func (s *service) LocalDataPath( - ctx context.Context, - in *vagrant_plugin_sdk.Machine_LocalDataPathRequest, -) (result *vagrant_plugin_sdk.Machine_LocalDataPathResponse, err error) { - return -} - -func (s *service) Provider( - ctx context.Context, - in *vagrant_plugin_sdk.Machine_ProviderRequest, -) (result *vagrant_plugin_sdk.Machine_ProviderResponse, err error) { - m, err := s.state.MachineGet( - &vagrant_server.Ref_Machine{ - ResourceId: in.Machine.ResourceId, - }, - ) - if err != nil { - return - } - - return &vagrant_plugin_sdk.Machine_ProviderResponse{ - Provider: m.Provider, - }, nil -} - -func (s *service) VagrantfileName( - ctx context.Context, - in *vagrant_plugin_sdk.Machine_VagrantfileNameRequest, -) (result *vagrant_plugin_sdk.Machine_VagrantfileNameResponse, err error) { - return -} - -func (s *service) VagrantfilePath( - ctx context.Context, - in *vagrant_plugin_sdk.Machine_VagrantfilePathRequest, -) (result *vagrant_plugin_sdk.Machine_VagrantfilePathResponse, err error) { - return -} - -func (s *service) UpdatedAt( - ctx context.Context, - in *vagrant_plugin_sdk.Machine_UpdatedAtRequest, -) (result *vagrant_plugin_sdk.Machine_UpdatedAtResponse, err error) { - return -} - -func (s *service) UI( - ctx context.Context, - in *vagrant_plugin_sdk.Machine_UIRequest, -) (result *vagrant_plugin_sdk.Machine_UIResponse, err error) { - return -} - -func (s *service) GetState( - ctx context.Context, - in *vagrant_plugin_sdk.Machine_GetStateRequest, -) (result *vagrant_plugin_sdk.Machine_GetStateResponse, err error) { - m, err := s.state.MachineGet( - &vagrant_server.Ref_Machine{ - ResourceId: in.Machine.ResourceId, - }, - ) - if err != nil { - return - } - - return &vagrant_plugin_sdk.Machine_GetStateResponse{ - State: m.State, - }, nil - -} - -func (s *service) GetUUID( - ctx context.Context, - in *vagrant_plugin_sdk.Machine_GetUUIDRequest, -) (result *vagrant_plugin_sdk.Machine_GetUUIDResponse, err error) { - return &vagrant_plugin_sdk.Machine_GetUUIDResponse{ - Uuid: "XXXXXXXXX", - }, nil -} - -func (s *service) SetUUID( - ctx context.Context, - in *vagrant_plugin_sdk.Machine_SetUUIDRequest, -) (result *vagrant_plugin_sdk.Machine_SetUUIDResponse, err error) { - return -} - -func (s *service) SetState( - ctx context.Context, - in *vagrant_plugin_sdk.Machine_SetStateRequest, -) (result *vagrant_plugin_sdk.Machine_SetStateResponse, err error) { - m, err := s.state.MachineGet( - &vagrant_server.Ref_Machine{ - ResourceId: in.Machine.ResourceId, - }, - ) - if err != nil { - return - } - - m.State = in.State - _, err = s.state.MachinePut(m) - return &vagrant_plugin_sdk.Machine_SetStateResponse{}, err -} diff --git a/internal/server/singleprocess/service_machine.go b/internal/server/singleprocess/service_machine.go deleted file mode 100644 index d51fc68a3..000000000 --- a/internal/server/singleprocess/service_machine.go +++ /dev/null @@ -1,59 +0,0 @@ -package singleprocess - -import ( - "context" - - "github.com/golang/protobuf/ptypes/empty" - - "github.com/hashicorp/vagrant/internal/server/proto/vagrant_server" -) - -// TODO: test -func (s *service) UpsertMachine( - ctx context.Context, - req *vagrant_server.UpsertMachineRequest, -) (*vagrant_server.UpsertMachineResponse, error) { - m, err := s.state.MachinePut(req.Machine) - if err != nil { - return nil, err - } - - return &vagrant_server.UpsertMachineResponse{Machine: m}, nil -} - -// TODO: test -func (s *service) GetMachine( - ctx context.Context, - req *vagrant_server.GetMachineRequest, -) (*vagrant_server.GetMachineResponse, error) { - result, err := s.state.MachineGet(req.Machine) - if err != nil { - return nil, err - } - - return &vagrant_server.GetMachineResponse{Machine: result}, nil -} - -func (s *service) FindMachine( - ctx context.Context, - req *vagrant_server.FindMachineRequest, -) (*vagrant_server.FindMachineResponse, error) { - result, err := s.state.MachineFind(req.Machine) - if err != nil { - return nil, err - } - return &vagrant_server.FindMachineResponse{Machine: result, Found: true}, nil -} - -// TODO: test -func (s *service) ListMachines( - ctx context.Context, - req *empty.Empty, -) (*vagrant_server.ListMachinesResponse, error) { - result, err := s.state.MachineList() - if err != nil { - return nil, err - } - - return &vagrant_server.ListMachinesResponse{Machines: result}, nil -} diff --git a/internal/server/singleprocess/service_target.go b/internal/server/singleprocess/service_target.go new file mode 100644 index 000000000..25e31d554 --- /dev/null +++ b/internal/server/singleprocess/service_target.go @@ -0,0 +1,59 @@ +package singleprocess + +import ( + "context" + + "github.com/golang/protobuf/ptypes/empty" + + "github.com/hashicorp/vagrant/internal/server/proto/vagrant_server" +) + +// TODO: test +func (s *service) UpsertTarget( + ctx context.Context, + req *vagrant_server.UpsertTargetRequest, +) (*vagrant_server.UpsertTargetResponse, error) { + m, err := s.state.TargetPut(req.Target) + if err != nil { + return nil, err + } + + return &vagrant_server.UpsertTargetResponse{Target: m}, nil +} + +// TODO: test +func (s *service) GetTarget( + ctx context.Context, + req *vagrant_server.GetTargetRequest, +) (*vagrant_server.GetTargetResponse, error) { + result, err := s.state.TargetGet(req.Target) + if err != nil { + return nil, err + } + + return &vagrant_server.GetTargetResponse{Target: result}, nil +} + +func (s *service) FindTarget( + ctx context.Context, + req *vagrant_server.FindTargetRequest, +) (*vagrant_server.FindTargetResponse, error) { + result, err := s.state.TargetFind(req.Target) + if err != nil { + return nil, err + } + return &vagrant_server.FindTargetResponse{Target: result, Found: true}, nil +} + +// TODO: test +func (s *service) ListTargets( + ctx context.Context, + req *empty.Empty, +) (*vagrant_server.ListTargetsResponse, error) { + result, err := s.state.TargetList() + if err != nil { + return nil, err + } + + return &vagrant_server.ListTargetsResponse{Targets: result}, nil +} diff --git a/internal/server/singleprocess/state/machine.go b/internal/server/singleprocess/state/machine.go deleted file mode 100644 index 375c19a86..000000000 --- a/internal/server/singleprocess/state/machine.go +++ /dev/null @@ -1,338 +0,0 @@ -package state - -import ( - "strings" - - "github.com/boltdb/bolt" - "github.com/golang/protobuf/proto" - "github.com/hashicorp/go-memdb" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - "github.com/hashicorp/vagrant/internal/server/proto/vagrant_server" - serverptypes "github.com/hashicorp/vagrant/internal/server/ptypes" -) - -var machineBucket = []byte("machine") - -func init() { - dbBuckets = append(dbBuckets, machineBucket) - dbIndexers = append(dbIndexers, (*State).machineIndexInit) - schemas = append(schemas, machineIndexSchema) -} - -func (s *State) MachineFind(m *vagrant_server.Machine) (*vagrant_server.Machine, error) { - memTxn := s.inmem.Txn(false) - defer memTxn.Abort() - - var result *vagrant_server.Machine - err := s.db.View(func(dbTxn *bolt.Tx) error { - var err error - result, err = s.machineFind(dbTxn, memTxn, m) - return err - }) - - return result, err -} - -func (s *State) MachinePut(machine *vagrant_server.Machine) (*vagrant_server.Machine, error) { - memTxn := s.inmem.Txn(true) - defer memTxn.Abort() - - err := s.db.Update(func(dbTxn *bolt.Tx) error { - return s.machinePut(dbTxn, memTxn, machine) - }) - if err == nil { - memTxn.Commit() - } - return machine, err -} - -func (s *State) MachineDelete(ref *vagrant_server.Ref_Machine) error { - memTxn := s.inmem.Txn(true) - defer memTxn.Abort() - - err := s.db.Update(func(dbTxn *bolt.Tx) error { - return s.machineDelete(dbTxn, memTxn, ref) - }) - if err == nil { - memTxn.Commit() - } - - return err -} - -func (s *State) MachineGet(ref *vagrant_server.Ref_Machine) (*vagrant_server.Machine, error) { - memTxn := s.inmem.Txn(false) - defer memTxn.Abort() - - var result *vagrant_server.Machine - err := s.db.View(func(dbTxn *bolt.Tx) error { - var err error - result, err = s.machineGet(dbTxn, memTxn, ref) - return err - }) - - return result, err -} - -func (s *State) MachineList() ([]*vagrant_server.Ref_Machine, error) { - memTxn := s.inmem.Txn(false) - defer memTxn.Abort() - - return s.machineList(memTxn) -} - -func (s *State) machineFind( - dbTxn *bolt.Tx, - memTxn *memdb.Txn, - m *vagrant_server.Machine, -) (*vagrant_server.Machine, error) { - var match *machineIndexRecord - req := s.newMachineIndexRecord(m) - - // Start with the resource id first - if req.Id != "" { - if raw, err := memTxn.First( - machineIndexTableName, - machineIndexIdIndexName, - req.Id, - ); raw != nil && err == nil { - match = raw.(*machineIndexRecord) - } - } - // Try the name next - if match == nil && req.Name != "" { - if raw, err := memTxn.First( - machineIndexTableName, - machineIndexNameIndexName, - req.Name, - ); raw != nil && err == nil { - match = raw.(*machineIndexRecord) - } - } - // Finally try the machine id - if match == nil && req.MachineId != "" { - if raw, err := memTxn.First( - machineIndexTableName, - machineIndexMachineIdIndexName, - req.MachineId, - ); raw != nil && err == nil { - match = raw.(*machineIndexRecord) - } - } - - if match == nil { - return nil, status.Errorf(codes.NotFound, "record not found for Machine") - } - - return s.machineGet(dbTxn, memTxn, &vagrant_server.Ref_Machine{ - ResourceId: match.Id, - }) -} - -func (s *State) machineList( - memTxn *memdb.Txn, -) ([]*vagrant_server.Ref_Machine, error) { - iter, err := memTxn.Get(machineIndexTableName, machineIndexIdIndexName+"_prefix", "") - if err != nil { - return nil, err - } - - var result []*vagrant_server.Ref_Machine - for { - next := iter.Next() - if next == nil { - break - } - result = append(result, &vagrant_server.Ref_Machine{ - ResourceId: next.(*machineIndexRecord).Id, - Name: next.(*machineIndexRecord).Name, - }) - } - - return result, nil -} - -func (s *State) machinePut( - dbTxn *bolt.Tx, - memTxn *memdb.Txn, - value *vagrant_server.Machine, -) (err error) { - s.log.Trace("storing machine", "machine", value, "project", - value.Project, "basis", value.Project.Basis) - - p, err := s.projectGet(dbTxn, memTxn, value.Project) - if err != nil { - s.log.Error("failed to locate project for machine", "machine", value, - "project", p, "error", err) - return - } - - if value.ResourceId == "" { - s.log.Trace("machine has no resource id, assuming new machine", - "machine", value) - if value.ResourceId, err = s.newResourceId(); err != nil { - s.log.Error("failed to create resource id for machine", "machine", value, - "error", err) - return - } - } - - s.log.Trace("storing machine to db", "machine", value) - id := s.machineId(value) - b := dbTxn.Bucket(machineBucket) - if err = dbPut(b, id, value); err != nil { - s.log.Error("failed to store machine in db", "machine", value, "error", err) - return - } - - s.log.Trace("indexing machine", "machine", value) - if err = s.machineIndexSet(memTxn, id, value); err != nil { - s.log.Error("failed to index machine", "machine", value, "error", err) - return - } - - s.log.Trace("adding machine to project", "machine", value, "project", p) - pp := serverptypes.Project{Project: p} - if pp.AddMachine(value) { - s.log.Trace("machine added to project, updating project", "project", p) - if err = s.projectPut(dbTxn, memTxn, p); err != nil { - s.log.Error("failed to update project", "project", p, "error", err) - return - } - } else { - s.log.Trace("machine already exists in project", "machine", value, "project", p) - } - - return -} - -func (s *State) machineGet( - dbTxn *bolt.Tx, - memTxn *memdb.Txn, - ref *vagrant_server.Ref_Machine, -) (*vagrant_server.Machine, error) { - var result vagrant_server.Machine - b := dbTxn.Bucket(machineBucket) - return &result, dbGet(b, s.machineIdByRef(ref), &result) -} - -func (s *State) machineDelete( - dbTxn *bolt.Tx, - memTxn *memdb.Txn, - ref *vagrant_server.Ref_Machine, -) (err error) { - p, err := s.projectGet(dbTxn, memTxn, &vagrant_server.Ref_Project{ResourceId: ref.Project.ResourceId}) - if err != nil { - return - } - - if err = dbTxn.Bucket(machineBucket).Delete(s.machineIdByRef(ref)); err != nil { - return - } - if err = memTxn.Delete(machineIndexTableName, s.newMachineIndexRecordByRef(ref)); err != nil { - return - } - - pp := serverptypes.Project{Project: p} - if pp.DeleteMachineRef(ref) { - if err = s.projectPut(dbTxn, memTxn, p); err != nil { - return - } - } - return -} - -func (s *State) machineIndexSet(txn *memdb.Txn, id []byte, value *vagrant_server.Machine) error { - return txn.Insert(machineIndexTableName, s.newMachineIndexRecord(value)) -} - -func (s *State) machineIndexInit(dbTxn *bolt.Tx, memTxn *memdb.Txn) error { - bucket := dbTxn.Bucket(machineBucket) - return bucket.ForEach(func(k, v []byte) error { - var value vagrant_server.Machine - if err := proto.Unmarshal(v, &value); err != nil { - return err - } - if err := s.machineIndexSet(memTxn, k, &value); err != nil { - return err - } - - return nil - }) -} - -func machineIndexSchema() *memdb.TableSchema { - return &memdb.TableSchema{ - Name: machineIndexTableName, - Indexes: map[string]*memdb.IndexSchema{ - machineIndexIdIndexName: { - Name: machineIndexIdIndexName, - AllowMissing: false, - Unique: true, - Indexer: &memdb.StringFieldIndex{ - Field: "Id", - Lowercase: false, - }, - }, - machineIndexNameIndexName: { - Name: machineIndexNameIndexName, - AllowMissing: false, - Unique: true, - Indexer: &memdb.StringFieldIndex{ - Field: "Name", - Lowercase: true, - }, - }, - machineIndexMachineIdIndexName: { - Name: machineIndexMachineIdIndexName, - AllowMissing: true, - Unique: true, - Indexer: &memdb.StringFieldIndex{ - Field: "MachineId", - Lowercase: false, - }, - }, - }, - } -} - -const ( - machineIndexIdIndexName = "id" - machineIndexNameIndexName = "name" - machineIndexMachineIdIndexName = "machine-id" - machineIndexTableName = "machine-index" -) - -type machineIndexRecord struct { - Id string // Resource ID - Name string // Project Resource ID + Machine Name - MachineId string // Project Resource ID + Machine ID (not machine resource id) -} - -func (s *State) newMachineIndexRecord(m *vagrant_server.Machine) *machineIndexRecord { - i := &machineIndexRecord{ - Id: m.ResourceId, - Name: strings.ToLower(m.Project.ResourceId + "+" + m.Name), - } - if m.Id != "" { - i.MachineId = m.Project.ResourceId + "+" + m.Id - } - return i -} - -func (s *State) newMachineIndexRecordByRef(ref *vagrant_server.Ref_Machine) *machineIndexRecord { - return &machineIndexRecord{ - Id: ref.ResourceId, - Name: strings.ToLower(ref.Project.ResourceId + "+" + ref.Name), - } -} - -func (s *State) machineId(m *vagrant_server.Machine) []byte { - return []byte(m.ResourceId) -} - -func (s *State) machineIdByRef(m *vagrant_server.Ref_Machine) []byte { - return []byte(m.ResourceId) -} diff --git a/internal/server/singleprocess/state/target.go b/internal/server/singleprocess/state/target.go new file mode 100644 index 000000000..93aaf7291 --- /dev/null +++ b/internal/server/singleprocess/state/target.go @@ -0,0 +1,338 @@ +package state + +import ( + "strings" + + "github.com/boltdb/bolt" + "github.com/golang/protobuf/proto" + "github.com/hashicorp/go-memdb" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/hashicorp/vagrant/internal/server/proto/vagrant_server" + serverptypes "github.com/hashicorp/vagrant/internal/server/ptypes" +) + +var targetBucket = []byte("target") + +func init() { + dbBuckets = append(dbBuckets, targetBucket) + dbIndexers = append(dbIndexers, (*State).targetIndexInit) + schemas = append(schemas, targetIndexSchema) +} + +func (s *State) TargetFind(m *vagrant_server.Target) (*vagrant_server.Target, error) { + memTxn := s.inmem.Txn(false) + defer memTxn.Abort() + + var result *vagrant_server.Target + err := s.db.View(func(dbTxn *bolt.Tx) error { + var err error + result, err = s.targetFind(dbTxn, memTxn, m) + return err + }) + + return result, err +} + +func (s *State) TargetPut(target *vagrant_server.Target) (*vagrant_server.Target, error) { + memTxn := s.inmem.Txn(true) + defer memTxn.Abort() + + err := s.db.Update(func(dbTxn *bolt.Tx) error { + return s.targetPut(dbTxn, memTxn, target) + }) + if err == nil { + memTxn.Commit() + } + return target, err +} + +func (s *State) TargetDelete(ref *vagrant_server.Ref_Target) error { + memTxn := s.inmem.Txn(true) + defer memTxn.Abort() + + err := s.db.Update(func(dbTxn *bolt.Tx) error { + return s.targetDelete(dbTxn, memTxn, ref) + }) + if err == nil { + memTxn.Commit() + } + + return err +} + +func (s *State) TargetGet(ref *vagrant_server.Ref_Target) (*vagrant_server.Target, error) { + memTxn := s.inmem.Txn(false) + defer memTxn.Abort() + + var result *vagrant_server.Target + err := s.db.View(func(dbTxn *bolt.Tx) error { + var err error + result, err = s.targetGet(dbTxn, memTxn, ref) + return err + }) + + return result, err +} + +func (s *State) TargetList() ([]*vagrant_server.Ref_Target, error) { + memTxn := s.inmem.Txn(false) + defer memTxn.Abort() + + return s.targetList(memTxn) +} + +func (s *State) targetFind( + dbTxn *bolt.Tx, + memTxn *memdb.Txn, + m *vagrant_server.Target, +) (*vagrant_server.Target, error) { + var match *targetIndexRecord + req := s.newTargetIndexRecord(m) + + // Start with the resource id first + if req.Id != "" { + if raw, err := memTxn.First( + targetIndexTableName, + targetIndexIdIndexName, + req.Id, + ); raw != nil && err == nil { + match = raw.(*targetIndexRecord) + } + } + // Try the name next + if match == nil && req.Name != "" { + if raw, err := memTxn.First( + targetIndexTableName, + targetIndexNameIndexName, + req.Name, + ); raw != nil && err == nil { + match = raw.(*targetIndexRecord) + } + } + // Finally try the target id + if match == nil && req.TargetId != "" { + if raw, err := memTxn.First( + targetIndexTableName, + targetIndexTargetIdIndexName, + req.TargetId, + ); raw != nil && err == nil { + match = raw.(*targetIndexRecord) + } + } + + if match == nil { + return nil, status.Errorf(codes.NotFound, "record not found for Target") + } + + return s.targetGet(dbTxn, memTxn, &vagrant_server.Ref_Target{ + ResourceId: match.Id, + }) +} + +func (s *State) targetList( + memTxn *memdb.Txn, +) ([]*vagrant_server.Ref_Target, error) { + iter, err := memTxn.Get(targetIndexTableName, targetIndexIdIndexName+"_prefix", "") + if err != nil { + return nil, err + } + + var result []*vagrant_server.Ref_Target + for { + next := iter.Next() + if next == nil { + break + } + result = append(result, &vagrant_server.Ref_Target{ + ResourceId: next.(*targetIndexRecord).Id, + Name: next.(*targetIndexRecord).Name, + }) + } + + return result, nil +} + +func (s *State) targetPut( + dbTxn *bolt.Tx, + memTxn *memdb.Txn, + value *vagrant_server.Target, +) (err error) { + s.log.Trace("storing target", "target", value, "project", + value.Project, "basis", value.Project.Basis) + + p, err := s.projectGet(dbTxn, memTxn, value.Project) + if err != nil { + s.log.Error("failed to locate project for target", "target", value, + "project", p, "error", err) + return + } + + if value.ResourceId == "" { + s.log.Trace("target has no resource id, assuming new target", + "target", value) + if value.ResourceId, err = s.newResourceId(); err != nil { + s.log.Error("failed to create resource id for target", "target", value, + "error", err) + return + } + } + + s.log.Trace("storing target to db", "target", value) + id := s.targetId(value) + b := dbTxn.Bucket(targetBucket) + if err = dbPut(b, id, value); err != nil { + s.log.Error("failed to store target in db", "target", value, "error", err) + return + } + + s.log.Trace("indexing target", "target", value) + if err = s.targetIndexSet(memTxn, id, value); err != nil { + s.log.Error("failed to index target", "target", value, "error", err) + return + } + + s.log.Trace("adding target to project", "target", value, "project", p) + pp := serverptypes.Project{Project: p} + if pp.AddTarget(value) { + s.log.Trace("target added to project, updating project", "project", p) + if err = s.projectPut(dbTxn, memTxn, p); err != nil { + s.log.Error("failed to update project", "project", p, "error", err) + return + } + } else { + s.log.Trace("target already exists in project", "target", value, "project", p) + } + + return +} + +func (s *State) targetGet( + dbTxn *bolt.Tx, + memTxn *memdb.Txn, + ref *vagrant_server.Ref_Target, +) (*vagrant_server.Target, error) { + var result vagrant_server.Target + b := dbTxn.Bucket(targetBucket) + return &result, dbGet(b, s.targetIdByRef(ref), &result) +} + +func (s *State) targetDelete( + dbTxn *bolt.Tx, + memTxn *memdb.Txn, + ref *vagrant_server.Ref_Target, +) (err error) { + p, err := s.projectGet(dbTxn, memTxn, &vagrant_server.Ref_Project{ResourceId: ref.Project.ResourceId}) + if err != nil { + return + } + + if err = dbTxn.Bucket(targetBucket).Delete(s.targetIdByRef(ref)); err != nil { + return + } + if err = memTxn.Delete(targetIndexTableName, s.newTargetIndexRecordByRef(ref)); err != nil { + return + } + + pp := serverptypes.Project{Project: p} + if pp.DeleteTargetRef(ref) { + if err = s.projectPut(dbTxn, memTxn, p); err != nil { + return + } + } + return +} + +func (s *State) targetIndexSet(txn *memdb.Txn, id []byte, value *vagrant_server.Target) error { + return txn.Insert(targetIndexTableName, s.newTargetIndexRecord(value)) +} + +func (s *State) targetIndexInit(dbTxn *bolt.Tx, memTxn *memdb.Txn) error { + bucket := dbTxn.Bucket(targetBucket) + return bucket.ForEach(func(k, v []byte) error { + var value vagrant_server.Target + if err := proto.Unmarshal(v, &value); err != nil { + return err + } + if err := s.targetIndexSet(memTxn, k, &value); err != nil { + return err + } + + return nil + }) +} + +func targetIndexSchema() *memdb.TableSchema { + return &memdb.TableSchema{ + Name: targetIndexTableName, + Indexes: map[string]*memdb.IndexSchema{ + targetIndexIdIndexName: { + Name: targetIndexIdIndexName, + AllowMissing: false, + Unique: true, + Indexer: &memdb.StringFieldIndex{ + Field: "Id", + Lowercase: false, + }, + }, + targetIndexNameIndexName: { + Name: targetIndexNameIndexName, + AllowMissing: false, + Unique: true, + Indexer: &memdb.StringFieldIndex{ + Field: "Name", + Lowercase: true, + }, + }, + targetIndexTargetIdIndexName: { + Name: targetIndexTargetIdIndexName, + AllowMissing: true, + Unique: true, + Indexer: &memdb.StringFieldIndex{ + Field: "TargetId", + Lowercase: false, + }, + }, + }, + } +} + +const ( + targetIndexIdIndexName = "id" + targetIndexNameIndexName = "name" + targetIndexTargetIdIndexName = "target-id" + targetIndexTableName = "target-index" +) + +type targetIndexRecord struct { + Id string // Resource ID + Name string // Project Resource ID + Target Name + TargetId string // Project Resource ID + Target ID (not target resource id) +} + +func (s *State) newTargetIndexRecord(m *vagrant_server.Target) *targetIndexRecord { + i := &targetIndexRecord{ + Id: m.ResourceId, + Name: strings.ToLower(m.Project.ResourceId + "+" + m.Name), + } + if m.Id != "" { + i.TargetId = m.Project.ResourceId + "+" + m.Id + } + return i +} + +func (s *State) newTargetIndexRecordByRef(ref *vagrant_server.Ref_Target) *targetIndexRecord { + return &targetIndexRecord{ + Id: ref.ResourceId, + Name: strings.ToLower(ref.Project.ResourceId + "+" + ref.Name), + } +} + +func (s *State) targetId(m *vagrant_server.Target) []byte { + return []byte(m.ResourceId) +} + +func (s *State) targetIdByRef(m *vagrant_server.Ref_Target) []byte { + return []byte(m.ResourceId) +}