carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1// Package infraview is what an infrastructure inventory IS, in terms no
2// cloud provider owns. It is deliberately free of every SDK: the AWS
3// implementation (internal/awsinv) imports this package, never the other
4// way round, so the console page that renders an inventory can be pointed
5// at a second provider by writing one file rather than by rewriting the
6// page.
7//
8// The wire shape here is written to a production bucket
9// (InventoryKey), so it obeys the repo's additive rule: every field is
10// optional, unknown fields parse, and an unknown Kind is carried through
11// as itself. A reader that drops what it does not recognise would make the
12// page LESS useful exactly where it is most useful — the resource nobody
13// wrote code for is the one worth seeing.
14package infraview
15
16import (
17 "context"
18 "time"
19)
20
21// InventoryKey is where a deployment's inventory snapshot lives in its own
22// bucket. One object, overwritten in place: this is a current-state
23// snapshot, not a history, and a history would need a retention policy
24// nobody has asked for.
25const InventoryKey = "infra/inventory.json"
26
27// The kind vocabulary. Small and neutral on purpose — a provider maps its
28// own types into these and carries the truth in NativeType, so the page's
29// layout rules ("machines sit in the box layer") never have to learn a new
30// cloud's nouns. KindOther is not a failure: it is the honest home for a
31// discovered resource this vocabulary has no word for.
32const (
33 KindMachine = "machine"
34 KindIP = "ip"
35 KindDisk = "disk"
36 KindFirewall = "firewall"
37 KindNetwork = "network"
38 KindBucket = "bucket"
39 KindDNSZone = "dns_zone"
40 KindDNSRecord = "dns_record"
41 KindIdentity = "identity"
42 KindAlarm = "alarm"
43 KindCertificate = "certificate"
44 KindOther = "other"
45)
46
47// Resource is one thing a provider is carrying. Attrs is stringly on
48// purpose: a typed struct per kind would need a migration every time a
49// provider exposes a new field, and this object must stay parseable by
50// readers written before that field existed. Keys the console renders are
51// documented where it reads them; keys it does not know are shown verbatim.
52type Resource struct {
53 Provider string `json:"provider"`
54 Kind string `json:"kind"`
55 NativeType string `json:"native_type,omitempty"`
56 ID string `json:"id"`
57 Name string `json:"name,omitempty"`
58 Region string `json:"region,omitempty"`
59 Attrs map[string]string `json:"attrs,omitempty"`
60 Tags map[string]string `json:"tags,omitempty"`
61}
62
63// Attr reads one attribute without the caller having to nil-check the map.
64func (r Resource) Attr(key string) string {
65 if r.Attrs == nil {
66 return ""
67 }
68 return r.Attrs[key]
69}
70
71// Inventory is one provider's estate at one moment. Partial names the reads
72// that FAILED, in words a person can act on ("security groups in eu-west-1:
73// throttled"). It exists because "no security groups" and "the security
74// group read failed" are different sentences and only one of them may be
75// rendered as a fact.
76type Inventory struct {
77 Provider string `json:"provider"`
78 Account string `json:"account,omitempty"`
79 TakenAt time.Time `json:"taken_at"`
80 Resources []Resource `json:"resources"`
81 Partial []string `json:"partial,omitempty"`
82}
83
84// ByKind returns every resource of one kind, in inventory order.
85func (i Inventory) ByKind(kind string) []Resource {
86 var out []Resource
87 for _, r := range i.Resources {
88 if r.Kind == kind {
89 out = append(out, r)
90 }
91 }
92 return out
93}
94
95// Find returns the first resource of kind whose attr equals value, or nil.
96// value == "" never matches: an empty attribute is absence, and matching on
97// it would join every machine with no public IP to every record with no
98// value.
99func (i Inventory) Find(kind, attr, value string) *Resource {
100 if value == "" {
101 return nil
102 }
103 for idx := range i.Resources {
104 if i.Resources[idx].Kind == kind && i.Resources[idx].Attr(attr) == value {
105 return &i.Resources[idx]
106 }
107 }
108 return nil
109}
110
111// Provider is one cloud (or one bare-metal estate) that can describe
112// itself. Implementations return construction-class failures as an error —
113// no credential, no reachable API — and everything else through
114// Inventory.Partial, because a page that can show eleven resource classes
115// must show eleven.
116type Provider interface {
117 Inventory(ctx context.Context) (Inventory, error)
118}
119