From fbfe950b7b260b26cdb16b3f4ba9de3a33e3f3b1 Mon Sep 17 00:00:00 2001 From: Frode Nordahl Date: Sat, 6 Jun 2020 14:31:44 +0200 Subject: [PATCH] Fix formatting of addresses passed to SCP When using SCP to a machine with an IPv6 address the IPv6 address must be encapsulated in brackets ('[]'). Fixes #424 --- juju/machine.py | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/juju/machine.py b/juju/machine.py index 66348d4e8..eb5afa949 100644 --- a/juju/machine.py +++ b/juju/machine.py @@ -1,4 +1,5 @@ import asyncio +import ipaddress import logging import os @@ -139,6 +140,22 @@ async def set_annotations(self, annotations): """ return await _set_annotations(self.tag, annotations, self.connection) + def _format_addr(self, addr): + """Validate and format IP address. + + :param addr: IPv6 or IPv4 address + :type addr: str + :returns: Address string, optionally encapsulated in brackets ([]) + :rtype: str + :raises: ValueError + """ + ipaddr = ipaddress.ip_address(addr) + if isinstance(ipaddr, ipaddress.IPv6Address): + fmt = '[{}]' + else: + fmt = '{}' + return fmt.format(ipaddr) + async def scp_to(self, source, destination, user='ubuntu', proxy=False, scp_opts=''): """Transfer files to this machine. @@ -153,8 +170,13 @@ async def scp_to(self, source, destination, user='ubuntu', proxy=False, if proxy: raise NotImplementedError('proxy option is not implemented') - address = self.dns_name - destination = '%s@%s:%s' % (user, address, destination) + try: + # if dns_name is an IP address format it appropriately + address = self._format_addr(self.dns_name) + except ValueError: + # otherwise we assume it to be a DNS resolvable string + address = self.dns_name + destination = '{}@{}:{}'.format(user, address, destination) await self._scp(source, destination, scp_opts) async def scp_from(self, source, destination, user='ubuntu', proxy=False, @@ -171,8 +193,13 @@ async def scp_from(self, source, destination, user='ubuntu', proxy=False, if proxy: raise NotImplementedError('proxy option is not implemented') - address = self.dns_name - source = '%s@%s:%s' % (user, address, source) + try: + # if dns_name is an IP address format it appropriately + address = self._format_addr(self.dns_name) + except ValueError: + # otherwise we assume it to be a DNS resolvable string + address = self.dns_name + source = '{}@{}:{}'.format(user, address, source) await self._scp(source, destination, scp_opts) async def _scp(self, source, destination, scp_opts):