Newer
Older
"github.com/sethvargo/go-password/password"
Andre Sterba
committed
apppb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/app"
pb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/core"
cpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/csbi"
mnepb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/networkelement"
ppb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd"
apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound"
tpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/topology"
Andre Sterba
committed
//TODO: check if both of 'app' are necessary?
Andre Sterba
committed
"code.fbi.h-da.de/danet/gosdn/controller/app"
apps "code.fbi.h-da.de/danet/gosdn/controller/app"
"code.fbi.h-da.de/danet/gosdn/controller/servmgmt"
Andre Sterba
committed
"code.fbi.h-da.de/danet/gosdn/controller/config"
"code.fbi.h-da.de/danet/gosdn/controller/conflict"
Fabian Seidl
committed
eventservice "code.fbi.h-da.de/danet/gosdn/controller/eventService"
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkdomain"
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkelement"
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac"
"code.fbi.h-da.de/danet/gosdn/controller/northbound/server"
nbi "code.fbi.h-da.de/danet/gosdn/controller/northbound/server"
rbacImpl "code.fbi.h-da.de/danet/gosdn/controller/rbac"
"code.fbi.h-da.de/danet/gosdn/controller/store"
"code.fbi.h-da.de/danet/gosdn/controller/topology"
"code.fbi.h-da.de/danet/gosdn/controller/topology/nodes"
"code.fbi.h-da.de/danet/gosdn/controller/topology/ports"
Andre Sterba
committed
routingtables "code.fbi.h-da.de/danet/gosdn/controller/topology/routing-tables"
Fabian Seidl
committed
eventInterfaces "code.fbi.h-da.de/danet/gosdn/controller/interfaces/event"
"code.fbi.h-da.de/danet/gosdn/controller/nucleus"
var coreLock sync.RWMutex
var coreOnce sync.Once
// Core is the representation of the controller's core.
pndStore networkdomain.PndStore
userService rbac.UserService
roleService rbac.RoleService
topologyService topology.Service
nodeService nodes.Service
portService ports.Service
routeService routingtables.Service
httpServer *http.Server
grpcServer *grpc.Server
nbi *nbi.NorthboundInterface
eventService eventInterfaces.Service
appService app.ManagementService
networkElementWatcher *nucleus.NetworkElementWatcher
stopChan chan os.Signal
serviceManager servmgmt.ServiceManager
// initialize does start-up housekeeping like reading controller config files.
func initialize() error {
err := config.InitializeConfig()
if err != nil {
return err
}
err = config.ReadGnmiSubscriptionPaths()
if err != nil {
log.Error("Error reading in gNMI subscription paths, can not watch network elements automatically: ", err)
}
Fabian Seidl
committed
eventService, err := eventservice.NewEventService()
if err != nil {
return err
}
nodeService := nodes.NewNodeService(nodes.NewDatabaseNodeStore(), eventService)
portService := ports.NewPortService(ports.NewDatabasePortStore(), eventService)
Andre Sterba
committed
routeService := routingtables.NewRoutingTableService(
routingtables.NewDatabaseRoutingTableStore(),
nodeService,
portService,
eventService,
)
serviveManager := initServiceManager(eventService)
pndStore: nucleus.NewPndStore(),
userService: rbacImpl.NewUserService(rbacImpl.NewUserStore(), eventService),
roleService: rbacImpl.NewRoleService(rbacImpl.NewRoleStore(), eventService),
topologyService: topology.NewTopologyService(
topology.NewDatabaseTopologyStore(),
nodeService,
portService,
eventService,
),
nodeService: nodeService,
portService: portService,
routeService: routeService,
eventService: eventService,
appService: apps.NewAppService(apps.NewAppStore()),
stopChan: make(chan os.Signal, 1),
serviceManager: serviveManager,
signal.Notify(c.stopChan, os.Interrupt, syscall.SIGTERM)
err = createPrincipalNetworkDomain()
if err != nil {
return err
}
c.networkElementWatcher = nucleus.NewNetworkElementWatcher(c.serviceManager, c.eventService)
c.networkElementWatcher.SubToNetworkElements(config.GetGnmiSubscriptionPaths(), nil)
err = ensureDefaultRoleExists()
if err != nil {
return err
}
err = ensureDefaultUserExists()
if err != nil {
return err
}
if err := startGrpc(); err != nil {
return err
}
coreLock.Lock()
startHttpServer()
coreLock.Unlock()
socket := viper.GetString("socket")
lislisten, err := net.Listen("tcp", socket)
log.Infof("listening to %v", lislisten.Addr())
jwtManager := rbacImpl.NewJWTManager(config.JWTSecret, config.JWTDuration)
Fabian Seidl
committed
setupGRPCServerWithCorrectSecurityLevel(jwtManager, c.serviceManager)
basePnd, err := c.serviceManager.PndService.Get(store.Query{ID: config.BasePndUUID})
if err != nil {
panic(err)
}
c.nbi = nbi.NewNBI(
c.pndStore,
c.userService,
c.roleService,
*jwtManager,
c.topologyService,
c.nodeService,
c.portService,
Andre Sterba
committed
c.routeService,
c.appService,
c.serviceManager,
pb.RegisterCoreServiceServer(c.grpcServer, c.nbi.Core)
ppb.RegisterPndServiceServer(c.grpcServer, c.nbi.Pnd)
cpb.RegisterCsbiServiceServer(c.grpcServer, c.nbi.Csbi)
spb.RegisterSbiServiceServer(c.grpcServer, c.nbi.Sbi)
apb.RegisterAuthServiceServer(c.grpcServer, c.nbi.Auth)
apb.RegisterUserServiceServer(c.grpcServer, c.nbi.User)
apb.RegisterRoleServiceServer(c.grpcServer, c.nbi.Role)
Andre Sterba
committed
apppb.RegisterAppServiceServer(c.grpcServer, c.nbi.App)
tpb.RegisterTopologyServiceServer(c.grpcServer, c.nbi.Topology)
mnepb.RegisterNetworkElementServiceServer(c.grpcServer, c.nbi.NetworkElement)
Andre Sterba
committed
tpb.RegisterRoutingTableServiceServer(c.grpcServer, c.nbi.Routes)
if err := c.grpcServer.Serve(lislisten); err != nil {
orchestrator := viper.GetString("csbi-orchestrator")
conn, err := grpc.Dial(orchestrator, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatal(err)
}
// createPrincipalNetworkDomain initializes the controller with an initial PND.
func createPrincipalNetworkDomain() error {
basePnd, err := c.serviceManager.PndService.Get(store.Query{ID: config.BasePndUUID})
log.Info(err)
if basePnd == nil {
pnd, err := nucleus.NewPND(
"base",
"gosdn base pnd",
config.BasePndUUID,
c.csbiClient,
callback,
)
if err != nil {
return err
}
err = c.pndStore.Add(pnd)
if err != nil {
return err
}
return nil
func ensureDefaultRoleExists() error {
defaultAdminRoleName := "admin"
adminRole, err := c.roleService.Get(store.Query{ID: uuid.Nil, Name: defaultAdminRoleName})
if err != nil {
log.Info(err)
}
if adminRole == nil {
err := c.roleService.Add(rbacImpl.NewRole(uuid.New(), defaultAdminRoleName, "admin role", []string{
"/gosdn.core.CoreService/GetPnd",
"/gosdn.core.CoreService/GetPndList",
"/gosdn.core.CoreService/CreatePndList",
"/gosdn.core.CoreService/DeletePnd",
"/gosdn.rbac.UserService/CreateUsers",
"/gosdn.rbac.UserService/GetUser",
"/gosdn.rbac.UserService/GetUsers",
"/gosdn.rbac.UserService/UpdateUsers",
"/gosdn.rbac.UserService/DeleteUsers",
"/gosdn.rbac.RoleService/CreateRoles",
"/gosdn.rbac.RoleService/GetRole",
"/gosdn.rbac.RoleService/GetRoles",
"/gosdn.rbac.RoleService/UpdateRoles",
"/gosdn.rbac.RoleService/DeletePermissionsForRole",
"/gosdn.rbac.RoleService/DeleteRoles",
"/gosdn.pnd.PndService/GetMne",
"/gosdn.pnd.PndService/GetFlattenedMneList",
"/gosdn.pnd.PndService/GetSbi",
"/gosdn.pnd.PndService/GetSbiList",
"/gosdn.pnd.PndService/GetPath",
"/gosdn.pnd.PndService/GetChange",
"/gosdn.pnd.PndService/GetChangeList",
"/gosdn.pnd.PndService/SetMneList",
"/gosdn.pnd.PndService/SetChangeList",
"/gosdn.pnd.PndService/SetPathList",
"/gosdn.pnd.PndService/SetSbiList",
"/gosdn.pnd.PndService/DeleteMne",
"/gosdn.pnd.PndService/SubscribePath",
"/gosdn.southbound.SbiService/GetSchema",
}))
if err != nil {
return err
}
}
return nil
}
func ensureDefaultUserExists() error {
defaultUserName := "admin"
adminUser, err := c.userService.Get(store.Query{ID: uuid.Nil, Name: defaultUserName})
if err != nil {
log.Info(err)
}
if adminUser == nil {
// Generate a password that is 16 characters long with 3 digits, 0 symbols,
// allowing upper and lower case letters, disallowing repeat characters.
generatedPassword, err := password.Generate(16, 3, 0, true, false)
if err != nil {
log.Fatal(err)
}
salt, err := password.Generate(16, 3, 0, true, false)
if err != nil {
log.Fatal(err)
}
hashedPassword := base64.RawStdEncoding.EncodeToString(argon2.IDKey([]byte(generatedPassword), []byte(salt), 1, 64*1024, 4, 32))
err = c.userService.Add(rbacImpl.NewUser(uuid.New(), defaultUserName, map[string]string{config.BasePndUUID.String(): "admin"}, string(hashedPassword), "", salt, conflict.Metadata{ResourceVersion: 0}))
if err != nil {
return err
}
fmt.Printf("########\n Generated admin password: %s\n########\n", generatedPassword)
}
return nil
}
// Run calls initialize to start the controller.
initError = initialize()
})
if initError != nil {
log.WithFields(log.Fields{}).Error(initError)
return initError
log.WithFields(log.Fields{}).Info("initialisation finished")
select {
case <-c.stopChan:
return shutdown()
case <-ctx.Done():
return shutdown()
Fabian Seidl
committed
c.eventService.CloseConnection()
func callback(id uuid.UUID, ch chan networkelement.Details) {
c.pndStore.AddPendingChannel(id, ch)
log.Infof("pending channel %v added", id)
} else {
c.pndStore.RemovePendingChannel(id)
log.Infof("pending channel %v removed", id)
}
}
// setupGRPCServerWithCorrectSecurityLevel sets up a gRPC server with desired security level
//
// Only two options for now: insecure or secure, add 'else if' if required.
// Secure is the recommended mode and is set as default.
// Insecure starts the controller without the gRPC interceptor which is supposed to handle authz.
// This allows users to operate on the controller without any authentication/authorization,
// but they could still login if they want to.
// Use insecure only for testing purposes and with caution.
Fabian Seidl
committed
func setupGRPCServerWithCorrectSecurityLevel(jwt *rbacImpl.JWTManager, serviceManager servmgmt.ServiceManager) {
securityLevel := viper.GetString("security")
if securityLevel == "insecure" {
c.grpcServer = grpc.NewServer()
log.Info("set up grpc server in insecure mode")
} else {
Fabian Seidl
committed
interceptor := server.NewAuthInterceptor(jwt, serviceManager)
c.grpcServer = grpc.NewServer(grpc.UnaryInterceptor(interceptor.Unary()), grpc.StreamInterceptor(interceptor.Stream()))
log.Info("set up grpc server in secure mode")
}
}
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
// TODO(PND): add changeStore here?!
func initServiceManager(eventService eventInterfaces.Service) servmgmt.ServiceManager {
pndStore := nucleus.NewPndStore()
pndService := nucleus.NewPndService(pndStore)
sbiStore := nucleus.NewSbiStore(uuid.New())
sbiService := nucleus.NewSbiService(sbiStore, eventService)
networkElementStore := nucleus.NewNetworkElementStore(uuid.New())
networkElementService := nucleus.NewNetworkElementService(
networkElementStore,
sbiService,
eventService,
)
userService := rbacImpl.NewUserService(rbacImpl.NewUserStore(), eventService)
roleService := rbacImpl.NewRoleService(rbacImpl.NewRoleStore(), eventService)
nodeService := nodes.NewNodeService(nodes.NewDatabaseNodeStore(), eventService)
portService := ports.NewPortService(ports.NewDatabasePortStore(), eventService)
//TODO(PND): find way to add servicemanager here instead of having al the extra services in constructor?!
routeService := routingtables.NewRoutingTableService(
routingtables.NewDatabaseRoutingTableStore(),
nodeService,
portService,
eventService,
)
topologyService := topology.NewTopologyService(
topology.NewDatabaseTopologyStore(),
nodeService,
portService,
eventService,
)
appService := app.NewAppService(app.NewAppStore())
//TODO(PND): add real change store!?
return *servmgmt.NewServiceManager(pndService, pndStore,
store.ChangeStore{},
sbiService,
networkElementService,
userService,
roleService,
nodeService,
portService,
topologyService,
routeService,
appService,
)
}