Providers/Scripts/2.6x-2.7x/Scripts/nxOMSContainers.py (222 lines of code) (raw):
#!/usr/bin/env python
#============================================================================
# Copyright (C) Microsoft Corporation, All rights reserved.
#============================================================================
import os
import sys
import imp
import re
import pwd
import grp
import codecs
import shutil
protocol = imp.load_source('protocol', '../protocol.py')
nxDSCLog = imp.load_source('nxDSCLog', '../nxDSCLog.py')
LG = nxDSCLog.DSCLog
MODULE_RESOURCE_DIR ='/opt/microsoft/omsconfig/modules/nxOMSContainers/DSCResources/MSFT_nxOMSContainersResource/containers'
PLUGIN_PATH = '/opt/microsoft/omsagent/plugin/'
CONF_PATH = '/etc/opt/microsoft/omsagent/<WorkspaceID>/conf/omsagent.d'
REG_PATH = '/etc/opt/omi/conf/omiregister/root-cimv2'
LIB_PATH = '/opt/microsoft/docker-cimprov/lib'
YAML_PATH = '/var/opt/microsoft/docker-cimprov/state'
STATE_DIR_PATH = '/var/opt/microsoft/omsagent/<WorkspaceID>/state'
PLUGIN_DIR = os.path.join(MODULE_RESOURCE_DIR, "plugin")
CONF_DIR = os.path.join(MODULE_RESOURCE_DIR, "conf")
REG_DIR = os.path.join(MODULE_RESOURCE_DIR, "reg")
LIB_DIR = os.path.join(MODULE_RESOURCE_DIR, "lib")
YAML_DIR = os.path.join(MODULE_RESOURCE_DIR, "yaml")
class IOMSAgent:
def restart_oms_agent(self):
pass
class OMSAgentUtil(IOMSAgent):
def restart_oms_agent(self, WorkspaceID):
wsId = WorkspaceID
if wsId is None:
wsId = ''
if os.system('sudo /opt/microsoft/omsagent/bin/service_control restart ' + wsId) == 0:
return True
else:
LG().Log('ERROR', 'Error restarting omsagent for workspace ' + wsId)
return False
class TestOMSAgent(IOMSAgent):
def restart_oms_agent(self):
return True
OMS_ACTION = OMSAgentUtil()
def init_vars(WorkspaceID = '', Ensure = ''):
global CONF_PATH
WorkspaceID = WorkspaceID.encode('ascii', 'ignore')
Ensure = Ensure.encode('ascii', 'ignore')
CONF_PATH = CONF_PATH.replace('<WorkspaceID>',WorkspaceID)
def Set_Marshall(WorkspaceID, Ensure):
init_vars(WorkspaceID, Ensure)
return Set(WorkspaceID, Ensure)
def Test_Marshall(WorkspaceID, Ensure):
init_vars(WorkspaceID, Ensure)
return Test(WorkspaceID, Ensure)
def Get_Marshall(WorkspaceID, Ensure):
init_vars(WorkspaceID, Ensure)
retval = 0
retd = dict()
retd['WorkspaceID'] = WorkspaceID
retd['Ensure'] = Ensure
return retval, retd
def Set(WorkspaceID, Ensure):
if Ensure == 'Present':
# copy all the required files to the client machine
copy_all_files(CONF_DIR, CONF_PATH)
update_state_dir_path(os.path.join(CONF_PATH, "container.conf"), WorkspaceID)
copy_all_files(PLUGIN_DIR, PLUGIN_PATH)
copy_all_files(LIB_DIR, LIB_PATH)
copy_all_files(REG_DIR, REG_PATH)
check_and_create_yaml(YAML_DIR, YAML_PATH)
elif Ensure == 'Absent':
# and delete CONF file in the directory
delete_all_files(CONF_DIR, CONF_PATH)
else:
# log error Ensure value not expected
LG().Log('ERROR', "Ensure value: " + Ensure + " not expected")
return [-1]
# restart oms agent
if OMS_ACTION.restart_oms_agent(WorkspaceID):
return [0]
else:
return [-1]
def Test(WorkspaceID, Ensure):
"""
Test method for the DSC resoruce
If it returns [0] no further action is taken
If it returns [-1] Set_Marshall is called
"""
# test for the existence of plugin and conf subfolders in the current plugin
if Ensure == 'Present':
# check all files exist
if (not check_all_files(PLUGIN_DIR, PLUGIN_PATH) or not check_all_files(CONF_DIR, CONF_PATH) or not check_all_files(LIB_DIR, LIB_PATH) or not check_all_files(REG_DIR, REG_PATH) or not check_all_files(YAML_DIR, YAML_PATH)):
return [-1]
elif Ensure == 'Absent':
if (check_conf_presence(conf_dir, CONF_PATH)):
return [-1]
else:
# log error Ensure value not expected
LG().Log('ERROR', "Ensure value: " + Ensure + " not expected")
return [-1]
def update_state_dir_path(dest, WorkspaceID):
replace_text = STATE_DIR_PATH.replace('<WorkspaceID>',WorkspaceID)
with open(dest) as f:
s = f.read()
with open(dest, 'w') as f:
s = s.replace('%STATE_DIR_WS%', replace_text)
f.write(s)
def copy_all_files(src, dest):
try:
src_files = os.listdir(src)
for file_name in src_files:
full_file_name = os.path.join(src, file_name)
if (os.path.isfile(full_file_name)):
shutil.copy(full_file_name, dest)
except:
LG().Log('ERROR', 'copy_all_files failed for src: ' + src + ' dest: ' + dest)
return False
def check_conf_presence(src, dest):
src_files = os.listdir(src)
for file_name in src_files:
full_dest_file = os.path.join(dest, file_name)
if os.path.isfile(full_dest_file):
return True
return False
def check_and_create_yaml(src, dest):
try:
src_files = os.listdir(src)
for file_name in src_files:
full_file_name = os.path.join(src, file_name)
if (not os.path.isfile(full_file_name)):
shutil.copy(full_file_name, dest)
os.chmod(os.path.join(dest, file_name), 0644)
os.chown(os.path.join(dest, file_name), GetUID('omsagent'), GetGID('omiusers'))
except:
LG().Log('ERROR', 'copy_all_files failed for src: ' + src + ' dest: ' + dest)
return False
def delete_all_files(src, dest):
try:
src_files = os.listdir(src)
for file_name in src_files:
full_file_name = os.path.join(dest, file_name)
if (os.path.isfile(full_file_name)):
os.remove(full_file_name)
except:
LG().Log('ERROR', 'delete_all_files failed for src: ' + src + ' dest: ' + dest)
return False
def check_all_files(src, dest):
try:
src_files = os.listdir(src)
for file_name in src_files:
full_src_file = os.path.join(src, file_name)
full_dest_file = os.path.join(dest, file_name)
if os.path.isfile(full_dest_file):
if CompareFiles(full_dest_file, full_src_file, "md5") == -1:
return False
else:
return False
return True
except:
LG().Log('ERROR', 'check_all_files failed for src: ' + src + ' dest: ' + dest)
return False
def CompareFiles(DestinationPath, SourcePath, Checksum):
"""
If the files differ in size, return -1.
Reading and computing the hash here is done in a block-by-block manner,
in case the file is quite large.
"""
if SourcePath == DestinationPath: # Files are the same!
return 0
stat_dest = StatFile(DestinationPath)
stat_src = StatFile(SourcePath)
if stat_src.st_size != stat_dest.st_size:
return -1
if Checksum == "md5":
src_error = None
dest_error = None
src_hash = md5const()
dest_hash = md5const()
src_block = 'loopme'
dest_block = 'loopme'
src_file,src_error = opened_bin_w_error(SourcePath, 'rb')
if src_error:
LG().Log('ERROR', "Exception opening source file " + SourcePath + " Error : " + str(src_error))
return -1
dest_file, dest_error = opened_bin_w_error(DestinationPath, 'rb')
if dest_error:
LG().Log('ERROR', "Exception opening destination file " + DestinationPath + " Error : " + str(dest_error))
src_file.close()
return -1
while src_block != '' and dest_block != '':
src_block = src_file.read(BLOCK_SIZE)
dest_block = dest_file.read(BLOCK_SIZE)
src_hash.update(src_block)
dest_hash.update(dest_block)
if src_hash.hexdigest() != dest_hash.hexdigest():
src_file.close()
dest_file.close()
return -1
if src_hash.hexdigest() == dest_hash.hexdigest():
src_file.close()
dest_file.close()
return 0
elif Checksum == "ctime":
if stat_src.st_ctime != stat_dest.st_ctime:
return -1
else:
return 0
elif Checksum == "mtime":
if stat_src.st_mtime != stat_dest.st_mtime:
return -1
else:
return 0
def GetUID(User):
uid = None
try:
uid = pwd.getpwnam(User)[2]
except KeyError:
LG().Log('ERROR', 'ERROR: Unknown UID for ' + User)
return uid
def GetGID(Group):
gid = None
try:
gid = grp.getgrnam(Group)[2]
except KeyError:
LG().Log('ERROR', 'ERROR: Unknown GID for ' + Group)
return gid
def StatFile(path):
"""
Stat the file, following the symlink.
"""
d = None
error = None
try:
d = os.stat(path)
except OSError as error:
LG().Log('ERROR', "Exception stating file " + path + " Error: " + str(error))
except IOError as error:
LG().Log('ERROR', "Exception stating file " + path + " Error: " + str(error))
return d
def opened_bin_w_error(filename, mode='rb'):
"""
This context ensures the file is closed.
"""
try:
f = open(filename, mode)
except IOError, error:
return None, error
return f, None