-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
166 lines (148 loc) · 5.14 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*
For all the devices registered under eensymachines,
or built by eensymachines this serves as the single source of truth for device status.
Devices also maintain their configuration alongsided where in changing that configuration would mean the change is pushed to the device on the ground
author : [email protected]
Copyright : eensymachines.in@2024
*/
package main
import (
"bytes"
"context"
"io"
"os"
"strings"
"time"
"github.com/eensymachines-in/utilities"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
const (
/* Secrets inside the container are mounted at the location,
check the deployment file for the name of the volume mounts and actual secret key literal for the path
NOTE: secret name in kubernetes has no bearing here, volumename/literal-key*/
MONGO_URI_SECRET = "/run/secrets/vol-mongouri/uri"
AMQP_URI_SECRET = "/run/secrets/vol-amqpuri/uri"
)
var (
mongoConnectURI string = ""
mongoDBName = ""
amqpConnectURI = ""
rabbitXchng = "" // name of the rabbit queue
)
// readK8SecretMount : secrets mounted on the pod read inside the container
// fp : filepath of the secret file
func readK8SecretMount(fp string) ([]string, error) {
f, err := os.Open(fp)
if err != nil {
return nil, err
}
byt, err := io.ReadAll(f)
if err != nil {
return nil, err
}
if bytes.HasSuffix(byt, []byte("\n")) {
byt, _ = bytes.CutSuffix(byt, []byte("\n")) //often file read in will have this as a suffix
}
/* There could be multiple secrets in the same file separated by white space */
return strings.Split(string(byt), " "), nil
}
// init : this will set logging parameters
// this will set mongo connection strings, database from env / secrets
// this will set amqp connection string from env / secrets
func init() {
log.SetFormatter(&log.TextFormatter{
DisableColors: false,
FullTimestamp: false,
PadLevelText: true,
})
log.SetReportCaller(false)
log.SetOutput(os.Stdout)
log.SetLevel(log.InfoLevel) // default is info level, if verbose then trace
val := os.Getenv("FLOG")
if val == "1" {
f, err := os.Open(os.Getenv("LOGF")) // file for logs
if err != nil {
log.SetOutput(os.Stdout) // error in opening log file
log.Warn("Failed to open log file, log output set to stdout")
}
log.SetOutput(f) // log output set to file direction
log.Infof("log output is set to file: %s", os.Getenv("LOGF"))
} else {
log.SetOutput(os.Stdout)
log.Info("log output to stdout")
}
val = os.Getenv("SILENT")
if val == "1" {
log.SetLevel(log.ErrorLevel) // for production
} else {
log.SetLevel(log.DebugLevel) // for development
}
/* Making the mongo connection params */
secrets, err := readK8SecretMount(MONGO_URI_SECRET)
if err != nil || len(secrets) == 0 {
log.WithFields(log.Fields{
"err": err,
"secrets": secrets,
}).Fatalf("failed to read secret from mount")
}
mongoConnectURI = secrets[0]
log.WithFields(log.Fields{
"uri": mongoConnectURI,
}).Debug("mongo connect uri from secret")
/* attempting to ping the database before we start firing requests in
if ofcourse each of the request will be using their own connection objects*/
ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
client, err := mongo.Connect(ctx, options.Client().ApplyURI(mongoConnectURI))
if err != nil || client == nil {
log.Fatalf("failed database connection, %s", err)
}
err = client.Ping(ctx, readpref.Primary())
if err != nil {
log.Fatalf("failed to ping database, %s", err)
}
log.Info("database is reachable..")
defer client.Disconnect(ctx) // purpose of this connection is served
mongoDBName = os.Getenv("MONGO_DB_NAME")
if mongoDBName == "" {
log.Fatal("invalid/empty name for mongo db, cannot proceed")
}
/* Making AMQP connection.. */
secrets, err = readK8SecretMount(AMQP_URI_SECRET)
if err != nil || len(secrets) == 0 {
log.WithFields(log.Fields{
"err": err,
"secrets": secrets,
}).Fatalf("failed to read secret from mount")
}
amqpConnectURI = secrets[0]
log.WithFields(log.Fields{
"uri": amqpConnectURI,
}).Debug("amqp connect uri from secret")
rabbitXchng = os.Getenv("AMQP_XNAME")
}
func main() {
log.Info("Starting webapi-devicereg..")
defer log.Warn("Closing webapi-devicereg")
gin.SetMode(gin.DebugMode)
r := gin.Default()
devices := r.Group("/api/devices").Use(utilities.CORS).Use(MongoConnectURI(mongoConnectURI, mongoDBName))
// Posting a new device registrations
// Getting a list of devices filtered on a field
devices.OPTIONS("", utilities.Preflight)
devices.POST("", HndlLstDvcs)
devices.GET("", HndlLstDvcs) //?filter=users&user=userid
devices.OPTIONS("/:deviceid", utilities.Preflight)
// Getting a single device details , either on mac or mongo oid
devices.GET("/:deviceid", DeviceOfID, HndlOneDvc)
// Patching device details - config or users
// ?path=users&action=append
// ?path=config
devices.PATCH("/:deviceid", RabbitConnectWithChn(amqpConnectURI, rabbitXchng), DeviceOfID, HndlOneDvc)
// Removing a device registration completely
devices.DELETE("/:deviceid", HndlOneDvc)
log.Fatal(r.Run(":8080"))
}