summaryrefslogtreecommitdiff
path: root/azurelinuxagent/common/osutil
diff options
context:
space:
mode:
Diffstat (limited to 'azurelinuxagent/common/osutil')
-rw-r--r--azurelinuxagent/common/osutil/alpine.py51
-rw-r--r--azurelinuxagent/common/osutil/bigip.py383
-rw-r--r--azurelinuxagent/common/osutil/clearlinux.py91
-rw-r--r--azurelinuxagent/common/osutil/coreos.py43
-rw-r--r--azurelinuxagent/common/osutil/default.py27
-rw-r--r--azurelinuxagent/common/osutil/factory.py15
-rw-r--r--azurelinuxagent/common/osutil/freebsd.py51
-rw-r--r--azurelinuxagent/common/osutil/redhat.py2
-rw-r--r--azurelinuxagent/common/osutil/suse.py3
-rw-r--r--azurelinuxagent/common/osutil/ubuntu.py4
10 files changed, 613 insertions, 57 deletions
diff --git a/azurelinuxagent/common/osutil/alpine.py b/azurelinuxagent/common/osutil/alpine.py
new file mode 100644
index 0000000..202d01d
--- /dev/null
+++ b/azurelinuxagent/common/osutil/alpine.py
@@ -0,0 +1,51 @@
+# 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.common.logger as logger
+import azurelinuxagent.common.utils.shellutil as shellutil
+from azurelinuxagent.common.osutil.default import DefaultOSUtil
+
+class AlpineOSUtil(DefaultOSUtil):
+ def __init__(self):
+ super(AlpineOSUtil, self).__init__()
+ self.agent_conf_file_path = '/etc/waagent.conf'
+
+ def is_dhcp_enabled(self):
+ return True
+
+ def get_dhcp_pid(self):
+ ret = shellutil.run_get_output('pidof dhcpcd', chk_err=False)
+ if ret[0] == 0:
+ logger.info('dhcpcd is pid {}'.format(ret[1]))
+ return ret[1].strip()
+ return None
+
+ def restart_if(self, ifname):
+ logger.info('restarting {} (sort of, actually SIGHUPing dhcpcd)'.format(ifname))
+ pid = self.get_dhcp_pid()
+ if pid != None:
+ ret = shellutil.run_get_output('kill -HUP {}'.format(pid))
+
+ def set_ssh_client_alive_interval(self):
+ # Alpine will handle this.
+ pass
+
+ def conf_sshd(self, disable_password):
+ # Alpine will handle this.
+ pass
diff --git a/azurelinuxagent/common/osutil/bigip.py b/azurelinuxagent/common/osutil/bigip.py
new file mode 100644
index 0000000..fea7aff
--- /dev/null
+++ b/azurelinuxagent/common/osutil/bigip.py
@@ -0,0 +1,383 @@
+# Copyright 2016 F5 Networks Inc.
+#
+# 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 array
+import fcntl
+import os
+import platform
+import re
+import socket
+import struct
+import time
+
+try:
+ # WAAgent > 2.1.3
+ import azurelinuxagent.common.logger as logger
+ import azurelinuxagent.common.utils.shellutil as shellutil
+
+ from azurelinuxagent.common.exception import OSUtilError
+ from azurelinuxagent.common.osutil.default import DefaultOSUtil
+except ImportError:
+ # WAAgent <= 2.1.3
+ import azurelinuxagent.logger as logger
+ import azurelinuxagent.utils.shellutil as shellutil
+
+ from azurelinuxagent.exception import OSUtilError
+ from azurelinuxagent.distro.default.osutil import DefaultOSUtil
+
+
+class BigIpOSUtil(DefaultOSUtil):
+ def __init__(self):
+ super(BigIpOSUtil, self).__init__()
+
+ def _wait_until_mcpd_is_initialized(self):
+ """Wait for mcpd to become available
+
+ All configuration happens in mcpd so we need to wait that this is
+ available before we go provisioning the system. I call this method
+ at the first opportunity I have (during the DVD mounting call).
+ This ensures that the rest of the provisioning does not need to wait
+ for mcpd to be available unless it absolutely wants to.
+
+ :return bool: Returns True upon success
+ :raises OSUtilError: Raises exception if mcpd does not come up within
+ roughly 50 minutes (100 * 30 seconds)
+ """
+ for retries in range(1, 100):
+ # Retry until mcpd completes startup:
+ logger.info("Checking to see if mcpd is up")
+ rc = shellutil.run("/usr/bin/tmsh -a show sys mcp-state field-fmt 2>/dev/null | grep phase | grep running", chk_err=False)
+ if rc == 0:
+ logger.info("mcpd is up!")
+ break
+ time.sleep(30)
+
+ if rc is 0:
+ return True
+
+ raise OSUtilError(
+ "mcpd hasn't completed initialization! Cannot proceed!"
+ )
+
+ def _save_sys_config(self):
+ cmd = "/usr/bin/tmsh save sys config"
+ rc = shellutil.run(cmd)
+ if rc != 0:
+ logger.error("WARNING: Cannot save sys config on 1st boot.")
+ return rc
+
+ def restart_ssh_service(self):
+ return shellutil.run("/usr/bin/bigstart restart sshd", chk_err=False)
+
+ def stop_agent_service(self):
+ return shellutil.run("/sbin/service waagent stop", chk_err=False)
+
+ def start_agent_service(self):
+ return shellutil.run("/sbin/service waagent start", chk_err=False)
+
+ def register_agent_service(self):
+ return shellutil.run("/sbin/chkconfig --add waagent", chk_err=False)
+
+ def unregister_agent_service(self):
+ return shellutil.run("/sbin/chkconfig --del waagent", chk_err=False)
+
+ def get_dhcp_pid(self):
+ ret = shellutil.run_get_output("/sbin/pidof dhclient")
+ return ret[1] if ret[0] == 0 else None
+
+ def set_hostname(self, hostname):
+ """Set the static hostname of the device
+
+ Normally, tmsh is used to set the hostname for the system. For our
+ purposes at this time though, I would hesitate to trust this function.
+
+ Azure(Stack) uses the name that you provide in the Web UI or ARM (for
+ example) as the value of the hostname argument to this method. The
+ problem is that there is nowhere in the UI that specifies the
+ restrictions and checks that tmsh has for the hostname.
+
+ For example, if you set the name "bigip1" in the Web UI, Azure(Stack)
+ considers that a perfectly valid name. When WAAgent gets around to
+ running though, tmsh will reject that value because it is not a fully
+ qualified domain name. The proper value should have been bigip.xxx.yyy
+
+ WAAgent will not fail if this command fails, but the hostname will not
+ be what the user set either. Currently we do not set the hostname when
+ WAAgent starts up, so I am passing on setting it here too.
+
+ :param hostname: The hostname to set on the device
+ """
+ return None
+
+ def set_dhcp_hostname(self, hostname):
+ """Sets the DHCP hostname
+
+ See `set_hostname` for an explanation of why I pass here
+
+ :param hostname: The hostname to set on the device
+ """
+ return None
+
+ def useradd(self, username, expiration=None):
+ """Create user account using tmsh
+
+ Our policy is to create two accounts when booting a BIG-IP instance.
+ The first account is the one that the user specified when they did
+ the instance creation. The second one is the admin account that is,
+ or should be, built in to the system.
+
+ :param username: The username that you want to add to the system
+ :param expiration: The expiration date to use. We do not use this
+ value.
+ """
+ if self.get_userentry(username):
+ logger.info("User {0} already exists, skip useradd", username)
+ return None
+
+ cmd = "/usr/bin/tmsh create auth user %s partition-access add { all-partitions { role admin } } shell bash" % (username)
+ retcode, out = shellutil.run_get_output(cmd, log_cmd=True, chk_err=True)
+ if retcode != 0:
+ raise OSUtilError(
+ "Failed to create user account:{0}, retcode:{1}, output:{2}".format(username, retcode, out)
+ )
+ self._save_sys_config()
+ return retcode
+
+ def chpasswd(self, username, password, crypt_id=6, salt_len=10):
+ """Change a user's password with tmsh
+
+ Since we are creating the user specified account and additionally
+ changing the password of the built-in 'admin' account, both must
+ be modified in this method.
+
+ Note that the default method also checks for a "system level" of the
+ user; based on the value of UID_MIN in /etc/login.defs. In our env,
+ all user accounts have the UID 0. So we can't rely on this value.
+
+ :param username: The username whose password to change
+ :param password: The unencrypted password to set for the user
+ :param crypt_id: If encrypting the password, the crypt_id that was used
+ :param salt_len: If encrypting the password, the length of the salt
+ value used to do it.
+ """
+
+ # Start by setting the password of the user provided account
+ cmd = "/usr/bin/tmsh modify auth user {0} password '{1}'".format(username, password)
+ ret, output = shellutil.run_get_output(cmd, log_cmd=False, chk_err=True)
+ if ret != 0:
+ raise OSUtilError(
+ "Failed to set password for {0}: {1}".format(username, output)
+ )
+
+ # Next, set the password of the built-in 'admin' account to be have
+ # the same password as the user provided account
+ userentry = self.get_userentry('admin')
+ if userentry is None:
+ raise OSUtilError("The 'admin' user account was not found!")
+
+ cmd = "/usr/bin/tmsh modify auth user 'admin' password '{0}'".format(password)
+ ret, output = shellutil.run_get_output(cmd, log_cmd=False, chk_err=True)
+ if ret != 0:
+ raise OSUtilError(
+ "Failed to set password for 'admin': {0}".format(output)
+ )
+ self._save_sys_config()
+ return ret
+
+ def del_account(self, username):
+ """Deletes a user account.
+
+ Note that the default method also checks for a "system level" of the
+ user; based on the value of UID_MIN in /etc/login.defs. In our env,
+ all user accounts have the UID 0. So we can't rely on this value.
+
+ We also don't use sudo, so we remove that method call as well.
+
+ :param username:
+ :return:
+ """
+ shellutil.run("> /var/run/utmp")
+ shellutil.run("/usr/bin/tmsh delete auth user " + username)
+
+ def get_dvd_device(self, dev_dir='/dev'):
+ """Find BIG-IP's CD/DVD device
+
+ This device is almost certainly /dev/cdrom so I added the ? to this pattern.
+ Note that this method will return upon the first device found, but in my
+ tests with 12.1.1 it will also find /dev/sr0 on occasion. This is NOT the
+ correct CD/DVD device though.
+
+ :todo: Consider just always returning "/dev/cdrom" here if that device device
+ exists on all platforms that are supported on Azure(Stack)
+ :param dev_dir: The root directory from which to look for devices
+ """
+ patten = r'(sr[0-9]|hd[c-z]|cdrom[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))
+ raise OSUtilError("Failed to get dvd device")
+
+ def mount_dvd(self, **kwargs):
+ """Mount the DVD containing the provisioningiso.iso file
+
+ This is the _first_ hook that WAAgent provides for us, so this is the
+ point where we should wait for mcpd to load. I am just overloading
+ this method to add the mcpd wait. Then I proceed with the stock code.
+
+ :param max_retry: Maximum number of retries waagent will make when
+ mounting the provisioningiso.iso DVD
+ :param chk_err: Whether to check for errors or not in the mounting
+ commands
+ """
+ self._wait_until_mcpd_is_initialized()
+ return super(BigIpOSUtil, self).mount_dvd(**kwargs)
+
+ def eject_dvd(self, chk_err=True):
+ """Runs the eject command to eject the provisioning DVD
+
+ BIG-IP does not include an eject command. It is sufficient to just
+ umount the DVD disk. But I will log that we do not support this for
+ future reference.
+
+ :param chk_err: Whether or not to check for errors raised by the eject
+ command
+ """
+ logger.warn("Eject is not supported on this platform")
+
+ def set_admin_access_to_ip(self, dest_ip):
+ """Sets admin access to an IP address
+
+ This method is primarily used to limit which user account is allowed to
+ communicate with the Azure(Stack) metadata service. This service is at
+ the address 169.254.169.254 and includes information about the device
+ that "normal" users should not be allowed to see.
+
+ We cannot use this iptables command that comes with the default class
+ because we do not ship the 'ipt_owner' iptables extension with BIG-IP.
+
+ This should not be a problem though as the only people who should have
+ access to BIG-IP are people who are root anyways. Our system is not
+ a "general purpose" user system. So for those reasons I am dropping
+ that requirement from our implementation.
+
+ :param dest_ip: The IP address that you want to allow admin access for
+ """
+ self._set_accept_admin_access_to_ip(dest_ip)
+ self._set_drop_admin_access_to_ip(dest_ip)
+
+ def _set_accept_admin_access_to_ip(self, dest_ip):
+ """Sets the "accept" IP Tables rules
+
+ I broke this out to a separate function so that I could more easily
+ test it in the tests/common/osutil/test_default.py code
+
+ :param dest_ip:
+ :return:
+ """
+ # This allows root to access dest_ip
+ rm_old = "iptables -D OUTPUT -d {0} -j ACCEPT"
+ rule = "iptables -A OUTPUT -d {0} -j ACCEPT"
+ shellutil.run(rm_old.format(dest_ip), chk_err=False)
+ shellutil.run(rule.format(dest_ip))
+
+ def _set_drop_admin_access_to_ip(self, dest_ip):
+ """Sets the "drop" IP Tables rules
+
+ I broke this out to a separate function so that I could more easily
+ test it in the tests/common/osutil/test_default.py code
+
+ :param dest_ip:
+ :return:
+ """
+ # This blocks all other users to access dest_ip
+ rm_old = "iptables -D OUTPUT -d {0} -j DROP"
+ rule = "iptables -A OUTPUT -d {0} -j DROP"
+ shellutil.run(rm_old.format(dest_ip), chk_err=False)
+ shellutil.run(rule.format(dest_ip))
+
+ def get_first_if(self):
+ """Return the interface name, and ip addr of the management interface.
+
+ We need to add a struct_size check here because, curiously, our 64bit
+ platform is identified by python in Azure(Stack) as 32 bit and without
+ adjusting the struct_size, we can't get the information we need.
+
+ I believe this may be caused by only python i686 being shipped with
+ BIG-IP instead of python x86_64??
+ """
+ iface = ''
+ expected = 16 # how many devices should I expect...
+
+ python_arc = platform.architecture()[0]
+ if python_arc == '64bit':
+ struct_size = 40 # for 64bit the size is 40 bytes
+ else:
+ struct_size = 32 # for 32bit the size is 32 bytes
+ sock = socket.socket(socket.AF_INET,
+ socket.SOCK_DGRAM,
+ socket.IPPROTO_UDP)
+ buff = array.array('B', b'\0' * (expected * struct_size))
+ param = struct.pack('iL',
+ expected*struct_size,
+ buff.buffer_info()[0])
+ ret = fcntl.ioctl(sock.fileno(), 0x8912, param)
+ retsize = (struct.unpack('iL', ret)[0])
+ if retsize == (expected * struct_size):
+ logger.warn(('SIOCGIFCONF returned more than {0} up '
+ 'network interfaces.'), expected)
+ sock = buff.tostring()
+ for i in range(0, struct_size * expected, struct_size):
+ iface = self._format_single_interface_name(sock, i)
+
+ # Azure public was returning "lo:1" when deploying WAF
+ if b'lo' in iface:
+ continue
+ else:
+ break
+ return iface.decode('latin-1'), socket.inet_ntoa(sock[i+20:i+24])
+
+ def _format_single_interface_name(self, sock, offset):
+ return sock[offset:offset+16].split(b'\0', 1)[0]
+
+ def route_add(self, net, mask, gateway):
+ """Add specified route using tmsh.
+
+ :param net:
+ :param mask:
+ :param gateway:
+ :return:
+ """
+ cmd = ("/usr/bin/tmsh create net route "
+ "{0}/{1} gw {2}").format(net, mask, gateway)
+ return shellutil.run(cmd, chk_err=False)
+
+ def device_for_ide_port(self, port_id):
+ """Return device name attached to ide port 'n'.
+
+ Include a wait in here because BIG-IP may not have yet initialized
+ this list of devices.
+
+ :param port_id:
+ :return:
+ """
+ for retries in range(1, 100):
+ # Retry until devices are ready
+ if os.path.exists("/sys/bus/vmbus/devices/"):
+ break
+ else:
+ time.sleep(10)
+ return super(BigIpOSUtil, self).device_for_ide_port(port_id)
diff --git a/azurelinuxagent/common/osutil/clearlinux.py b/azurelinuxagent/common/osutil/clearlinux.py
new file mode 100644
index 0000000..5116ff4
--- /dev/null
+++ b/azurelinuxagent/common/osutil/clearlinux.py
@@ -0,0 +1,91 @@
+#
+# 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 os
+import re
+import pwd
+import shutil
+import socket
+import array
+import struct
+import fcntl
+import time
+import base64
+import azurelinuxagent.common.conf as conf
+import azurelinuxagent.common.logger as logger
+import azurelinuxagent.common.utils.fileutil as fileutil
+import azurelinuxagent.common.utils.shellutil as shellutil
+import azurelinuxagent.common.utils.textutil as textutil
+from azurelinuxagent.common.osutil.default import DefaultOSUtil
+
+class ClearLinuxUtil(DefaultOSUtil):
+ def __init__(self):
+ super(ClearLinuxUtil, self).__init__()
+ self.agent_conf_file_path = '/usr/share/defaults/waagent/waagent.conf'
+
+ def is_dhcp_enabled(self):
+ return True
+
+ def start_network(self) :
+ return shellutil.run("systemctl start systemd-networkd", chk_err=False)
+
+ def restart_if(self, iface):
+ shellutil.run("systemctl restart systemd-networkd")
+
+ def restart_ssh_service(self):
+ # SSH is socket activated. No need to restart it.
+ pass
+
+ def stop_dhcp_service(self):
+ return shellutil.run("systemctl stop systemd-networkd", chk_err=False)
+
+ def start_dhcp_service(self):
+ return shellutil.run("systemctl start systemd-networkd", chk_err=False)
+
+ def start_agent_service(self):
+ return shellutil.run("systemctl start waagent", chk_err=False)
+
+ def stop_agent_service(self):
+ return shellutil.run("systemctl stop waagent", chk_err=False)
+
+ def get_dhcp_pid(self):
+ ret= shellutil.run_get_output("pidof systemd-networkd")
+ return ret[1] if ret[0] == 0 else None
+
+ def conf_sshd(self, disable_password):
+ # Don't whack the system default sshd conf
+ pass
+
+ def del_root_password(self):
+ try:
+ passwd_file_path = conf.get_passwd_file_path()
+ try:
+ passwd_content = fileutil.read_file(passwd_file_path)
+ if not passwd_content:
+ # Empty file is no better than no file
+ raise FileNotFoundError
+ except FileNotFoundError:
+ new_passwd = ["root:*LOCK*:14600::::::"]
+ else:
+ passwd = passwd_content.split('\n')
+ new_passwd = [x for x in passwd if not x.startswith("root:")]
+ new_passwd.insert(0, "root:*LOCK*:14600::::::")
+ fileutil.write_file(passwd_file_path, "\n".join(new_passwd))
+ except IOError as e:
+ raise OSUtilError("Failed to delete root password:{0}".format(e))
+ pass
diff --git a/azurelinuxagent/common/osutil/coreos.py b/azurelinuxagent/common/osutil/coreos.py
index e26fd97..9d4f9b8 100644
--- a/azurelinuxagent/common/osutil/coreos.py
+++ b/azurelinuxagent/common/osutil/coreos.py
@@ -17,27 +17,15 @@
#
import os
-import re
-import pwd
-import shutil
-import socket
-import array
-import struct
-import fcntl
-import time
-import base64
-import azurelinuxagent.common.logger as logger
-import azurelinuxagent.common.utils.fileutil as fileutil
import azurelinuxagent.common.utils.shellutil as shellutil
-import azurelinuxagent.common.utils.textutil as textutil
from azurelinuxagent.common.osutil.default import DefaultOSUtil
class CoreOSUtil(DefaultOSUtil):
def __init__(self):
super(CoreOSUtil, self).__init__()
self.agent_conf_file_path = '/usr/share/oem/waagent.conf'
- self.waagent_path='/usr/share/oem/bin/waagent'
- self.python_path='/usr/share/oem/python/bin'
+ self.waagent_path = '/usr/share/oem/bin/waagent'
+ self.python_path = '/usr/share/oem/python/bin'
if 'PATH' in os.environ:
path = "{0}:{1}".format(os.environ['PATH'], self.python_path)
else:
@@ -52,22 +40,22 @@ class CoreOSUtil(DefaultOSUtil):
os.environ['PYTHONPATH'] = py_path
def is_sys_user(self, username):
- #User 'core' is not a sysuser
- if username == 'core':
- return False
- return super(CoreOSUtil, self).is_sys_user(username)
+ # User 'core' is not a sysuser.
+ if username == 'core':
+ return False
+ return super(CoreOSUtil, self).is_sys_user(username)
def is_dhcp_enabled(self):
return True
- def start_network(self) :
+ def start_network(self):
return shellutil.run("systemctl start systemd-networkd", chk_err=False)
- def restart_if(self, iface):
+ def restart_if(self, *dummy, **_):
shellutil.run("systemctl restart systemd-networkd")
def restart_ssh_service(self):
- # SSH is socket activated on CoreOS. No need to restart it.
+ # SSH is socket activated on CoreOS. No need to restart it.
pass
def stop_dhcp_service(self):
@@ -77,16 +65,17 @@ class CoreOSUtil(DefaultOSUtil):
return shellutil.run("systemctl start systemd-networkd", chk_err=False)
def start_agent_service(self):
- return shellutil.run("systemctl start wagent", chk_err=False)
+ return shellutil.run("systemctl start waagent", chk_err=False)
def stop_agent_service(self):
- return shellutil.run("systemctl stop wagent", chk_err=False)
+ return shellutil.run("systemctl stop waagent", chk_err=False)
def get_dhcp_pid(self):
- ret= shellutil.run_get_output("pidof systemd-networkd")
- return ret[1] if ret[0] == 0 else None
+ ret = shellutil.run_get_output("systemctl show -p MainPID "
+ "systemd-networkd", chk_err=False)
+ pid = ret[1].split('=', 1)[-1].strip() if ret[0] == 0 else None
+ return pid if pid != '0' else None
def conf_sshd(self, disable_password):
- #In CoreOS, /etc/sshd_config is mount readonly. Skip the setting
+ # In CoreOS, /etc/sshd_config is mount readonly. Skip the setting.
pass
-
diff --git a/azurelinuxagent/common/osutil/default.py b/azurelinuxagent/common/osutil/default.py
index c243c85..dc73379 100644
--- a/azurelinuxagent/common/osutil/default.py
+++ b/azurelinuxagent/common/osutil/default.py
@@ -16,6 +16,7 @@
# Requires Python 2.4+ and Openssl 1.0+
#
+import multiprocessing
import os
import re
import shutil
@@ -247,16 +248,6 @@ class DefaultOSUtil(object):
else:
return False
- def set_selinux_enforce(self, state):
- """
- Calls shell command 'setenforce' with 'state'
- and returns resulting exit code.
- """
- if self.is_selinux_system():
- if state: s = '1'
- else: s='0'
- return shellutil.run("setenforce "+s)
-
def set_selinux_context(self, path, con):
"""
Calls shell 'chcon' with 'path' and 'con' context.
@@ -649,7 +640,7 @@ class DefaultOSUtil(object):
return shellutil.run(cmd, chk_err=False)
def get_dhcp_pid(self):
- ret= shellutil.run_get_output("pidof dhclient")
+ ret = shellutil.run_get_output("pidof dhclient", chk_err=False)
return ret[1] if ret[0] == 0 else None
def set_hostname(self, hostname):
@@ -761,19 +752,11 @@ class DefaultOSUtil(object):
return base64.b64decode(data)
def get_total_mem(self):
- cmd = "grep MemTotal /proc/meminfo |awk '{print $2}'"
- ret = shellutil.run_get_output(cmd)
- if ret[0] == 0:
- return int(ret[1])/1024
- else:
- raise OSUtilError("Failed to get total memory: {0}".format(ret[1]))
+ # Get total memory in bytes and divide by 1024**2 to get the valu in MB.
+ return os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES') / (1024**2)
def get_processor_cores(self):
- ret = shellutil.run_get_output("grep 'processor.*:' /proc/cpuinfo |wc -l")
- if ret[0] == 0:
- return int(ret[1])
- else:
- raise OSUtilError("Failed to get processor cores")
+ return multiprocessing.cpu_count()
def set_admin_access_to_ip(self, dest_ip):
#This allows root to access dest_ip
diff --git a/azurelinuxagent/common/osutil/factory.py b/azurelinuxagent/common/osutil/factory.py
index 5e8ae6e..2718ba1 100644
--- a/azurelinuxagent/common/osutil/factory.py
+++ b/azurelinuxagent/common/osutil/factory.py
@@ -21,6 +21,7 @@ from azurelinuxagent.common.version import DISTRO_NAME, DISTRO_VERSION, \
DISTRO_FULL_NAME
from .default import DefaultOSUtil
+from .clearlinux import ClearLinuxUtil
from .coreos import CoreOSUtil
from .debian import DebianOSUtil
from .freebsd import FreeBSDOSUtil
@@ -28,9 +29,13 @@ from .redhat import RedhatOSUtil, Redhat6xOSUtil
from .suse import SUSEOSUtil, SUSE11OSUtil
from .ubuntu import UbuntuOSUtil, Ubuntu12OSUtil, Ubuntu14OSUtil, \
UbuntuSnappyOSUtil
+from .alpine import AlpineOSUtil
+from .bigip import BigIpOSUtil
def get_osutil(distro_name=DISTRO_NAME, distro_version=DISTRO_VERSION,
distro_full_name=DISTRO_FULL_NAME):
+ if distro_name == "clear linux software for intel architecture":
+ return ClearLinuxUtil()
if distro_name == "ubuntu":
if Version(distro_version) == Version("12.04") or \
Version(distro_version) == Version("12.10"):
@@ -42,6 +47,10 @@ def get_osutil(distro_name=DISTRO_NAME, distro_version=DISTRO_VERSION,
return UbuntuSnappyOSUtil()
else:
return UbuntuOSUtil()
+ if distro_name == "alpine":
+ return AlpineOSUtil()
+ if distro_name == "kali":
+ return DebianOSUtil()
if distro_name == "coreos":
return CoreOSUtil()
if distro_name == "suse":
@@ -62,8 +71,10 @@ def get_osutil(distro_name=DISTRO_NAME, distro_version=DISTRO_VERSION,
return RedhatOSUtil()
elif distro_name == "freebsd":
return FreeBSDOSUtil()
+ elif distro_name == "bigip":
+ return BigIpOSUtil()
else:
- logger.warn("Unable to load distro implemetation for {0}.", distro_name)
- logger.warn("Use default distro implemetation instead.")
+ logger.warn("Unable to load distro implementation for {0}.", distro_name)
+ logger.warn("Use default distro implementation instead.")
return DefaultOSUtil()
diff --git a/azurelinuxagent/common/osutil/freebsd.py b/azurelinuxagent/common/osutil/freebsd.py
index ddf8db6..54c7452 100644
--- a/azurelinuxagent/common/osutil/freebsd.py
+++ b/azurelinuxagent/common/osutil/freebsd.py
@@ -22,7 +22,7 @@ import azurelinuxagent.common.utils.textutil as textutil
import azurelinuxagent.common.logger as logger
from azurelinuxagent.common.exception import OSUtilError
from azurelinuxagent.common.osutil.default import DefaultOSUtil
-
+from azurelinuxagent.common.future import ustr
class FreeBSDOSUtil(DefaultOSUtil):
def __init__(self):
@@ -118,7 +118,7 @@ class FreeBSDOSUtil(DefaultOSUtil):
shellutil.run("route delete 255.255.255.255 -iface {0}".format(ifname), chk_err=False)
def get_dhcp_pid(self):
- ret = shellutil.run_get_output("pgrep -n dhclient")
+ ret = shellutil.run_get_output("pgrep -n dhclient", chk_err=False)
return ret[1] if ret[0] == 0 else None
def eject_dvd(self, chk_err=True):
@@ -196,3 +196,50 @@ class FreeBSDOSUtil(DefaultOSUtil):
logger.verbose("Interface info: ({0},{1},{2})", iface, inet, mac)
return iface, inet, mac
+
+ def device_for_ide_port(self, port_id):
+ """
+ Return device name attached to ide port 'n'.
+ """
+ if port_id > 3:
+ return None
+ g0 = "00000000"
+ if port_id > 1:
+ g0 = "00000001"
+ port_id = port_id - 2
+ err, output = shellutil.run_get_output('sysctl dev.storvsc | grep pnpinfo | grep deviceid=')
+ if err:
+ return None
+ g1 = "000" + ustr(port_id)
+ g0g1 = "{0}-{1}".format(g0, g1)
+ """
+ search 'X' from 'dev.storvsc.X.%pnpinfo: classid=32412632-86cb-44a2-9b5c-50d1417354f5 deviceid=00000000-0001-8899-0000-000000000000'
+ """
+ cmd_search_ide = "sysctl dev.storvsc | grep pnpinfo | grep deviceid={0}".format(g0g1)
+ err, output = shellutil.run_get_output(cmd_search_ide)
+ if err:
+ return None
+ cmd_extract_id = cmd_search_ide + "|awk -F . '{print $3}'"
+ err, output = shellutil.run_get_output(cmd_extract_id)
+ """
+ try to search 'blkvscX' and 'storvscX' to find device name
+ """
+ output = output.rstrip()
+ cmd_search_blkvsc = "camcontrol devlist -b | grep blkvsc{0} | awk '{{print $1}}'".format(output)
+ err, output = shellutil.run_get_output(cmd_search_blkvsc)
+ if err == 0:
+ output = output.rstrip()
+ cmd_search_dev="camcontrol devlist | grep {0} | awk -F \( '{{print $2}}'|awk -F , '{{print $1}}'".format(output)
+ err, output = shellutil.run_get_output(cmd_search_dev)
+ if err == 0:
+ return output.rstrip()
+
+ cmd_search_storvsc = "camcontrol devlist -b | grep storvsc{0} | awk '{{print $1}}'".format(output)
+ err, output = shellutil.run_get_output(cmd_search_storvsc)
+ if err == 0:
+ output = output.rstrip()
+ cmd_search_dev="camcontrol devlist | grep {0} | awk -F \( '{{print $2}}'|awk -F , '{{print $1}}'".format(output)
+ err, output = shellutil.run_get_output(cmd_search_dev)
+ if err == 0:
+ return output.rstrip()
+ return None
diff --git a/azurelinuxagent/common/osutil/redhat.py b/azurelinuxagent/common/osutil/redhat.py
index 03084b6..80370a2 100644
--- a/azurelinuxagent/common/osutil/redhat.py
+++ b/azurelinuxagent/common/osutil/redhat.py
@@ -69,7 +69,7 @@ class Redhat6xOSUtil(DefaultOSUtil):
#Override
def get_dhcp_pid(self):
- ret= shellutil.run_get_output("pidof dhclient")
+ ret = shellutil.run_get_output("pidof dhclient", chk_err=False)
return ret[1] if ret[0] == 0 else None
def set_hostname(self, hostname):
diff --git a/azurelinuxagent/common/osutil/suse.py b/azurelinuxagent/common/osutil/suse.py
index f0ed0c0..60d6f28 100644
--- a/azurelinuxagent/common/osutil/suse.py
+++ b/azurelinuxagent/common/osutil/suse.py
@@ -42,7 +42,8 @@ class SUSE11OSUtil(DefaultOSUtil):
shellutil.run("hostname {0}".format(hostname), chk_err=False)
def get_dhcp_pid(self):
- ret= shellutil.run_get_output("pidof {0}".format(self.dhclient_name))
+ ret = shellutil.run_get_output("pidof {0}".format(self.dhclient_name),
+ chk_err=False)
return ret[1] if ret[0] == 0 else None
def is_dhcp_enabled(self):
diff --git a/azurelinuxagent/common/osutil/ubuntu.py b/azurelinuxagent/common/osutil/ubuntu.py
index 4032cf4..3c353cf 100644
--- a/azurelinuxagent/common/osutil/ubuntu.py
+++ b/azurelinuxagent/common/osutil/ubuntu.py
@@ -45,9 +45,9 @@ class Ubuntu12OSUtil(Ubuntu14OSUtil):
def __init__(self):
super(Ubuntu12OSUtil, self).__init__()
- #Override
+ # Override
def get_dhcp_pid(self):
- ret= shellutil.run_get_output("pidof dhclient3")
+ ret = shellutil.run_get_output("pidof dhclient3", chk_err=False)
return ret[1] if ret[0] == 0 else None
class UbuntuOSUtil(Ubuntu14OSUtil):