blob: 5da82d678bb80105fb91dc3fa77b696c71c7667b [file] [log] [blame]
Author Namea594e632018-08-10 11:33:58 -04001/*
2 Copyright 2017 the original author or authors.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17package main
18
19import (
20 "flag"
21 "fmt"
donNewtonAlphae7ab5b92018-09-27 15:09:14 -040022 "io/ioutil"
Author Namea594e632018-08-10 11:33:58 -040023 "log"
24 "net"
25 "net/http"
26 "os"
27 "strings"
donNewtonAlphac997d642018-10-17 13:22:48 -040028 "time"
Author Namea594e632018-08-10 11:33:58 -040029
30 "gerrit.opencord.org/abstract-olt/api"
Don Newtone973d342018-10-26 16:44:12 -040031 "gerrit.opencord.org/abstract-olt/internal/pkg/impl"
Author Namea594e632018-08-10 11:33:58 -040032 "gerrit.opencord.org/abstract-olt/internal/pkg/settings"
donNewtonAlphae7ab5b92018-09-27 15:09:14 -040033 "gerrit.opencord.org/abstract-olt/models"
Author Namea594e632018-08-10 11:33:58 -040034 "github.com/grpc-ecosystem/grpc-gateway/runtime"
donNewtonAlphac997d642018-10-17 13:22:48 -040035 "github.com/mongodb/mongo-go-driver/mongo"
Don Newton16520672018-11-28 14:44:42 -050036 "github.com/mongodb/mongo-go-driver/mongo/options"
37 "github.com/mongodb/mongo-go-driver/x/bsonx"
Author Namea594e632018-08-10 11:33:58 -040038 "golang.org/x/net/context"
39 "google.golang.org/grpc"
40 "google.golang.org/grpc/credentials"
41 "google.golang.org/grpc/metadata"
42)
43
44// private type for Context keys
45type contextKey int
46
donNewtonAlphab3279ea2018-09-18 15:55:32 -040047var useSsl *bool
48var useAuthentication *bool
49var certDirectory *string
50
Author Namea594e632018-08-10 11:33:58 -040051const (
52 clientIDKey contextKey = iota
53)
54
55/*
56GetLogger - returns the logger
57*/
58func credMatcher(headerName string) (mdName string, ok bool) {
59 if headerName == "Login" || headerName == "Password" {
60 return headerName, true
61 }
62 return "", false
63}
64
65// authenticateAgent check the client credentials
66func authenticateClient(ctx context.Context, s *api.Server) (string, error) {
donNewtonAlphab3279ea2018-09-18 15:55:32 -040067 //TODO if we decide to handle Authentication with AbstractOLT this will need to be bound to an authentication service
Author Namea594e632018-08-10 11:33:58 -040068 if md, ok := metadata.FromIncomingContext(ctx); ok {
69 clientLogin := strings.Join(md["login"], "")
70 clientPassword := strings.Join(md["password"], "")
71
72 if clientLogin != "john" {
73 return "", fmt.Errorf("unknown user %s", clientLogin)
74 }
75 if clientPassword != "doe" {
76 return "", fmt.Errorf("bad password %s", clientPassword)
77 }
78
79 log.Printf("authenticated client: %s", clientLogin)
80 return "42", nil
81 }
82 return "", fmt.Errorf("missing credentials")
83}
84
85// unaryInterceptor call authenticateClient with current context
86func unaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
87 s, ok := info.Server.(*api.Server)
88 if !ok {
89 return nil, fmt.Errorf("unable to cast server")
90 }
91 clientID, err := authenticateClient(ctx, s)
92 if err != nil {
93 return nil, err
94 }
95
96 ctx = context.WithValue(ctx, clientIDKey, clientID)
97 return handler(ctx, req)
98}
99
100func startGRPCServer(address, certFile, keyFile string) error {
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400101 if settings.GetDebug() {
102 log.Printf("startGRPCServer(LisenAddress:%s,CertFile:%s,KeyFile:%s\n", address, certFile, keyFile)
103 }
Author Namea594e632018-08-10 11:33:58 -0400104 // create a listener on TCP port
105 lis, err := net.Listen("tcp", address)
Author Namea594e632018-08-10 11:33:58 -0400106
107 // create a server instance
108 s := api.Server{}
109
110 // Create the TLS credentials
Author Namea594e632018-08-10 11:33:58 -0400111
112 // Create an array of gRPC options with the credentials
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400113 var opts []grpc.ServerOption
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400114 creds, err := credentials.NewClientTLSFromFile(certFile, "")
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400115 if *useSsl && *useAuthentication {
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400116 if err != nil {
117 return fmt.Errorf("could not load TLS keys: %s", err)
118 }
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400119 opts = []grpc.ServerOption{grpc.Creds(creds),
120 grpc.UnaryInterceptor(unaryInterceptor)}
121 } else if *useAuthentication {
122 opts = []grpc.ServerOption{grpc.UnaryInterceptor(unaryInterceptor)}
123 } else if *useSsl {
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400124 if err != nil {
125 return fmt.Errorf("could not load TLS keys: %s", err)
126 }
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400127 opts = []grpc.ServerOption{grpc.Creds(creds)}
128 } else {
129 opts = []grpc.ServerOption{}
130 }
Author Namea594e632018-08-10 11:33:58 -0400131
132 // create a gRPC server object
133 grpcServer := grpc.NewServer(opts...)
134
135 // attach the Ping service to the server
donNewtonAlpha5234b132018-08-16 14:12:28 -0400136 api.RegisterAbstractOLTServer(grpcServer, &s)
Author Namea594e632018-08-10 11:33:58 -0400137
138 // start the server
139 log.Printf("starting HTTP/2 gRPC server on %s", address)
140 if err := grpcServer.Serve(lis); err != nil {
141 return fmt.Errorf("failed to serve: %s", err)
142 }
143
144 return nil
145}
146func startRESTServer(address, grpcAddress, certFile string) error {
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400147 if settings.GetDebug() {
148 log.Printf("startRESTServer(Address:%s, GRPCAddress:%s,Cert File:%s\n", address, grpcAddress, certFile)
149 }
Author Namea594e632018-08-10 11:33:58 -0400150 ctx := context.Background()
151 ctx, cancel := context.WithCancel(ctx)
152 defer cancel()
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400153 var mux *runtime.ServeMux
Author Namea594e632018-08-10 11:33:58 -0400154
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400155 var opts []grpc.DialOption
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400156 if *useAuthentication {
157 mux = runtime.NewServeMux(runtime.WithIncomingHeaderMatcher(credMatcher))
158 } else {
159 mux = runtime.NewServeMux()
160 }
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400161 if *useSsl {
162 creds, err := credentials.NewClientTLSFromFile(certFile, "")
163 opts = []grpc.DialOption{grpc.WithTransportCredentials(creds)}
164 if err != nil {
165 return fmt.Errorf("could not load TLS certificate: %s", err)
166 }
167 } else {
168 opts = []grpc.DialOption{grpc.WithInsecure()}
Author Namea594e632018-08-10 11:33:58 -0400169 }
Author Namea594e632018-08-10 11:33:58 -0400170 // Setup the client gRPC options
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400171 err := api.RegisterAbstractOLTHandlerFromEndpoint(ctx, mux, grpcAddress, opts)
Author Namea594e632018-08-10 11:33:58 -0400172 if err != nil {
173 return fmt.Errorf("could not register service Ping: %s", err)
174 }
175
176 log.Printf("starting HTTP/1.1 REST server on %s", address)
177 http.ListenAndServe(address, mux)
178
179 return nil
180}
181func main() {
182 debugPtr := flag.Bool("d", false, "Log Level Debug")
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400183 useAuthentication = flag.Bool("a", false, "Use Authentication")
184 useSsl = flag.Bool("s", false, "Use SSL")
185 certDirectory = flag.String("cert_dir", "cert", "Directory where key files exist")
186 listenAddress := flag.String("listenAddress", "localhost", "IP Address to listen on")
187 grpcPort := flag.String("grpc_port", "7777", "Port to listen for GRPC")
188 restPort := flag.String("rest_port", "7778", "Port to listen for Rest Server")
189 logFile := flag.String("log_file", "AbstractOLT.log", "Name of the LogFile to write to")
190 h := flag.Bool("h", false, "Show usage")
191 help := flag.Bool("help", false, "Show usage")
donNewtonAlphaaf229742018-09-19 13:22:00 -0400192 dummy := flag.Bool("dummy", false, "Run in dummy mode where YAML is not sent to XOS")
Don Newton16520672018-11-28 14:44:42 -0500193 grpc := flag.Bool("grpc", false, "Use XOS GRPC interface instead of TOSCA")
Author Namea594e632018-08-10 11:33:58 -0400194
donNewtonAlphac997d642018-10-17 13:22:48 -0400195 useMongo := flag.Bool("useMongo", false, "use mongo db for backup/restore")
196 mongodb := flag.String("mongodb", "mongodb://foundry:foundry@localhost:27017", "connect string for mongodb backup/restore")
197
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400198 flag.Parse()
donNewtonAlphaaf229742018-09-19 13:22:00 -0400199 settings.SetDummy(*dummy)
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400200
201 if *help || *h {
202 var usage = `./AbstractOLT -d [default false] : Runs in Debug mode
203Params:
204 -s [default false] -cert_dir [default $WORKING_DIR/cert] DIR : Runs in SSL mode with server.crt and server.key found in DIR
205 -a [default false] : Run in Authentication mode currently very basic
206 -listenAddress IP_ADDRESS [default localhost] -grpc_port [default 7777] PORT1 -rest_port [default 7778] PORT2: Listen for grpc on IP_ADDRESS:PORT1 and rest on IP_ADDRESS:PORT2
207 -log_file [default $WORKING_DIR/AbstractOLT.log] LOG_FILE
donNewtonAlphac997d642018-10-17 13:22:48 -0400208 -mongo [default false] use mongodb for backup restore
209 -mongodb [default mongodb://foundry:foundry@localhost:27017] connect string for mongodb - Required if mongo == true
Don Newton16520672018-11-28 14:44:42 -0500210 -grpc [default false] tell AbstractOLT to use XOS GRPC interface instead of TOSCA
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400211 -h(elp) print this usage
donNewtonAlphac997d642018-10-17 13:22:48 -0400212
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400213`
214 fmt.Println(usage)
215 return
216 }
217 settings.SetDebug(*debugPtr)
donNewtonAlphac997d642018-10-17 13:22:48 -0400218 settings.SetMongo(*useMongo)
219 settings.SetMongodb(*mongodb)
Don Newton16520672018-11-28 14:44:42 -0500220 settings.SetGrpc(*grpc)
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400221 fmt.Println("Startup Params: debug:", *debugPtr, " Authentication:", *useAuthentication, " SSL:", *useSsl, "Cert Directory", *certDirectory,
Don Newton16520672018-11-28 14:44:42 -0500222 "ListenAddress:", *listenAddress, " grpc port:", *grpcPort, " rest port:", *restPort, "Logging to ", *logFile, "Use XOS GRPC ", *grpc)
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400223
224 file, err := os.OpenFile(*logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
Author Namea594e632018-08-10 11:33:58 -0400225 if err != nil {
226 log.Fatalln("Failed to open log file", file, ":", err)
227 }
228 log.SetOutput(file)
229 log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Lshortfile)
donNewtonAlphaaf229742018-09-19 13:22:00 -0400230 if *dummy {
231 fmt.Println("RUNNING IN DUMMY MODE NO YAML WILL BE SENT TO XOS")
232 log.Println("RUNNING IN DUMMY MODE NO YAML WILL BE SENT TO XOS")
233 }
Author Namea594e632018-08-10 11:33:58 -0400234 log.Printf("Setting Debug to %t\n", settings.GetDebug())
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400235 if settings.GetDebug() {
236 log.Println("Startup Params: debug:", *debugPtr, " Authentication:", *useAuthentication, " SSL:", *useSsl, "Cert Directory", *certDirectory,
237 "ListenAddress:", *listenAddress, " grpc port:", *grpcPort, " rest port:", *restPort, "Logging to ", *logFile)
238 }
Author Namea594e632018-08-10 11:33:58 -0400239
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400240 grpcAddress := fmt.Sprintf("%s:%s", *listenAddress, *grpcPort)
241 restAddress := fmt.Sprintf("%s:%s", *listenAddress, *restPort)
242
243 certFile := fmt.Sprintf("%s/server.crt", *certDirectory)
244 keyFile := fmt.Sprintf("%s/server.key", *certDirectory)
Author Namea594e632018-08-10 11:33:58 -0400245
246 // fire the gRPC server in a goroutine
247 go func() {
248 err := startGRPCServer(grpcAddress, certFile, keyFile)
249 if err != nil {
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400250 log.Printf("failed to start gRPC server: %s", err)
Author Namea594e632018-08-10 11:33:58 -0400251 }
252 }()
253
254 // fire the REST server in a goroutine
255 go func() {
256 err := startRESTServer(restAddress, grpcAddress, certFile)
257 if err != nil {
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400258 log.Printf("failed to start REST server: %s", err)
Author Namea594e632018-08-10 11:33:58 -0400259 }
260 }()
261
262 // infinite loop
donNewtonAlphac997d642018-10-17 13:22:48 -0400263 if *useMongo {
Don Newton16520672018-11-28 14:44:42 -0500264 clientOptions := options.Client()
265 creds := options.Credential{AuthMechanism: "SCRAM-SHA-256", AuthSource: "AbstractOLT", Username: "seba", Password: "seba"}
266 clientOptions.SetAuth(creds)
267
268 client, err := mongo.NewClientWithOptions(*mongodb, clientOptions)
269
donNewtonAlphac997d642018-10-17 13:22:48 -0400270 client.Connect(context.Background())
Don Newton16520672018-11-28 14:44:42 -0500271 fmt.Println(client)
donNewtonAlphac997d642018-10-17 13:22:48 -0400272 defer client.Disconnect(context.Background())
273 if err != nil {
274 log.Fatalf("unable to connect to mongodb with %v\n", err)
275 }
Don Newton16520672018-11-28 14:44:42 -0500276 collection := client.Database("AbstractOLT").Collection("backups")
donNewtonAlphac997d642018-10-17 13:22:48 -0400277 cur, err := collection.Find(context.Background(), nil)
278 if err != nil {
279 log.Fatalf("Unable to connect to collection with %v\n", err)
280 }
281 defer cur.Close(context.Background())
282 for cur.Next(context.Background()) {
Don Newton16520672018-11-28 14:44:42 -0500283 doc := bsonx.Doc{}
284 err := cur.Decode(&doc)
donNewtonAlphab8f30752018-10-04 11:57:41 -0400285 if err != nil {
donNewtonAlphac997d642018-10-17 13:22:48 -0400286 log.Fatal(err)
donNewtonAlphab8f30752018-10-04 11:57:41 -0400287 }
Don Newton16520672018-11-28 14:44:42 -0500288 clli := doc.LookupElement("_id").Value
289 body := doc.LookupElement("body").Value
290 _, bodyBin := (body).Binary()
donNewtonAlphac997d642018-10-17 13:22:48 -0400291
292 chassisHolder := models.ChassisHolder{}
293 err = chassisHolder.Deserialize(bodyBin)
294 if err != nil {
Don Newton16520672018-11-28 14:44:42 -0500295 log.Printf("Deserialize threw an error for clli %s %v\n", (clli).StringValue(), err)
donNewtonAlphac997d642018-10-17 13:22:48 -0400296 } else {
297 chassisMap := models.GetChassisMap()
Don Newton16520672018-11-28 14:44:42 -0500298 (*chassisMap)[(clli).StringValue()] = &chassisHolder
donNewtonAlphac997d642018-10-17 13:22:48 -0400299
300 }
301 }
302 } else {
303 files, err := ioutil.ReadDir("backup")
304 if err != nil {
305 log.Fatal(err)
306 }
307 for _, file := range files {
308 chassisHolder := models.ChassisHolder{}
309 if file.Name() != "BackupPlaceHolder" {
310 fileName := fmt.Sprintf("backup/%s", file.Name())
311 json, _ := ioutil.ReadFile(fileName)
312 err := chassisHolder.Deserialize([]byte(json))
313 if err != nil {
314 fmt.Printf("Deserialize threw an error %v\n", err)
315 }
316 chassisMap := models.GetChassisMap()
317 (*chassisMap)[file.Name()] = &chassisHolder
318 } else {
319 fmt.Println("Ignoring BackupPlaceHolder")
320 }
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400321 }
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400322 }
323
Author Namea594e632018-08-10 11:33:58 -0400324 log.Printf("Entering infinite loop")
donNewtonAlphac997d642018-10-17 13:22:48 -0400325 var ticker = time.NewTicker(60 * time.Second)
326 for {
327 select {
328 case <-ticker.C:
Don Newtone973d342018-10-26 16:44:12 -0400329 impl.DoOutput()
donNewtonAlphac997d642018-10-17 13:22:48 -0400330 }
331 }
332
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400333 //TODO publish periodic stats etc
Author Namea594e632018-08-10 11:33:58 -0400334 fmt.Println("AbstractOLT")
335}