Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Netops refactor #5117

Merged
merged 2 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cloudinit/distros/networking.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from cloudinit import net, subp, util
from cloudinit.distros.parsers import ifconfig
from cloudinit.net.netops.iproute2 import Iproute2

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -299,5 +300,5 @@ def try_set_link_up(self, devname: DeviceName) -> bool:
"""Try setting the link to up explicitly and return if it is up.
Not guaranteed to bring the interface up. The caller is expected to
add wait times before retrying."""
subp.subp(["ip", "link", "set", devname, "up"])
Iproute2.link_up(devname)
return self.is_up(devname)
16 changes: 6 additions & 10 deletions cloudinit/net/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from urllib.parse import urlparse

from cloudinit import subp, util
from cloudinit.net.netops.iproute2 import Iproute2
from cloudinit.url_helper import UrlError, readurl

LOG = logging.getLogger(__name__)
Expand Down Expand Up @@ -723,15 +724,6 @@ def _rename_interfaces(
def update_byname(bymac):
return dict((data["name"], data) for data in cur_info.values())

def rename(cur, new):
subp.subp(["ip", "link", "set", cur, "name", new], capture=True)

def down(name):
subp.subp(["ip", "link", "set", name, "down"], capture=True)

def up(name):
subp.subp(["ip", "link", "set", name, "up"], capture=True)

ops = []
errors = []
ups = []
Expand Down Expand Up @@ -835,7 +827,11 @@ def find_entry(mac, driver, device_id):
cur_byname = update_byname(cur_info)
ops += cur_ops

opmap = {"rename": rename, "down": down, "up": up}
opmap = {
"rename": Iproute2.link_rename,
"down": Iproute2.link_down,
"up": Iproute2.link_up,
}

if len(ops) + len(ups) == 0:
if len(errors):
Expand Down
35 changes: 24 additions & 11 deletions cloudinit/net/activators.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# This file is part of cloud-init. See LICENSE file for license information.
import logging
from abc import ABC, abstractmethod
from typing import Dict, Iterable, List, Optional, Type, Union
from functools import partial
from typing import Callable, Dict, Iterable, List, Optional, Type, Union

from cloudinit import subp, util
from cloudinit.net.eni import available as eni_available
from cloudinit.net.netops.iproute2 import Iproute2
from cloudinit.net.netplan import available as netplan_available
from cloudinit.net.network_manager import available as nm_available
from cloudinit.net.network_state import NetworkState
Expand All @@ -17,15 +19,24 @@ class NoActivatorException(Exception):
pass


def _alter_interface(cmd, device_name) -> bool:
LOG.debug("Attempting command %s for device %s", cmd, device_name)
def _alter_interface(cmd: list, device_name: str) -> bool:
"""Attempt to alter an interface using a command list"""
return _alter_interface_callable(partial(subp.subp, cmd))


def _alter_interface_callable(callable: Callable) -> bool:
"""Attempt to alter an interface using a callable

this function standardizes logging and response to failure for
various activators
"""
try:
(_out, err) = subp.subp(cmd)
_out, err = callable()
if len(err):
LOG.warning("Running %s resulted in stderr output: %s", cmd, err)
LOG.warning("Received stderr output: %s", err)
return True
except subp.ProcessExecutionError:
util.logexc(LOG, "Running interface command %s failed", cmd)
except subp.ProcessExecutionError as e:
util.logexc(LOG, "Running interface command %s failed", e.cmd)
return False


Expand Down Expand Up @@ -231,8 +242,9 @@ def available(target=None) -> bool:
@staticmethod
def bring_up_interface(device_name: str) -> bool:
"""Return True is successful, otherwise return False"""
cmd = ["ip", "link", "set", "up", device_name]
return _alter_interface(cmd, device_name)
return _alter_interface_callable(
partial(Iproute2.link_up, device_name)
)

@staticmethod
def bring_up_all_interfaces(network_state: NetworkState) -> bool:
Expand All @@ -243,8 +255,9 @@ def bring_up_all_interfaces(network_state: NetworkState) -> bool:
@staticmethod
def bring_down_interface(device_name: str) -> bool:
"""Return True is successful, otherwise return False"""
cmd = ["ip", "link", "set", "down", device_name]
return _alter_interface(cmd, device_name)
return _alter_interface_callable(
partial(Iproute2.link_down, device_name)
)


# This section is mostly copied and pasted from renderers.py. An abstract
Expand Down
18 changes: 15 additions & 3 deletions cloudinit/net/netops/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
from typing import Optional

from cloudinit.subp import SubpResult


class NetOps:
@staticmethod
def link_up(interface: str):
def link_up(interface: str) -> SubpResult:
pass

@staticmethod
def link_down(interface: str) -> SubpResult:
pass

@staticmethod
def link_down(interface: str):
def link_rename(current_name: str, new_name: str):
pass

@staticmethod
Expand Down Expand Up @@ -39,9 +45,15 @@ def get_default_route() -> str:
pass

@staticmethod
def add_addr(interface: str, address: str, broadcast: str):
def add_addr(
interface: str, address: str, broadcast: Optional[str] = None
):
pass

@staticmethod
def del_addr(interface: str, address: str):
pass

@staticmethod
def flush_addr(interface: str):
pass
18 changes: 11 additions & 7 deletions cloudinit/net/netops/bsd_netops.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@

class BsdNetOps(netops.NetOps):
@staticmethod
def link_up(interface: str):
subp.subp(["ifconfig", interface, "up"])
def link_up(interface: str) -> subp.SubpResult:
return subp.subp(["ifconfig", interface, "up"])

@staticmethod
def link_down(interface: str):
subp.subp(["ifconfig", interface, "down"])
def link_down(interface: str) -> subp.SubpResult:
return subp.subp(["ifconfig", interface, "down"])

@staticmethod
def add_route(
Expand Down Expand Up @@ -50,14 +50,18 @@ def get_default_route() -> str:
return std.splitlines()[-1].strip()

@staticmethod
def add_addr(interface: str, address: str, broadcast: str):
def add_addr(
interface: str, address: str, broadcast: Optional[str] = None
):
broadcast_args = []
if broadcast:
broadcast_args = ["broadcast", broadcast]
subp.subp(
[
"ifconfig",
interface,
address,
"broadcast",
broadcast,
*broadcast_args,
"alias",
],
)
Expand Down
103 changes: 77 additions & 26 deletions cloudinit/net/netops/iproute2.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,36 @@
from typing import Optional

import cloudinit.net.netops as netops
from cloudinit import subp
from cloudinit.net.netops import NetOps


class Iproute2(netops.NetOps):
class Iproute2(NetOps):
@staticmethod
def link_up(interface: str, family: Optional[str] = None):
subp.subp(
["ip"]
+ (["-family", family] if family else [])
+ ["link", "set", "dev", interface, "up"]
def link_up(
interface: str, family: Optional[str] = None
) -> subp.SubpResult:
family_args = []
if family:
family_args = ["-family", family]
return subp.subp(
["ip", *family_args, "link", "set", "dev", interface, "up"]
)

@staticmethod
def link_down(interface: str, family: Optional[str] = None):
subp.subp(
["ip"]
+ (["-family", family] if family else [])
+ ["link", "set", "dev", interface, "down"]
def link_down(
interface: str, family: Optional[str] = None
) -> subp.SubpResult:
family_args = []
if family:
family_args = ["-family", family]
return subp.subp(
["ip", *family_args, "link", "set", "dev", interface, "down"]
)

@staticmethod
def link_rename(current_name: str, new_name: str):
subp.subp(["ip", "link", "set", current_name, "name", new_name])

@staticmethod
def add_route(
interface: str,
Expand All @@ -29,22 +39,42 @@ def add_route(
gateway: Optional[str] = None,
source_address: Optional[str] = None,
):
gateway_args = []
source_args = []
if gateway and gateway != "0.0.0.0":
gateway_args = ["via", gateway]
if source_address:
source_args = ["src", source_address]
subp.subp(
["ip", "-4", "route", "add", route]
+ (["via", gateway] if gateway and gateway != "0.0.0.0" else [])
+ [
[
"ip",
"-4",
"route",
"add",
route,
*gateway_args,
"dev",
interface,
*source_args,
]
+ (["src", source_address] if source_address else []),
)

@staticmethod
def append_route(interface: str, address: str, gateway: str):
gateway_args = []
if gateway and gateway != "0.0.0.0":
gateway_args = ["via", gateway]
subp.subp(
["ip", "-4", "route", "append", address]
+ (["via", gateway] if gateway and gateway != "0.0.0.0" else [])
+ ["dev", interface]
[
"ip",
"-4",
"route",
"append",
address,
*gateway_args,
"dev",
interface,
]
)

@staticmethod
Expand All @@ -55,11 +85,24 @@ def del_route(
gateway: Optional[str] = None,
source_address: Optional[str] = None,
):
gateway_args = []
source_args = []
if gateway and gateway != "0.0.0.0":
gateway_args = ["via", gateway]
if source_address:
source_args = ["src", source_address]
subp.subp(
["ip", "-4", "route", "del", address]
+ (["via", gateway] if gateway and gateway != "0.0.0.0" else [])
+ ["dev", interface]
+ (["src", source_address] if source_address else [])
[
"ip",
"-4",
"route",
"del",
address,
*gateway_args,
"dev",
interface,
*source_args,
]
)

@staticmethod
Expand All @@ -69,7 +112,12 @@ def get_default_route() -> str:
).stdout

@staticmethod
def add_addr(interface: str, address: str, broadcast: str):
def add_addr(
interface: str, address: str, broadcast: Optional[str] = None
):
broadcast_args = []
if broadcast:
broadcast_args = ["broadcast", broadcast]
subp.subp(
[
"ip",
Expand All @@ -78,8 +126,7 @@ def add_addr(interface: str, address: str, broadcast: str):
"addr",
"add",
address,
"broadcast",
broadcast,
*broadcast_args,
"dev",
interface,
],
Expand All @@ -91,3 +138,7 @@ def del_addr(interface: str, address: str):
subp.subp(
["ip", "-family", "inet", "addr", "del", address, "dev", interface]
)

@staticmethod
def flush_addr(interface: str):
subp.subp(["ip", "flush", "dev", interface])
2 changes: 1 addition & 1 deletion cloudinit/sources/DataSourceDigitalOcean.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def _get_data(self):
self.userdata_raw = md.get("user_data", None)

if ipv4LL_nic:
do_helper.del_ipv4_link_local(ipv4LL_nic)
do_helper.del_ipv4_link_local(self.distro, ipv4LL_nic)

return True

Expand Down
Loading
Loading