Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions e2e/backup_restore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -526,8 +526,11 @@ func TestS3CreateDBFromBackup(t *testing.T) {
PatroniPort: pointerTo(0),
Nodes: []*controlplane.DatabaseNodeSpec{
{
Name: "n1",
HostIds: []controlplane.Identifier{controlplane.Identifier(host2)},
Name: "n1",
HostIds: []controlplane.Identifier{
controlplane.Identifier(host1),
controlplane.Identifier(host2),
},
},
},
RestoreConfig: &controlplane.RestoreConfigSpec{
Expand Down
27 changes: 27 additions & 0 deletions server/internal/database/instance_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/samber/do"

"github.com/pgEdge/control-plane/server/internal/certificates"
"github.com/pgEdge/control-plane/server/internal/ds"
"github.com/pgEdge/control-plane/server/internal/patroni"
"github.com/pgEdge/control-plane/server/internal/postgres"
"github.com/pgEdge/control-plane/server/internal/resource"
Expand Down Expand Up @@ -153,6 +154,32 @@ func (r *InstanceResource) Connection(ctx context.Context, rc *resource.Context,
return conn, nil
}

func (r *InstanceResource) InstanceID() string {
return r.Spec.InstanceID
}

func (r *InstanceResource) PostgresVersion() (*ds.Version, error) {
if r.Spec.PgEdgeVersion == nil {
return nil, errors.New("instance spec is missing a pgedge version")
}
if r.Spec.PgEdgeVersion.PostgresVersion == nil {
return nil, errors.New("instance spec is missing a postgres version")
}
return r.Spec.PgEdgeVersion.PostgresVersion, nil
}

func (r *InstanceResource) Paths(orchestrator Orchestrator) (InstancePaths, error) {
postgresVersion, err := r.PostgresVersion()
if err != nil {
return InstancePaths{}, err
}
paths, err := orchestrator.InstancePaths(postgresVersion, r.InstanceID())
if err != nil {
return InstancePaths{}, fmt.Errorf("failed to compute instance paths: %w", err)
}
return paths, nil
}

func (r *InstanceResource) initializeInstance(ctx context.Context, rc *resource.Context) error {
if err := r.updateConnectionInfo(ctx, rc); err != nil {
return err
Expand Down
4 changes: 2 additions & 2 deletions server/internal/database/operations/add_nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ func AddNode(node *NodeResources) ([]*resource.State, error) {

states := make([]*resource.State, 0, 2)

primary, err := instanceState(node.InstanceResources[0])
primary, err := node.InstanceResources[0].InstanceState()
if err != nil {
return nil, err
}
states = append(states, primary)

var replicas *resource.State
for _, inst := range node.InstanceResources[1:] {
replica, err := instanceState(inst)
replica, err := inst.InstanceState()
if err != nil {
return nil, fmt.Errorf("failed to compute replica instance resource state: %w", err)
}
Expand Down
77 changes: 61 additions & 16 deletions server/internal/database/operations/add_nodes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ func TestAddNode(t *testing.T) {
instance1 := makeInstance(t, "n1", 1)
instance2 := makeInstance(t, "n1", 2)
instance3 := makeInstance(t, "n1", 3)
// This is similar to how the PgBackRestStanza resource is returned with the
// instance resources, but it's not a dependency of the instance and it
// depends on the node resource.
n1NodeDependent := makeNodeDependentResource(t, "n1", 1)
instance1OrchestratorResource := makeOrchestratorResource(t, "n1", 1, 1)
instance1WithNodeDependent := makeInstance(t, "n1", 1, instance1OrchestratorResource)
instance1WithNodeDependent.AddNodeDependents(n1NodeDependent)
instance2OrchestratorResource := makeOrchestratorResource(t, "n1", 2, 1)
instance2WithNodeDependent := makeInstance(t, "n1", 2, instance2OrchestratorResource)
instance2WithNodeDependent.AddNodeDependents(n1NodeDependent)

for _, tc := range []struct {
name string
Expand All @@ -40,7 +50,7 @@ func TestAddNode(t *testing.T) {
InstanceIDs: []string{instance1.InstanceID()},
},
},
instance1.Resources,
instance1.InstanceDependencies,
),
},
},
Expand All @@ -62,7 +72,7 @@ func TestAddNode(t *testing.T) {
[]resource.Resource{
instance1.Instance,
},
instance1.Resources,
instance1.InstanceDependencies,
),
makeState(t,
[]resource.Resource{
Expand All @@ -75,7 +85,7 @@ func TestAddNode(t *testing.T) {
},
},
},
instance2.Resources,
instance2.InstanceDependencies,
),
},
},
Expand All @@ -98,7 +108,7 @@ func TestAddNode(t *testing.T) {
[]resource.Resource{
instance1.Instance,
},
instance1.Resources,
instance1.InstanceDependencies,
),
makeState(t,
[]resource.Resource{
Expand All @@ -114,8 +124,8 @@ func TestAddNode(t *testing.T) {
},
},
slices.Concat(
instance2.Resources,
instance3.Resources,
instance2.InstanceDependencies,
instance3.InstanceDependencies,
),
),
},
Expand All @@ -125,6 +135,41 @@ func TestAddNode(t *testing.T) {
input: &operations.NodeResources{NodeName: "n1"},
expectedErr: "got empty instances for node n1",
},
{
name: "two instances with node dependent resource",
input: &operations.NodeResources{
DatabaseName: "test",
NodeName: "n1",
InstanceResources: []*database.InstanceResources{
instance1WithNodeDependent,
instance2WithNodeDependent,
},
},
expected: []*resource.State{
makeState(t,
[]resource.Resource{
instance1WithNodeDependent.Instance,
instance1OrchestratorResource,
},
nil,
),
makeState(t,
[]resource.Resource{
instance2WithNodeDependent.Instance,
instance2OrchestratorResource,
&database.NodeResource{
Name: "n1",
InstanceIDs: []string{
instance1WithNodeDependent.InstanceID(),
instance2WithNodeDependent.InstanceID(),
},
},
n1NodeDependent,
},
nil,
),
},
},
} {
t.Run(tc.name, func(t *testing.T) {
out, err := operations.AddNode(tc.input)
Expand Down Expand Up @@ -170,7 +215,7 @@ func TestAddNodes(t *testing.T) {
InstanceIDs: []string{n1Instance1.InstanceID()},
},
},
n1Instance1.Resources,
n1Instance1.InstanceDependencies,
),
},
},
Expand Down Expand Up @@ -204,8 +249,8 @@ func TestAddNodes(t *testing.T) {
},
},
slices.Concat(
n1Instance1.Resources,
n2Instance1.Resources,
n1Instance1.InstanceDependencies,
n2Instance1.InstanceDependencies,
),
),
},
Expand Down Expand Up @@ -240,8 +285,8 @@ func TestAddNodes(t *testing.T) {
},
},
slices.Concat(
n1Instance1.Resources,
n2Instance1.Resources,
n1Instance1.InstanceDependencies,
n2Instance1.InstanceDependencies,
),
),
makeState(t,
Expand All @@ -256,7 +301,7 @@ func TestAddNodes(t *testing.T) {
},
},
slices.Concat(
n1Instance2.Resources,
n1Instance2.InstanceDependencies,
),
),
},
Expand Down Expand Up @@ -290,8 +335,8 @@ func TestAddNodes(t *testing.T) {
n2Instance1.Instance,
},
slices.Concat(
n1Instance1.Resources,
n2Instance1.Resources,
n1Instance1.InstanceDependencies,
n2Instance1.InstanceDependencies,
),
),
makeState(t,
Expand All @@ -314,8 +359,8 @@ func TestAddNodes(t *testing.T) {
},
},
slices.Concat(
n1Instance2.Resources,
n2Instance2.Resources,
n1Instance2.InstanceDependencies,
n2Instance2.InstanceDependencies,
),
),
},
Expand Down
9 changes: 1 addition & 8 deletions server/internal/database/operations/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func (n *NodeResources) nodeResourceState() (*resource.State, error) {
state := resource.NewState()
for _, instance := range n.InstanceResources {
instanceIDs = append(instanceIDs, instance.InstanceID())
state.Add(instance.NodeDependents...)
}

err := state.AddResource(&database.NodeResource{
Expand Down Expand Up @@ -91,14 +92,6 @@ func (n *NodeResources) databaseResourceState() (*resource.State, error) {
return state, nil
}

func instanceState(inst *database.InstanceResources) (*resource.State, error) {
state, err := inst.State()
if err != nil {
return nil, fmt.Errorf("failed to compute updated instance state: %w", err)
}
return state, nil
}

func mergePartialStates(in [][]*resource.State) []*resource.State {
var out []*resource.State

Expand Down
2 changes: 1 addition & 1 deletion server/internal/database/operations/end.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func EndState(nodes []*NodeResources, services []*ServiceResources) (*resource.S
var resources []resource.Resource

for _, inst := range node.InstanceResources {
state, err := instanceState(inst)
state, err := inst.InstanceState()
if err != nil {
return nil, err
}
Expand Down
30 changes: 30 additions & 0 deletions server/internal/database/operations/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ func makeInstance(t testing.TB, node string, num int, dependencies ...resource.R
},
dependencies,
nil,
nil,
)
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -304,3 +305,32 @@ func makeServiceResources(t testing.TB, databaseID, serviceID, hostID string, no
MonitorResource: monitorResource,
}
}

var _ resource.Resource = (*nodeDependentResource)(nil)

func makeNodeDependentResource(t testing.TB, node string, depNum int) *nodeDependentResource {
t.Helper()

return &nodeDependentResource{
orchestratorResource: orchestratorResource{
ID: fmt.Sprintf("%s-node-dependent-%d-id", node, depNum),
},
node: node,
}
}

type nodeDependentResource struct {
orchestratorResource
node string
}

func (r *nodeDependentResource) Identifier() resource.Identifier {
return resource.Identifier{
ID: r.ID,
Type: "orchestrator.node_dependent_resource",
}
}

func (r *nodeDependentResource) Dependencies() []resource.Identifier {
return []resource.Identifier{database.NodeResourceIdentifier(r.node)}
}
8 changes: 4 additions & 4 deletions server/internal/database/operations/restore_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,25 +67,25 @@ func RestoreNode(node *NodeRestoreResources) ([]*resource.State, error) {

// The pre-restore state only contains the orchestrator resources.
preRestoreState := resource.NewState()
preRestoreState.Add(node.PrimaryInstance.Resources...)
preRestoreState.Add(node.PrimaryInstance.InstanceDependencies...)
states = append(states, preRestoreState)

// The restore state has the restore resources, the instance and the
// instance monitor.
restoreState, err := instanceState(node.RestoreInstance)
restoreState, err := node.RestoreInstance.InstanceState()
if err != nil {
return nil, fmt.Errorf("failed to compute state for restore resources: %w", err)
}
states = append(states, restoreState)

postRestore, err := instanceState(node.PrimaryInstance)
postRestore, err := node.PrimaryInstance.InstanceState()
if err != nil {
return nil, fmt.Errorf("failed to compute post-restore state for primary instance: %w", err)
}
states = append(states, postRestore)

for _, inst := range node.ReplicaInstances {
replica, err := instanceState(inst)
replica, err := inst.InstanceState()
if err != nil {
return nil, fmt.Errorf("failed to compute post-restore state for replica instance: %w", err)
}
Expand Down
12 changes: 6 additions & 6 deletions server/internal/database/operations/restore_database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func TestRestoreDatabase(t *testing.T) {
DatabaseName: "test",
},
},
n1Instance1.Resources,
n1Instance1.InstanceDependencies,
)
twoNodeState := makeState(t,
[]resource.Resource{
Expand Down Expand Up @@ -87,8 +87,8 @@ func TestRestoreDatabase(t *testing.T) {
},
},
slices.Concat(
n1Instance1.Resources,
n2Instance1.Resources,
n1Instance1.InstanceDependencies,
n2Instance1.InstanceDependencies,
),
)
twoNodeStateWithReplica := makeState(t,
Expand Down Expand Up @@ -147,9 +147,9 @@ func TestRestoreDatabase(t *testing.T) {
},
},
slices.Concat(
n1Instance1.Resources,
n1Instance2.Resources,
n2Instance1.Resources,
n1Instance1.InstanceDependencies,
n1Instance2.InstanceDependencies,
n2Instance1.InstanceDependencies,
),
)

Expand Down
Loading