-
Notifications
You must be signed in to change notification settings - Fork 9
/
service.go
128 lines (109 loc) · 4 KB
/
service.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
// 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 cuefrontendopaque
import (
"strings"
"golang.org/x/exp/maps"
"google.golang.org/protobuf/types/known/anypb"
"k8s.io/utils/strings/slices"
"namespacelabs.dev/foundation/internal/fnerrors"
"namespacelabs.dev/foundation/internal/runtime"
"namespacelabs.dev/foundation/schema"
"namespacelabs.dev/foundation/std/pkggraph"
)
type cueService struct {
Kind string `json:"kind"`
Port int `json:"port"`
Ingress cueIngress `json:"ingress"`
ReadinessProbe map[string]string `json:"probe"` // `probe: http: "/"`
Probes map[string]map[string]string `json:"probes"` // `probes: readiness: http: "/"`
}
type cueIngress struct {
InternetFacing bool `json:"internetFacing"`
HttpRoutes map[string][]string `json:"httpRoutes"`
}
var knownKinds = []string{"tcp", schema.ClearTextGrpcProtocol, schema.GrpcProtocol, schema.HttpProtocol}
func parseService(loc pkggraph.Location, name string, svc cueService) (*schema.Server_ServiceSpec, schema.Endpoint_Type, error) {
if !slices.Contains(knownKinds, svc.Kind) {
return nil, schema.Endpoint_INGRESS_UNSPECIFIED, fnerrors.NewWithLocation(loc, "service kind is not supported: %s (support %v)", svc.Kind, strings.Join(knownKinds, ", "))
}
var endpointType schema.Endpoint_Type
if svc.Ingress.InternetFacing {
endpointType = schema.Endpoint_INTERNET_FACING
} else {
endpointType = schema.Endpoint_PRIVATE
}
urlMap := &schema.HttpUrlMap{}
for _, routes := range svc.Ingress.HttpRoutes {
for _, route := range routes {
urlMap.Entry = append(urlMap.Entry, &schema.HttpUrlMap_Entry{
PathPrefix: route,
})
}
}
var details *anypb.Any
if len(urlMap.Entry) > 0 {
details = &anypb.Any{}
if err := details.MarshalFrom(urlMap); err != nil {
return nil, schema.Endpoint_INGRESS_UNSPECIFIED, err
}
}
// For the time being, having a grpc service implies exporting all GRPC services.
if svc.Kind == schema.GrpcProtocol || svc.Kind == schema.ClearTextGrpcProtocol {
details = &anypb.Any{}
if err := details.MarshalFrom(&schema.GrpcExportAllServices{}); err != nil {
return nil, schema.Endpoint_INGRESS_UNSPECIFIED, fnerrors.New("failed to serialize grpc configuration: %w", err)
}
}
parsed := &schema.Server_ServiceSpec{
Name: name,
Port: &schema.Endpoint_Port{Name: name, ContainerPort: int32(svc.Port)},
Metadata: []*schema.ServiceMetadata{{
Protocol: svc.Kind,
Details: details,
}},
}
if svc.Probes != nil && svc.ReadinessProbe != nil {
return nil, schema.Endpoint_INGRESS_UNSPECIFIED, fnerrors.BadInputError("probes and probe are exclusive")
}
if svc.ReadinessProbe != nil {
md, err := parseProbe(runtime.FnServiceReadyz, svc.ReadinessProbe)
if err != nil {
return nil, schema.Endpoint_INGRESS_UNSPECIFIED, err
}
parsed.Metadata = append(parsed.Metadata, md)
}
for name, data := range svc.Probes {
var kind string
switch name {
case "readiness":
kind = runtime.FnServiceReadyz
case "liveness":
kind = runtime.FnServiceLivez
default:
return nil, schema.Endpoint_INGRESS_UNSPECIFIED, fnerrors.BadInputError("%s: unsupported probe kind", name)
}
md, err := parseProbe(kind, data)
if err != nil {
return nil, schema.Endpoint_INGRESS_UNSPECIFIED, err
}
parsed.Metadata = append(parsed.Metadata, md)
}
return parsed, endpointType, nil
}
func parseProbe(kind string, data map[string]string) (*schema.ServiceMetadata, error) {
for _, key := range maps.Keys(data) {
if key == "http" {
httpmd := &schema.HttpExportedService{Path: data[key]}
serializedHttpmd, err := anypb.New(httpmd)
if err != nil {
return nil, fnerrors.InternalError("failed to serialize ServiceMetadata")
}
return &schema.ServiceMetadata{Kind: kind, Details: serializedHttpmd}, nil
} else {
return nil, fnerrors.BadInputError("%s: unsupported probe type", key)
}
}
return nil, nil
}