-
Notifications
You must be signed in to change notification settings - Fork 9
/
env.go
148 lines (118 loc) · 3.56 KB
/
env.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
// Copyright 2022 Namespace Labs Inc; All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
package core
import (
"context"
"encoding/json"
"flag"
"fmt"
"log"
"net/http"
"os"
"sync/atomic"
"time"
"github.com/rs/zerolog"
"google.golang.org/protobuf/encoding/prototext"
"namespacelabs.dev/foundation/framework/runtime"
"namespacelabs.dev/foundation/schema"
runtimepb "namespacelabs.dev/foundation/schema/runtime"
"namespacelabs.dev/foundation/std/core/types"
)
func init() {
zerolog.TimeFieldFormat = time.RFC3339Nano // Setting external package globals does not make me happy.
}
var (
debug = flag.Bool("debug_init", false, "If set to true, emits additional initialization information.")
datamarker atomic.Pointer[data]
)
type data struct {
rt *runtimepb.RuntimeConfig
rtVcs *runtimepb.BuildVCS
serverName string
startupTime time.Time
}
var (
// Deprecated: use ZLog.
Log = log.New(os.Stderr, "[ns] ", log.Ldate|log.Ltime|log.Lmicroseconds)
ZLog = zerolog.New(os.Stderr).With().Timestamp().Logger().Level(zerolog.DebugLevel)
)
func PrepareEnv(specifiedServerName string) *ServerResources {
d, err := loadData(specifiedServerName)
if err != nil {
log.Fatal(err)
}
if !datamarker.CompareAndSwap(nil, &d) {
log.Fatal("already initialized")
}
ZLog.Info().Msg("Initializing server...")
return &ServerResources{startupTime: time.Now()}
}
func loadData(specifiedServerName string) (data, error) {
rt, err := runtime.LoadRuntimeConfig()
if err != nil {
return data{}, err
}
rtVcs, err := runtime.LoadBuildVCS()
if err != nil {
return data{}, err
}
return data{rt, rtVcs, specifiedServerName, time.Now()}, nil
}
func initializedData() data {
data := datamarker.Load()
if data == nil {
panic("not initialized")
}
return *data
}
func ProvideServerInfo(ctx context.Context, _ *types.ServerInfoArgs) (*types.ServerInfo, error) {
data := initializedData()
return &types.ServerInfo{
ServerName: data.serverName,
EnvName: data.rt.Environment.Name,
EnvPurpose: data.rt.Environment.Purpose,
Vcs: data.rtVcs,
}, nil
}
func EnvPurpose() schema.Environment_Purpose {
v, ok := schema.Environment_Purpose_value[initializedData().rt.Environment.Purpose]
if ok {
return schema.Environment_Purpose(v)
}
return schema.Environment_PURPOSE_UNKNOWN
}
func EnvIs(purpose schema.Environment_Purpose) bool {
return EnvPurpose() == purpose
}
type frameworkKey string
const ctxResourcesKey = frameworkKey("ns.serverresources")
func WithResources(ctx context.Context, res *ServerResources) context.Context {
return context.WithValue(ctx, ctxResourcesKey, res)
}
func ServerResourcesFrom(ctx context.Context) *ServerResources {
v := ctx.Value(ctxResourcesKey)
if v == nil {
return nil
}
return v.(*ServerResources)
}
func StatusHandler(registered []string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
data := datamarker.Load()
if data == nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
vcsStr, _ := json.Marshal(data.rtVcs)
fmt.Fprintf(w, "<!doctype html><html><body><pre>%s\nimage_version=%s\n%s\n%s</pre>",
data.serverName, data.rt.Current.ImageRef, prototext.Format(data.rt.Environment), vcsStr)
fmt.Fprintf(w, "<b>Registered endpoints</b></br><ul>")
for _, endpoint := range registered {
fmt.Fprintf(w, "<li><a href=%s>%s</a></li>", endpoint, endpoint)
}
fmt.Fprintf(w, "</ul>")
fmt.Fprintf(w, "</body></html>")
})
}