carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package host
2
3import (
4 "net"
5 "strings"
6
7 "github.com/carlosframework/platform/internal/edgesfile"
8)
9
10// BoxAddresses are the addresses this box publishes in its edges file for
11// other edges to dial (region HA spec 2 §6). Public is for an edge in
12// another region. Private, with PrivateCIDR (the region network it lies
13// in), is for an edge in the same region. They are routing data only: an
14// edge dials them, and nothing grants anything on them. "" is an address
15// the source could not report, or one that failed validation, and nothing
16// is published for it.
17type BoxAddresses struct {
18 Private string
19 PrivateCIDR string
20 Public string
21}
22
23// AddressSource reads this box's addresses afresh on every call. The edges
24// file publisher asks it before every publication and publishes only what
25// it reports, so an address the box no longer holds is never republished.
26// Every source is root-configured: the cloud's metadata service, or
27// host.env. None reads a file the agent can write.
28//
29// ok is false when the source could not tell: a metadata request that
30// failed, timed out or answered something other than "here it is" or "there
31// is none". Unknown is not blank. A caller that gets !ok writes nothing and
32// leaves what it published before standing; only an authoritative answer,
33// blank fields included, changes the published address.
34type AddressSource interface {
35 BoxAddresses() (BoxAddresses, bool)
36}
37
38// envAddresses is the provider-neutral source (§25), from host.env:
39// CARLOS_PRIVATE_IP with CARLOS_PRIVATE_CIDR, and CARLOS_PUBLIC_IP. A field
40// whose setting is present is the answer for that field, and a value that
41// does not validate publishes nothing: an operator's setting is never
42// silently replaced. CARLOS_PRIVATE_IP without CARLOS_PRIVATE_CIDR is
43// invalid (census ruling region-ha-2a). A field left unset comes from
44// provider, the cloud's adapter, when there is one.
45type envAddresses struct {
46 getenv func(string) string
47 provider AddressSource
48}
49
50func (s envAddresses) BoxAddresses() (BoxAddresses, bool) {
51 ip := strings.TrimSpace(s.getenv("CARLOS_PRIVATE_IP"))
52 cidr := strings.TrimSpace(s.getenv("CARLOS_PRIVATE_CIDR"))
53 public := strings.TrimSpace(s.getenv("CARLOS_PUBLIC_IP"))
54 privateSet, publicSet := ip != "" || cidr != "", public != ""
55 out := BoxAddresses{}
56 if privateSet {
57 out.Private, out.PrivateCIDR = edgesfile.PrivateAddress(ip, []string{cidr})
58 }
59 if publicSet {
60 out.Public = ipv4Only(public)
61 }
62 if (!privateSet || !publicSet) && s.provider != nil {
63 p, ok := s.provider.BoxAddresses()
64 if !ok {
65 return BoxAddresses{}, false
66 }
67 if !privateSet {
68 out.Private, out.PrivateCIDR = edgesfile.PrivateAddress(p.Private, []string{p.PrivateCIDR})
69 }
70 if !publicSet {
71 out.Public = ipv4Only(p.Public)
72 }
73 }
74 return out, true
75}
76
77// ipv4Only is s when it is an IPv4 address, in its canonical form, and ""
78// otherwise.
79func ipv4Only(s string) string {
80 ip := net.ParseIP(strings.TrimSpace(s))
81 if ip == nil || ip.To4() == nil {
82 return ""
83 }
84 return ip.To4().String()
85}
86