blob: e94a2187c04002dd86bf3eba2f399a4701e3b993 [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/bson"
36 "github.com/mongodb/mongo-go-driver/mongo"
Author Namea594e632018-08-10 11:33:58 -040037 "golang.org/x/net/context"
38 "google.golang.org/grpc"
39 "google.golang.org/grpc/credentials"
40 "google.golang.org/grpc/metadata"
41)
42
43// private type for Context keys
44type contextKey int
45
donNewtonAlphab3279ea2018-09-18 15:55:32 -040046var useSsl *bool
47var useAuthentication *bool
48var certDirectory *string
49
Author Namea594e632018-08-10 11:33:58 -040050const (
51 clientIDKey contextKey = iota
52)
53
54/*
55GetLogger - returns the logger
56*/
57func credMatcher(headerName string) (mdName string, ok bool) {
58 if headerName == "Login" || headerName == "Password" {
59 return headerName, true
60 }
61 return "", false
62}
63
64// authenticateAgent check the client credentials
65func authenticateClient(ctx context.Context, s *api.Server) (string, error) {
donNewtonAlphab3279ea2018-09-18 15:55:32 -040066 //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 -040067 if md, ok := metadata.FromIncomingContext(ctx); ok {
68 clientLogin := strings.Join(md["login"], "")
69 clientPassword := strings.Join(md["password"], "")
70
71 if clientLogin != "john" {
72 return "", fmt.Errorf("unknown user %s", clientLogin)
73 }
74 if clientPassword != "doe" {
75 return "", fmt.Errorf("bad password %s", clientPassword)
76 }
77
78 log.Printf("authenticated client: %s", clientLogin)
79 return "42", nil
80 }
81 return "", fmt.Errorf("missing credentials")
82}
83
84// unaryInterceptor call authenticateClient with current context
85func unaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
86 s, ok := info.Server.(*api.Server)
87 if !ok {
88 return nil, fmt.Errorf("unable to cast server")
89 }
90 clientID, err := authenticateClient(ctx, s)
91 if err != nil {
92 return nil, err
93 }
94
95 ctx = context.WithValue(ctx, clientIDKey, clientID)
96 return handler(ctx, req)
97}
98
99func startGRPCServer(address, certFile, keyFile string) error {
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400100 if settings.GetDebug() {
101 log.Printf("startGRPCServer(LisenAddress:%s,CertFile:%s,KeyFile:%s\n", address, certFile, keyFile)
102 }
Author Namea594e632018-08-10 11:33:58 -0400103 // create a listener on TCP port
104 lis, err := net.Listen("tcp", address)
Author Namea594e632018-08-10 11:33:58 -0400105
106 // create a server instance
107 s := api.Server{}
108
109 // Create the TLS credentials
Author Namea594e632018-08-10 11:33:58 -0400110
111 // Create an array of gRPC options with the credentials
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400112 var opts []grpc.ServerOption
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400113 creds, err := credentials.NewClientTLSFromFile(certFile, "")
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400114 if *useSsl && *useAuthentication {
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400115 if err != nil {
116 return fmt.Errorf("could not load TLS keys: %s", err)
117 }
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400118 opts = []grpc.ServerOption{grpc.Creds(creds),
119 grpc.UnaryInterceptor(unaryInterceptor)}
120 } else if *useAuthentication {
121 opts = []grpc.ServerOption{grpc.UnaryInterceptor(unaryInterceptor)}
122 } else if *useSsl {
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400123 if err != nil {
124 return fmt.Errorf("could not load TLS keys: %s", err)
125 }
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400126 opts = []grpc.ServerOption{grpc.Creds(creds)}
127 } else {
128 opts = []grpc.ServerOption{}
129 }
Author Namea594e632018-08-10 11:33:58 -0400130
131 // create a gRPC server object
132 grpcServer := grpc.NewServer(opts...)
133
134 // attach the Ping service to the server
donNewtonAlpha5234b132018-08-16 14:12:28 -0400135 api.RegisterAbstractOLTServer(grpcServer, &s)
Author Namea594e632018-08-10 11:33:58 -0400136
137 // start the server
138 log.Printf("starting HTTP/2 gRPC server on %s", address)
139 if err := grpcServer.Serve(lis); err != nil {
140 return fmt.Errorf("failed to serve: %s", err)
141 }
142
143 return nil
144}
145func startRESTServer(address, grpcAddress, certFile string) error {
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400146 if settings.GetDebug() {
147 log.Printf("startRESTServer(Address:%s, GRPCAddress:%s,Cert File:%s\n", address, grpcAddress, certFile)
148 }
Author Namea594e632018-08-10 11:33:58 -0400149 ctx := context.Background()
150 ctx, cancel := context.WithCancel(ctx)
151 defer cancel()
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400152 var mux *runtime.ServeMux
Author Namea594e632018-08-10 11:33:58 -0400153
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400154 var opts []grpc.DialOption
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400155 if *useAuthentication {
156 mux = runtime.NewServeMux(runtime.WithIncomingHeaderMatcher(credMatcher))
157 } else {
158 mux = runtime.NewServeMux()
159 }
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400160 if *useSsl {
161 creds, err := credentials.NewClientTLSFromFile(certFile, "")
162 opts = []grpc.DialOption{grpc.WithTransportCredentials(creds)}
163 if err != nil {
164 return fmt.Errorf("could not load TLS certificate: %s", err)
165 }
166 } else {
167 opts = []grpc.DialOption{grpc.WithInsecure()}
Author Namea594e632018-08-10 11:33:58 -0400168 }
Author Namea594e632018-08-10 11:33:58 -0400169 // Setup the client gRPC options
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400170 err := api.RegisterAbstractOLTHandlerFromEndpoint(ctx, mux, grpcAddress, opts)
Author Namea594e632018-08-10 11:33:58 -0400171 if err != nil {
172 return fmt.Errorf("could not register service Ping: %s", err)
173 }
174
175 log.Printf("starting HTTP/1.1 REST server on %s", address)
176 http.ListenAndServe(address, mux)
177
178 return nil
179}
180func main() {
181 debugPtr := flag.Bool("d", false, "Log Level Debug")
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400182 useAuthentication = flag.Bool("a", false, "Use Authentication")
183 useSsl = flag.Bool("s", false, "Use SSL")
184 certDirectory = flag.String("cert_dir", "cert", "Directory where key files exist")
185 listenAddress := flag.String("listenAddress", "localhost", "IP Address to listen on")
186 grpcPort := flag.String("grpc_port", "7777", "Port to listen for GRPC")
187 restPort := flag.String("rest_port", "7778", "Port to listen for Rest Server")
188 logFile := flag.String("log_file", "AbstractOLT.log", "Name of the LogFile to write to")
189 h := flag.Bool("h", false, "Show usage")
190 help := flag.Bool("help", false, "Show usage")
donNewtonAlphaaf229742018-09-19 13:22:00 -0400191 dummy := flag.Bool("dummy", false, "Run in dummy mode where YAML is not sent to XOS")
Author Namea594e632018-08-10 11:33:58 -0400192
donNewtonAlphac997d642018-10-17 13:22:48 -0400193 useMongo := flag.Bool("useMongo", false, "use mongo db for backup/restore")
194 mongodb := flag.String("mongodb", "mongodb://foundry:foundry@localhost:27017", "connect string for mongodb backup/restore")
195
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400196 flag.Parse()
donNewtonAlphaaf229742018-09-19 13:22:00 -0400197 settings.SetDummy(*dummy)
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400198
199 if *help || *h {
200 var usage = `./AbstractOLT -d [default false] : Runs in Debug mode
201Params:
202 -s [default false] -cert_dir [default $WORKING_DIR/cert] DIR : Runs in SSL mode with server.crt and server.key found in DIR
203 -a [default false] : Run in Authentication mode currently very basic
204 -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
205 -log_file [default $WORKING_DIR/AbstractOLT.log] LOG_FILE
donNewtonAlphac997d642018-10-17 13:22:48 -0400206 -mongo [default false] use mongodb for backup restore
207 -mongodb [default mongodb://foundry:foundry@localhost:27017] connect string for mongodb - Required if mongo == true
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400208 -h(elp) print this usage
donNewtonAlphac997d642018-10-17 13:22:48 -0400209
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400210`
211 fmt.Println(usage)
212 return
213 }
214 settings.SetDebug(*debugPtr)
donNewtonAlphac997d642018-10-17 13:22:48 -0400215 settings.SetMongo(*useMongo)
216 settings.SetMongodb(*mongodb)
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400217 fmt.Println("Startup Params: debug:", *debugPtr, " Authentication:", *useAuthentication, " SSL:", *useSsl, "Cert Directory", *certDirectory,
218 "ListenAddress:", *listenAddress, " grpc port:", *grpcPort, " rest port:", *restPort, "Logging to ", *logFile)
219
220 file, err := os.OpenFile(*logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
Author Namea594e632018-08-10 11:33:58 -0400221 if err != nil {
222 log.Fatalln("Failed to open log file", file, ":", err)
223 }
224 log.SetOutput(file)
225 log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Lshortfile)
donNewtonAlphaaf229742018-09-19 13:22:00 -0400226 if *dummy {
227 fmt.Println("RUNNING IN DUMMY MODE NO YAML WILL BE SENT TO XOS")
228 log.Println("RUNNING IN DUMMY MODE NO YAML WILL BE SENT TO XOS")
229 }
Author Namea594e632018-08-10 11:33:58 -0400230 log.Printf("Setting Debug to %t\n", settings.GetDebug())
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400231 if settings.GetDebug() {
232 log.Println("Startup Params: debug:", *debugPtr, " Authentication:", *useAuthentication, " SSL:", *useSsl, "Cert Directory", *certDirectory,
233 "ListenAddress:", *listenAddress, " grpc port:", *grpcPort, " rest port:", *restPort, "Logging to ", *logFile)
234 }
Author Namea594e632018-08-10 11:33:58 -0400235
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400236 grpcAddress := fmt.Sprintf("%s:%s", *listenAddress, *grpcPort)
237 restAddress := fmt.Sprintf("%s:%s", *listenAddress, *restPort)
238
239 certFile := fmt.Sprintf("%s/server.crt", *certDirectory)
240 keyFile := fmt.Sprintf("%s/server.key", *certDirectory)
Author Namea594e632018-08-10 11:33:58 -0400241
242 // fire the gRPC server in a goroutine
243 go func() {
244 err := startGRPCServer(grpcAddress, certFile, keyFile)
245 if err != nil {
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400246 log.Printf("failed to start gRPC server: %s", err)
Author Namea594e632018-08-10 11:33:58 -0400247 }
248 }()
249
250 // fire the REST server in a goroutine
251 go func() {
252 err := startRESTServer(restAddress, grpcAddress, certFile)
253 if err != nil {
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400254 log.Printf("failed to start REST server: %s", err)
Author Namea594e632018-08-10 11:33:58 -0400255 }
256 }()
257
258 // infinite loop
donNewtonAlphac997d642018-10-17 13:22:48 -0400259 if *useMongo {
260 client, err := mongo.NewClient(*mongodb)
261 client.Connect(context.Background())
262 defer client.Disconnect(context.Background())
263 if err != nil {
264 log.Fatalf("unable to connect to mongodb with %v\n", err)
265 }
266 collection := client.Database("AbstractOLT").Collection("backup")
267 cur, err := collection.Find(context.Background(), nil)
268 if err != nil {
269 log.Fatalf("Unable to connect to collection with %v\n", err)
270 }
271 defer cur.Close(context.Background())
272 for cur.Next(context.Background()) {
273 elem := bson.NewDocument()
274 err := cur.Decode(elem)
donNewtonAlphab8f30752018-10-04 11:57:41 -0400275 if err != nil {
donNewtonAlphac997d642018-10-17 13:22:48 -0400276 log.Fatal(err)
donNewtonAlphab8f30752018-10-04 11:57:41 -0400277 }
donNewtonAlphac997d642018-10-17 13:22:48 -0400278 clli := elem.LookupElement("_id").Value()
279 body := elem.LookupElement("body").Value()
280 _, bodyBin := (*body).Binary()
281
282 chassisHolder := models.ChassisHolder{}
283 err = chassisHolder.Deserialize(bodyBin)
284 if err != nil {
285 log.Printf("Deserialize threw an error for clli %s %v\n", (*clli).StringValue(), err)
286 } else {
287 chassisMap := models.GetChassisMap()
288 (*chassisMap)[(*clli).StringValue()] = &chassisHolder
289
290 }
291 }
292 } else {
293 files, err := ioutil.ReadDir("backup")
294 if err != nil {
295 log.Fatal(err)
296 }
297 for _, file := range files {
298 chassisHolder := models.ChassisHolder{}
299 if file.Name() != "BackupPlaceHolder" {
300 fileName := fmt.Sprintf("backup/%s", file.Name())
301 json, _ := ioutil.ReadFile(fileName)
302 err := chassisHolder.Deserialize([]byte(json))
303 if err != nil {
304 fmt.Printf("Deserialize threw an error %v\n", err)
305 }
306 chassisMap := models.GetChassisMap()
307 (*chassisMap)[file.Name()] = &chassisHolder
308 } else {
309 fmt.Println("Ignoring BackupPlaceHolder")
310 }
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400311 }
donNewtonAlphae7ab5b92018-09-27 15:09:14 -0400312 }
313
Author Namea594e632018-08-10 11:33:58 -0400314 log.Printf("Entering infinite loop")
donNewtonAlphac997d642018-10-17 13:22:48 -0400315 var ticker = time.NewTicker(60 * time.Second)
316 for {
317 select {
318 case <-ticker.C:
Don Newtone973d342018-10-26 16:44:12 -0400319 impl.DoOutput()
donNewtonAlphac997d642018-10-17 13:22:48 -0400320 }
321 }
322
donNewtonAlphab3279ea2018-09-18 15:55:32 -0400323 //TODO publish periodic stats etc
Author Namea594e632018-08-10 11:33:58 -0400324 fmt.Println("AbstractOLT")
325}