blob: 3cdc661f0f094c209441c5a1f5d2e9f04d495d19 [file] [log] [blame]
Serge Bazanskic00318e2021-03-03 12:39:24 +01001// Copyright 2020 The Monogon Project Authors.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17package event
18
19import (
20 "context"
21 "fmt"
22 "net"
23 "time"
24)
25
26// NetworkStatus is example data that will be stored in a Value.
27type NetworkStatus struct {
28 ExternalAddress net.IP
29 DefaultGateway net.IP
30}
31
32// NetworkStatusWatcher is a typesafe wrapper around a Watcher.
33type NetworkStatusWatcher struct {
34 watcher Watcher
35}
36
37// Get wraps Watcher.Get and performs type assertion.
38func (s *NetworkStatusWatcher) Get(ctx context.Context) (*NetworkStatus, error) {
39 val, err := s.watcher.Get(ctx)
40 if err != nil {
41 return nil, err
42 }
43 ns := val.(NetworkStatus)
44 return &ns, nil
45}
46
47// NetworkService is a fake/example network service that is responsible for
48// communicating the newest information about a machine's network configuration
49// to consumers/watchers.
50type NetworkService struct {
51 Provider MemoryValue
52}
53
54// Watch is a thin wrapper around Value.Watch that returns the typesafe
55// NetworkStatusWatcher wrapper.
56func (s *NetworkService) Watch() NetworkStatusWatcher {
57 watcher := s.Provider.Watch()
58 return NetworkStatusWatcher{
59 watcher: watcher,
60 }
61}
62
63// Run pretends to execute the network service's main logic loop, in which it
64// pretends to have received an IP address over DHCP, and communicates that to
65// consumers/watchers.
66func (s *NetworkService) Run(ctx context.Context) {
67 s.Provider.Set(NetworkStatus{
68 ExternalAddress: nil,
69 DefaultGateway: nil,
70 })
71
72 select {
73 case <-time.After(100*time.Millisecond):
74 case <-ctx.Done():
75 return
76 }
77
78 fmt.Printf("NS: Got DHCP Lease\n")
79 s.Provider.Set(NetworkStatus{
80 ExternalAddress: net.ParseIP("203.0.113.24"),
81 DefaultGateway: net.ParseIP("203.0.113.1"),
82 })
83
84 select {
85 case <-time.After(100*time.Millisecond):
86 case <-ctx.Done():
87 return
88 }
89
90 fmt.Printf("NS: DHCP Address changed\n")
91 s.Provider.Set(NetworkStatus{
92 ExternalAddress: net.ParseIP("203.0.113.103"),
93 DefaultGateway: net.ParseIP("203.0.113.1"),
94 })
95
96 time.Sleep(100 * time.Millisecond)
97}
98
99// ExampleValue_full demonstrates a typical usecase for Event Values, in which
100// a mock network service lets watchers know that the machine on which the code
101// is running has received a new network configuration.
102// It also shows the typical boilerplate required in order to wrap a Value (eg.
103// MemoryValue) within a typesafe wrapper.
104func ExampleValue_full() {
105 ctx, ctxC := context.WithCancel(context.Background())
106 defer ctxC()
107
108 // Create a fake NetworkService.
109 ns := NetworkService{}
110
111 // Run an /etc/hosts updater. It will watch for updates from the NetworkService
112 // about the current IP address of the node.
113 go func() {
114 w := ns.Watch()
115 for {
116 status, err := w.Get(ctx)
117 if err != nil {
118 break
119 }
120 if status.ExternalAddress == nil {
121 continue
122 }
123 // Pretend to write /etc/hosts with the newest ExternalAddress.
124 // In production code, you would also check for whether ExternalAddress has
125 // changed from the last written value, if writing to /etc/hosts is expensive.
126 fmt.Printf("/etc/hosts: foo.example.com is now %s\n", status.ExternalAddress.String())
127 }
128 }()
129
130 // Run fake network service.
131 ns.Run(ctx)
132
133 // Output:
134 // NS: Got DHCP Lease
135 // /etc/hosts: foo.example.com is now 203.0.113.24
136 // NS: DHCP Address changed
137 // /etc/hosts: foo.example.com is now 203.0.113.103
138}
139