Skip to content

Commit 04621bc

Browse files
APP-7995: Don't allow two module configs to point to same ExePath (#4897)
1 parent e83000a commit 04621bc

File tree

2 files changed

+65
-4
lines changed

2 files changed

+65
-4
lines changed

module/modmanager/manager.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,11 @@ func (mgr *Manager) add(ctx context.Context, conf config.Module, moduleLogger lo
343343
return nil
344344
}
345345

346+
exists, existingName := mgr.execPathAlreadyExists(&conf)
347+
if exists {
348+
return errors.Errorf("An existing module %s already exists with the same executable path as module %s", existingName, conf.Name)
349+
}
350+
346351
var moduleDataDir string
347352
// only set the module data directory if the parent dir is present (which it might not be during tests)
348353
if mgr.moduleDataParentDir != "" {
@@ -442,6 +447,11 @@ func (mgr *Manager) Reconfigure(ctx context.Context, conf config.Module) ([]reso
442447
return nil, errors.Errorf("cannot reconfigure module %s as it does not exist", conf.Name)
443448
}
444449

450+
exists, existingName := mgr.execPathAlreadyExists(&conf)
451+
if exists {
452+
return nil, errors.Errorf("An existing module %s already exists with the same executable path as module %s", existingName, conf.Name)
453+
}
454+
445455
handledResources := mod.resources
446456
var handledResourceNames []resource.Name
447457
var handledResourceNameStrings []string
@@ -852,6 +862,20 @@ func (mgr *Manager) getModule(conf resource.Config) (foundMod *module, exists bo
852862
return
853863
}
854864

865+
func (mgr *Manager) execPathAlreadyExists(conf *config.Module) (bool, string) {
866+
var exists bool
867+
var existingName string
868+
mgr.modules.Range(func(_ string, m *module) bool {
869+
if m.cfg.Name != conf.Name && m.cfg.ExePath == conf.ExePath {
870+
exists = true
871+
existingName = m.cfg.Name
872+
return false
873+
}
874+
return true
875+
})
876+
return exists, existingName
877+
}
878+
855879
// CleanModuleDataDirectory removes unexpected folders and files from the robot's module data directory.
856880
// Modules removed from the robot config (even temporarily) will get pruned here.
857881
func (mgr *Manager) CleanModuleDataDirectory() error {

module/modmanager/manager_test.go

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func setupModManager(
9696
func TestModManagerFunctions(t *testing.T) {
9797
// Precompile module copies to avoid timeout issues when building takes too long.
9898
modPath := rtestutils.BuildTempModule(t, "examples/customresources/demos/simplemodule")
99-
modPath2 := rtestutils.BuildTempModule(t, "examples/customresources/demos/simplemodule")
99+
modPath2 := rtestutils.BuildTempModule(t, "examples/customresources/demos/complexmodule")
100100

101101
for _, mode := range []string{"tcp", "unix"} {
102102
t.Run(mode, func(t *testing.T) {
@@ -207,20 +207,35 @@ func TestModManagerFunctions(t *testing.T) {
207207
t.Log("test AllModels")
208208
modCfg2 := config.Module{
209209
Name: "simple-module2",
210-
ExePath: modPath,
210+
ExePath: modPath2,
211211
Type: config.ModuleTypeLocal,
212212
}
213213
err = mgr.Add(ctx, modCfg2)
214214
test.That(t, err, test.ShouldBeNil)
215215
models := mgr.AllModels()
216+
217+
type expectedModel struct {
218+
model resource.Model
219+
api resource.API
220+
}
221+
222+
expectedMod2Models := []expectedModel{
223+
{resource.NewModel("acme", "demo", "mycounter"), resource.NewAPI("rdk", "component", "generic")},
224+
{resource.NewModel("acme", "demo", "mygizmo"), resource.NewAPI("acme", "component", "gizmo")},
225+
{resource.NewModel("acme", "demo", "mysum"), resource.NewAPI("acme", "service", "summation")},
226+
{resource.NewModel("acme", "demo", "mynavigation"), resource.NewAPI("rdk", "service", "navigation")},
227+
{resource.NewModel("acme", "demo", "mybase"), resource.NewAPI("rdk", "component", "base")},
228+
}
229+
216230
for _, model := range models {
217-
test.That(t, model.Model, test.ShouldResemble, resource.NewModel("acme", "demo", "mycounter"))
218-
test.That(t, model.API, test.ShouldResemble, resource.NewAPI("rdk", "component", "generic"))
219231
switch model.ModuleName {
220232
case "simple-module":
221233
test.That(t, model.FromLocalModule, test.ShouldEqual, false)
234+
test.That(t, model.Model, test.ShouldResemble, resource.NewModel("acme", "demo", "mycounter"))
235+
test.That(t, model.API, test.ShouldResemble, resource.NewAPI("rdk", "component", "generic"))
222236
case "simple-module2":
223237
test.That(t, model.FromLocalModule, test.ShouldEqual, true)
238+
test.That(t, expectedModel{model.Model, model.API}, test.ShouldBeIn, expectedMod2Models)
224239
default:
225240
t.Fail()
226241
t.Logf("test AllModels failure: unrecoginzed moduleName %v", model.ModuleName)
@@ -301,6 +316,19 @@ func TestModManagerFunctions(t *testing.T) {
301316
test.That(t, err, test.ShouldBeNil)
302317
test.That(t, ret["total"], test.ShouldEqual, 24)
303318

319+
// Reconfigure module with duplicate ExePath.
320+
err = mgr.Add(ctx, modCfg2)
321+
test.That(t, err, test.ShouldBeNil)
322+
323+
modCfg.ExePath = modPath2
324+
_, err = mgr.Reconfigure(ctx, modCfg)
325+
test.That(t, err, test.ShouldNotBeNil)
326+
test.That(t, err.Error(), test.ShouldContainSubstring,
327+
"An existing module simple-module2 already exists with the same executable path as module simple-module")
328+
329+
_, err = mgr.Remove(modCfg2.Name)
330+
test.That(t, err, test.ShouldBeNil)
331+
304332
// Change underlying binary path of module to be a different copy of the same module
305333
modCfg.ExePath = modPath2
306334

@@ -495,6 +523,15 @@ func TestModManagerValidation(t *testing.T) {
495523
test.That(t, err, test.ShouldNotBeNil)
496524
test.That(t, err.Error(), test.ShouldResemble,
497525
"rpc error: code = DeadlineExceeded desc = context deadline exceeded")
526+
527+
modCfg = config.Module{
528+
Name: "second-module",
529+
ExePath: modPath,
530+
}
531+
err = mgr.Add(ctx, modCfg)
532+
test.That(t, err, test.ShouldNotBeNil)
533+
test.That(t, err.Error(), test.ShouldResemble,
534+
"An existing module complex-module already exists with the same executable path as module second-module")
498535
}
499536

500537
func TestModuleReloading(t *testing.T) {

0 commit comments

Comments
 (0)