-
Notifications
You must be signed in to change notification settings - Fork 222
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Vivin Thomas Wilson <vivintwilson@gmail.com> Co-authored-by: Vivin <vivin@netapp.com>
- Loading branch information
1 parent
1779f49
commit e0e1fac
Showing
43 changed files
with
2,771 additions
and
163 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package execution | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/netapp/trident/internal/nodeprep/instruction" | ||
. "github.com/netapp/trident/logging" | ||
) | ||
|
||
func Execute(ctx context.Context, instructions []instruction.Instructions) (err error) { | ||
for _, i := range instructions { | ||
Log().WithField("instructions", i.GetName()).Info("Preparing node") | ||
if err = i.PreCheck(ctx); err != nil { | ||
return | ||
} | ||
if err = i.Apply(ctx); err != nil { | ||
return | ||
} | ||
if err = i.PostCheck(ctx); err != nil { | ||
return | ||
} | ||
} | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
// Copyright 2024 NetApp, Inc. All Rights Reserved. | ||
|
||
package execution_test | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"go.uber.org/mock/gomock" | ||
|
||
"github.com/netapp/trident/internal/nodeprep/execution" | ||
"github.com/netapp/trident/internal/nodeprep/instruction" | ||
"github.com/netapp/trident/mocks/mock_internal/mock_nodeprep/mock_instruction" | ||
"github.com/netapp/trident/utils/errors" | ||
) | ||
|
||
func TestExecute(t *testing.T) { | ||
type parameters struct { | ||
getInstructions func(controller *gomock.Controller) []instruction.Instructions | ||
assertError assert.ErrorAssertionFunc | ||
} | ||
|
||
tests := map[string]parameters{ | ||
"execute single instruction successfully": { | ||
getInstructions: func(controller *gomock.Controller) []instruction.Instructions { | ||
mockInstruction := mock_instruction.NewMockInstructions(controller) | ||
mockInstruction.EXPECT().GetName().Return("mockInstruction") | ||
mockInstruction.EXPECT().PreCheck(gomock.Any()).Return(nil) | ||
mockInstruction.EXPECT().Apply(gomock.Any()).Return(nil) | ||
mockInstruction.EXPECT().PostCheck(gomock.Any()).Return(nil) | ||
return []instruction.Instructions{mockInstruction} | ||
}, | ||
assertError: assert.NoError, | ||
}, | ||
"execute single instruction pre check failure": { | ||
getInstructions: func(controller *gomock.Controller) []instruction.Instructions { | ||
mockInstruction := mock_instruction.NewMockInstructions(controller) | ||
mockInstruction.EXPECT().GetName().Return("mockInstruction") | ||
mockInstruction.EXPECT().PreCheck(gomock.Any()).Return(errors.New("mock error")) | ||
return []instruction.Instructions{mockInstruction} | ||
}, | ||
assertError: assert.Error, | ||
}, | ||
"execute single instruction apply failure": { | ||
getInstructions: func(controller *gomock.Controller) []instruction.Instructions { | ||
mockInstruction := mock_instruction.NewMockInstructions(controller) | ||
mockInstruction.EXPECT().GetName().Return("mockInstruction") | ||
mockInstruction.EXPECT().PreCheck(gomock.Any()).Return(nil) | ||
mockInstruction.EXPECT().Apply(gomock.Any()).Return(errors.New("mock error")) | ||
return []instruction.Instructions{mockInstruction} | ||
}, | ||
assertError: assert.Error, | ||
}, | ||
"execute single instruction post check failure": { | ||
getInstructions: func(controller *gomock.Controller) []instruction.Instructions { | ||
mockInstruction := mock_instruction.NewMockInstructions(controller) | ||
mockInstruction.EXPECT().GetName().Return("mockInstruction") | ||
mockInstruction.EXPECT().PreCheck(gomock.Any()).Return(nil) | ||
mockInstruction.EXPECT().Apply(gomock.Any()).Return(nil) | ||
mockInstruction.EXPECT().PostCheck(gomock.Any()).Return(errors.New("mock error")) | ||
return []instruction.Instructions{mockInstruction} | ||
}, | ||
assertError: assert.Error, | ||
}, | ||
"execute multi instruction successfully": { | ||
getInstructions: func(controller *gomock.Controller) []instruction.Instructions { | ||
mockInstruction1 := mock_instruction.NewMockInstructions(controller) | ||
mockInstruction1.EXPECT().GetName().Return("mockInstruction") | ||
mockInstruction1.EXPECT().PreCheck(gomock.Any()).Return(nil) | ||
mockInstruction1.EXPECT().Apply(gomock.Any()).Return(nil) | ||
mockInstruction1.EXPECT().PostCheck(gomock.Any()).Return(nil) | ||
|
||
mockInstruction2 := mock_instruction.NewMockInstructions(controller) | ||
mockInstruction2.EXPECT().GetName().Return("mockInstruction") | ||
mockInstruction2.EXPECT().PreCheck(gomock.Any()).Return(nil) | ||
mockInstruction2.EXPECT().Apply(gomock.Any()).Return(nil) | ||
mockInstruction2.EXPECT().PostCheck(gomock.Any()).Return(nil) | ||
|
||
return []instruction.Instructions{mockInstruction1, mockInstruction2} | ||
}, | ||
assertError: assert.NoError, | ||
}, | ||
"execute multi instruction first instruction failure": { | ||
getInstructions: func(controller *gomock.Controller) []instruction.Instructions { | ||
mockInstruction1 := mock_instruction.NewMockInstructions(controller) | ||
mockInstruction1.EXPECT().GetName().Return("mockInstruction") | ||
mockInstruction1.EXPECT().PreCheck(gomock.Any()).Return(nil) | ||
mockInstruction1.EXPECT().Apply(gomock.Any()).Return(errors.New("mock error")) | ||
|
||
mockInstruction2 := mock_instruction.NewMockInstructions(controller) | ||
|
||
return []instruction.Instructions{mockInstruction1, mockInstruction2} | ||
}, | ||
assertError: assert.Error, | ||
}, | ||
"execute multi instruction second instruction failure": { | ||
getInstructions: func(controller *gomock.Controller) []instruction.Instructions { | ||
mockInstruction1 := mock_instruction.NewMockInstructions(controller) | ||
mockInstruction1.EXPECT().GetName().Return("mockInstruction") | ||
mockInstruction1.EXPECT().PreCheck(gomock.Any()).Return(nil) | ||
mockInstruction1.EXPECT().Apply(gomock.Any()).Return(nil) | ||
mockInstruction1.EXPECT().PostCheck(gomock.Any()).Return(nil) | ||
|
||
mockInstruction2 := mock_instruction.NewMockInstructions(controller) | ||
mockInstruction2.EXPECT().GetName().Return("mockInstruction") | ||
mockInstruction2.EXPECT().PreCheck(gomock.Any()).Return(nil) | ||
mockInstruction2.EXPECT().Apply(gomock.Any()).Return(errors.New("mock error")) | ||
|
||
return []instruction.Instructions{mockInstruction1, mockInstruction2} | ||
}, | ||
assertError: assert.Error, | ||
}, | ||
} | ||
|
||
for name, params := range tests { | ||
t.Run(name, func(t *testing.T) { | ||
ctrl := gomock.NewController(t) | ||
|
||
err := execution.Execute(context.TODO(), params.getInstructions(ctrl)) | ||
if params.assertError != nil { | ||
params.assertError(t, err) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// Copyright 2024 NetApp, Inc. All Rights Reserved. | ||
|
||
package instruction | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/netapp/trident/internal/nodeprep/step" | ||
. "github.com/netapp/trident/logging" | ||
) | ||
|
||
const defaultInstructionName = "default instructions" | ||
|
||
type Default struct { | ||
name string | ||
steps []step.Step | ||
} | ||
|
||
func (r *Default) GetName() string { | ||
if r.name == "" { | ||
return defaultInstructionName | ||
} | ||
return r.name | ||
} | ||
|
||
func (r *Default) GetSteps() []step.Step { | ||
return r.steps | ||
} | ||
|
||
func (r *Default) PreCheck(_ context.Context) error { | ||
return nil | ||
} | ||
|
||
func (r *Default) Apply(ctx context.Context) error { | ||
Log().Infof("Applying %s", r.GetName()) | ||
for _, s := range r.steps { | ||
if err := executeStep(ctx, s); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func executeStep(context context.Context, step step.Step) error { | ||
Log().WithField("step", step.GetName()).Info("Executing step") | ||
|
||
if err := step.Apply(context); err != nil { | ||
if step.IsRequired() { | ||
return err | ||
} | ||
Log().WithError(err).WithField("step", step.GetName()). | ||
Info("apply failed but step is not required, continuing") | ||
} | ||
|
||
Log().WithField("step", step.GetName()). | ||
Info("successfully applied step") | ||
return nil | ||
} | ||
|
||
func (r *Default) PostCheck(_ context.Context) error { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// Copyright 2024 NetApp, Inc. All Rights Reserved. | ||
|
||
package instruction | ||
|
||
//go:generate mockgen -destination=../../../mocks/mock_internal/mock_nodeprep/mock_instruction/mock_instruction.go github.com/netapp/trident/internal/nodeprep/instruction Instructions | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/netapp/trident/internal/nodeprep/nodeinfo" | ||
"github.com/netapp/trident/internal/nodeprep/protocol" | ||
"github.com/netapp/trident/internal/nodeprep/step" | ||
utilserrors "github.com/netapp/trident/utils/errors" | ||
) | ||
|
||
// Planning for future distros and protocols which may not align easily with each other and need different instructions | ||
// For example windows might need different instructions for iSCSI than linux or ROSA might be very different from amazon linux | ||
// And some may not need package managers and some will | ||
|
||
type Key struct { | ||
Protocol protocol.Protocol | ||
Distro nodeinfo.Distro | ||
PkgMgr nodeinfo.PkgMgr | ||
} | ||
|
||
var instructionMap = map[Key]Instructions{} | ||
|
||
func init() { | ||
instructionMap[Key{Protocol: protocol.ISCSI, Distro: nodeinfo.DistroAmzn, PkgMgr: nodeinfo.PkgMgrYum}] = newAmznYumISCSI() | ||
instructionMap[Key{Protocol: protocol.ISCSI, Distro: nodeinfo.DistroUbuntu, PkgMgr: nodeinfo.PkgMgrApt}] = newDebianAptISCSI() | ||
} | ||
|
||
type Instructions interface { | ||
GetName() string | ||
PreCheck(ctx context.Context) error | ||
Apply(ctx context.Context) error | ||
PostCheck(ctx context.Context) error | ||
GetSteps() []step.Step | ||
} | ||
|
||
// ScopedInstructions is used to mock out the default instructions for testing, | ||
// this should not be called anywhere else other than tests | ||
func ScopedInstructions(instructions map[Key]Instructions) func() { | ||
existingInstructions := instructionMap | ||
instructionMap = instructions | ||
return func() { | ||
instructionMap = existingInstructions | ||
} | ||
} | ||
|
||
func GetInstructions(nodeInfo *nodeinfo.NodeInfo, protocols []protocol.Protocol) ([]Instructions, error) { | ||
instructions := make([]Instructions, 0) | ||
for _, p := range protocols { | ||
if instruction, ok := instructionMap[Key{Protocol: p, Distro: nodeInfo.Distro, PkgMgr: nodeInfo.PkgMgr}]; ok { | ||
instructions = append(instructions, instruction) | ||
} | ||
} | ||
if len(instructions) == 0 { | ||
return nil, utilserrors.UnsupportedError(fmt.Sprintf("distribution %s for protocols %s is not supported", nodeInfo.Distro, protocols)) | ||
} | ||
return instructions, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright 2024 NetApp, Inc. All Rights Reserved. | ||
|
||
package instruction | ||
|
||
import ( | ||
"github.com/netapp/trident/internal/nodeprep/packagemanager" | ||
"github.com/netapp/trident/internal/nodeprep/packagemanager/apt" | ||
"github.com/netapp/trident/internal/nodeprep/packagemanager/yum" | ||
"github.com/netapp/trident/internal/nodeprep/step" | ||
"github.com/netapp/trident/internal/nodeprep/systemmanager" | ||
"github.com/netapp/trident/internal/nodeprep/systemmanager/amzn" | ||
"github.com/netapp/trident/internal/nodeprep/systemmanager/debian" | ||
) | ||
|
||
type ISCSI struct { | ||
Default | ||
} | ||
|
||
func newDebianAptISCSI() (instruction Instructions) { | ||
return newISCSI(apt.New(), debian.New()) | ||
} | ||
|
||
func newAmznYumISCSI() (instruction Instructions) { | ||
return newISCSI(yum.New(), amzn.New()) | ||
} | ||
|
||
func newISCSI(packageManager packagemanager.PackageManager, systemManager systemmanager.SystemManager) (instruction *ISCSI) { | ||
instruction = &ISCSI{} | ||
instruction.name = "iscsi instructions" | ||
// ordering of steps matter here, multipath must be configured before installing iscsi tools to be idempotent | ||
instruction.steps = []step.Step{ | ||
step.NewMultipathConfigureStep(packageManager), | ||
step.NewInstallIscsiTools(packageManager), | ||
step.NewEnableIscsiServices(systemManager), | ||
} | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.