Newer
Older
"github.com/sethvargo/go-password/password"
"github.com/spf13/viper"
"google.golang.org/grpc"
pb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/core"
cpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/csbi"
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"
"code.fbi.h-da.de/danet/gosdn/controller/config"
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/device"
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkdomain"
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac"
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound"
"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/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
httpServer *http.Server
grpcServer *grpc.Server
nbi *nbi.NorthboundInterface
stopChan chan os.Signal
// initialize does start-up housekeeping like reading controller config files
func initialize() error {
err := config.InitializeConfig()
if err != nil {
return err
}
pndStore: nucleus.NewPndStore(),
userService: rbacImpl.NewUserService(rbacImpl.NewUserStore()),
roleService: rbacImpl.NewRoleService(rbacImpl.NewRoleStore()),
stopChan: make(chan os.Signal, 1),
signal.Notify(c.stopChan, os.Interrupt, syscall.SIGTERM)
err = config.InitializeConfig()
if err != nil {
return err
}
err = createPrincipalNetworkDomain()
if err != nil {
return err
}
err = ensureDefaultRoleExists()
if err != nil {
return err
}
err = ensureDefaultUserExists()
if err != nil {
return err
}
sock := viper.GetString("socket")
lis, err := net.Listen("tcp", sock)
if err != nil {
return err
}
log.Infof("listening to %v", lis.Addr())
jwtManager := rbacImpl.NewJWTManager("", (10000 * time.Hour)) //TODO(faseid): add real secret and proper duration data here!
setupGRPCServerWithCorrectSecurityLevel(jwtManager)
c.nbi = nbi.NewNBI(c.pndStore, c.userService, c.roleService)
c.nbi.Auth = nbi.NewAuthServer(jwtManager)
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)
go func() {
if err := c.grpcServer.Serve(lis); err != nil {
log.Fatal(err)
}
}()
orchestrator := viper.GetString("csbi-orchestrator")
conn, err := grpc.Dial(orchestrator, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatal(err)
}
// createSouthboundInterfaces initializes the controller with its supported SBIs
func createSouthboundInterfaces() (southbound.SouthboundInterface, error) {
sbi, err := nucleus.NewSBI(spb.Type(config.BaseSouthBoundType), config.BaseSouthBoundUUID)
if err != nil {
return nil, err
}
}
// createPrincipalNetworkDomain initializes the controller with an initial PND
func createPrincipalNetworkDomain() error {
basePnd, err := c.pndStore.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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
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.AuthService/CreateUsers",
"/gosdn.rbac.AuthService/GetUser",
"/gosdn.rbac.AuthService/GetUsers",
"/gosdn.rbac.AuthService/UpdateUsers",
"/gosdn.rbac.AuthService/DeleteUsers",
"/gosdn.rbac.AuthService/CreateRoles",
"/gosdn.rbac.AuthService/GetRole",
"/gosdn.rbac.AuthService/GetRoles",
"/gosdn.rbac.AuthService/UpdateRoles",
"/gosdn.rbac.AuthService/DeletePermissionsForRole",
"/gosdn.rbac.AuthService/DeleteRoles",
"/gosdn.pnd.PndService/GetOnd",
"/gosdn.pnd.PndService/GetOndList",
"/gosdn.pnd.PndService/GetSbi",
"/gosdn.pnd.PndService/GetSbiList",
"/gosdn.pnd.PndService/GetPath",
"/gosdn.pnd.PndService/GetChange",
"/gosdn.pnd.PndService/GetChangeList",
"/gosdn.pnd.PndService/SetOndList",
"/gosdn.pnd.PndService/SetChangeList",
"/gosdn.pnd.PndService/SetPathList",
"/gosdn.pnd.PndService/SetSbiList",
"/gosdn.pnd.PndService/DeleteOnd",
"/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)
}
fmt.Printf("########\n Generated admin password: %s\n ########\n", generatedPassword)
err = c.userService.Add(rbacImpl.NewUser(uuid.New(), defaultUserName, map[string]string{config.BasePndUUID.String(): "admin"}, generatedPassword, ""))
if err != nil {
return err
}
}
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()
func callback(id uuid.UUID, ch chan device.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.
func setupGRPCServerWithCorrectSecurityLevel(jwt *rbacImpl.JWTManager) {
securityLevel := viper.GetString("security")
if securityLevel == "insecure" {
c.grpcServer = grpc.NewServer()
log.Info("set up grpc server in insecure mode")
} else {
interceptor := server.NewAuthInterceptor(jwt)
c.grpcServer = grpc.NewServer(grpc.UnaryInterceptor(interceptor.Unary()), grpc.StreamInterceptor(interceptor.Stream()))
log.Info("set up grpc server in secure mode")
}
}