Add manual ipv4 network configuration
Signed-off-by: Adam Stokes <adam.stokes@ubuntu.com>
This commit is contained in:
parent
4a878baa21
commit
a82fb9e6a8
|
@ -16,7 +16,9 @@
|
||||||
from subiquity.controller import ControllerPolicy
|
from subiquity.controller import ControllerPolicy
|
||||||
from subiquity.models import NetworkModel
|
from subiquity.models import NetworkModel
|
||||||
from subiquity.ui.views import (NetworkView,
|
from subiquity.ui.views import (NetworkView,
|
||||||
NetworkSetDefaultRouteView)
|
NetworkSetDefaultRouteView,
|
||||||
|
NetworkConfigureInterfaceView,
|
||||||
|
NetworkConfigureIPv4InterfaceView)
|
||||||
from subiquity.ui.dummy import DummyView
|
from subiquity.ui.dummy import DummyView
|
||||||
|
|
||||||
from subiquity.curtin import curtin_write_network_actions
|
from subiquity.curtin import curtin_write_network_actions
|
||||||
|
@ -42,9 +44,38 @@ class NetworkController(ControllerPolicy):
|
||||||
self.signal.emit_signal('filesystem:show')
|
self.signal.emit_signal('filesystem:show')
|
||||||
|
|
||||||
def set_default_route(self):
|
def set_default_route(self):
|
||||||
|
self.model.prev_signal = ('Back to network view',
|
||||||
|
'network:show',
|
||||||
|
'network')
|
||||||
|
self.ui.set_header("Default route")
|
||||||
self.ui.set_body(NetworkSetDefaultRouteView(self.model,
|
self.ui.set_body(NetworkSetDefaultRouteView(self.model,
|
||||||
self.signal))
|
self.signal))
|
||||||
|
|
||||||
|
def network_configure_interface(self, iface):
|
||||||
|
self.model.prev_signal = ('Back to network view',
|
||||||
|
'network:show',
|
||||||
|
'network')
|
||||||
|
self.ui.set_header("Network interface {}".format(iface))
|
||||||
|
self.ui.set_body(NetworkConfigureInterfaceView(self.model,
|
||||||
|
self.signal,
|
||||||
|
iface))
|
||||||
|
|
||||||
|
def network_configure_ipv4_interface(self, iface):
|
||||||
|
self.model.prev_signal = ('Back to configure interface menu',
|
||||||
|
'network:configure-interface-menu',
|
||||||
|
'network_configure_interface')
|
||||||
|
self.ui.set_header("Network interface {} manual IPv4 "
|
||||||
|
"configuration".format(iface))
|
||||||
|
self.ui.set_body(NetworkConfigureIPv4InterfaceView(self.model,
|
||||||
|
self.signal,
|
||||||
|
iface))
|
||||||
|
|
||||||
|
def network_configure_ipv6_interface(self, iface):
|
||||||
|
self.model.prev_signal = ('Back to configure interface menu',
|
||||||
|
'network:configure-interface-menu',
|
||||||
|
'network_configure_interface')
|
||||||
|
self.ui.set_body(DummyView(self.signal))
|
||||||
|
|
||||||
def bond_interfaces(self):
|
def bond_interfaces(self):
|
||||||
self.ui.set_body(DummyView(self.signal))
|
self.ui.set_body(DummyView(self.signal))
|
||||||
|
|
||||||
|
|
|
@ -59,16 +59,22 @@ class NetworkModel(ModelPolicy):
|
||||||
'network'),
|
'network'),
|
||||||
('Network finish',
|
('Network finish',
|
||||||
'network:finish',
|
'network:finish',
|
||||||
'network_finish')
|
'network_finish'),
|
||||||
|
('Network configure interface',
|
||||||
|
'network:configure-interface-menu',
|
||||||
|
'network_configure_interface'),
|
||||||
|
('Network configure ipv4 interface',
|
||||||
|
'network:configure-ipv4-interface',
|
||||||
|
'network_configure_ipv4_interface')
|
||||||
]
|
]
|
||||||
|
|
||||||
additional_options = [
|
additional_options = [
|
||||||
('Set default route',
|
('Set default route',
|
||||||
'network:set-default-route',
|
'network:set-default-route',
|
||||||
'set_default_route'),
|
'set_default_route'),
|
||||||
('Bond interfaces',
|
# ('Bond interfaces',
|
||||||
'network:bond-interfaces',
|
# 'network:bond-interfaces',
|
||||||
'bond_interfaces'),
|
# 'bond_interfaces'),
|
||||||
# ('Install network driver',
|
# ('Install network driver',
|
||||||
# 'network:install-network-driver',
|
# 'network:install-network-driver',
|
||||||
# 'install_network_driver')
|
# 'install_network_driver')
|
||||||
|
|
|
@ -22,6 +22,8 @@ from .ceph import CephDiskView # NOQA
|
||||||
from .iscsi import IscsiDiskView # NOQA
|
from .iscsi import IscsiDiskView # NOQA
|
||||||
from .network import NetworkView # NOQA
|
from .network import NetworkView # NOQA
|
||||||
from .network_default_route import NetworkSetDefaultRouteView # NOQA
|
from .network_default_route import NetworkSetDefaultRouteView # NOQA
|
||||||
|
from .network_configure_interface import NetworkConfigureInterfaceView #NOQA
|
||||||
|
from .network_configure_ipv4_interface import NetworkConfigureIPv4InterfaceView #NOQA
|
||||||
from .installpath import InstallpathView # NOQA
|
from .installpath import InstallpathView # NOQA
|
||||||
from .installprogress import ProgressView # NOQA
|
from .installprogress import ProgressView # NOQA
|
||||||
from .welcome import WelcomeView # NOQA
|
from .welcome import WelcomeView # NOQA
|
||||||
|
|
|
@ -24,7 +24,7 @@ from urwid import (ListBox, Pile, BoxAdapter,
|
||||||
Text, Columns)
|
Text, Columns)
|
||||||
import yaml
|
import yaml
|
||||||
from subiquity.ui.lists import SimpleList
|
from subiquity.ui.lists import SimpleList
|
||||||
from subiquity.ui.buttons import cancel_btn, menu_btn
|
from subiquity.ui.buttons import cancel_btn, menu_btn, done_btn
|
||||||
from subiquity.ui.utils import Padding, Color
|
from subiquity.ui.utils import Padding, Color
|
||||||
from subiquity.view import ViewPolicy
|
from subiquity.view import ViewPolicy
|
||||||
from subiquity.models.actions import RouteAction
|
from subiquity.models.actions import RouteAction
|
||||||
|
@ -48,9 +48,12 @@ class NetworkView(ViewPolicy):
|
||||||
super().__init__(ListBox(self.body))
|
super().__init__(ListBox(self.body))
|
||||||
|
|
||||||
def _build_buttons(self):
|
def _build_buttons(self):
|
||||||
|
cancel = cancel_btn(on_press=self.cancel)
|
||||||
|
done = done_btn(on_press=self.done)
|
||||||
|
|
||||||
buttons = [
|
buttons = [
|
||||||
Color.button(cancel_btn(on_press=self.cancel),
|
Color.button(done, focus_map='button focus'),
|
||||||
focus_map='button focus'),
|
Color.button(cancel, focus_map='button focus')
|
||||||
]
|
]
|
||||||
return Pile(buttons)
|
return Pile(buttons)
|
||||||
|
|
||||||
|
@ -145,6 +148,10 @@ class NetworkView(ViewPolicy):
|
||||||
|
|
||||||
def on_net_dev_press(self, result):
|
def on_net_dev_press(self, result):
|
||||||
log.debug("Selected network dev: {}".format(result.label))
|
log.debug("Selected network dev: {}".format(result.label))
|
||||||
|
self.signal.emit_signal('network:configure-interface-menu',
|
||||||
|
result.label)
|
||||||
|
|
||||||
|
def done(self, result):
|
||||||
actions = [action.get() for _, action in
|
actions = [action.get() for _, action in
|
||||||
self.model.configured_interfaces.items()]
|
self.model.configured_interfaces.items()]
|
||||||
actions += self.model.get_default_route()
|
actions += self.model.get_default_route()
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
# Copyright 2015 Canonical, Ltd.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from urwid import Text, Pile, ListBox
|
||||||
|
from subiquity.view import ViewPolicy
|
||||||
|
from subiquity.ui.buttons import done_btn, confirm_btn
|
||||||
|
from subiquity.ui.utils import Color, Padding
|
||||||
|
import logging
|
||||||
|
|
||||||
|
log = logging.getLogger('subiquity.network.network_configure_interface')
|
||||||
|
|
||||||
|
|
||||||
|
class NetworkConfigureInterfaceView(ViewPolicy):
|
||||||
|
def __init__(self, model, signal, iface):
|
||||||
|
self.model = model
|
||||||
|
self.signal = signal
|
||||||
|
self.iface = iface
|
||||||
|
body = [
|
||||||
|
Padding.center_79(Text("Will use DHCP for IPv4:")),
|
||||||
|
Padding.center_79(self._build_gateway_info()),
|
||||||
|
Padding.center_79(self._build_manual_ipv4_button()),
|
||||||
|
Padding.line_break(""),
|
||||||
|
Padding.center_79(Text("Checking IPv6...")),
|
||||||
|
Padding.center_79(self._build_manual_ipv6_button()),
|
||||||
|
Padding.line_break(""),
|
||||||
|
Padding.center_20(self._build_buttons())
|
||||||
|
]
|
||||||
|
super().__init__(ListBox(body))
|
||||||
|
|
||||||
|
def _build_gateway_info(self):
|
||||||
|
return Pile([Text("<ip> offered by DHCP server <gateway ip>")])
|
||||||
|
|
||||||
|
def _build_manual_ipv4_button(self):
|
||||||
|
btn = confirm_btn(label="Switch to manual IPv4 configuration",
|
||||||
|
on_press=self.show_ipv4_configuration)
|
||||||
|
return Pile([Color.menu_button(btn, focus_map="menu_button focus")])
|
||||||
|
|
||||||
|
def _build_manual_ipv6_button(self):
|
||||||
|
return Pile([Text("Switch to manual IPv6 configuration")])
|
||||||
|
|
||||||
|
def _build_buttons(self):
|
||||||
|
done = done_btn(on_press=self.done)
|
||||||
|
|
||||||
|
buttons = [
|
||||||
|
Color.button(done, focus_map='button focus'),
|
||||||
|
]
|
||||||
|
return Pile(buttons)
|
||||||
|
|
||||||
|
def show_ipv4_configuration(self, btn):
|
||||||
|
self.signal.emit_signal('network:configure-ipv4-interface', self.iface)
|
||||||
|
|
||||||
|
def done(self, result):
|
||||||
|
self.signal.emit_signal('network:show')
|
|
@ -0,0 +1,102 @@
|
||||||
|
# Copyright 2015 Canonical, Ltd.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from urwid import Text, Pile, ListBox, Columns
|
||||||
|
from subiquity.view import ViewPolicy
|
||||||
|
from subiquity.ui.buttons import done_btn, confirm_btn, cancel_btn
|
||||||
|
from subiquity.ui.utils import Color, Padding
|
||||||
|
from subiquity.ui.interactive import StringEditor
|
||||||
|
import logging
|
||||||
|
|
||||||
|
log = logging.getLogger('subiquity.network.network_configure_ipv4_interface')
|
||||||
|
|
||||||
|
|
||||||
|
class NetworkConfigureIPv4InterfaceView(ViewPolicy):
|
||||||
|
def __init__(self, model, signal, iface):
|
||||||
|
self.model = model
|
||||||
|
self.signal = signal
|
||||||
|
self.iface = iface
|
||||||
|
self.gateway_input = StringEditor(caption="")
|
||||||
|
self.address_input = StringEditor(caption="")
|
||||||
|
self.subnet_input = StringEditor(caption="")
|
||||||
|
body = [
|
||||||
|
Padding.center_79(self._build_iface_inputs()),
|
||||||
|
Padding.line_break(""),
|
||||||
|
Padding.center_79(self._build_set_as_default_gw_button()),
|
||||||
|
Padding.center_20(self._build_buttons())
|
||||||
|
]
|
||||||
|
super().__init__(ListBox(body))
|
||||||
|
|
||||||
|
def _build_iface_inputs(self):
|
||||||
|
col1 = [
|
||||||
|
Columns(
|
||||||
|
[
|
||||||
|
("weight", 0.2, Text("Subnet")),
|
||||||
|
("weight", 0.3,
|
||||||
|
Color.string_input(self.subnet_input,
|
||||||
|
focus_map="string_input focus")),
|
||||||
|
("weight", 0.5, Text("CIDR e.g. 192.168.9.0/24"))
|
||||||
|
], dividechars=2
|
||||||
|
),
|
||||||
|
Columns(
|
||||||
|
[
|
||||||
|
("weight", 0.2, Text("Address")),
|
||||||
|
("weight", 0.3,
|
||||||
|
Color.string_input(self.address_input,
|
||||||
|
focus_map="string_input focus")),
|
||||||
|
("weight", 0.5, Text(""))
|
||||||
|
], dividechars=2
|
||||||
|
),
|
||||||
|
Columns(
|
||||||
|
[
|
||||||
|
("weight", 0.2, Text("Gateway")),
|
||||||
|
("weight", 0.3,
|
||||||
|
Color.string_input(self.gateway_input,
|
||||||
|
focus_map="string_input focus")),
|
||||||
|
("weight", 0.5, Text(""))
|
||||||
|
], dividechars=2
|
||||||
|
)
|
||||||
|
]
|
||||||
|
return Pile(col1)
|
||||||
|
|
||||||
|
def _build_set_as_default_gw_button(self):
|
||||||
|
ifaces = self.model.get_interfaces()
|
||||||
|
if len(ifaces) > 1:
|
||||||
|
btn = confirm_btn(label="Set this as default gateway",
|
||||||
|
on_press=self.set_default_gateway)
|
||||||
|
else:
|
||||||
|
btn = Text("This will be your default gateway")
|
||||||
|
return Pile([btn])
|
||||||
|
|
||||||
|
def set_default_gateway(self):
|
||||||
|
if self.gateway_input.value:
|
||||||
|
self.model.default_gateway = self.gateway_input.value
|
||||||
|
|
||||||
|
def _build_buttons(self):
|
||||||
|
cancel = cancel_btn(on_press=self.cancel)
|
||||||
|
done = done_btn(on_press=self.done)
|
||||||
|
|
||||||
|
buttons = [
|
||||||
|
Color.button(done, focus_map='button focus'),
|
||||||
|
Color.button(cancel, focus_map='button focus')
|
||||||
|
]
|
||||||
|
return Pile(buttons)
|
||||||
|
|
||||||
|
def done(self, result):
|
||||||
|
self.signal.emit_signal('network:show')
|
||||||
|
|
||||||
|
def cancel(self, button):
|
||||||
|
self.model.default_gateway = None
|
||||||
|
self.signal.emit_signal('network:show')
|
|
@ -29,23 +29,30 @@ class NetworkSetDefaultRouteView(ViewPolicy):
|
||||||
self.signal = signal
|
self.signal = signal
|
||||||
self.default_gateway_w = None
|
self.default_gateway_w = None
|
||||||
body = [
|
body = [
|
||||||
Padding.center_50(self._build_default_routes()),
|
Padding.center_79(Text("Please set the default gateway:")),
|
||||||
|
Padding.line_break(""),
|
||||||
|
Padding.center_79(self._build_default_routes()),
|
||||||
Padding.line_break(""),
|
Padding.line_break(""),
|
||||||
Padding.center_20(self._build_buttons())
|
Padding.center_20(self._build_buttons())
|
||||||
]
|
]
|
||||||
super().__init__(ListBox(body))
|
super().__init__(ListBox(body))
|
||||||
|
|
||||||
def _build_default_routes(self):
|
def _build_default_routes(self):
|
||||||
items = [
|
ifaces = self.model.get_interfaces()
|
||||||
Text("Please set the default gateway:"),
|
items = []
|
||||||
Color.menu_button(done_btn(label="192.168.9.1 (em1, em2)",
|
for iface in ifaces:
|
||||||
|
items.append(Padding.center_50(
|
||||||
|
Color.menu_button(done_btn(
|
||||||
|
label="{ip} ({iface})".format(
|
||||||
|
ip="FIXME: needs default gateway",
|
||||||
|
iface=iface),
|
||||||
on_press=self.done),
|
on_press=self.done),
|
||||||
focus_map="menu_button focus"),
|
focus_map="menu_button focus")))
|
||||||
|
items.append(Padding.center_50(
|
||||||
Color.menu_button(
|
Color.menu_button(
|
||||||
done_btn(label="Specify the default route manually",
|
done_btn(label="Specify the default route manually",
|
||||||
on_press=self.show_edit_default_route),
|
on_press=self.show_edit_default_route),
|
||||||
focus_map="menu_button focus")
|
focus_map="menu_button focus")))
|
||||||
]
|
|
||||||
self.pile = Pile(items)
|
self.pile = Pile(items)
|
||||||
return self.pile
|
return self.pile
|
||||||
|
|
||||||
|
@ -63,14 +70,17 @@ class NetworkSetDefaultRouteView(ViewPolicy):
|
||||||
log.debug("Re-rendering specify default route")
|
log.debug("Re-rendering specify default route")
|
||||||
self.default_gateway_w = StringEditor(
|
self.default_gateway_w = StringEditor(
|
||||||
caption="Default gateway will be ")
|
caption="Default gateway will be ")
|
||||||
self.pile.contents[-1] = (Color.string_input(
|
self.pile.contents[-1] = (Padding.center_50(
|
||||||
|
Color.string_input(
|
||||||
self.default_gateway_w,
|
self.default_gateway_w,
|
||||||
focus_map="string_input focus"), self.pile.options())
|
focus_map="string_input focus")), self.pile.options())
|
||||||
# self.signal.emit_signal('refresh')
|
# self.signal.emit_signal('refresh')
|
||||||
|
|
||||||
def done(self, result):
|
def done(self, result):
|
||||||
if self.default_gateway_w.value:
|
if self.default_gateway_w and self.default_gateway_w.value:
|
||||||
self.model.default_gateway = self.default_gateway_w.value
|
self.model.default_gateway = self.default_gateway_w.value
|
||||||
|
else:
|
||||||
|
self.model.default_gateway = result.label
|
||||||
self.signal.emit_signal('network:show')
|
self.signal.emit_signal('network:show')
|
||||||
|
|
||||||
def cancel(self, button):
|
def cancel(self, button):
|
||||||
|
|
Loading…
Reference in New Issue