Skip to content

Commit 4119760

Browse files
authored
Add a create_link management command. (#459)
* Add a create_link management command. Just by using the admin webpage, it is extremely difficult to create links among hosts. This tool should allow easier creation until we build a better admin page. * Linter.
1 parent d2038c6 commit 4119760

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Copyright 2024 ETH Zurich
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import sys
16+
17+
from django.core.management.base import BaseCommand, CommandParser
18+
19+
from scionlab.models.core import Host, Link
20+
21+
22+
class Command(BaseCommand):
23+
help = 'Create Link between two hosts'
24+
25+
def add_arguments(self, parser: CommandParser) -> None:
26+
parser.add_argument('-t', '--type', type=str, required=True,
27+
choices=['core', 'provider', 'peer'],
28+
help='Type of the link. ' +
29+
'If provider, host_a is parent, host_b is child.')
30+
parser.add_argument('host_a', type=str,
31+
help='First host. If link is of type provider, this is the parent.')
32+
parser.add_argument('host_b', type=str,
33+
help='Second host. If link is of type provider, this is the child.')
34+
35+
def handle(self, *args, **kwargs):
36+
# Check the type is correct.
37+
type = None
38+
for t in Link.LINK_TYPES:
39+
if kwargs['type'].lower() == t[0].lower():
40+
type = t[0]
41+
if type is None:
42+
raise RuntimeError('logic error: link types have changed')
43+
44+
# Find the hosts.
45+
host_a = self.find_host(kwargs['host_a'])
46+
host_b = self.find_host(kwargs['host_b'])
47+
48+
# Create the link.
49+
self.create_link(type, host_a, host_b)
50+
51+
def find_host(self, hostname):
52+
hosts = Host.objects.filter(label=hostname)
53+
if hosts.count() == 1:
54+
return hosts.get()
55+
if hosts.count() > 1:
56+
exit(f'more than one host with the same label "{hostname}"')
57+
58+
# No host with that exact label found, try to find substrings.
59+
hosts = Host.objects.filter(label__contains=hostname)
60+
if hosts.count() == 0:
61+
exit(f'no host found with or containing label "{hostname}"')
62+
63+
labels = [h.label for h in hosts]
64+
print(f'no host with exact label "{hostname}". Found similar:\n' + '\n'.join(labels))
65+
if len(labels) > 1:
66+
# More than one host found, bail and ask the user to be specific.
67+
exit('be more specific')
68+
69+
# If only one matches the substring, use it.
70+
print(f'replacing "{hostname}" -> "{labels[0]}"')
71+
return hosts.get()
72+
73+
def create_link(self, type, host_a, host_b):
74+
# The create_from_hosts method checks the validity of the type for those ASes.
75+
Link.objects.create_from_hosts(type, host_a, host_b)
76+
77+
78+
def exit(msg: str):
79+
print(msg)
80+
sys.exit(1)

0 commit comments

Comments
 (0)