diff --git a/azurelinuxagent/conf.py b/azurelinuxagent/conf.py index 7921e79..1ac65cb 100644 --- a/azurelinuxagent/conf.py +++ b/azurelinuxagent/conf.py @@ -104,6 +104,9 @@ def get_home_dir(conf=__conf__): def get_passwd_file_path(conf=__conf__): return conf.get("OS.PasswordPath", "/etc/shadow") +def get_sudoers_dir(conf=__conf__): + return conf.get("OS.SudoersDir", "/etc/sudoers.d") + def get_sshd_conf_file_path(conf=__conf__): return conf.get("OS.SshdConfigPath", "/etc/ssh/sshd_config") diff --git a/azurelinuxagent/distro/default/daemon.py b/azurelinuxagent/distro/default/daemon.py index cf9eb16..aa7f4e6 100644 --- a/azurelinuxagent/distro/default/daemon.py +++ b/azurelinuxagent/distro/default/daemon.py @@ -65,7 +65,7 @@ class DaemonHandler(object): if os.path.isfile(pid_file): pid = fileutil.read_file(pid_file) - if pid is not None and os.path.isdir(os.path.join("/proc", pid)): + if self.distro.osutil.check_pid_alive(pid): logger.info("Daemon is already running: {0}", pid) sys.exit(0) diff --git a/azurelinuxagent/distro/default/env.py b/azurelinuxagent/distro/default/env.py index 7878cff..be47eaf 100644 --- a/azurelinuxagent/distro/default/env.py +++ b/azurelinuxagent/distro/default/env.py @@ -84,7 +84,7 @@ class EnvHandler(object): return #The dhcp process hasn't changed since last check - if os.path.isdir(os.path.join('/proc', self.dhcpid.strip())): + if self.distro.osutil.check_pid_alive(self.dhcpid.strip()): return newpid = self.distro.osutil.get_dhcp_pid() diff --git a/azurelinuxagent/distro/default/osutil.py b/azurelinuxagent/distro/default/osutil.py index 18ab2ba..e391e69 100644 --- a/azurelinuxagent/distro/default/osutil.py +++ b/azurelinuxagent/distro/default/osutil.py @@ -114,21 +114,36 @@ class DefaultOSUtil(object): raise OSUtilError(("Failed to set password for {0}: {1}" "").format(username, output)) - def conf_sudoer(self, username, nopasswd): - # for older distros create sudoers.d - if not os.path.isdir('/etc/sudoers.d/'): - # create the /etc/sudoers.d/ directory - os.mkdir('/etc/sudoers.d/') - # add the include of sudoers.d to the /etc/sudoers - sudoers = '\n' + '#includedir /etc/sudoers.d/\n' - fileutil.append_file('/etc/sudoers', sudoers) - sudoer = None - if nopasswd: - sudoer = "{0} ALL = (ALL) NOPASSWD\n".format(username) + def conf_sudoer(self, username, nopasswd=False, remove=False): + sudoers_dir = conf.get_sudoers_dir() + sudoers_wagent = os.path.join(sudoers_dir, 'waagent') + + if not remove: + # for older distros create sudoers.d + if not os.path.isdir(sudoers_dir): + sudoers_file = os.path.join(sudoers_dir, '../sudoers') + # create the sudoers.d directory + os.mkdir(sudoers_dir) + # add the include of sudoers.d to the /etc/sudoers + sudoers = '\n#includedir ' + sudoers_dir + '\n' + fileutil.append_file(sudoers_file, sudoers) + sudoer = None + if nopasswd: + sudoer = "{0} ALL=(ALL) NOPASSWD: ALL\n".format(username) + else: + sudoer = "{0} ALL=(ALL) ALL\n".format(username) + fileutil.append_file(sudoers_wagent, sudoer) + fileutil.chmod(sudoers_wagent, 0o440) else: - sudoer = "{0} ALL = (ALL) ALL\n".format(username) - fileutil.append_file('/etc/sudoers.d/waagent', sudoer) - fileutil.chmod('/etc/sudoers.d/waagent', 0o440) + #Remove user from sudoers + if os.path.isfile(sudoers_wagent): + try: + content = fileutil.read_file(sudoers_wagent) + sudoers = content.split("\n") + sudoers = [x for x in sudoers if username not in x] + fileutil.write_file(sudoers_wagent, "\n".join(sudoers)) + except IOError as e: + raise OSUtilError("Failed to remove sudoer: {0}".format(e)) def del_root_password(self): try: @@ -267,7 +282,7 @@ class DefaultOSUtil(object): def get_dvd_device(self, dev_dir='/dev'): - patten=r'(sr[0-9]|hd[c-z]|cdrom[0-9])' + patten=r'(sr[0-9]|hd[c-z]|cdrom[0-9]|cd[0-9])' for dvd in [re.match(patten, dev) for dev in os.listdir(dev_dir)]: if dvd is not None: return "/dev/{0}".format(dvd.group(0)) @@ -285,7 +300,7 @@ class DefaultOSUtil(object): os.makedirs(mount_point) for retry in range(0, max_retry): - retcode = self.mount(dvd, mount_point, option="-o ro -t iso9660,udf", + retcode = self.mount(dvd, mount_point, option="-o ro -t udf,iso9660", chk_err=chk_err) if retcode == 0: logger.info("Successfully mounted dvd") @@ -338,7 +353,7 @@ class DefaultOSUtil(object): return False def mount(self, dvd, mount_point, option="", chk_err=True): - cmd = "mount {0} {1} {2}".format(dvd, option, mount_point) + cmd = "mount {0} {1} {2}".format(option, dvd, mount_point) return shellutil.run_get_output(cmd, chk_err)[0] def umount(self, mount_point, chk_err=True): @@ -492,7 +507,7 @@ class DefaultOSUtil(object): def set_dhcp_hostname(self, hostname): autosend = r'^[^#]*?send\s*host-name.*?(|gethostname[(,)])' - dhclient_files = ['/etc/dhcp/dhclient.conf', '/etc/dhcp3/dhclient.conf'] + dhclient_files = ['/etc/dhcp/dhclient.conf', '/etc/dhcp3/dhclient.conf', '/etc/dhclient.conf'] for conf_file in dhclient_files: if not os.path.isfile(conf_file): continue @@ -501,7 +516,7 @@ class DefaultOSUtil(object): return fileutil.update_conf_file(conf_file, 'send host-name', - 'send host-name {0}'.format(hostname)) + 'send host-name "{0}";'.format(hostname)) def restart_if(self, ifname): shellutil.run("ifdown {0} && ifup {1}".format(ifname, ifname)) @@ -579,16 +594,7 @@ class DefaultOSUtil(object): logger.error("{0} is a system user. Will not delete it.", username) shellutil.run("> /var/run/utmp") shellutil.run("userdel -f -r " + username) - #Remove user from suders - if os.path.isfile("/etc/suders.d/waagent"): - try: - content = fileutil.read_file("/etc/sudoers.d/waagent") - sudoers = content.split("\n") - sudoers = [x for x in sudoers if username not in x] - fileutil.write_file("/etc/sudoers.d/waagent", - "\n".join(sudoers)) - except IOError as e: - raise OSUtilError("Failed to remove sudoer: {0}".format(e)) + self.conf_sudoer(username, remove=True) def decode_customdata(self, data): return base64.b64decode(data) @@ -606,7 +612,7 @@ class DefaultOSUtil(object): if ret[0] == 0: return int(ret[1]) else: - raise OSUtilError("Failed to get procerssor cores") + raise OSUtilError("Failed to get processor cores") def set_admin_access_to_ip(self, dest_ip): #This allows root to access dest_ip @@ -621,3 +627,5 @@ class DefaultOSUtil(object): shellutil.run(rm_old.format(dest_ip), chk_err=False) shellutil.run(rule.format(dest_ip)) + def check_pid_alive(self, pid): + return pid is not None and os.path.isdir(os.path.join('/proc', pid)) diff --git a/azurelinuxagent/distro/default/provision.py b/azurelinuxagent/distro/default/provision.py index 695b82a..ae2951d 100644 --- a/azurelinuxagent/distro/default/provision.py +++ b/azurelinuxagent/distro/default/provision.py @@ -122,7 +122,7 @@ class ProvisionHandler(object): crypt_id=crypt_id, salt_len=salt_len) logger.info("Configure sudoer") - self.distro.osutil.conf_sudoer(ovfenv.username, ovfenv.user_password is None) + self.distro.osutil.conf_sudoer(ovfenv.username, nopasswd=ovfenv.user_password is None) logger.info("Configure sshd") self.distro.osutil.conf_sshd(ovfenv.disable_ssh_password_auth) diff --git a/azurelinuxagent/distro/freebsd/__init__.py b/azurelinuxagent/distro/freebsd/__init__.py new file mode 100644 index 0000000..d9b82f5 --- /dev/null +++ b/azurelinuxagent/distro/freebsd/__init__.py @@ -0,0 +1,19 @@ +# Microsoft Azure Linux Agent +# +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# + diff --git a/azurelinuxagent/distro/freebsd/distro.py b/azurelinuxagent/distro/freebsd/distro.py new file mode 100644 index 0000000..a889b53 --- /dev/null +++ b/azurelinuxagent/distro/freebsd/distro.py @@ -0,0 +1,29 @@ +# Microsoft Azure Linux Agent +# +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# + +from azurelinuxagent.distro.default.distro import DefaultDistro +from azurelinuxagent.distro.freebsd.resourceDisk import FreeBSDResourceDiskHandler +from azurelinuxagent.distro.freebsd.osutil import FreeBSDOSUtil + + +class FreeBSDDistro(DefaultDistro): + def __init__(self): + super(FreeBSDDistro, self).__init__() + self.osutil = FreeBSDOSUtil() + self.resource_disk_handler = FreeBSDResourceDiskHandler(self) diff --git a/azurelinuxagent/distro/freebsd/osutil.py b/azurelinuxagent/distro/freebsd/osutil.py new file mode 100644 index 0000000..fa19a64 --- /dev/null +++ b/azurelinuxagent/distro/freebsd/osutil.py @@ -0,0 +1,181 @@ +# Microsoft Azure Linux Agent +# +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ + +import azurelinuxagent.utils.shellutil as shellutil +import azurelinuxagent.utils.textutil as textutil +import azurelinuxagent.logger as logger +from azurelinuxagent.distro.default.osutil import DefaultOSUtil +from azurelinuxagent.exception import OSUtilError + + +class FreeBSDOSUtil(DefaultOSUtil): + def __init__(self): + super(FreeBSDOSUtil, self).__init__() + self._scsi_disks_timeout_set = False + + def restart_ssh_service(self): + return shellutil.run('service sshd restart', chk_err=False) + + def useradd(self, username, expiration=None): + """ + Create user account with 'username' + """ + userentry = self.get_userentry(username) + if userentry is not None: + logger.warn("User {0} already exists, skip useradd", username) + return + + if expiration is not None: + cmd = "pw useradd {0} -e {1} -m".format(username, expiration) + else: + cmd = "pw useradd {0} -m".format(username) + retcode, out = shellutil.run_get_output(cmd) + if retcode != 0: + raise OSUtilError(("Failed to create user account:{0}, " + "retcode:{1}, " + "output:{2}").format(username, retcode, out)) + + def del_account(self, username): + if self.is_sys_user(username): + logger.error("{0} is a system user. Will not delete it.", username) + shellutil.run('> /var/run/utx.active') + shellutil.run('rmuser -y ' + username) + self.conf_sudoer(username, remove=True) + + def chpasswd(self, username, password, crypt_id=6, salt_len=10): + if self.is_sys_user(username): + raise OSUtilError(("User {0} is a system user. " + "Will not set passwd.").format(username)) + passwd_hash = textutil.gen_password_hash(password, crypt_id, salt_len) + cmd = "echo '{0}'|pw usermod {1} -H 0 ".format(passwd_hash, username) + ret, output = shellutil.run_get_output(cmd, log_cmd=False) + if ret != 0: + raise OSUtilError(("Failed to set password for {0}: {1}" + "").format(username, output)) + + def del_root_password(self): + err = shellutil.run('pw mod user root -w no') + if err: + raise OSUtilError("Failed to delete root password: Failed to update password database.") + + def get_if_mac(self, ifname): + data = self._get_net_info() + if data[0] == ifname: + return data[2].replace(':', '').upper() + return None + + def get_first_if(self): + return self._get_net_info()[:2] + + def route_add(self, net, mask, gateway): + cmd = 'route add {0} {1} {2}'.format(net, gateway, mask) + return shellutil.run(cmd, chk_err=False) + + def is_missing_default_route(self): + """ + For FreeBSD, the default broadcast goes to current default gw, not a all-ones broadcast address, need to + specify the route manually to get it work in a VNET environment. + SEE ALSO: man ip(4) IP_ONESBCAST, + """ + return True + + def set_route_for_dhcp_broadcast(self, ifname): + return shellutil.run("route add 255.255.255.255 0.0.0.0 -ifp {0}".format(ifname), chk_err=False) + + def remove_route_for_dhcp_broadcast(self, ifname): + shellutil.run("route delete 255.255.255.255", chk_err=False) + + def get_dhcp_pid(self): + ret = shellutil.run_get_output("pgrep -n dhclient") + return ret[1] if ret[0] == 0 else None + + def eject_dvd(self, chk_err=True): + dvd = self.get_dvd_device() + retcode = shellutil.run("cdcontrol -f {0} eject".format(dvd)) + if chk_err and retcode != 0: + raise OSUtilError("Failed to eject dvd: ret={0}".format(retcode)) + + def restart_if(self, ifname): + # Restart dhclient only to publish hostname + shellutil.run("/etc/rc.d/dhclient restart {0}".format(ifname), chk_err=False) + + def get_total_mem(self): + cmd = "sysctl hw.physmem |awk '{print $2}'" + ret, output = shellutil.run_get_output(cmd) + if ret: + raise OSUtilError("Failed to get total memory: {0}".format(output)) + try: + return int(output)/1024/1024 + except ValueError: + raise OSUtilError("Failed to get total memory: {0}".format(output)) + + def get_processor_cores(self): + ret, output = shellutil.run_get_output("sysctl hw.ncpu |awk '{print $2}'") + if ret: + raise OSUtilError("Failed to get processor cores.") + + try: + return int(output) + except ValueError: + raise OSUtilError("Failed to get total memory: {0}".format(output)) + + def set_scsi_disks_timeout(self, timeout): + if self._scsi_disks_timeout_set: + return + + ret, output = shellutil.run_get_output('sysctl kern.cam.da.default_timeout={0}'.format(timeout)) + if ret: + raise OSUtilError("Failed set SCSI disks timeout: {0}".format(output)) + self._scsi_disks_timeout_set = True + + def check_pid_alive(self, pid): + return shellutil.run('ps -p {0}'.format(pid), chk_err=False) == 0 + + @staticmethod + def _get_net_info(): + """ + There is no SIOCGIFCONF + on freeBSD - just parse ifconfig. + Returns strings: iface, inet4_addr, and mac + or 'None,None,None' if unable to parse. + We will sleep and retry as the network must be up. + """ + iface = '' + inet = '' + mac = '' + + err, output = shellutil.run_get_output('ifconfig -l ether', chk_err=False) + if err: + raise OSUtilError("Can't find ether interface:{0}".format(output)) + ifaces = output.split() + if not ifaces: + raise OSUtilError("Can't find ether interface.") + iface = ifaces[0] + + err, output = shellutil.run_get_output('ifconfig ' + iface, chk_err=False) + if err: + raise OSUtilError("Can't get info for interface:{0}".format(iface)) + + for line in output.split('\n'): + if line.find('inet ') != -1: + inet = line.split()[1] + elif line.find('ether ') != -1: + mac = line.split()[1] + logger.verb("Interface info: ({0},{1},{2})", iface, inet, mac) + + return iface, inet, mac diff --git a/azurelinuxagent/distro/freebsd/resourceDisk.py b/azurelinuxagent/distro/freebsd/resourceDisk.py new file mode 100644 index 0000000..455eb39 --- /dev/null +++ b/azurelinuxagent/distro/freebsd/resourceDisk.py @@ -0,0 +1,118 @@ +# Microsoft Azure Linux Agent +# +# Copyright 2014 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Requires Python 2.4+ and Openssl 1.0+ +# +import azurelinuxagent.logger as logger +import azurelinuxagent.utils.fileutil as fileutil +import azurelinuxagent.utils.shellutil as shellutil +from azurelinuxagent.distro.default.resourceDisk import ResourceDiskHandler +from azurelinuxagent.exception import ResourceDiskError + + +class FreeBSDResourceDiskHandler(ResourceDiskHandler): + """ + This class handles resource disk mounting for FreeBSD. + + The resource disk locates at following slot: + scbus2 on blkvsc1 bus 0: + at scbus2 target 1 lun 0 (da1,pass2) + + There are 2 variations based on partition table type: + 1. MBR: The resource disk partition is /dev/da1s1 + 2. GPT: The resource disk partition is /dev/da1p2, /dev/da1p1 is for reserved usage. + """ + def __init__(self, distro): + super(FreeBSDResourceDiskHandler, self).__init__(distro) + + @staticmethod + def parse_gpart_list(data): + dic = {} + for line in data.split('\n'): + if line.find("Geom name: ") != -1: + geom_name = line[11:] + elif line.find("scheme: ") != -1: + dic[geom_name] = line[8:] + return dic + + def mount_resource_disk(self, mount_point, fs): + if fs != 'ufs': + raise ResourceDiskError("Unsupported filesystem type:{0}, only ufs is supported.".format(fs)) + + # 1. Detect device + err, output = shellutil.run_get_output('gpart list') + if err: + raise ResourceDiskError("Unable to detect resource disk device:{0}".format(output)) + disks = self.parse_gpart_list(output) + + err, output = shellutil.run_get_output('camcontrol periphlist 2:1:0') + if err: + raise ResourceDiskError("Unable to detect resource disk device:{0}".format(output)) + + # 'da1: generation: 4 index: 1 status: MORE\npass2: generation: 4 index: 2 status: LAST\n' + device = None + for line in output.split('\n'): + index = line.find(':') + if index > 0: + geom_name = line[:index] + if geom_name in disks: + device = geom_name + break + + if not device: + raise ResourceDiskError("Unable to detect resource disk device.") + logger.info('Resource disk device {0} found.', device) + + # 2. Detect partition + partition_table_type = disks[device] + + if partition_table_type == 'MBR': + provider_name = device + 's1' + elif partition_table_type == 'GPT': + provider_name = device + 'p2' + else: + raise ResourceDiskError("Unsupported partition table type:{0}".format(output)) + + err, output = shellutil.run_get_output('gpart show -p {0}'.format(device)) + if err or output.find(provider_name) == -1: + raise ResourceDiskError("Resource disk partition not found.") + + partition = '/dev/' + provider_name + logger.info('Resource disk partition {0} found.', partition) + + # 3. Mount partition + mount_list = shellutil.run_get_output("mount")[1] + existing = self.distro.osutil.get_mount_point(mount_list, partition) + + if existing: + logger.info("Resource disk {0} is already mounted", partition) + return existing + + fileutil.mkdir(mount_point, mode=0o755) + mount_cmd = 'mount -t {0} {1} {2}'.format(fs, partition, mount_point) + err = shellutil.run(mount_cmd, chk_err=False) + if err: + logger.info('Creating {0} filesystem on partition {1}'.format(fs, partition)) + err, output = shellutil.run_get_output('newfs -U {0}'.format(partition)) + if err: + raise ResourceDiskError("Failed to create new filesystem on partition {0}, error:{1}" + .format(partition, output)) + err, output = shellutil.run_get_output(mount_cmd, chk_err=False) + if err: + raise ResourceDiskError("Failed to mount partition {0}, error".format(partition, output)) + + logger.info("Resource disk partition {0} is mounted at {1} with fstype {2}", partition, mount_point, fs) + return mount_point diff --git a/azurelinuxagent/distro/loader.py b/azurelinuxagent/distro/loader.py index 74ea9e7..f6800b3 100644 --- a/azurelinuxagent/distro/loader.py +++ b/azurelinuxagent/distro/loader.py @@ -28,6 +28,7 @@ from azurelinuxagent.distro.redhat.distro import RedhatDistro, Redhat6xDistro from azurelinuxagent.distro.coreos.distro import CoreOSDistro from azurelinuxagent.distro.suse.distro import SUSE11Distro, SUSEDistro from azurelinuxagent.distro.debian.distro import DebianDistro +from azurelinuxagent.distro.freebsd.distro import FreeBSDDistro def get_distro(distro_name=DISTRO_NAME, distro_version=DISTRO_VERSION, distro_full_name=DISTRO_FULL_NAME): @@ -60,6 +61,8 @@ def get_distro(distro_name=DISTRO_NAME, distro_version=DISTRO_VERSION, return Redhat6xDistro() else: return RedhatDistro() + elif distro_name == "freebsd": + return FreeBSDDistro() else: logger.warn("Unable to load distro implemetation for {0}.", distro_name) logger.warn("Use default distro implemetation instead.") diff --git a/azurelinuxagent/metadata.py b/azurelinuxagent/metadata.py index 34fdcf9..80a4453 100644 --- a/azurelinuxagent/metadata.py +++ b/azurelinuxagent/metadata.py @@ -28,7 +28,7 @@ def get_distro(): if 'FreeBSD' in platform.system(): release = re.sub('\-.*\Z', '', ustr(platform.release())) osinfo = ['freebsd', release, '', 'freebsd'] - if 'linux_distribution' in dir(platform): + elif 'linux_distribution' in dir(platform): osinfo = list(platform.linux_distribution(full_distribution_name=0)) full_name = platform.linux_distribution()[0].strip() osinfo.append(full_name) diff --git a/azurelinuxagent/utils/fileutil.py b/azurelinuxagent/utils/fileutil.py index 5369a7c..82fd973 100644 --- a/azurelinuxagent/utils/fileutil.py +++ b/azurelinuxagent/utils/fileutil.py @@ -66,40 +66,6 @@ def append_file(filepath, contents, asbin=False, encoding='utf-8'): """ write_file(filepath, contents, asbin=asbin, encoding=encoding, append=True) -def replace_file(filepath, contents): - """ - Write 'contents' to 'filepath' by creating a temp file, - and replacing original. - """ - handle, temp = tempfile.mkstemp(dir=os.path.dirname(filepath)) - #if type(contents) == str: - #contents=contents.encode('latin-1') - try: - os.write(handle, contents) - except IOError as err: - logger.error('Write to file {0}, Exception is {1}', filepath, err) - return 1 - finally: - os.close(handle) - - try: - os.rename(temp, filepath) - except IOError as err: - logger.info('Rename {0} to {1}, Exception is {2}', temp, filepath, err) - logger.info('Remove original file and retry') - try: - os.remove(filepath) - except IOError as err: - logger.error('Remove {0}, Exception is {1}', temp, filepath, err) - - try: - os.rename(temp, filepath) - except IOError as err: - logger.error('Rename {0} to {1}, Exception is {2}', temp, filepath, - err) - return 1 - return 0 - def base_name(path): head, tail = os.path.split(path) @@ -156,7 +122,7 @@ def update_conf_file(path, line_start, val, chk_err=False): conf = read_file(path).split('\n') conf = [x for x in conf if not x.startswith(line_start)] conf.append(val) - replace_file(path, '\n'.join(conf)) + write_file(path, '\n'.join(conf)) def search_file(target_dir_name, target_file_name): for root, dirs, files in os.walk(target_dir_name): diff --git a/config/freebsd/waagent.conf b/config/freebsd/waagent.conf new file mode 100644 index 0000000..441bcc7 --- /dev/null +++ b/config/freebsd/waagent.conf @@ -0,0 +1,92 @@ +# +# Microsoft Azure Linux Agent Configuration +# + +# Specified program is invoked with the argument "Ready" when we report ready status +# to the endpoint server. +Role.StateConsumer=None + +# Specified program is invoked with XML file argument specifying role +# configuration. +Role.ConfigurationConsumer=None + +# Specified program is invoked with XML file argument specifying role topology. +Role.TopologyConsumer=None + +# Enable instance creation +Provisioning.Enabled=y + +# Password authentication for root account will be unavailable. +Provisioning.DeleteRootPassword=y + +# Generate fresh host key pair. +Provisioning.RegenerateSshHostKeyPair=y + +# Supported values are "rsa", "dsa" and "ecdsa". +Provisioning.SshHostKeyPairType=rsa + +# Monitor host name changes and publish changes via DHCP requests. +Provisioning.MonitorHostName=y + +# Decode CustomData from Base64. +Provisioning.DecodeCustomData=n + +# Execute CustomData after provisioning. +Provisioning.ExecuteCustomData=n + +# Algorithm used by crypt when generating password hash. +#Provisioning.PasswordCryptId=6 + +# Length of random salt used when generating password hash. +#Provisioning.PasswordCryptSaltLength=10 + +# Format if unformatted. If 'n', resource disk will not be mounted. +ResourceDisk.Format=y + +# File system on the resource disk +# Typically ext3 or ext4. FreeBSD images should use 'ufs' here. +ResourceDisk.Filesystem=ufs + +# Mount point for the resource disk +ResourceDisk.MountPoint=/mnt/resource + +# Create and use swapfile on resource disk. +ResourceDisk.EnableSwap=n + +# Size of the swapfile. +ResourceDisk.SwapSizeMB=0 + +# Enable verbose logging (y|n) +Logs.Verbose=n + +# Root device timeout in seconds. +OS.RootDeviceScsiTimeout=300 + +# If "None", the system default version is used. +OS.OpensslPath=None + +OS.PasswordPath=/etc/master.passwd + +OS.SudoersDir=/usr/local/etc/sudoers.d + +# If set, agent will use proxy server to access internet +#HttpProxy.Host=None +#HttpProxy.Port=None + +# Detect Scvmm environment, default is n +# DetectScvmmEnv=n + +# +# Lib.Dir=/var/lib/waagent + +# +# DVD.MountPoint=/mnt/cdrom/secure + +# +# Pid.File=/var/run/waagent.pid + +# +# Extension.LogDir=/var/log/azure + +# +# Home.Dir=/home diff --git a/init/freebsd/waagent b/init/freebsd/waagent new file mode 100755 index 0000000..99ddef7 --- /dev/null +++ b/init/freebsd/waagent @@ -0,0 +1,18 @@ +#!/bin/sh + +# PROVIDE: waagent +# REQUIRE: sshd netif dhclient +# KEYWORD: nojail + +. /etc/rc.subr + +PATH=$PATH:/usr/local/bin +name="waagent" +rcvar="waagent_enable" +pidfile="/var/run/waagent.pid" +command="/usr/local/sbin/${name}" +command_interpreter="python" +command_args="start" + +load_rc_config $name +run_rc_command "$1" diff --git a/setup.py b/setup.py index c799787..1291b66 100755 --- a/setup.py +++ b/setup.py @@ -51,6 +51,10 @@ def set_systemd_files(data_files, dest="/lib/systemd/system", src=["init/waagent.service"]): data_files.append((dest, src)) +def set_rc_files(data_files, dest="/etc/rc.d/", src=["init/freebsd/waagent"]): + data_files.append((dest, src)) + + def get_data_files(name, version, fullname): """ Determine data_files according to distro name, version and init system type @@ -106,6 +110,10 @@ def get_data_files(name, version, fullname): else: #sles 12+ and openSUSE 13.2+ use systemd set_systemd_files(data_files, dest='/usr/lib/systemd/system') + elif name == 'freebsd': + set_bin_files(data_files, dest="/usr/local/sbin") + set_conf_files(data_files, src=["config/freebsd/waagent.conf"]) + set_rc_files(data_files) else: #Use default setting set_bin_files(data_files)