Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rudimentary windows support for bcfg2 #391

Open
wants to merge 29 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b5ed496
Add basic windows support for bcfg2
chschenk Jul 12, 2017
354df63
Fix PEP-8 Style issues
chschenk Jul 18, 2017
cb7c965
Return extra services in WinService
chschenk Jul 18, 2017
63a45c2
Add import for binary Files
chschenk Jul 18, 2017
7c7990c
Implement a locking mechanism which works on Windows and Linux
chschenk Jul 21, 2017
6c5832d
Readd locked function for bcfg2-server
chschenk Jul 21, 2017
0dc7c3f
Fix Style Issues
chschenk Jul 21, 2017
19f05d5
More Style Fixes
chschenk Jul 21, 2017
1a28369
Fix style issues
chschenk Jul 21, 2017
4c907fe
Fix Error with lambda functions
chschenk Jul 24, 2017
54c0c1e
Use compat to import modules which doesnt exists on windows
chschenk Jul 24, 2017
ef4aea5
Fix more Style Issues
chschenk Jul 24, 2017
a19f5c3
Fix Style Issues
chschenk Jul 24, 2017
ad69ab5
More Style Fixes
chschenk Jul 24, 2017
cdd5a7d
Fix more Style Issues
chschenk Jul 24, 2017
4059e22
Better error handling in Flock class
chschenk Jul 24, 2017
190d785
Fix style and error handling issues
chschenk Jul 24, 2017
2bd891f
In Actions Shell should be False by default
chschenk Aug 8, 2017
c7e9e5a
Add WinFS support for nonexistent path types
chschenk Apr 23, 2018
c40da03
Fixing pylint errors
chschenk Jun 8, 2018
03ad988
Fixing more pylint errors
chschenk Jun 13, 2018
82dd867
Don't use "except as" because it only works in python 2.6 and newer
chschenk Aug 1, 2018
17d8888
Don't use "except as" because it only works in python 2.6 and newer
chschenk Aug 1, 2018
80efd67
Added the "real" logger to locking mechanism
chschenk Sep 20, 2018
febfafd
Added missing import for python3 compatibility
chschenk Sep 20, 2018
460979c
Fixing exception Handling for Python 2.4
chschenk Sep 25, 2018
73adee8
Fixing exception Handling for Python 2.4
chschenk Sep 25, 2018
ebc546d
Disable pylint W0622 in WinFS.py like in POSIX/File.py
chschenk Sep 25, 2018
8815e8f
Added missing space to comment
chschenk Sep 25, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 48 additions & 47 deletions src/lib/Bcfg2/Client/Tools/WinFS.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,24 @@ def __init__(self, config):
Bcfg2.Client.Tools.Tool.__init__(self, config)
self.__req__ = dict(Path=dict())
self.__req__['Path']['file'] = ['name', 'mode', 'owner', 'group']

def _getFilePath(self, entry):
filePath = os.path.expandvars(os.path.normpath(entry.get('name')[1:]))
if(not filePath[1] == ':'):
self.logger.info("Skipping \"%s\" because it doesnt look like a Windows Path" % filePath)
"""Evaluates the enviroment Variables and returns the file path"""
file_path = os.path.expandvars(os.path.normpath(entry.get('name')[1:]))
if(not file_path[1] == ':'):
self.logger.info(
"Skipping \"%s\" because it doesnt look like a Windows Path" %
file_path)
return False
return filePath
return file_path

def VerifyPath(self, entry, _):
"""Path always verify true."""
filePath = self._getFilePath(entry)
if(not filePath):
file_path = self._getFilePath(entry)
if(not file_path):
return False
ondisk = self._exists(filePath)
tempdata, is_binary = self._get_data(entry)
ondisk = self._exists(file_path)
tempdata = self._get_data(entry)[0]
if isinstance(tempdata, str) and str != unicode:
tempdatasize = len(tempdata)
else:
Expand All @@ -53,45 +56,39 @@ def VerifyPath(self, entry, _):
# which might be faster for big binary files, but slower
# for everything else
try:
content = open(filePath).read()
content = open(file_path).read()
except UnicodeDecodeError:
content = open(filePath,
content = open(file_path,
encoding=Bcfg2.Options.setup.encoding).read()
except IOError:
self.logger.error("Windows: Failed to read %s: %s" %
(filePath, sys.exc_info()[1]))
(file_path, sys.exc_info()[1]))
return False
different = str(content) != str(tempdata)
return not different

def InstallPath(self, entry):
"""Install device entries."""
filePath = self._getFilePath(entry)
file_path = self._getFilePath(entry)

if not filePath:
if not file_path:
return False
self.logger.debug("Installing: " + filePath)
if not os.path.exists(os.path.dirname(filePath)):
if not self._makedirs(path=filePath):

self.logger.debug("Installing: " + file_path)
if not os.path.exists(os.path.dirname(file_path)):
if not self._makedirs(path=file_path):
return False
newfile = self._write_tmpfile(entry, filePath)
newfile = self._write_tmpfile(entry, file_path)
if not newfile:
return False
rv = True
if not self._rename_tmpfile(newfile, filePath):
if not self._rename_tmpfile(newfile, file_path):
return False

return rv

def _makedirs(self, path):
""" os.makedirs helpfully creates all parent directories for us."""
created = []
cur = path
#while cur and cur != '/':
# if not os.path.exists(cur):
# created.append(cur)
# cur = os.path.dirname(cur)
rv = True
try:
os.makedirs(os.path.dirname(path))
Expand All @@ -102,7 +99,7 @@ def _makedirs(self, path):
rv = False
return rv

