Fix unittest for osinfo and osutil

This commit is contained in:
Yue Zhang
2015-05-07 14:50:51 +08:00
parent 8dc3d78989
commit 746bbcd76f
19 changed files with 330 additions and 1095 deletions
+27 -91
View File
@@ -26,7 +26,9 @@ import traceback
import threading
import azureguestagent.logger as logger
import azureguestagent.conf as conf
from azureguestagent.os import CurrOS, CurrOSInfo
from azureguestagent.osinfo import CurrOSInfo
from azureguestagent.handle import CurrOSHandlerFactory
from azureguestagent.utils.osutil import CurrOSUtil
import azureguestagent.utils.shellutil as shellutil
import azureguestagent.utils.fileutil as fileutil
@@ -37,39 +39,28 @@ GuestAgentLongVersion = "{0}-{1}".format(GuestAgentName, GuestAgentVersion)
GuestAgentAuthor='MS OSTC'
GuestAgentUri='https://github.com/Azure/WALinuxAgent'
VmmConfigFileName = "linuxosconfiguration.xml"
VmmStartupScriptName= "install"
DataLossWarningFile="DATALOSS_WARNING_README.txt"
DataLossWarning="""\
WARNING: THIS IS A TEMPORARY DISK.
Any data stored on this drive is SUBJECT TO LOSS and THERE IS NO WAY TO RECOVER IT.
Please do not use this disk for storing any personal or application data.
For additional details to please refer to the MSDN documentation at : http://msdn.microsoft.com/en-us/library/windowsazure/jj672979.aspx
"""
class Agent():
class Agent(object):
def __init__(self, config):
self.config = config
def run(self):
os.chdir(CurrOS.GetLibDir())
os.chdir(CurrOSUtil.GetLibDir())
self.savePid()
if CurrOS.scvmmHandler.detectScvmmEnv():
CurrOS.scvmmHandler.startScvmmAgent()
scvmmHandler = CurrOSHandlerFactory.GetScvmmHandler()
if scvmmHandler.detectScvmmEnv():
scvmmHandler.startScvmmAgent()
return
CurrOS.dhcpHandler.waitForNetwork()
CurrOS.dhcpHandler.probe()
dhcpHandler = CurrOSHandlerFactory.GetDhcpHandler()
dhcpHandler.waitForNetwork()
dhcpHandler.probe()
CurrOSUtil.SetWireServerEndpoint(dhcpHandler.getEndpoint())
CurrOS.SetWireServerEndpoint(self.dhcpHandler.getEndpoint())
self.protocol = proto.DetectDefaultProtocol()
provisoned = os.path.join(CurrOS.GetLibDir(), "provisioned")
provisoned = os.path.join(CurrOSUtil.GetLibDir(), "provisioned")
if(not os.path.isfile(provisoned)):
provisionHandler = provision.ProvisionHandler(self.config,
self.protocol)
@@ -83,11 +74,10 @@ class Agent():
raise e
if self.config.getSwitch("ResourceDisk.Format", False):
#TODO FreeBSD use Popen to open another process to do this
#Need to investigate why?
diskThread = threading.Thread(target = self.activateResourceDisk)
diskThread.start()
rdHandler = CurrOSHandlerFactory.GetResourceDiskHandler()
rdHandler.startActivateResourceDisk(self.config)
self.envmonitor = envmon.EnvMonitor(self.config, self.dhcpHandler)
#TODO Start load balancer
#Need to check whether this should be kept
@@ -109,30 +99,10 @@ class Agent():
agentStatusDetail)
#Wait for 25 seconds and detect protocol again.
time.sleep(25)
def activateResourceDisk(self):
mountpoint = self.config.get("ResourceDisk.MountPoint", "/mnt/resource")
fs = self.config.get("ResourceDisk.Filesystem", "ext3")
mountpoint = CurrOS.MountResourceDisk(mountpoint, fs)
warningFile = os.path.join(mountpoint, DataLossWarningFile)
fileutil.SetFileContents(warningFile, DataLossWarning)
if self.config.getSwitch("ResourceDisk.EnabledSwap", False):
sizeMB = self.config.getInt("ResourceDisk.SwapSizeMB", 0)
CurrOS.CreateSwapSpace(mountpoint, sizeMB)
def detectScvmmEnv(self):
CurrOS.MountDvd(maxRetry=0, chk_err=False)
mountPoint = CurrOS.GetDvdMountPoint()
return os.path.isfile(os.path.join(mountPoint, VmmConfigFileName))
def startScvmmAgent(self):
logger.Info("Starting Microsoft System Center VMM Initialization Process")
mountPoint = CurrOS.GetDvdMountPoint()
startupScript = os.path.join(mountPoint, VmmStartupScriptName)
subprocess.Popen(["/bin/bash", startupScript, "-p " + mountPoint])
def savePid(self):
fileutil.SetFileContents(CurrOS.GetAgentPidPath(), str(os.getpid()))
fileutil.SetFileContents(CurrOSUtil.GetAgentPidPath(),
str(os.getpid()))
def ParseArgs(sysArgv):
cmd = None
@@ -167,62 +137,28 @@ def Usage():
print ("usage: {0} [-verbose] [-force] "
"[-help|-deprovision[+user]|-version|-serialconsole|-daemon]")
def Deprovision(force=False, deluser=False):
configPath = CurrOS.GetConfigurationPath()
config = conf.LoadConfiguration(configPath)
print("WARNING! The waagent service will be stopped.")
print("WARNING! All SSH host key pairs will be deleted.")
print("WARNING! Cached DHCP leases will be deleted.")
CurrOS.OnDeprovisionStart()
delRootPasswd = config.getSwitch("Provisioning.DeleteRootPassword", False)
if delRootPasswd:
print("WARNING! root password will be disabled. "
"You will not be able to login as root.")
protocol = proto.GetDefaultProtocol()
ovf = protocol.getOvf()
if ovf is not None and deluser:
print ("WARNING! {0} account and entire home directory "
"will be deleted.").format(ovf.getUserName())
if not force:
confirm = raw_input("Do you want to proceed (y/n)")
if not confirm.lower().startswith('y'):
return
CurrOS.StopAgentService()
if delRootPasswd:
CurrOS.DeleteRootPassword()
if config.getSwitch("Provisioning.RegenerateSshHostkey", False):
shellutil.Run("rm -f /etc/ssh/ssh_host_*key*")
CurrOS.SetHostname('localhost.localdomain')
fileutil.CleanupDirs(CurrOS.GetLibDir(), "/var/lib/dhclient",
"/var/lib/dhcpcd", "/var/lib/dhcp")
fileutil.RemoveFiles('/root/.bash_history', '/var/log/waagent.log')
CurrOS.OnDeprovision()
if ovf is not None and deluser:
CurrOS.DeleteAccount(ovf.getUserName())
def Main():
command, force, verbose = ParseArgs(sys.argv[1:])
if command == "deprovision+user":
Deprovision(force=force, deluser=True)
deprovisionHandler = CurrOSHandlerFactory.GetDeprovisionHandler()
deprovisionHandler.deprovision(force=force, deluser=True)
elif command == "deprovision":
Deprovision(force=force, deluser=False)
deprovisionHandler = CurrOSHandlerFactory.GetDeprovisionHandler()
deprovisionHandler.deprovision(force=force, deluser=True)
elif command == "daemon":
configPath = CurrOS.GetConfigurationPath()
configPath = CurrOSUtil.GetConfigurationPath()
config = conf.LoadConfiguration(configPath)
verbose = config.getSwitch("Logs.Verbose", False)
logger.LoggerInit('/var/log/waagent.log',
'/dev/console',
verbose=verbose)
fileutil.CreateDir(CurrOS.GetLibDir(), mode='0700')
os.chdir(CurrOS.GetLibDir())
fileutil.CreateDir(CurrOSUtil.GetLibDir(), mode='0700')
os.chdir(CurrOSUtil.GetLibDir())
Agent(config).run()
elif command == "serialconsole":
#TODO
pass
elif command == "version":
Version()
else:# command == 'help':
else:
Usage()
+28 -5
View File
@@ -19,14 +19,37 @@
import os
import azureguestagent.utils.fileutil as fileutil
from azureguestagent.exception import *
from azureguestagent.utils.osutil import CurrOSUtil
def LoadConfiguration(confFilePath):
if os.path.isfile(confFilePath) == False:
raise Exception("Missing configuration in {0}", confFilePath)
raise AgentConfigError("Missing configuration in {0}", confFilePath)
try:
return ConfigurationProvider(fileutil.GetFileContents(confFilePath))
content = fileutil.GetFileContents(confFilePath)
__Config__ = ConfigurationProvider(content)
return __Config__
except IOError, e:
raise Exception("Failed to load conf file:{0}", confFilePath)
raise AgentConfigError("Failed to load conf file:{0}", confFilePath)
__Config__ = None
def Get(key, defaultValue=None):
if __Config__ is not None:
return __Config__.get(key, defaultValue)
else:
return defaultValue
def GetSwitch(key, defaultValue=None):
if __Config__ is not None:
return __Config__.getSwitch(key, defaultValue)
else:
return defaultValue
def GetInt(key, defaultValue=None):
if __Config__ is not None:
return __Config__.getInt(key, defaultValue)
else:
return defaultValue
class ConfigurationProvider(object):
"""
@@ -35,7 +58,7 @@ class ConfigurationProvider(object):
def __init__(self, content):
self.values = dict()
if not content:
raise Exception("Can't not parse empty configuration")
raise AgentConfigError("Can't not parse empty configuration")
for line in content.split('\n'):
if not line.startswith("#") and "=" in line:
parts = line.split()[0].split('=')
@@ -59,4 +82,4 @@ class ConfigurationProvider(object):
except:
return defaultValue
+24
View File
@@ -0,0 +1,24 @@
# Windows 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+
#
class AgentError(Exception):
pass
class AgentConfigError(AgentError):
pass
-2
View File
@@ -18,5 +18,3 @@
#
from azureguestagent.handler.factory import CurrOSHandlerFactory
__all__ = ["CurrOSHandlerFactory"]
@@ -16,3 +16,49 @@
#
# Requires Python 2.4+ and Openssl 1.0+
#
from azureguestagent.utils.osutil import CurrOSUtilUtil
import azureguestagent.utils.fileutil as fileutil
class Deprovisionhandler(object):
def promptUser(self, delRootPasswd, ovf):
print("WARNING! The waagent service will be stopped.")
print("WARNING! All SSH host key pairs will be deleted.")
print("WARNING! Cached DHCP leases will be deleted.")
if delRootPasswd:
print("WARNING! root password will be disabled. "
"You will not be able to login as root.")
if ovf is not None and deluser:
print ("WARNING! {0} account and entire home directory "
"will be deleted.").format(ovf.getUserName())
def deprovision(force=False, deluser=False):
configPath = CurrOSUtil.GetConfigurationPath()
config = conf.LoadConfiguration(configPath)
delRootPasswd = config.getSwitch("Provisioning.DeleteRootPassword", False)
protocol = proto.GetDefaultProtocol()
ovf = protocol.getOvf()
self.promptUser(delRootPasswd, ovf)
if not force:
confirm = raw_input("Do you want to proceed (y/n)")
if not confirm.lower().startswith('y'):
return
self.cleanup(delRootPasswd)
def cleanup(self, delRootPasswd, ovf)
CurrOSUtil.StopAgentService()
if delRootPasswd:
CurrOSUtil.DeleteRootPassword()
if config.getSwitch("Provisioning.RegenerateSshHostkey", False):
shellutil.Run("rm -f /etc/ssh/ssh_host_*key*")
CurrOSUtil.SetHostname('localhost.localdomain')
fileutil.CleanupDirs(CurrOSUtil.GetLibDir(), "/var/lib/dhclient",
"/var/lib/dhcpcd", "/var/lib/dhcp")
fileutil.RemoveFiles('/root/.bash_history', '/var/log/waagent.log')
if ovf is not None and deluser:
CurrOSUtil.DeleteAccount(ovf.getUserName())
@@ -22,6 +22,7 @@ import socket
import array
import time
import azureguestagent.logger as logger
from azureguestagent.utils.osutil import CurrOSUtil
import azureguestagent.utils.restutil as restutil
import azureguestagent.utils.fileutil as fileutil
import azureguestagent.utils.shellutil as shellutil
@@ -29,22 +30,21 @@ from azureguestagent.utils.textutil import *
class DhcpHandler(object):
def __init__(self, osutil):
def __init__(self):
self.endpoint = None
self.gateway = None
self.routes = None
self.osutil = osutil
def waitForNetwork(self):
ipv4 = self.osutil.GetIpv4Address()
ipv4 = CurrOSUtil.GetIpv4Address()
while ipv4 == '' or ipv4 == '0.0.0.0':
logger.Info("Waiting for network.")
time.sleep(10)
self.osutil.StartNetwork()
ipv4 = self.osutil.GetIpv4Address()
CurrOSUtil.StartNetwork()
ipv4 = CurrOSUtil.GetIpv4Address()
def probe(self):
macAddress = self.osutil.GetMacAddress()
macAddress = CurrOSUtil.GetMacAddress()
req = BuildDhcpRequest(macAddress)
resp = SendDhcpRequest(req)
endpoint, gateway, routes = ParseDhcpResponse(resp)
@@ -59,10 +59,10 @@ class DhcpHandler(object):
def configRoutes(self):
#Add default gateway
if self.gateway is not None:
self.osutil.RouteAdd(0 , 0, self.gateway)
CurrOSUtil.RouteAdd(0 , 0, self.gateway)
if self.routes is not None:
for route in self.routes:
self.osutil.RouteAdd(route[0], route[1], route[2])
CurrOSUtil.RouteAdd(route[0], route[1], route[2])
def ValidateDhcpResponse(request, response):
bytesReceived = len(response)
@@ -16,3 +16,37 @@
#
# Requires Python 2.4+ and Openssl 1.0+
#
import os
from azureguestagent.utils.osutil import CurrOSUtil
import azureguestagent.utils.fileutil as fileutil
DataLossWarningFile="DATALOSS_WARNING_README.txt"
DataLossWarning="""\
WARNING: THIS IS A TEMPORARY DISK.
Any data stored on this drive is SUBJECT TO LOSS and THERE IS NO WAY TO RECOVER IT.
Please do not use this disk for storing any personal or application data.
For additional details to please refer to the MSDN documentation at : http://msdn.microsoft.com/en-us/library/windowsazure/jj672979.aspx
"""
class ResourceDiskHandler(object):
def startActivateResourceDisk(self, config):
#TODO FreeBSD use Popen to open another process to do this
diskThread = threading.Thread(target = self.activateResourceDisk,
args = (config))
diskThread.start()
def activateResourceDisk(self, config):
mountpoint = config.get("ResourceDisk.MountPoint", "/mnt/resource")
fs = config.get("ResourceDisk.Filesystem", "ext3")
mountpoint = CurrOSUtil.MountResourceDisk(mountpoint, fs)
warningFile = os.path.join(mountpoint, DataLossWarningFile)
fileutil.SetFileContents(warningFile, DataLossWarning)
if config.getSwitch("ResourceDisk.EnabledSwap", False):
sizeMB = config.getInt("ResourceDisk.SwapSizeMB", 0)
CurrOSUtil.CreateSwapSpace(mountpoint, sizeMB)
@@ -16,3 +16,24 @@
#
# Requires Python 2.4+ and Openssl 1.0+
#
import os
from azureguestagent.utils.osutil import CurrOSUtil
import azureguestagent.utils.fileutil as fileutil
VmmConfigFileName = "linuxosconfiguration.xml"
VmmStartupScriptName= "install"
class ScvmmHandler(object):
def detectScvmmEnv(self):
CurrOSUtil.MountDvd(maxRetry=0, chk_err=False)
mountPoint = CurrOSUtil.GetDvdMountPoint()
return os.path.isfile(os.path.join(mountPoint, VmmConfigFileName))
def startScvmmAgent(self):
logger.Info("Starting Microsoft System Center VMM Initialization Process")
mountPoint = CurrOSUtil.GetDvdMountPoint()
startupScript = os.path.join(mountPoint, VmmStartupScriptName)
subprocess.Popen(["/bin/bash", startupScript, "-p " + mountPoint])
+2 -3
View File
@@ -17,8 +17,7 @@
# Requires Python 2.4+ and Openssl 1.0+
#
import azureguestagent.osinfo as osinfo
from azureguestagent.osinfo import CurrOSInfo
import azureguestagent.handler.default as default
def GetOSHandlerFactory(osInfo):
@@ -33,5 +32,5 @@ def GetOSHandlerFactory(osInfo):
#Return default implementation
return default.DefaultHandlers()
CurrOSHandlerFactory = GetOSHandlerFactory()
CurrOSHandlerFactory = GetOSHandlerFactory(CurrOSInfo)
-1
View File
@@ -18,7 +18,6 @@
#
import platform
import azureguestagent.os.baseos.DefaultDistro
def GetDistroInfo():
if 'FreeBSD' in platform.system():
-900
View File
@@ -1,900 +0,0 @@
#
# 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 platform
import os
import re
import pwd
import shutil
import tempfile
import subprocess
import socket
import array
import struct
import fcntl
import time
import base64
import azureguestagent.logger as logger
import azureguestagent.utils.fileutil as fileutil
import azureguestagent.utils.shellutil as shellutil
import azureguestagent.utils.textutil as textutil
RulesFiles = [ "/lib/udev/rules.d/75-persistent-net-generator.rules",
"/etc/udev/rules.d/70-persistent-net.rules" ]
"""
Define distro specific behavior. DefaultDistro class defines default behavior
for all distros. Each concrete distro classes could overwrite default behavior
if needed.
"""
class DefaultDistro(object):
__WireServer=None
def __init__(self):
self.libDir = "/var/lib/waagent"
self.extLogDir = "/var/log/azure"
self.dvdMountPoint = "/mnt/cdrom/secure"
self.ovfenvPathOnDvd = "/mnt/cdrom/secure/ovf-env.xml"
self.agentPidPath = "/var/run/waagent.pid"
self.passwdPath = "/etc/shadow"
self.home = '/home'
self.sshdConfigPath = '/etc/ssh/sshd_config'
self.opensslCmd = '/usr/bin/openssl'
self.configPath = '/etc/waagent.conf'
self.selinux=None
def GetLibDir(self):
return self.libDir
def GetExtLogDir(self):
return self.extLogDir
def GetDvdMountPoint(self):
return self.dvdMountPoint
def GetConfigurationPath(self):
return self.configPath
def GetOvfEnvPathOnDvd(self):
return self.ovfenvPathOnDvd
def GetAgentPidPath(self):
return self.agentPidPath
def GetOpensslCmd(self):
return self.opensslCmd
def GetWireServerEndpoint(self):
return DefaultDistro.__WireServer
def SetWireServerEndpoint(self, endpoint):
DefaultDistro.__WireServer = endpoint
def UpdateUserAccount(self, userName, password, expiration=None):
"""
Update password and ssh key for user account.
New account will be created if not exists.
"""
if userName is None:
raise Exception("User name is empty")
if self._IsSysUser(userName):
raise Exception(("User {0} is a system user. "
"Will not set passwd.").format(userName))
userentry = self.GetUserEntry(userName)
if userentry is None:
self._CreateUserAccount(userName, expiration)
if password is not None:
self.ChangePassword(userName, password)
self.ConfigSudoer(userName, password is None)
def GetUserEntry(self, userName):
try:
return pwd.getpwnam(userName)
except KeyError:
return None
def _IsSysUser(self, userName):
userentry = self.GetUserEntry(userName)
uidmin = None
try:
uidminDef = GetLineStartingWith("UID_MIN", "/etc/login.defs")
uidmin = int(uidminDef.split()[1])
except:
pass
if uidmin == None:
uidmin = 100
if userentry != None and userentry[2] < uidmin:
return True
else:
return False
def _CreateUserAccount(self, userName, expiration=None):
cmd = "useradd -m {0}".format(userName)
if expiration is not None:
cmd = "{0} -e {1}".format(cmd, expiration)
retcode, out = shellutil.RunGetOutput(cmd)
if retcode != 0:
raise Exception(("Failed to create user account:{0}, "
"retcode:{1}, "
"output:{2}").format(userName, retcode, out))
def ChangePassword(self, userName, password):
shellutil.RunSendStdin("chpasswd",
"{0}:{1}\n".format(userName, password))
def ConfigSudoer(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 = fileutil.GetFileContents('/etc/sudoers')
sudoers = sudoers + '\n' + '#includedir /etc/sudoers.d/\n'
fileutil.SetFileContents('/etc/sudoers', sudoers)
sudoer = None
if nopasswd:
sudoer = "{0} ALL = (ALL) NOPASSWD\n".format(userName)
else:
sudoer = "{0} ALL = (ALL) ALL\n".format(userName)
fileutil.SetFileContents('/etc/sudoers.d/waagent', sudoer, append=True)
fileutil.ChangeMod('/etc/sudoers.d/waagent', 0440)
def DeleteRootPassword(self):
passwdContent = fileutil.GetFileContents(self.passwdPath)
if passwdContent is None:
raise Exception("Failed to delete root password.")
passwd = passwdContent.split('\n')
newPasswd = filter(lambda x : not x.startswith("root:"), passwd)
newPasswd.insert(0, "root:*LOCK*:14600::::::")
fileutil.ReplaceFileContentsAtomic(self.passwdPath, "\n".join(newPasswd))
def GetHome(self):
return self.home
def GetPubKeyFromPrv(self, fileName):
cmd = "{0} rsa -in {1} -pubout 2>/dev/null".format(self.opensslCmd,
fileName)
pub = shellutil.RunGetOutput(cmd)[1]
return pub
def GetPubKeyFromCrt(self, fileName):
cmd = "{0} x509 -in {1} -pubkey -noout".format(self.opensslCmd,
fileName)
pub = shellutil.RunGetOutput(cmd)[1]
return pub
def _NormPath(self, filepath):
home = CurrOS.GetHome()
# Expand HOME variable if present in path
path = os.path.normpath(filepath.replace("$HOME", home))
return path
def GetThumbprintFromCrt(self, fileName):
cmd="{0} x509 -in {1} -fingerprint -noout".format(self.opensslCmd,
fileName)
thumbprint = shellutil.RunGetOutput(cmd)[1]
thumbprint = thumbprint.rstrip().split('=')[1].replace(':', '').upper()
return thumbprint
def DeploySshKeyPair(self, userName, thumbprint, path):
"""
Deploy id_rsa and id_rsa.pub
"""
path = self._NormPath(path)
dirPath = os.path.dirname(path)
fileutil.CreateDir(dirPath, mode=0700, owner=userName)
libDir = CurrOS.GetLibDir()
prvPath = os.path.join(libDir, thumbprint + '.prv')
if not os.path.isfile(prvPath):
logger.Error("Failed to deploy key pair, thumbprint: {0}",
thumbprint)
return
shutil.copyfile(prvPath, path)
pubPath = path + '.pub'
pub = self.GetPubKeyFromPrv(prvPath)
fileutil.SetFileContents(pubPath, pub)
self.SetSelinuxContext(path, 'unconfined_u:object_r:ssh_home_t:s')
self.SetSelinuxContext(pubPath, 'unconfined_u:object_r:ssh_home_t:s')
os.chmod(path, 0600)
os.chmod(pubPath, 0600)
def DeploySshPublicKey(self, userName, thumbprint, path):
"""
Deploy authorized_key
"""
path = self._NormPath(path)
dirPath = os.path.dirname(path)
fileutil.CreateDir(dirPath, mode=0700, owner=userName)
libDir = CurrOS.GetLibDir()
crtPath = os.path.join(libDir, thumbprint + '.crt')
if not os.path.isfile(crtPath):
logger.Error("Failed to deploy public key, thumbprint: {0}",
thumbprint)
return
pubPath = os.path.join(libDir, thumbprint + '.pub')
pub = self.GetPubKeyFromCrt(crtPath)
fileutil.SetFileContents(pubPath, pub)
self.SetSelinuxContext(pubPath, 'unconfined_u:object_r:ssh_home_t:s')
#TODO some distros doesn't support PKCS8. Need to figure out.
shellutil.Run("ssh-keygen -i -m PKCS8 -f {0} >> {1}".format(pubPath,
path))
self.SetSelinuxContext(path, 'unconfined_u:object_r:ssh_home_t:s')
os.chmod(path, 0600)
os.chmod(pubPath, 0600)
def IsSelinuxSystem(self):
"""
Checks and sets self.selinux = True if SELinux is available on system.
"""
if self.selinux == None:
if shellutil.Run("which getenforce", chk_err=False) == 0:
self.selinux = True
else:
self.selinux = False
return self.selinux
def IsSelinuxRunning(self):
"""
Calls shell command 'getenforce' and returns True if 'Enforcing'.
"""
if self.IsSelinuxSystem():
output = shellutil.RunGetOutput("getenforce")[1]
return output.startswith("Enforcing")
else:
return False
def SetSelinuxEnforce(self, state):
"""
Calls shell command 'setenforce' with 'state'
and returns resulting exit code.
"""
if self.IsSelinuxSystem():
if state: s = '1'
else: s='0'
return shellutil.Run("setenforce "+s)
def SetSelinuxContext(self, path, cn):
"""
Calls shell 'chcon' with 'path' and 'cn' context.
Returns exit result.
"""
if self.IsSelinuxSystem():
return shellutil.Run('chcon ' + cn + ' ' + path)
def GetSshdConfigPath(self):
return self.sshdConfigPath
def SetSshClientAliveInterval(self):
configPath = self.GetSshdConfigPath()
config = fileutil.GetFileContents(configPath).split("\n")
textutil.SetSshConfig(config, "ClientAliveInterval", "180")
fileutil.ReplaceFileContentsAtomic(configPath, '\n'.join(config))
logger.Info("Configured SSH client probing to keep connections alive.")
def ConfigSshd(self, disablePassword):
option = "no" if disablePassword else "yes"
configPath = self.GetSshdConfigPath()
config = fileutil.GetFileContents(configPath).split("\n")
textutil.SetSshConfig(config, "PasswordAuthentication", option)
textutil.SetSshConfig(config, "ChallengeResponseAuthentication", option)
fileutil.ReplaceFileContentsAtomic(configPath, "\n".join(config))
logger.Info("Disabled SSH password-based authentication methods.")
def RegenerateSshHostkey(self, keyPairType):
shellutil.Run("rm -f /etc/ssh/ssh_host_*key*")
shellutil.Run("ssh-keygen -N '' -t {0} -f /etc/ssh/ssh_host_{1}_key"
.format(keyPairType, keyPairType))
def GetSshHostKeyThumbprint(self, keyPairType):
cmd = "ssh-keygen -lf /etc/ssh/ssh_host_{0}_key.pub".format(keyPairType)
ret = shellutil.RunGetOutput(cmd)
if ret[0] == 0:
return ret[1].rstrip().split()[1].replace(':', '')
else:
return None
def WaitForSshHostKey(self, keyPairType, maxRetry=6):
path = '/etc/ssh/ssh_host_{0}_key'.format(keyPairType)
for retry in range(0, maxRetry):
if os.path.isfile(path):
return
logger.Info("Wait for ssh host key be generated: {0}", path)
time.sleep(1)
raise Exception("Can't find ssh host key.")
def GetDvdDevice(self, devDir='/dev'):
patten=r'(sr[0-9]|hd[c-z]|cdrom[0-9])'
for dvd in [re.match(patten, dev) for dev in os.listdir(devDir)]:
if dvd is not None:
return "/dev/{0}".format(dvd.group(0))
return None
def MountDvd(self, maxRetry=6, chk_err=True):
dvd = self.GetDvdDevice()
mountPoint = self.GetDvdMountPoint()
#TODO Why do we need to load atapiix?
#self.LoadAtapiixModule()
mountlist = shellutil.RunGetOutput("mount")[1]
existing = self._GetMountPoint(mountlist, dvd)
if existing is not None: #Already mounted
return
if not os.path.isdir(mountPoint):
os.makedirs(mountPoint)
retcode = self.Mount(dvd, mountPoint, chk_err)
for retry in range(0, maxRetry):
if retcode == 0:
logger.Info("Successfully mounted provision dvd")
return
else:
logger.Warn("Mount dvd failed: retry={0}, ret={1}",
retry,
retcode)
time.sleep(5)
self.Mount(dvd, mountPoint, chk_err)
if chk_err:
raise Exception("Failed to mount provision dvd")
def UmountDvd(self):
mountPoint = self.GetDvdMountPoint()
self.Umount(mountPoint)
def LoadAtapiixModule(self):
if self.IsAtaPiixModuleLoaded():
return
ret, kernVersion = shellutil.RunGetOutput("uname -r")
if ret != 0:
raise Exception("Failed to call uname -r")
modulePath = os.path.join('/lib/modules',
kernVersion.strip('\n'),
'kernel/drivers/ata/ata_piix.ko')
if not os.path.isfile(modulePath):
raise Exception("Can't find module file:{0}".format(modulePath))
ret, output = shellutil.RunGetOutput("insmod " + modulePath)
if ret != 0:
raise Exception("Error calling insmod for ATAPI CD-ROM driver")
if not self.IsAtaPiixModuleLoaded(maxRetry=3):
raise Exception("Failed to load ATAPI CD-ROM driver")
def IsAtaPiixModuleLoaded(self, maxRetry=1):
for retry in range(0, maxRetry):
ret = shellutil.Run("lsmod | grep ata_piix", chk_err=False)
if ret == 0:
logger.Info("Module driver for ATAPI CD-ROM is already present.")
return True
time.sleep(1)
return False
def Mount(self, dvd, mountPoint, chk_err=True):
return shellutil.RunGetOutput("mount {0} {1}".format(dvd, mountPoint),
chk_err)[0]
def Umount(self, mountPoint):
return shellutil.Run("umount {0}".format(mountPoint))
def OpenPortForDhcp(self):
#Open DHCP port if iptables is enabled.
# We supress error logging on error.
shellutil.Run("iptables -D INPUT -p udp --dport 68 -j ACCEPT",
chk_err=False)
shellutil.Run("iptables -I INPUT -p udp --dport 68 -j ACCEPT",
chk_err=False)
def GenerateTransportCert(self):
"""
Create ssl certificate for https communication with endpoint server.
"""
cmd = ("{0} req -x509 -nodes -subj /CN=LinuxTransport -days 32768 "
"-newkey rsa:2048 -keyout TransportPrivate.pem "
"-out TransportCert.pem").format(self.opensslCmd)
shellutil.Run(cmd)
def RemoveRulesFiles(self, rulesFiles=RulesFiles):
libDir = self.GetLibDir()
for src in rulesFiles:
fileName = fileutil.GetLastPathElement(src)
dest = os.path.join(libDir, fileName)
if os.path.isfile(dest):
os.remove(dest)
if os.path.isfile(src):
logger.Warn("Move rules file {0} to {1}", fileName, dest)
shutil.move(src, dest)
def RestoreRulesFiles(self, rulesFiles=RulesFiles):
libDir = self.GetLibDir()
for dest in rulesFiles:
fileName = fileutil.GetLastPathElement(dest)
src = os.path.join(libDir, fileName)
if os.path.isfile(dest):
continue
if os.path.isfile(src):
logger.Warn("Move rules file {0} to {1}", fileName, dest)
shutil.move(src, dest)
def CheckDependencies(self):
#TODO Add dependency check
pass
def GetMacAddress(self):
"""
Convienience function, returns mac addr bound to
first non-loobback interface.
"""
ifname=''
while len(ifname) < 2 :
ifname=self.GetFirstActiveNetworkInterfaceNonLoopback()[0]
addr = self.GetInterfaceMac(ifname)
return textutil.HexStringToByteArray(addr)
def GetInterfaceMac(self, ifname):
"""
Return the mac-address bound to the socket.
"""
sock = socket.socket(socket.AF_INET,
socket.SOCK_DGRAM,
socket.IPPROTO_UDP)
param = struct.pack('256s', (ifname[:15]+('\0'*241)).encode('latin-1'))
info = fcntl.ioctl(sock.fileno(), 0x8927, param)
return ''.join(['%02X' % textutil.Ord(char) for char in info[18:24]])
def GetFirstActiveNetworkInterfaceNonLoopback(self):
"""
Return the interface name, and ip addr of the
first active non-loopback interface.
"""
iface=''
expected=16 # how many devices should I expect...
struct_size=40 # for 64bit the size is 40 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=sock[i:i+16].split(b'\0', 1)[0]
if iface == b'lo':
continue
else:
break
return iface.decode('latin-1'), socket.inet_ntoa(sock[i+20:i+24])
def IsMissingDefaultRoute(self):
routes = shellutil.RunGetOutput("route -n")[1]
for route in routes:
if route.startswith("0.0.0.0 ") or route.startswith("default "):
return False
return True
def GetInterfaceName(self):
return self.GetFirstActiveNetworkInterfaceNonLoopback()[0]
def GetIpv4Address(self):
return self.GetFirstActiveNetworkInterfaceNonLoopback()[1]
def SetBroadcastRouteForDhcp(self, ifname):
return shellutil.Run("route add 255.255.255.255 dev {0}".format(ifname),
chk_err=False)
def RemoveBroadcastRouteForDhcp(self, ifname):
shellutil.Run("route del 255.255.255.255 dev {0}".format(ifname),
chk_err=False)
def IsDhcpEnabled(self):
return False
def StopDhcpService(self):
raise NotImplementedError('StopDhcpService method missing')
def StartDhcpService(self):
raise NotImplementedError('StartDhcpService method missing')
def StartNetwork(self):
raise NotImplementedError('StartNetwork method missing')
def StartAgentService(self):
raise NotImplementedError('StartAgentService method missing')
def StopAgentService(self):
raise NotImplementedError('StopAgentService method missing')
def RegisterAgentService(self):
self.StartAgentService()
def UnregisterAgentService(self):
self.StopAgentService()
def RestartSshService(self):
raise NotImplementedError('RestartSshService method missing')
def RouteAdd(self, net, mask, gateway):
"""
Add specified route using /sbin/route add -net.
"""
cmd = ("/sbin/route add -net "
"{0} netmask {1} gw {2}").format(net, mask, gateway)
return shellutil.Run(cmd, chk_err=False)
def GetDhcpProcessId(self):
ret= shellutil.RunGetOutput("pidof dhclient")
return ret[1] if ret[0] == 0 else None
def SetHostname(self, hostname):
fileutil.SetFileContents('/etc/hostname', hostname)
shellutil.Run("hostname {0}".format(hostname), chk_err=False)
def SetDhcpHostname(self, hostname):
autoSend = r'^[^#]*?send\s*host-name.*?(<hostname>|gethostname[(,)])'
dhclientFiles = ['/etc/dhcp/dhclient.conf', '/etc/dhcp3/dhclient.conf']
for confFile in dhclientFiles:
if not os.path.isfile(confFile):
continue
if fileutil.FindStringInFile(confFile, autoSend):
#Return if auto send host-name is configured
return
fileutil.UpdateConfigFile(confFile,
'send host-name',
'send host-name {0}'.format(hostname))
def RestartInterface(self, ifname):
shellutil.Run("ifdown {0} && ifup {1}".format(ifname, ifname))
def PublishHostname(self, hostname):
self.SetDhcpHostname(hostname)
ifname = self.GetInterfaceName()
self.RestartInterface(ifname)
def SetScsiDiskTimeout(self, timeout):
for dev in os.listdir("/sys/block"):
if dev.startswith('sd'):
self.SetBlockDeviceTimeout(dev, timeout)
def SetBlockDeviceTimeout(self, dev, timeout):
if dev is not None and timeout is not None:
filePath = "/sys/block/{0}/device/timeout".format(dev)
original = fileutil.GetFileContents(filePath).splitlines()[0].rstrip()
if original != timeout:
fileutil.SetFileContents(filePath, timeout)
logger.Info("Set block dev timeout: {0} with timeout: {1}",
dev,
timeout)
def _GetMountPoint(self, mountlist, device):
"""
Example of mountlist:
/dev/sda1 on / type ext4 (rw)
proc on /proc type proc (rw)
sysfs on /sys type sysfs (rw)
devpts on /dev/pts type devpts (rw,gid=5,mode=620)
tmpfs on /dev/shm type tmpfs
(rw,rootcontext="system_u:object_r:tmpfs_t:s0")
none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)
/dev/sdb1 on /mnt/resource type ext4 (rw)
"""
if (mountlist and device):
for entry in mountlist.split('\n'):
if(re.search(device, entry)):
tokens = entry.split()
#Return the 3rd column of this line
return tokens[2] if len(tokens) > 2 else None
return None
def MountResourceDisk(self, mountpoint, fs):
device = self.DeviceForIdePort(1)
if device is None:
logger.Error("Activate resource disk failed: "
"unable to detect disk topology")
return None
device = "/dev/" + device
mountlist = shellutil.RunGetOutput("mount")[1]
existing = self._GetMountPoint(mountlist, device)
if(existing):
logger.Info("Resource disk {0} is already mounted", device)
return existing
fileutil.CreateDir(mountpoint, mode=0755)
output = shellutil.RunGetOutput("sfdisk -q -c {0} 1".format(device))
if output[1].rstrip() == "7" and fs != "ntfs":
shellutil.Run("sfdisk -c {0} 1 83".format(device))
shellutil.Run("mkfs.{0} {1}1".format(fs, device))
ret = shellutil.Run("mount {0}1 {1}".format(device, mountpoint))
if ret:
logger.Error("Failed to mount resource disk ({0})".format(device))
raise Exception("Failed to mount resource disk")
else:
logger.Info(("Resource disk ({0}) is mounted at {1} "
"with fstype {2}").format(device, mountpoint, fs))
return mountpoint
def DeviceForIdePort(self, n):
"""
Return device name attached to ide port 'n'.
"""
if n > 3:
return None
g0 = "00000000"
if n > 1:
g0 = "00000001"
n = n - 2
device = None
path = "/sys/bus/vmbus/devices/"
for vmbus in os.listdir(path):
deviceid = fileutil.GetFileContents(os.path.join(path,
vmbus,
"device_id"))
guid = deviceid.lstrip('{').split('-')
if guid[0] == g0 and guid[1] == "000" + str(n):
for root, dirs, files in os.walk(path + vmbus):
if root.endswith("/block"):
device = dirs[0]
break
else : #older distros
for d in dirs:
if ':' in d and "block" == d.split(':')[0]:
device = d.split(':')[1]
break
break
return device
def CreateSwapSpace(self, mountpoint, sizeMB):
sizeKB = sizeMB * 1024
size = sizeKB * 1024
swapfile = os.path.join(mountpoint, 'swapfile')
if os.path.isfile(swapfile) and os.path.getsize(swapfile) != size:
os.remove(swapfile)
if not os.path.isfile(swapfile):
shellutil.Run(("dd if=/dev/zero of={0} bs=1024 "
"count={1}").format(swapfile, sizeKB))
shellutil.Run("mkswap {0}".format(swapfile))
if shellutil.Run("swapon {0}".format(swapfile)):
logger.Error("Failed to activate swap at: {0}".format(swapfile))
else:
logger.Info("Enabled {0}KB of swap at {1}".format(sizeKB, swapfile))
def DeleteAccount(self, userName):
if self._IsSysUser(userName):
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
sudoers = fileutil.GetFileContents("/etc/sudoers.d/waagent").split("\n")
sudoers = filter(lambda x : userName not in x, sudoers)
fileutil.SetFileContents("/etc/sudoers.d/waagent", "\n".join(sudoers))
def OnDeprovisionStart(self):
print ("WARNING! Nameserver configuration in "
"/etc/resolv.conf will be deleted.")
def OnDeprovision(self):
"""
Distro specific clean up work during deprovision
"""
fileutil.RemoveFiles('/etc/resolv.conf')
def TranslateCustomData(self, data):
return data
class DebianDistro(DefaultDistro):
def __init__(self):
super(DebianDistro, self).__init__()
def RestartSshService(self):
return shellutil.Run("service sshd restart", chk_err=False)
def StopAgentService(self):
return shellutil.Run("service azureguestagent stop", chk_err=False)
def StartAgentService(self):
return shellutil.Run("service azureguestagent start", chk_err=False)
class UbuntuDistro(DebianDistro):
def __init__(self):
super(UbuntuDistro, self).__init__()
def StartNetwork(self):
return shellutil.Run("service networking start", chk_err=False)
def OnDeprovisionStart(self):
print("WARNING! Nameserver configuration in "
"/etc/resolvconf/resolv.conf.d/{tail,originial} will be deleted.")
def OnDeprovision(self):
if os.path.realpath('/etc/resolv.conf') != '/run/resolvconf/resolv.conf':
logger.Info("resolvconf is not configured. Removing /etc/resolv.conf")
fileutil.RemoveFiles('/etc/resolv.conf')
else:
logger.Info("resolvconf is enabled; leaving /etc/resolv.conf intact")
fileutil.RemoveFiles('/etc/resolvconf/resolv.conf.d/tail',
'/etc/resolvconf/resolv.conf.d/originial')
class Ubuntu1204Distro(UbuntuDistro):
def __init__(self):
super(Ubuntu1204Distro, self).__init__()
#Override
def GetDhcpProcessId(self):
ret= shellutil.RunGetOutput("pidof dhclient3")
return ret[1] if ret[0] == 0 else None
class RedhatDistro(DefaultDistro):
def __init__(self):
super(RedhatDistro, self).__init__()
self.sshdConfigPath = '/etc/ssh/sshd_config'
self.opensslCmd = '/usr/bin/openssl'
self.configPath = '/etc/waagent.conf'
self.selinux=None
def StartNetwork(self):
return shellutil.Run("/sbin/service networking start", chk_err=False)
def RestartSshService(self):
return shellutil.Run("/sbin/service sshd condrestart", chk_err=False)
def StopAgentService(self):
return shellutil.Run("/sbin/service waagent stop", chk_err=False)
def StartAgentService(self):
return shellutil.Run("/sbin/service waagent start", chk_err=False)
#Override
def GetDhcpProcessId(self):
ret= shellutil.RunGetOutput("pidof dhclient")
return ret[1] if ret[0] == 0 else None
class Redhat7Distro(RedhatDistro):
def __init__(self):
super(Redhat7Distro, self).__init__()
def SetHostname(self, hostname):
super(Redhat7Distro, self).SetHostname(hostname)
fileutil.UpdateConfigFile('/etc/sysconfig/network',
'HOSTNAME',
'HOSTNAME={0}'.format(hostname))
def SetDhcpHostname(self, hostname):
ifname = self.GetInterfaceName()
filepath = "/etc/sysconfig/network-scripts/ifcfg-{0}".format(ifname)
fileutil.UpdateConfigFile(filepath,
'DHCP_HOSTNAME',
'DHCP_HOSTNAME={0}'.format(hostname))
class FedoraDistro(DefaultDistro):
pass
class CoreOSDistro(DefaultDistro):
def __init(self):
super(CoreOSDistro, self).__init__()
self.configPath = '/usr/share/oem/waagent.conf'
def _IsSysUser(self, userName):
#User 'core' is not a sysuser
if userName == 'core':
return False
return super(CoreOSDistro, self).isSysUser(userName)
def IsDhcpEnabled(self):
return True
def StartNetwork(self) :
return shellutil.Run("systemctl start systemd-networkd", chk_err=False)
def RestartInterface(self, iface):
Run("systemctl restart systemd-networkd")
def RestartSshService(self):
return shellutil.Run("systemctl restart sshd", chk_err=False)
def StopDhcpService(self):
return shellutil.Run("systemctl stop systemd-networkd", chk_err=False)
def StartDhcpService(self):
return shellutil.Run("systemctl start systemd-networkd", chk_err=False)
def GetDhcpProcessId(self):
ret= shellutil.RunGetOutput("pidof systemd-networkd")
return ret[1] if ret[0] == 0 else None
def OnDeprovisionStart(self):
print "WARNING! /etc/machine-id will be removed."
def OnDeprovision(self):
fileutil.RemoveFiles('/etc/machine-id')
def TranslateCustomData(self, data):
return base64.b64decode(data)
class GentooDistro(DefaultDistro):
pass
class SUSEDistro(DefaultDistro):
def __init__(self):
super(SUSEDistro, self).__init__()
self.dhcpClientName='dhcpcd'
def SetHostname(self, hostname):
fileutil.SetFileContents('/etc/HOSTNAME', hostname)
shellutil.Run("hostname {0}".format(hostname), chk_err=False)
def GetDhcpProcessId(self):
ret= shellutil.RunGetOutput("pidof {0}".format(self.dhcpClientName))
return ret[1] if ret[0] == 0 else None
def IsDhcpEnabled(self):
return True
def StopDhcpService(self):
cmd = "/sbin/service {0} stop".format(self.dhcpClientName)
return shellutil.Run(cmd, chk_err=False)
def StartDhcpService(self):
cmd = "/sbin/service {0} start".format(self.dhcpClientName)
return shellutil.Run(cmd, chk_err=False)
def StartNetwork(self) :
return shellutil.Run("/sbin/service start network", chk_err=False)
def RestartSshService(self):
return shellutil.Run("/sbin/service sshd restart", chk_err=False)
def StopAgentService(self):
return shellutil.Run("/sbin/service waagent stop", chk_err=False)
def StartAgentService(self):
return shellutil.Run("/sbin/service waagent start", chk_err=False)
def RegisterAgentService(self):
ret = shellutil.Run("insserv waagent", chk_err=False)
if ret != 0:
return ret
ret = super(SUSEDistro, self).RegisterAgentService()
return ret
def UnregisterAgentService(self):
ret = super(SUSEDistro, self).UnregisterAgentService()
if ret != 0:
return ret
return shellutil.Run("insserv -r waagent", chk_err=False)
class SUSE12Distro(SUSEDistro):
def __init__(self):
super(SUSE12Distro, self).__init__()
self.dhcpClientName = 'wickedd-dhcp4'
class FreeBSDDistro(DefaultDistro):
def __init__(self):
self.scsiConfigured = False
def SetScsiDiskTimeout(self, timeout):
if scsiConfigured:
return
shellutil.Run("sysctl kern.cam.da.default_timeout=" + timeout)
self.scsiConfigured = True
-2
View File
@@ -18,5 +18,3 @@
#
from azureguestagent.utils.osutil.factory import CurrOSUtil
__all__ = ['CurrOSUtil']
+3 -3
View File
@@ -186,7 +186,7 @@ class DefaultOSUtil(object):
return pub
def _NormPath(self, filepath):
home = CurrOS.GetHome()
home = self.GetHome()
# Expand HOME variable if present in path
path = os.path.normpath(filepath.replace("$HOME", home))
return path
@@ -205,7 +205,7 @@ class DefaultOSUtil(object):
path = self._NormPath(path)
dirPath = os.path.dirname(path)
fileutil.CreateDir(dirPath, mode=0700, owner=userName)
libDir = CurrOS.GetLibDir()
libDir = self.GetLibDir()
prvPath = os.path.join(libDir, thumbprint + '.prv')
if not os.path.isfile(prvPath):
logger.Error("Failed to deploy key pair, thumbprint: {0}",
@@ -227,7 +227,7 @@ class DefaultOSUtil(object):
path = self._NormPath(path)
dirPath = os.path.dirname(path)
fileutil.CreateDir(dirPath, mode=0700, owner=userName)
libDir = CurrOS.GetLibDir()
libDir = self.GetLibDir()
crtPath = os.path.join(libDir, thumbprint + '.crt')
if not os.path.isfile(crtPath):
logger.Error("Failed to deploy public key, thumbprint: {0}",
+1 -1
View File
@@ -17,7 +17,7 @@
# Requires Python 2.4+ and Openssl 1.0+
#
import azureguestagent.osinfo as osinfo
import azureguestagent.utils.osutil.default as default
from default import *
def GetOSUtil(osInfo):
name = osInfo[0]
+4 -4
View File
@@ -18,14 +18,14 @@
# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx
# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx
import os
import env
import tests.tools as tools
import uuid
import unittest
import os
import tests.tools as tools
import azureguestagent.utils.fileutil as fileutil
import azureguestagent.conf as conf
import test
from azureguestagent.exception import *
TestConf="""\
#
@@ -52,7 +52,7 @@ class TestConfiguration(unittest.TestCase):
self.assertEquals(-1, config.getInt("foo.bar.str"))
def test_parse_malformed_conf(self):
with self.assertRaises(Exception) as cm:
with self.assertRaises(AgentConfigError) as cm:
conf.ConfigurationProvider(None)
def test_load_conf_file(self):
+31
View File
@@ -0,0 +1,31 @@
# 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+
#
# Implements parts of RFC 2131, 1541, 1497 and
# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx
# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx
import env
from tests.tools import *
import unittest
from azureguestagent.handler import CurrOSHandlerFactory
class TestOSHandlerFactory(unittest.TestCase):
def test_curr_os_handler_factory(self):
self.assertNotEquals(None, CurrOSHandlerFactory)
if __name__ == '__main__':
unittest.main()
+36
View File
@@ -0,0 +1,36 @@
# 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+
#
# Implements parts of RFC 2131, 1541, 1497 and
# http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx
# http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx
import env
from tests.tools import *
import unittest
from azureguestagent.osinfo import CurrOSInfo
class TestOSInfo(unittest.TestCase):
def test_curr_os_info(self):
print "hehe"
self.assertNotEquals(None, CurrOSInfo)
self.assertNotEquals(None, CurrOSInfo[0])
self.assertNotEquals(None, CurrOSInfo[1])
self.assertNotEquals(None, CurrOSInfo[2])
self.assertNotEquals(None, CurrOSInfo[3])
if __name__ == '__main__':
unittest.main()
+62 -72
View File
@@ -28,24 +28,13 @@ import time
import azureguestagent.utils.fileutil as fileutil
import azureguestagent.utils.shellutil as shellutil
import azureguestagent.utils.osutil as osutil
from azureguestagent.utils.osutil import CurrOS, CurrOSInfo
from azureguestagent.utils.osutil import CurrOSUtil
import azureguestagent.conf as conf
import test
class TestGetDistro(unittest.TestCase):
def test_get_distro(self):
distroInfo = osutil.GetDistroInfo()
self.assertNotEquals(None, distroInfo)
self.assertNotEquals(None, distroInfo[0])
self.assertNotEquals(None, distroInfo[1])
self.assertNotEquals(None, distroInfo[2])
self.assertNotEquals(None, distroInfo[3])
distro = osutil.GetDistro(distroInfo)
self.assertNotEquals(None, distro)
class TestCurrOSUtil(unittest.TestCase):
def test_current_distro(self):
self.assertNotEquals(None, osutil.CurrOSInfo)
self.assertNotEquals(None, osutil.CurrOS)
self.assertNotEquals(None, CurrOSUtil)
MountlistSample="""\
/dev/sda1 on / type ext4 (rw)
@@ -58,35 +47,36 @@ none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)
"""
class TestCurrOS(unittest.TestCase):
#class TestCurrOS(object):
def test_get_paths(self):
self.assertNotEquals(None, CurrOS.GetHome())
self.assertNotEquals(None, CurrOS.GetLibDir())
self.assertNotEquals(None, CurrOS.GetAgentPidPath())
self.assertNotEquals(None, CurrOS.GetConfigurationPath())
self.assertNotEquals(None, CurrOS.GetDvdMountPoint())
self.assertNotEquals(None, CurrOS.GetOvfEnvPathOnDvd())
self.assertNotEquals(None, CurrOSUtil.GetHome())
self.assertNotEquals(None, CurrOSUtil.GetLibDir())
self.assertNotEquals(None, CurrOSUtil.GetAgentPidPath())
self.assertNotEquals(None, CurrOSUtil.GetConfigurationPath())
self.assertNotEquals(None, CurrOSUtil.GetDvdMountPoint())
self.assertNotEquals(None, CurrOSUtil.GetOvfEnvPathOnDvd())
@Mockup(osutil.shellutil, 'RunGetOutput', MockFunc(retval=[0, '']))
@Mockup(osutil.shellutil, 'RunSendStdin', MockFunc(retval=[0, '']))
@Mockup(osutil.fileutil, 'SetFileContents', MockFunc())
@Mockup(osutil.fileutil, 'GetFileContents', MockFunc(retval=''))
@Mockup(osutil.fileutil, 'ChangeMod', MockFunc())
@Mockup(shellutil, 'RunGetOutput', MockFunc(retval=[0, '']))
@Mockup(shellutil, 'RunSendStdin', MockFunc(retval=[0, '']))
@Mockup(fileutil, 'SetFileContents', MockFunc())
@Mockup(fileutil, 'GetFileContents', MockFunc(retval=''))
@Mockup(fileutil, 'ChangeMod', MockFunc())
def test_update_user_account(self):
CurrOS.UpdateUserAccount('api', 'api')
CurrOS.DeleteAccount('api')
CurrOSUtil.UpdateUserAccount('api', 'api')
CurrOSUtil.DeleteAccount('api')
@Mockup(osutil.fileutil, 'GetFileContents', MockFunc(retval='root::::'))
@Mockup(osutil.fileutil, 'ReplaceFileContentsAtomic', MockFunc())
@Mockup(fileutil, 'GetFileContents', MockFunc(retval='root::::'))
@Mockup(fileutil, 'ReplaceFileContentsAtomic', MockFunc())
def test_delete_root_password(self):
CurrOS.DeleteRootPassword()
CurrOSUtil.DeleteRootPassword()
self.assertEquals('root:*LOCK*:14600::::::',
fileutil.ReplaceFileContentsAtomic.args[1])
def test_wireserver_endpoint(self):
if os.path.isfile('/tmp/wireserver'):
os.remove('/tmp/wireserver')
CurrOS.SetWireServerEndpoint("wireserver")
endpoint = CurrOS.GetWireServerEndpoint()
CurrOSUtil.SetWireServerEndpoint("wireserver")
endpoint = CurrOSUtil.GetWireServerEndpoint()
self.assertEquals('wireserver', endpoint)
def test_cert_operation(self):
@@ -98,70 +88,70 @@ class TestCurrOS(unittest.TestCase):
os.remove('/tmp/test.crt')
shutil.copyfile(os.path.join(env.test_root, 'test.crt'),
'/tmp/test.crt')
pub1 = CurrOS.GetPubKeyFromPrv('/tmp/test.prv')
pub2 = CurrOS.GetPubKeyFromCrt('/tmp/test.crt')
pub1 = CurrOSUtil.GetPubKeyFromPrv('/tmp/test.prv')
pub2 = CurrOSUtil.GetPubKeyFromCrt('/tmp/test.crt')
self.assertEquals(pub1, pub2)
thumbprint = CurrOS.GetThumbprintFromCrt('/tmp/test.crt')
thumbprint = CurrOSUtil.GetThumbprintFromCrt('/tmp/test.crt')
self.assertEquals('33B0ABCE4673538650971C10F7D7397E71561F35', thumbprint)
def test_selinux(self):
if not CurrOS.IsSelinuxSystem():
if not CurrOSUtil.IsSelinuxSystem():
return
isRunning = CurrOS.IsSelinuxRunning()
if not CurrOS.IsSelinuxRunning():
CurrOS.SetSelinuxEnforce(0)
self.assertEquals(False, CurrOS.IsSelinuxRunning())
CurrOS.SetSelinuxEnforce(1)
self.assertEquals(True, CurrOS.IsSelinuxRunning())
isRunning = CurrOSUtil.IsSelinuxRunning()
if not CurrOSUtil.IsSelinuxRunning():
CurrOSUtil.SetSelinuxEnforce(0)
self.assertEquals(False, CurrOSUtil.IsSelinuxRunning())
CurrOSUtil.SetSelinuxEnforce(1)
self.assertEquals(True, CurrOSUtil.IsSelinuxRunning())
if os.path.isfile('/tmp/abc'):
os.remove('/tmp/abc')
fileutil.SetFileContents('/tmp/abc', '')
CurrOS.SetSelinuxContext('/tmp/abc','unconfined_u:object_r:ssh_home_t:s')
CurrOS.SetSelinuxEnforce(1 if isRunning else 0)
CurrOSUtil.SetSelinuxContext('/tmp/abc','unconfined_u:object_r:ssh_home_t:s')
CurrOSUtil.SetSelinuxEnforce(1 if isRunning else 0)
@Mockup(shellutil, 'RunGetOutput', MockFunc(retval=[0, '']))
@Mockup(fileutil, 'SetFileContents', MockFunc())
def test_network_operation(self):
CurrOS.StartNetwork()
CurrOS.OpenPortForDhcp()
CurrOS.GenerateTransportCert()
mac = CurrOS.GetMacAddress()
CurrOSUtil.StartNetwork()
CurrOSUtil.OpenPortForDhcp()
CurrOSUtil.GenerateTransportCert()
mac = CurrOSUtil.GetMacAddress()
self.assertNotEquals(None, mac)
CurrOS.IsMissingDefaultRoute()
CurrOS.SetBroadcastRouteForDhcp('api')
CurrOS.RemoveBroadcastRouteForDhcp('api')
CurrOS.RouteAdd('', '', '')
CurrOS.GetDhcpProcessId()
CurrOS.SetHostname('api')
CurrOS.PublishHostname('api')
CurrOSUtil.IsMissingDefaultRoute()
CurrOSUtil.SetBroadcastRouteForDhcp('api')
CurrOSUtil.RemoveBroadcastRouteForDhcp('api')
CurrOSUtil.RouteAdd('', '', '')
CurrOSUtil.GetDhcpProcessId()
CurrOSUtil.SetHostname('api')
CurrOSUtil.PublishHostname('api')
@Mockup(CurrOS, 'GetHome', MockFunc(retval='/tmp/home'))
@Mockup(CurrOSUtil, 'GetHome', MockFunc(retval='/tmp/home'))
def test_deploy_key(self):
if os.path.isdir('/tmp/home'):
shutil.rmtree('/tmp/home')
user = shellutil.RunGetOutput('whoami')[1].strip()
CurrOS.DeploySshKeyPair(user, 'test', '$HOME/.ssh/id_rsa')
CurrOS.DeploySshPublicKey(user, 'test', '$HOME/.ssh/authorized_keys')
CurrOSUtil.DeploySshKeyPair(user, 'test', '$HOME/.ssh/id_rsa')
CurrOSUtil.DeploySshPublicKey(user, 'test', '$HOME/.ssh/authorized_keys')
self.assertTrue(os.path.isfile('/tmp/home/.ssh/id_rsa'))
self.assertTrue(os.path.isfile('/tmp/home/.ssh/id_rsa.pub'))
self.assertTrue(os.path.isfile('/tmp/home/.ssh/authorized_keys'))
@Mockup(shellutil, 'RunGetOutput', MockFunc(retval=[0, '']))
@Mockup(CurrOS, 'GetSshdConfigPath', MockFunc(retval='/tmp/sshd_config'))
@Mockup(CurrOSUtil, 'GetSshdConfigPath', MockFunc(retval='/tmp/sshd_config'))
def test_ssh_operation(self):
CurrOS.RegenerateSshHostkey('rsa')
CurrOSUtil.RegenerateSshHostkey('rsa')
shellutil.RunGetOutput.retval=[0,
'2048 f1:fe:14:66:9d:46:9a:60:8b:8c:'
'80:43:39:1c:20:9e root@api (RSA)']
thumbprint = CurrOS.GetSshHostKeyThumbprint('rsa')
thumbprint = CurrOSUtil.GetSshHostKeyThumbprint('rsa')
self.assertEquals('f1fe14669d469a608b8c8043391c209e', thumbprint)
sshdConfig = CurrOS.GetSshdConfigPath()
sshdConfig = CurrOSUtil.GetSshdConfigPath()
self.assertEquals('/tmp/sshd_config', sshdConfig)
if os.path.isfile(sshdConfig):
os.remove(sshdConfig)
shutil.copyfile(os.path.join(env.test_root, 'sshd_config'), sshdConfig)
CurrOS.SetSshClientAliveInterval()
CurrOS.ConfigSshd(True)
CurrOSUtil.SetSshClientAliveInterval()
CurrOSUtil.ConfigSshd(True)
self.assertTrue(simple_file_grep(sshdConfig,
'PasswordAuthentication no'))
self.assertTrue(simple_file_grep(sshdConfig,
@@ -170,25 +160,25 @@ class TestCurrOS(unittest.TestCase):
'ClientAliveInterval 180'))
@Mockup(shellutil, 'RunGetOutput', MockFunc(retval=[0, '']))
@Mockup(CurrOS, 'GetDvdMountPoint', MockFunc(retval='/tmp/cdrom'))
@Mockup(CurrOSUtil, 'GetDvdMountPoint', MockFunc(retval='/tmp/cdrom'))
def test_mount(self):
CurrOS.MountDvd()
CurrOS.UmountDvd()
mountPoint = CurrOS._GetMountPoint(MountlistSample, '/dev/sda')
CurrOSUtil.MountDvd()
CurrOSUtil.UmountDvd()
mountPoint = CurrOSUtil._GetMountPoint(MountlistSample, '/dev/sda')
self.assertNotEquals(None, mountPoint)
@Mockup(shellutil, 'RunGetOutput', MockFunc(retval=[0, '']))
@Mockup(fileutil, 'CreateDir', MockFunc())
@Mockup(CurrOS, 'DeviceForIdePort', MockFunc(retval='api'))
@Mockup(CurrOSUtil, 'DeviceForIdePort', MockFunc(retval='api'))
def test_resource_disk(self):
CurrOS.MountResourceDisk('/tmp/resource', 'ext3')
CurrOSUtil.MountResourceDisk('/tmp/resource', 'ext3')
@Mockup(shellutil, 'RunGetOutput', MockFunc(retval=[0, '']))
def test_swap(self):
CurrOS.CreateSwapSpace('/tmp', 1024)
CurrOSUtil.CreateSwapSpace('/tmp', 1024)
def test_getdvd(self):
CurrOS.GetDvdDevice()
CurrOSUtil.GetDvdDevice()
if __name__ == '__main__':
unittest.main()
+3 -3
View File
@@ -21,7 +21,7 @@
import os
import sys
from azureguestagent.utils.osutil import CurrOS, CurrOSInfo
from azureguestagent.utils.osutil import CurrOSUtil
parent = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(parent)
@@ -61,5 +61,5 @@ def Dummy():
pass
#Mock CurrOS so that the test of other part will be os unrelated
CurrOS.GetLibDir = MockFunc(retval='/tmp')
CurrOS.GetExtLogDir = MockFunc(retval='/tmp/log')
CurrOSUtil.GetLibDir = MockFunc(retval='/tmp')
CurrOSUtil.GetExtLogDir = MockFunc(retval='/tmp/log')