summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/server/plugins/connectors/properties.txt39
-rw-r--r--man/bcfg2-admin.82
-rw-r--r--man/bcfg2-build-reports.82
-rw-r--r--man/bcfg2-crypt.812
-rw-r--r--man/bcfg2-info.82
-rw-r--r--man/bcfg2-lint.82
-rw-r--r--man/bcfg2-lint.conf.52
-rw-r--r--man/bcfg2-reports.82
-rw-r--r--man/bcfg2-server.82
-rw-r--r--man/bcfg2.12
-rw-r--r--man/bcfg2.conf.52
-rw-r--r--src/lib/Bcfg2/Client/Frame.py8
-rw-r--r--src/lib/Bcfg2/Options.py17
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Properties.py12
-rwxr-xr-xsrc/sbin/bcfg2-crypt174
-rwxr-xr-xsrc/sbin/bcfg2-info38
-rw-r--r--tools/manpagegen/bcfg2-crypt.8.ronn10
17 files changed, 235 insertions, 93 deletions
diff --git a/doc/server/plugins/connectors/properties.txt b/doc/server/plugins/connectors/properties.txt
index b56c2a488..9e1100610 100644
--- a/doc/server/plugins/connectors/properties.txt
+++ b/doc/server/plugins/connectors/properties.txt
@@ -89,11 +89,12 @@ Automatch
.. versionadded:: 1.3.0
-You can enable ``XMLMatch()`` for all Property files by setting
-``automatch`` to ``true`` in the ``[properties]`` section of
-``bcfg2.conf``. This makes ``metadata.Properties`` values
-lxml.etree._Element objects that contain only matching data. (This
-makes it impossible to do
+You can enable
+:func:`Bcfg2.Server.Plugins.Properties.PropertyFile.XMLMatch()` for
+all Property files by setting ``automatch`` to ``true`` in the
+``[properties]`` section of ``bcfg2.conf``. This makes
+``metadata.Properties`` values :class:`lxml.etree._Element` objects
+that contain only matching data. (This makes it impossible to do
:ref:`server-plugins-connectors-properties-write-back` as a
side-effect.)
@@ -114,7 +115,30 @@ simply::
%}
You can also enable automatch for individual Property files by setting
-the attribute ``automatch="true"`` in the top-level ``<Property>`` tag.
+the attribute ``automatch="true"`` on the top-level ``<Property>``
+tag. Conversely, if automatch is enabled by default in
+``bcfg2.conf``, you can disable it for an individual Property file by
+setting ``automatch="false"`` on the top-level ``<Property>`` tag.
+
+If you want to see what ``XMLMatch()``/automatch would produce for a
+given client on a given Properties file, you can use :ref:`bcfg2-info
+<server-bcfg2-info>`::
+
+ bcfg2-info automatch props.xml foo.example.com
+
+If automatch is not enabled, you can force ``bcfg2-info`` to perform
+it anyway with ``-f``::
+
+ bcfg2-info automatch -f props.xml foo.example.com
+
+.. note::
+
+ Be sure to notice that enabling automatch changes the type of the
+ data in ``metadata.Properties``; with automatch disabled, the
+ values of the ``metadata.Properties`` dict are
+ :class:`Bcfg2.Server.Plugins.Properties.PropertyFile` objects.
+ With automatch enabled, they are :class:`lxml.etree._Element`
+ objects.
.. _server-plugins-connectors-properties-write-back:
@@ -124,7 +148,8 @@ Writing to Properties files
.. versionadded:: 1.2.0
If you need to make persistent changes to properties data, you can use
-the ``write`` method of the ``PropertyFile`` class::
+the ``write`` method of the
+:class:`Bcfg2.Server.Plugins.Properties.PropertyFile` class::
{% python
import lxml.etree
diff --git a/man/bcfg2-admin.8 b/man/bcfg2-admin.8
index bed51ff9a..e5bcc55f3 100644
--- a/man/bcfg2-admin.8
+++ b/man/bcfg2-admin.8
@@ -1,5 +1,5 @@
.
-.TH "BCFG2\-ADMIN" "8" "August 2012" "" ""
+.TH "BCFG2\-ADMIN" "8" "September 2012" "" ""
.
.SH "NAME"
\fBbcfg2\-admin\fR \- Perform repository administration tasks
diff --git a/man/bcfg2-build-reports.8 b/man/bcfg2-build-reports.8
index 3c61e8356..55aff8b31 100644
--- a/man/bcfg2-build-reports.8
+++ b/man/bcfg2-build-reports.8
@@ -1,5 +1,5 @@
.
-.TH "BCFG2\-BUILD\-REPORTS" "8" "August 2012" "" ""
+.TH "BCFG2\-BUILD\-REPORTS" "8" "September 2012" "" ""
.
.SH "NAME"
\fBbcfg2\-build\-reports\fR \- Generate state reports for Bcfg2 clients
diff --git a/man/bcfg2-crypt.8 b/man/bcfg2-crypt.8
index a73f3e066..64c10a902 100644
--- a/man/bcfg2-crypt.8
+++ b/man/bcfg2-crypt.8
@@ -1,11 +1,11 @@
.
-.TH "BCFG2\-CRYPT" "8" "August 2012" "" ""
+.TH "BCFG2\-CRYPT" "8" "September 2012" "" ""
.
.SH "NAME"
\fBbcfg2\-crypt\fR \- Bcfg2 encryption and decryption utility
.
.SH "SYNOPSIS"
-\fBbcfg2\-crypt\fR [\fI\-C configfile\fR] [\-\-decrypt|\-\-encrypt] [\-\-cfg|\-\-properties] [\-\-remove] [\-\-xpath \fIxpath\fR] [\-p \fIpassphrase\-or\-name\fR] [\-v] \fIfilename\fR [\fIfilename\fR\.\.\.]
+\fBbcfg2\-crypt\fR [\fI\-C configfile\fR] [\-\-decrypt|\-\-encrypt] [\-\-cfg|\-\-properties] [\-\-stdout] [\-\-remove] [\-\-xpath \fIxpath\fR] [\-p \fIpassphrase\-or\-name\fR] [\-v] [\-I] \fIfilename\fR [\fIfilename\fR\.\.\.]
.
.SH "DESCRIPTION"
\fBbcfg2\-crypt\fR performs encryption and decryption of Cfg and Properties files\. It\'s often sufficient to run \fBbcfg2\-crypt\fR with only the name of the file you wish to encrypt or decrypt; it can usually figure out what to do\.
@@ -29,6 +29,10 @@ Tell \fBbcfg2\-crypt\fR that an XML file should be encrypted in its entirety rat
Tell \fBbcfg2\-crypt\fR to process a file as an XML Properties file, and encrypt the text of each element separately\. This is necessary if, for example, you\'ve used a different top\-level tag than \fB<Properties>\fR in your Properties files\. See \fIMODES\fR below for details\.
.
.TP
+\fB\-\-stdout\fR
+Print the resulting file to stdout instead of writing it to a file\.
+.
+.TP
\fB\-\-remove\fR
Remove the plaintext file after it has been encrypted\. Only meaningful for Cfg files\.
.
@@ -45,6 +49,10 @@ Specify the name of a passphrase specified in the \fB[encryption]\fR section of
Be verbose\.
.
.TP
+\fB\-I\fR
+When encrypting a Properties file, interactively select the elements whose data should be encrypted\.
+.
+.TP
\fB\-h\fR
Display help and exit\.
.
diff --git a/man/bcfg2-info.8 b/man/bcfg2-info.8
index bb515079f..9362776a1 100644
--- a/man/bcfg2-info.8
+++ b/man/bcfg2-info.8
@@ -1,5 +1,5 @@
.
-.TH "BCFG2\-INFO" "8" "August 2012" "" ""
+.TH "BCFG2\-INFO" "8" "September 2012" "" ""
.
.SH "NAME"
\fBbcfg2\-info\fR \- Creates a local version of the Bcfg2 server core for state observation
diff --git a/man/bcfg2-lint.8 b/man/bcfg2-lint.8
index 7a5a69b7a..a6bfffb8a 100644
--- a/man/bcfg2-lint.8
+++ b/man/bcfg2-lint.8
@@ -1,5 +1,5 @@
.
-.TH "BCFG2\-LINT" "8" "August 2012" "" ""
+.TH "BCFG2\-LINT" "8" "September 2012" "" ""
.
.SH "NAME"
\fBbcfg2\-lint\fR \- Check Bcfg2 specification for validity, common mistakes, and style
diff --git a/man/bcfg2-lint.conf.5 b/man/bcfg2-lint.conf.5
index d23afa8dc..55dfa5cc2 100644
--- a/man/bcfg2-lint.conf.5
+++ b/man/bcfg2-lint.conf.5
@@ -1,5 +1,5 @@
.
-.TH "BCFG2\-LINT\.CONF" "5" "August 2012" "" ""
+.TH "BCFG2\-LINT\.CONF" "5" "September 2012" "" ""
.
.SH "NAME"
\fBbcfg2\-lint\.conf\fR \- configuration parameters for bcfg2\-lint
diff --git a/man/bcfg2-reports.8 b/man/bcfg2-reports.8
index b2c0cad43..78b594047 100644
--- a/man/bcfg2-reports.8
+++ b/man/bcfg2-reports.8
@@ -1,5 +1,5 @@
.
-.TH "BCFG2\-REPORTS" "8" "August 2012" "" ""
+.TH "BCFG2\-REPORTS" "8" "September 2012" "" ""
.
.SH "NAME"
\fBbcfg2\-reports\fR \- Query reporting system for client status
diff --git a/man/bcfg2-server.8 b/man/bcfg2-server.8
index 955f541c9..7bbfb87c3 100644
--- a/man/bcfg2-server.8
+++ b/man/bcfg2-server.8
@@ -1,5 +1,5 @@
.
-.TH "BCFG2\-SERVER" "8" "August 2012" "" ""
+.TH "BCFG2\-SERVER" "8" "September 2012" "" ""
.
.SH "NAME"
\fBbcfg2\-server\fR \- Server for client configuration specifications
diff --git a/man/bcfg2.1 b/man/bcfg2.1
index 2aa219756..231155797 100644
--- a/man/bcfg2.1
+++ b/man/bcfg2.1
@@ -1,5 +1,5 @@
.
-.TH "BCFG2" "1" "August 2012" "" ""
+.TH "BCFG2" "1" "September 2012" "" ""
.
.SH "NAME"
\fBbcfg2\fR \- Bcfg2 client tool
diff --git a/man/bcfg2.conf.5 b/man/bcfg2.conf.5
index b62d223c9..c7f8bf4ed 100644
--- a/man/bcfg2.conf.5
+++ b/man/bcfg2.conf.5
@@ -1,5 +1,5 @@
.
-.TH "BCFG2\.CONF" "5" "August 2012" "" ""
+.TH "BCFG2\.CONF" "5" "September 2012" "" ""
.
.SH "NAME"
\fBbcfg2\.conf\fR \- configuration parameters for Bcfg2
diff --git a/src/lib/Bcfg2/Client/Frame.py b/src/lib/Bcfg2/Client/Frame.py
index 508e3b616..2fb81d6ba 100644
--- a/src/lib/Bcfg2/Client/Frame.py
+++ b/src/lib/Bcfg2/Client/Frame.py
@@ -7,6 +7,7 @@ import logging
import sys
import time
import Bcfg2.Client.Tools
+from Bcfg2.Compat import input
def cmpent(ent1, ent2):
@@ -150,12 +151,7 @@ class Frame(object):
else:
iprompt = prompt % (entry.tag, entry.get('name'))
try:
- # py3k compatibility
- try:
- ans = raw_input(iprompt.encode(sys.stdout.encoding,
- 'replace'))
- except NameError:
- ans = input(iprompt)
+ ans = input(iprompt.encode(sys.stdout.encoding, 'replace'))
if ans in ['y', 'Y']:
ret.append(entry)
except EOFError:
diff --git a/src/lib/Bcfg2/Options.py b/src/lib/Bcfg2/Options.py
index 34f4b2bc6..6ac9cafb1 100644
--- a/src/lib/Bcfg2/Options.py
+++ b/src/lib/Bcfg2/Options.py
@@ -21,9 +21,9 @@ DEFAULT_INSTALL_PREFIX = '/usr'
class DefaultConfigParser(ConfigParser.ConfigParser):
- def __init__(self,*args,**kwargs):
+ def __init__(self, *args, **kwargs):
"""Make configuration options case sensitive"""
- ConfigParser.ConfigParser.__init__(self,*args,**kwargs)
+ ConfigParser.ConfigParser.__init__(self, *args, **kwargs)
self.optionxform = str
def get(self, section, option, **kwargs):
@@ -100,7 +100,7 @@ class Option(object):
rv.append("%s %s" % (self.cmd, self.odesc))
else:
rv.append("%s" % self.cmd)
-
+
if self.cf:
if self.cmd:
rv.append("; ")
@@ -175,9 +175,10 @@ class Option(object):
% (self.deprecated_cf[0], self.deprecated_cf[1],
self.cf[0], self.cf[1]))
return
- except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+ except (ConfigParser.NoSectionError,
+ ConfigParser.NoOptionError):
pass
-
+
# Default value not cooked
self.value = self.default
@@ -907,8 +908,8 @@ DECRYPT = \
default=False,
cmd='--decrypt',
long_arg=True)
-DECRYPT_STDOUT = \
- Option('Decrypt the specified file to stdout',
+CRYPT_STDOUT = \
+ Option('Decrypt or encrypt the specified file to stdout',
default=False,
cmd='--stdout',
long_arg=True)
@@ -968,7 +969,7 @@ SERVER_COMMON_OPTIONS = dict(repo=SERVER_REPOSITORY,
CRYPT_OPTIONS = dict(encrypt=ENCRYPT,
decrypt=DECRYPT,
- decrypt_stdout=DECRYPT_STDOUT,
+ crypt_stdout=CRYPT_STDOUT,
passphrase=CRYPT_PASSPHRASE,
xpath=CRYPT_XPATH,
properties=CRYPT_PROPERTIES,
diff --git a/src/lib/Bcfg2/Server/Plugins/Properties.py b/src/lib/Bcfg2/Server/Plugins/Properties.py
index 49500e915..1b925ce46 100644
--- a/src/lib/Bcfg2/Server/Plugins/Properties.py
+++ b/src/lib/Bcfg2/Server/Plugins/Properties.py
@@ -16,6 +16,7 @@ logger = logging.getLogger(__name__)
SETUP = None
+
class PropertyFile(Bcfg2.Server.Plugin.StructFile):
"""Class for properties files."""
def write(self):
@@ -124,12 +125,15 @@ class Properties(Bcfg2.Server.Plugin.Plugin,
SETUP = core.setup
def get_additional_data(self, metadata):
- autowatch = self.core.setup.cfp.getboolean("properties", "automatch",
- default=False)
+ if self.core.setup.cfp.getboolean("properties", "automatch",
+ default=False):
+ default_automatch = "true"
+ else:
+ default_automatch = "false"
rv = dict()
for fname, pfile in self.store.entries.items():
- if (autowatch or
- pfile.xdata.get("automatch", "false").lower() == "true"):
+ if pfile.xdata.get("automatch",
+ default_automatch).lower() == "true":
rv[fname] = pfile.XMLMatch(metadata)
else:
rv[fname] = copy.copy(pfile)
diff --git a/src/sbin/bcfg2-crypt b/src/sbin/bcfg2-crypt
index cb1b956fb..1af1771cf 100755
--- a/src/sbin/bcfg2-crypt
+++ b/src/sbin/bcfg2-crypt
@@ -3,16 +3,18 @@
import os
import sys
+import copy
import logging
import lxml.etree
import Bcfg2.Logger
import Bcfg2.Options
+from Bcfg2.Server import XMLParser
+from Bcfg2.Compat import input
try:
import Bcfg2.Encryption
except ImportError:
err = sys.exc_info()[1]
- print("Import failed '%s'. Is M2Crypto installed?" %
- err)
+ print("Could not import %s. Is M2Crypto installed?" % err)
raise SystemExit(1)
LOGGER = None
@@ -103,7 +105,8 @@ class Encryptor(object):
self.logger.error("Error reading %s, skipping: %s" % (fname, err))
return False
- self.set_passphrase()
+ if not self.set_passphrase():
+ return False
crypted = []
try:
@@ -119,22 +122,7 @@ class Encryptor(object):
self.logger.error("Error getting data to encrypt from %s: %s" %
(fname, err))
return False
-
- new_fname = self.get_encrypted_filename(fname)
- try:
- open(new_fname, "wb").write(self.unchunk(crypted, plaintext))
- self.logger.info("Wrote encrypted data to %s" % new_fname)
- return True
- except IOError:
- err = sys.exc_info()[1]
- self.logger.error("Error writing encrypted data from %s to %s: %s" %
- (fname, new_fname, err))
- return False
- except EncryptionChunkingError:
- err = sys.exc_info()[1]
- self.logger.error("Error assembling encrypted data from %s: %s" %
- (fname, err))
- return False
+ return self.unchunk(crypted, plaintext)
def _encrypt(self, plaintext, passphrase, name=None):
return Bcfg2.Encryption.ssl_encrypt(plaintext, passphrase)
@@ -200,6 +188,25 @@ class Encryptor(object):
(fname, err))
return False
+ def write_encrypted(self, fname, data=None):
+ if data is None:
+ data = self.decrypt(fname)
+ new_fname = self.get_encrypted_filename(fname)
+ try:
+ open(new_fname, "wb").write(data)
+ self.logger.info("Wrote encrypted data to %s" % new_fname)
+ return True
+ except IOError:
+ err = sys.exc_info()[1]
+ self.logger.error("Error writing encrypted data from %s to %s: %s" %
+ (fname, new_fname, err))
+ return False
+ except EncryptionChunkingError:
+ err = sys.exc_info()[1]
+ self.logger.error("Error assembling encrypted data from %s: %s" %
+ (fname, err))
+ return False
+
def write_decrypted(self, fname, data=None):
if data is None:
data = self.decrypt(fname)
@@ -262,12 +269,12 @@ class PropertiesEncryptor(Encryptor):
name = "true"
if plaintext.text and plaintext.text.strip():
plaintext.text = Bcfg2.Encryption.ssl_encrypt(plaintext.text,
- passphrase)
+ passphrase).strip()
plaintext.set("encrypted", name)
return plaintext
def chunk(self, data):
- xdata = lxml.etree.XML(data)
+ xdata = lxml.etree.XML(data, parser=XMLParser)
if self.setup['xpath']:
elements = xdata.xpath(self.setup['xpath'])
if not elements:
@@ -276,7 +283,28 @@ class PropertiesEncryptor(Encryptor):
else:
elements = xdata.xpath('//*[@encrypted]')
if not elements:
- elements = list(xdata.getiterator())
+ elements = list(xdata.getiterator(tag=lxml.etree.Element))
+
+ # filter out elements without text data
+ for el in elements[:]:
+ if not el.text:
+ elements.remove(el)
+
+ if self.setup['interactive']:
+ for element in elements[:]:
+ if len(element):
+ elt = copy.copy(element)
+ for child in elt.iterchildren():
+ elt.remove(child)
+ else:
+ elt = element
+ print(lxml.etree.tostring(
+ elt,
+ xml_declaration=False).decode("UTF-8").strip())
+ ans = input("Encrypt this element? [y/N] ")
+ if not ans.lower().startswith("y"):
+ elements.remove(element)
+
# this is not a good use of a generator, but we need to
# generate the full list of elements in order to ensure that
# some exist before we know what to return
@@ -291,7 +319,9 @@ class PropertiesEncryptor(Encryptor):
while xdata.getparent() != None:
xdata = xdata.getparent()
xdata.set("encryption", "true")
- return lxml.etree.tostring(xdata, xml_declaration=False).decode('UTF-8')
+ return lxml.etree.tostring(xdata,
+ xml_declaration=False,
+ pretty_print=True).decode('UTF-8')
def _get_passphrase(self, chunk):
pname = chunk.get("encrypted") or chunk.get("encryption")
@@ -304,13 +334,13 @@ class PropertiesEncryptor(Encryptor):
if not crypted.text or not crypted.text.strip():
self.logger.warning("Skipping empty element %s" % crypted.tag)
return crypted
- rv = Bcfg2.Encryption.ssl_decrypt(crypted.text, passphrase)
- crypted.text = rv
+ crypted.text = Bcfg2.Encryption.ssl_decrypt(crypted.text,
+ passphrase).strip()
return crypted
def main():
- optinfo = dict()
+ optinfo = dict(interactive=Bcfg2.Options.INTERACTIVE)
optinfo.update(Bcfg2.Options.CRYPT_OPTIONS)
optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS)
setup = Bcfg2.Options.OptionParser(optinfo)
@@ -321,18 +351,33 @@ def main():
if not setup['args']:
print(setup.hm)
raise SystemExit(1)
- elif setup['encrypt'] and (setup['decrypt_stdout'] or setup['decrypt']):
- print("You cannot specify both --encrypt and --decrypt or --stdout")
- raise SystemExit(1)
- elif setup['cfg'] and setup['properties']:
- print("You cannot specify both --cfg and --properties")
- raise SystemExit(1)
- elif setup['cfg'] and setup['properties']:
- print("Specifying --xpath with --cfg is nonsensical, ignoring --xpath")
- setup['xpath'] = Bcfg2.Options.CRYPT_XPATH.default
- elif setup['decrypt'] and setup['remove']:
- print("--remove cannot be used with --decrypt, ignoring")
- setup['remove'] = Bcfg2.Options.CRYPT_REMOVE.default
+
+ if setup['decrypt']:
+ if setup['encrypt']:
+ print("You cannot specify both --encrypt and --decrypt")
+ raise SystemExit(1)
+ elif setup['remove']:
+ print("--remove cannot be used with --decrypt, ignoring")
+ setup['remove'] = Bcfg2.Options.CRYPT_REMOVE.default
+ elif setup['interactive']:
+ print("Cannot decrypt interactively")
+ setup['interactive'] = False
+
+ if setup['cfg']:
+ if setup['properties']:
+ print("You cannot specify both --cfg and --properties")
+ raise SystemExit(1)
+ if setup['xpath']:
+ print("Specifying --xpath with --cfg is nonsensical, ignoring "
+ "--xpath")
+ setup['xpath'] = Bcfg2.Options.CRYPT_XPATH.default
+ if setup['interactive']:
+ print("You cannot use interactive mode with --cfg, ignoring -I")
+ setup['interactive'] = False
+ elif setup['properties']:
+ if setup['remove']:
+ print("--remove cannot be used with --properties, ignoring")
+ setup['remove'] = Bcfg2.Options.CRYPT_REMOVE.default
logger = get_logger(setup['verbose'])
@@ -369,32 +414,49 @@ def main():
if props:
encryptor = props_crypt
+ if setup['remove']:
+ logger.info("Cannot use --remove with Properties file %s, "
+ "ignoring for this file" % fname)
else:
+ if setup['xpath']:
+ logger.info("Cannot use xpath with Cfg file %s, ignoring xpath "
+ "for this file" % fname)
+ if setup['interactive']:
+ logger.info("Cannot use interactive mode with Cfg file %s, "
+ "ignoring -I for this file" % fname)
encryptor = cfg_crypt
+ data = None
if setup['encrypt']:
- if not encryptor.encrypt(fname):
- print("Failed to encrypt %s, skipping" % fname)
- elif setup['decrypt'] or setup['decrypt_stdout']:
- data = encryptor.decrypt(fname)
- if not data:
- print("Failed to decrypt %s, skipping" % fname)
- continue
- if setup['decrypt_stdout']:
- if len(setup['args']) > 1:
- print("----- %s -----" % fname)
- print(data)
- if len(setup['args']) > 1:
- print("")
- else:
- encryptor.write_decrypted(fname, data=data)
+ xform = encryptor.encrypt
+ write = encryptor.write_encrypted
+ elif setup['decrypt']:
+ xform = encryptor.decrypt
+ write = encryptor.write_decrypted
else:
logger.info("Neither --encrypt nor --decrypt specified, "
"determining mode")
- if not encryptor.decrypt(fname):
+ data = encryptor.decrypt(fname)
+ if data:
+ write = encryptor.write_decrypted
+ else:
logger.info("Failed to decrypt %s, trying encryption" % fname)
- if not encryptor.encrypt(fname):
- print("Failed to encrypt %s, skipping" % fname)
+ data = None
+ xform = encryptor.encrypt
+ write = encryptor.write_encrypted
+
+ if data is None:
+ data = xform(fname)
+ if not data:
+ print("Failed to %s %s, skipping" % (xform.__name__, fname))
+ if setup['crypt_stdout']:
+ if len(setup['args']) > 1:
+ print("----- %s -----" % fname)
+ print(data)
+ if len(setup['args']) > 1:
+ print("")
+ else:
+ write(fname, data=data)
if setup['remove'] and encryptor.get_encrypted_filename(fname) != fname:
try:
diff --git a/src/sbin/bcfg2-info b/src/sbin/bcfg2-info
index 9ee02fd71..95a18b608 100755
--- a/src/sbin/bcfg2-info
+++ b/src/sbin/bcfg2-info
@@ -42,6 +42,7 @@ buildall <directory> [<hostnames*>] - Build configs for all clients in directory
buildallfile <directory> <filename> [<hostnames*>] - Build config file for all clients in directory
buildfile <filename> <hostname> - Build config file for hostname (not written to disk)
buildbundle <bundle> <hostname> - Render a templated bundle for hostname (not written to disk)
+automatch <propertyfile> <hostname> - Perform automatch on a Properties file
bundles - Print out group/bundle information
clients - Print out client/profile information
config - Print out the configuration of the Bcfg2 server
@@ -427,6 +428,43 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.BaseCore):
else:
print('Usage: buildbundle filename hostname')
+ def do_automatch(self, args):
+ alist = args.split()
+ force = False
+ for arg in alist:
+ if arg == '-f':
+ alist.remove('-f')
+ force = True
+ if len(alist) != 2:
+ print("Usage: automatch [-f] <propertiesfile> <hostname>")
+ return
+
+ if 'Properties' not in self.plugins:
+ print("Properties plugin not enabled")
+ return
+
+ pname, client = alist
+ try:
+ automatch = self.setup.cfp.getboolean("properties",
+ "automatch",
+ default=False)
+
+ pfile = self.plugins['Properties'].store.entries[pname]
+ if (not force and
+ not automatch and
+ pfile.xdata.get("automatch", "false").lower() != "true"):
+ print("Automatch not enabled on %s" % pname)
+ else:
+ metadata = self.build_metadata(client)
+ print(lxml.etree.tostring(pfile.XMLMatch(metadata),
+ xml_declaration=False,
+ pretty_print=True).decode('UTF-8'))
+ except:
+ err = sys.exc_info()[1]
+ print("Failed to automatch %s for host %s: %s" % (pname,
+ client,
+ err))
+
def do_bundles(self, _):
"""Print out group/bundle info."""
data = [('Group', 'Bundles')]
diff --git a/tools/manpagegen/bcfg2-crypt.8.ronn b/tools/manpagegen/bcfg2-crypt.8.ronn
index a164d47f1..64077ec3b 100644
--- a/tools/manpagegen/bcfg2-crypt.8.ronn
+++ b/tools/manpagegen/bcfg2-crypt.8.ronn
@@ -3,7 +3,7 @@ bcfg2-crypt(8) -- Bcfg2 encryption and decryption utility
## SYNOPSIS
-`bcfg2-crypt` [<-C configfile>] [--decrypt|--encrypt] [--cfg|--properties] [--remove] [--xpath <xpath>] [-p <passphrase-or-name>] [-v] <filename> [<filename>...]
+`bcfg2-crypt` [<-C configfile>] [--decrypt|--encrypt] [--cfg|--properties] [--stdout] [--remove] [--xpath <xpath>] [-p <passphrase-or-name>] [-v] [-I] <filename> [<filename>...]
## DESCRIPTION
@@ -35,6 +35,10 @@ what to do.
than `<Properties>` in your Properties files. See [MODES] below
for details.
+ * `--stdout`:
+ Print the resulting file to stdout instead of writing it to a
+ file.
+
* `--remove`:
Remove the plaintext file after it has been encrypted. Only
meaningful for Cfg files.
@@ -53,6 +57,10 @@ what to do.
* `-v`:
Be verbose.
+ * `-I`:
+ When encrypting a Properties file, interactively select the
+ elements whose data should be encrypted.
+
* `-h`:
Display help and exit.