def _write_tmpfile(self, entry, filePath):
def _write_tmpfile(self, entry, file_path):
""" Write the file data to a temp file """
filedata = self._get_data(entry)[0]
# get a temp file to write to that is in the same directory as
Expand All @@ -112,11 +109,12 @@ def _write_tmpfile(self, entry, filePath):
# be setuid
try:
(newfd, newfile) = \
tempfile.mkstemp(prefix=os.path.basename(filePath),
dir=os.path.dirname(filePath))
tempfile.mkstemp(prefix=os.path.basename(file_path),
dir=os.path.dirname(file_path))
except OSError:
err = sys.exc_info()[1]
self.logger.error("Windows: Failed to create temp file in %s: %s" % (filePath, err))
self.logger.error(
"Windows: Failed to create temp file in %s: %s" % (file_path, err))
return False
try:
if isinstance(filedata, str) and str != unicode:
Expand All @@ -126,9 +124,10 @@ def _write_tmpfile(self, entry, filePath):
filedata.encode(Bcfg2.Options.setup.encoding))
except (OSError, IOError):
err = sys.exc_info()[1]
self.logger.error("Windows: Failed to open temp file %s for writing "
"%s: %s" %
(newfile, filePath, err))
self.logger.error(
"Windows: Failed to open temp file %s for writing "
"%s: %s" %
(newfile, file_path, err))
return False
return newfile

Expand All @@ -149,30 +148,32 @@ def _get_data(self, entry):
self.logger.error("Windows: Error encoding file %s: %s" %
(entry.get('name'), err))
return (tempdata, is_binary)
def _rename_tmpfile(self, newfile, filePath):

def _rename_tmpfile(self, newfile, file_path):
""" Rename the given file to the appropriate filename for entry """
try:
if(os.path.isfile(filePath)):
os.unlink(filePath)
os.rename(newfile, filePath)
if(os.path.isfile(file_path)):
os.unlink(file_path)
os.rename(newfile, file_path)
return True
except OSError:
err = sys.exc_info()[1]
self.logger.error("Windows: Failed to rename temp file %s to %s: %s"
% (newfile, filePath, err))
self.logger.error(
"Windows: Failed to rename temp file %s to %s: %s"
% (newfile, file_path, err))
try:
os.unlink(newfile)
except OSError:
err = sys.exc_info()[1]
self.logger.error("Windows: Could not remove temp file %s: %s" %
(newfile, err))
self.logger.error(
"Windows: Could not remove temp file %s: %s" %
(newfile, err))
return False
def _exists(self, filePath):

def _exists(self, file_path):
""" check for existing paths and optionally remove them. if
the path exists, return the lstat of it """
try:
return os.lstat(filePath)
return os.lstat(file_path)
except OSError:
return None
23 changes: 10 additions & 13 deletions src/lib/Bcfg2/Client/Tools/WinService.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"""WinService support for Bcfg2."""

import glob
import re
import subprocess

import Bcfg2.Client.Tools
Expand All @@ -18,17 +16,11 @@ def get_svc_command(self, service, action):
return "powershell.exe %s-Service %s" % (action, service.get('name'))

def VerifyService(self, entry, _):
"""Verify Service status for entry
"""
"""Verify Service status for entry"""

if entry.get('status') == 'ignore':
return True

if entry.get('parameters'):
params = entry.get('parameters')
else:
params = ''

try:
output = self.cmd.run('powershell.exe (Get-Service %s).Status' %
(entry.get('name')),
Expand All @@ -40,7 +32,6 @@ def VerifyService(self, entry, _):
entry.get('name'))
return False


if output is None:
# service does not exist
entry.set('current_status', 'off')
Expand Down Expand Up @@ -68,8 +59,11 @@ def InstallService(self, entry):
cmd = "start"
elif entry.get('status') == 'off':
cmd = "stop"
return self.cmd.run(self.get_svc_command(entry, cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False).success

return self.cmd.run(self.get_svc_command(entry, cmd),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=False).success

def restart_service(self, service):
"""Restart a service.

Expand All @@ -80,7 +74,10 @@ def restart_service(self, service):
"""
self.logger.debug('Restarting service %s' % service.get('name'))
restart_target = service.get('target', 'restart')
return self.cmd.run(self.get_svc_command(service, restart_target), stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False)
return self.cmd.run(self.get_svc_command(service, restart_target),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=False)

def FindExtra(self):
"""Locate extra Windows services."""
Expand Down
3 changes: 2 additions & 1 deletion src/lib/Bcfg2/Client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,8 @@ def run_probe(self, probe):
try:
fileending = ''
if os.name == 'nt':
(interpreter, fileending) = probe.attrib.get('interpreter').split('*')
(interpreter, fileending) =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a \ missing at the end of the line.

probe.attrib.get('interpreter').split('*')
scripthandle, scriptname = tempfile.mkstemp(suffix = fileending)
if sys.hexversion >= 0x03000000:
script = os.fdopen(scripthandle, 'w',
Expand Down
10 changes: 5 additions & 5 deletions src/lib/Bcfg2/Utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,24 +86,24 @@ def __str__(self):
return "[%s]" % self.str


def locked(file):
def locked(file_path):
""" Acquire a lock on a file.

:param file: The path to the lockfile
:param file_path: The path to the lockfile
:type fd: string
:returns: bool - True if the file is already locked, False
otherwise """
if os.name == 'nt':
if (os.path.isfile(file)):
if (os.path.isfile(file_path)):
return True
try:
lockfile = open(file, 'w')
lockfile = open(file_path, 'w')
lockfile.write(str(os.getpid()))
except IOError:
return True
return False
else:
lockfile = open(file, 'w')
lockfile = open(file_path, 'w')
try:
fcntl.lockf(lockfile.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
Expand Down