forked from metallb/metallb
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfabfile.py
More file actions
169 lines (138 loc) · 6.57 KB
/
fabfile.py
File metadata and controls
169 lines (138 loc) · 6.57 KB
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
import contextlib
import subprocess
import tempfile
import time
import shutil
import sys
from fabric.api import *
def _silent_nofail(*args, **kwargs):
with settings(warn_only=True):
return _silent(*args, **kwargs)
def _silent(*args, **kwargs):
with hide('warnings', 'running'):
return local(*args, capture=True, **kwargs)
@contextlib.contextmanager
def _tempdir():
name = tempfile.mkdtemp()
try:
yield name
finally:
shutil.rmtree(name)
## Dockerfile generation
def gen_docker():
"""Generate ./dockerfiles/{dev,prod}"""
local("mkdir -p ./dockerfiles/prod ./dockerfiles/dev")
for env in ('dev', 'prod'):
for binary in ('controller', 'bgp-speaker'):
local('sed -e "s/%%BINARY%%/{0}/g" ./dockerfiles/{1}.tmpl >./dockerfiles/{1}/{0}'.format(binary, env))
## Debugging
def wireshark():
node = _silent('kubectl get nodes -o go-template="{{ (index (index .items 0).status.addresses 0).address }}"')
nodePort = _silent('kubectl get svc -n metallb-system test-bgp-router-ui -o go-template="{{ (index .spec.ports 0).nodePort }}"')
with _tempdir() as tmp:
local('curl -o {0}/pcap http://{1}:{2}/pcap'.format(tmp, node, nodePort))
local('wireshark-gtk {0}/pcap'.format(tmp))
## Releases
def _error(msg):
print(msg)
sys.exit(1)
def release(version):
# Import here so that people who aren't making releases don't
# need to pip install.
import semver
if _silent("git status --porcelain"):
_error("git working directory not clean, cannot prepare release")
vi = semver.parse_version_info(version)
branch_name = 'v{0}.{1}'.format(vi.major, vi.minor)
if vi.patch != 0 and _silent_nofail("git rev-parse --verify {0}".format(branch_name)).failed:
_error("Cannot release {0}, branch {1} does not exist".format(version, branch_name))
if vi.patch == 0:
local("git checkout master")
local("git checkout -b {0}".format(branch_name))
with lcd("website/content"):
local("perl -pi -e 's#/google/metallb/master#/google/metallb/v{0}#g' *".format(version))
with lcd("manifests"):
local("perl -pi -e 's/:latest/:v{0}/g' *".format(version))
else:
local("git checkout {0}".format(branch_name))
with lcd("website/content"):
local("perl -pi -e 's#/google/metallb/v{0}.{1}.{2}#/google/metallb/v{0}.{1}.{3}#g' *".format(vi.major, vi.minor, vi.patch-1, vi.patch))
with lcd("manifests"):
local("perl -pi -e 's/:v{0}.{1}.{2}/:v{0}.{1}.{3}/g' *".format(vi.major, vi.minor, vi.patch-1, vi.patch))
with lcd("website"):
local("perl -pi -e 's/version = .*/version = \"v{0}\"/g' config.toml".format(version))
local('git commit -a -m "Update documentation for release {0}"'.format(version))
local('git tag v{0} -m "See the release notes for details:\n\nhttps://metallb.universe.tf/release-notes/#version-0-2-0"'.format(version))
local('git checkout master')
## Minikube bringup/teardown
def _minikube_running():
return _silent_nofail("minikube ip").succeeded
def start():
"""Start minikube and configure it for MetalLB"""
if not _minikube_running():
local("minikube start")
local("minikube addons enable registry")
print("waiting for registry to start")
while _silent_nofail("kubectl get svc -n kube-system registry").failed:
time.sleep(1)
regSvcType = _silent("kubectl get svc -n kube-system registry -o go-template=\"{{.spec.type}}\"")
if _silent_nofail("kubectl get ns metallb-system").failed:
push_manifests()
def stop():
"""Delete running minikube cluster"""
if _minikube_running():
local("minikube delete")
## Platform-agnostic stuff - just uses kubectl and assumes the kube-system registry is running
def _registry_clusterip():
return "%s:80" % _silent("kubectl get svc -n kube-system registry -o go-template='{{.spec.clusterIP}}'")
def _kube_obj_exists(n):
return _silent_nofail("kubectl get %s").succeeded
@contextlib.contextmanager
def _proxy_to_registry():
registry_pod = _silent("kubectl get pod -n kube-system -l kubernetes.io/minikube-addons=registry -o go-template=\"{{(index .items 0).metadata.name}}\"")
p = subprocess.Popen("kubectl port-forward -n kube-system %s 5000:5000" % registry_pod, shell=True)
try:
print("Waiting for kube port-forward to come up...")
while _silent_nofail("curl http://localhost:5000/").failed:
time.sleep(0.1)
yield
finally:
p.kill()
def push_config():
"""Push a basic MetalLB config that connects to test-bgp-router."""
# As it happens, the tutorial config is exactly what we need here.
local("kubectl apply -f manifests/tutorial-1.yaml")
def push_manifests():
"""Push the metallb binary manifests"""
local("kubectl apply -f manifests/metallb.yaml,manifests/test-bgp-router.yaml")
if _silent_nofail("kubectl get configmap -n metallb-system config").failed:
push_config()
def _build(ts, name, registry):
with _tempdir() as tmp:
local("env GOOS=linux GOARCH=amd64 go install ./%s" % name)
local("env GOOS=linux GOARCH=amd64 go build -o %s/%s ./%s" % (tmp, name, name))
local("cp ./dockerfiles/dev/%s %s/Dockerfile" % (name, tmp))
local("sudo docker build -t %s/%s:latest %s" % (registry, name, tmp))
local("sudo docker tag %s/%s:latest %s/%s:%s" % (registry, name, registry, name, ts))
with _proxy_to_registry():
local("sudo docker push %s/%s:%s" % (registry, name, ts))
local("sudo docker rmi %s/%s:%s" % (registry, name, ts))
def _set_image(ts, name, job, registry):
set_from_registry = _registry_clusterip() if "localhost" in registry else registry
local("kubectl set image -n metallb-system {2} {1}={3}/{1}:{0}".format(ts, name, job, set_from_registry))
def _wait_for_rollout(typ, name):
local("kubectl rollout status -n metallb-system {0} {1}".format(typ, name))
def push(registry="localhost:5000"):
"""Build and repush metallb binaries"""
if _silent_nofail("kubectl get ns metallb-system").failed:
push_manifests()
ts = "%f" % time.time()
_build(ts, "controller", registry)
_build(ts, "bgp-speaker", registry)
_build(ts, "test-bgp-router", registry)
_set_image(ts, "controller", "deploy/controller", registry)
_set_image(ts, "bgp-speaker", "ds/bgp-speaker", registry)
_set_image(ts, "test-bgp-router", "deploy/test-bgp-router", registry)
_wait_for_rollout("deployment", "controller")
_wait_for_rollout("daemonset", "bgp-speaker")
_wait_for_rollout("deployment", "test-bgp-router")