i should commit this.

This commit is contained in:
brent s. 2018-05-24 08:24:46 -04:00
parent b134ee67bd
commit 9f74e97c45
7 changed files with 1076 additions and 369 deletions

View File

@ -3,9 +3,247 @@
targetNamespace="http://bdisk.square-r00t.net/" targetNamespace="http://bdisk.square-r00t.net/"
xmlns="http://bdisk.square-r00t.net/" xmlns="http://bdisk.square-r00t.net/"
elementFormDefault="qualified"> elementFormDefault="qualified">

<!-- CUSTOM TYPES -->
<!-- t_btag_uri: a string that will allow btags (xpath or variable only) or a URI string (but NOT a URN). -->
<!-- We can't use xs:anyURI because it is too loose (allows things like relative paths, etc.) -->
<!-- but ALSO too restrictive in that btags fail validation ({ and } are invalid for anyURI, -->
<!-- ironically). -->
<xs:simpleType name="t_btag_uri">
<xs:restriction base="xs:string">
<xs:pattern value="\w+:(/?/?)[^\s]+"/>
<xs:pattern value=".*\{variable%[A-Za-z0-9_]\}.*"/>
<xs:pattern value=".*\{xpath%[A-Za-z0-9_/\(\)\.\*@\-]+\}.*"/>
</xs:restriction>
</xs:simpleType>
<!-- END t_btag_uri -->

<!-- t_filename: a POSIX fully-portable filename. -->
<xs:simpleType name="t_filename">
<xs:restriction base="xs:string">
<xs:pattern value="([a-z0-9._-]+){1,255}"/>
<xs:pattern value=".*\{variable%[A-Za-z0-9_]\}.*"/>
<xs:pattern value=".*\{xpath%[A-Za-z0-9_/\(\)\.\*@\-]+\}.*"/>
<!-- We don't allow (string)(regex) or (regex)(string) or (string)(regex)(string) or multiple regexes -->
<!-- because that's just... not feasible to manage from a parsing perspective. -->
<xs:pattern value="\{regex%.+\}"/>
</xs:restriction>
</xs:simpleType>
<!-- END t_filename -->

<!-- t_gpg_keyid: a set of various patterns that match GPG key IDs. -->
<xs:simpleType name="t_gpg_keyid">
<xs:restriction base="xs:string">
<xs:pattern value="(none|new)"/>
<xs:pattern value="(auto|default)"/>
<xs:pattern value="(0x)?[0-9A-Fa-f]{40}"/>
<xs:pattern value="(0x)?[0-9A-Fa-f]{16}"/>
<xs:pattern value="(0x)?[0-9A-Fa-f]{8}"/>
<xs:pattern value="([0-9A-Fa-f ]{4}){5} ?([0-9A-Fa-f ]{4}){4}[0-9A-Fa-f]{4}"/>
</xs:restriction>
</xs:simpleType>
<!-- END t_gpg_keyid -->

<!-- t_gpg_keyid_list: a type for a list of key IDs. -->
<xs:simpleType name="t_gpg_keyid_list">
<xs:list itemType="t_gpg_keyid"/>
</xs:simpleType>
<!-- END t_gpg_key_list -->

<!-- t_net_loc: a remote host. Used for PKI Subject's commonName and host for rsync. -->
<xs:simpleType name="t_net_loc">
<xs:restriction base="xs:string">
<xs:pattern
value="(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])"/>
</xs:restriction>
</xs:simpleType>
<!-- END t_net_loc -->

<!-- t_pass_hash_algo: used for t_password. -->
<xs:simpleType name="t_pass_hash_algo">
<xs:restriction base="xs:string">
<xs:enumeration value="des"/>
<xs:enumeration value="md5"/>
<xs:enumeration value="sha256"/>
<xs:enumeration value="sha512"/>
</xs:restriction>
</xs:simpleType>
<!-- END t_pass_hash_algo -->

<!-- t_pass_salt: used for t_password. -->
<xs:simpleType name="t_pass_salt">
<xs:restriction base="xs:string">
<xs:pattern value="($[156]($rounds=[0-9]+)?$[a-zA-Z0-9./]{1,16}$?|auto|)"/>
<xs:pattern value="\{variable%[A-Za-z0-9_]\}"/>
<xs:pattern value="\{xpath%[A-Za-z0-9_\(\)\.\*\-/]+\}"/>
</xs:restriction>
</xs:simpleType>
<!-- END t_pass_salt -->

<!-- t_password: used for rootpass and user/password elements. -->
<xs:complexType name="t_password">
<!-- The below will need some fleshing out and testing. It may not be possible strictly via XSD. -->
<!-- TODO: restrict the value further with a union or multi-group regex that checks for a valid length? -->
<!-- des: ????? -->
<!-- md5: "[a-zA-Z0-9./]{22}" -->
<!-- sha256: "[a-zA-Z0-9./]{43}" -->
<!-- sha512: "[a-zA-Z0-9./]{86}" -->
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="hash_algo" type="t_pass_hash_algo"/>
<xs:attribute name="hashed" type="xs:boolean" use="required"/>
<xs:attribute name="salt" type="t_pass_salt"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!-- END t_password -->

<!-- t_path: for specifying subdirectories (either local filesystem or remote paths). -->
<xs:simpleType name="t_path">
<xs:restriction base="xs:string">
<!-- We include blank to operate on default actions (or default filepaths). -->
<xs:pattern value=""/>
<xs:pattern value="(.+)/([^/]+)"/>
<xs:pattern value="((.+)/([^/]+))?\{variable%[A-Za-z0-9_]\}((.+)/([^/]+))?"/>
<xs:pattern value="((.+)/([^/]+))?\{xpath%[A-Za-z0-9_\(\)\.\*\-/]+\}((.+)/([^/]+))?"/>
</xs:restriction>
</xs:simpleType>
<!-- END t_path -->

<!-- t_pki_cert: used for pki/ca/cert and pki/client/cert. -->
<xs:complexType name="t_pki_cert">
<xs:simpleContent>
<xs:extension base="t_path">
<xs:attribute name="hash_algo" use="required">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="blake2b512"/>
<xs:enumeration value="blake2s256"/>
<xs:enumeration value="gost"/>
<xs:enumeration value="md4"/>
<xs:enumeration value="md5"/>
<xs:enumeration value="mdc2"/>
<xs:enumeration value="rmd160"/>
<xs:enumeration value="sha1"/>
<xs:enumeration value="sha224"/>
<xs:enumeration value="sha256"/>
<xs:enumeration value="sha384"/>
<xs:enumeration value="sha512"/>
<xs:enumeration value="none"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!-- END t_pki_cert -->

<!-- t_pki_key: used for pki/ca/key and pki/client/key -->
<xs:complexType name="t_pki_key">
<xs:simpleContent>
<xs:extension base="t_path">
<xs:attribute name="cipher" use="required">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="aes128"/>
<xs:enumeration value="aes192"/>
<xs:enumeration value="bf"/>
<xs:enumeration value="blowfish"/>
<xs:enumeration value="camellia128"/>
<xs:enumeration value="camellia192"/>
<xs:enumeration value="camellia256"/>
<xs:enumeration value="des"/>
<xs:enumeration value="rc2"/>
<xs:enumeration value="seed"/>
<xs:enumeration value="none"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="passphrase" type="xs:string"/>
<xs:attribute name="keysize"
type="xs:positiveInteger"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!-- END t_pki_key -->

<!-- t_pki_subject: used for pki/ca/subject and pki/client/subject -->
<xs:complexType name="t_pki_subject">
<xs:all>
<!-- .../SUBJECT/COMMONNAME -->
<xs:element name="commonName" type="t_net_loc"/>
<!-- END .../SUBJECT/COMMONNAME -->
<!-- .../SUBJECT/COUNTRYNAME -->
<xs:element name="countryName">
<xs:simpleType>
<xs:restriction base="xs:string">
<!-- We can't validate an actual ISO-3166 ALPHA-2 code, but we can validate the format. -->
<!-- TODO: maybe cron the generation of an external namespace? -->
<xs:pattern value="[A-Z]{2}"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<!-- END .../SUBJECT/COUNTRYNAME -->
<!-- .../SUBJECT/LOCALITYNAME -->
<xs:element name="localityName" type="xs:string"/>
<!-- END .../SUBJECT/LOCALITYNAME -->
<!-- .../SUBJECT/STATEORPROVINCENAME -->
<xs:element name="stateOrProvinceName"
type="xs:string"/>
<!-- END .../SUBJECT/STATEORPROVINCENAME -->
<!-- .../SUBJECT/ORGANIZATION -->
<xs:element name="organization" type="xs:string"/>
<!-- END .../SUBJECT/ORGANIZATION -->
<!-- .../SUBJECT/ORGANIZATIONALUNITNAME -->
<xs:element name="organizationalUnitName"
type="xs:string"/>
<!-- END .../SUBJECT/ORGANIZATIONALUNITNAME -->
<!-- .../SUBJECT/EMAILADDRESS -->
<xs:element name="emailAddress" type="xs:string"/>
<!-- END .../SUBJECT/EMAILADDRESS -->
</xs:all>
</xs:complexType>
<!-- END t_pki_subject -->

<!-- t_remote_file: an element that lets us define both a file pattern for remote content and flags attribute. -->
<xs:complexType name="t_remote_file">
<xs:simpleContent>
<xs:extension base="t_filename">
<xs:attribute name="flags" type="t_remote_file_flags" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!-- END t_remote_file -->

<!-- t_remote_file_flags: a type to match a list of known flags. -->
<xs:simpleType name="t_remote_file_flags">
<xs:list>
<xs:simpleType>
<xs:restriction base="xs:string">
<!-- Currently we only support two flags. -->
<xs:enumeration value="regex"/>
<xs:enumeration value="latest"/>
</xs:restriction>
</xs:simpleType>
</xs:list>
</xs:simpleType>
<!-- END t_remote_file_flags -->

<!-- t_username: enforce a POSIX-compliant username. Used for user/username elements. -->
<xs:simpleType name="t_username">
<xs:restriction base="xs:string">
<xs:pattern value="[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}$)"/>
<xs:pattern value="\{variable%[A-Za-z0-9_]\}"/>
<xs:pattern value="\{xpath%[A-Za-z0-9_\(\)\.\*\-/]+\}"/>
</xs:restriction>
</xs:simpleType>
<!-- END t_username -->
<!-- END CUSTOM TYPES -->

<!-- ROOT ELEMENT ("BDISK") --> <!-- ROOT ELEMENT ("BDISK") -->
<xs:element name="bdisk"> <xs:element name="bdisk">
<xs:complexType> <xs:complexType>
<!-- Should this be xs:sequence instead? -->
<xs:choice> <xs:choice>
<!-- BDISK/PROFILE --> <!-- BDISK/PROFILE -->
<xs:element name="profile" maxOccurs="unbounded" minOccurs="1"> <xs:element name="profile" maxOccurs="unbounded" minOccurs="1">
@ -23,8 +261,9 @@
<xs:element name="name" maxOccurs="1" minOccurs="1"> <xs:element name="name" maxOccurs="1" minOccurs="1">
<xs:simpleType> <xs:simpleType>
<xs:restriction base="xs:string"> <xs:restriction base="xs:string">
<xs:pattern <xs:pattern value="[A-Z0-9]{1,8}"/>
value="(\{(xpath|variable)%[A-Za-z0-9_]\}|[A-Z0-9]{1,8})"/> <xs:pattern value="\{variable%[A-Za-z0-9_]\}"/>
<xs:pattern value="\{xpath%[A-Za-z0-9_\(\)\.\*\-/]+\}"/>
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>
</xs:element> </xs:element>
@ -33,8 +272,12 @@
<xs:element name="uxname" maxOccurs="1" minOccurs="1"> <xs:element name="uxname" maxOccurs="1" minOccurs="1">
<xs:simpleType> <xs:simpleType>
<xs:restriction base="xs:string"> <xs:restriction base="xs:string">
<xs:pattern <!-- refer to the 2009 POSIX spec, "3.282 Portable Filename Character Set" -->
value="(\{(xpath|variable)%[A-Za-z0-9_]+\}|[A-Za-z0-9]{1,255})"/> <!-- http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_282 -->
<!-- (We use this string to name some files.) -->
<xs:pattern value="([a-z0-9._-]+){1,255}"/>
<xs:pattern value="\{variable%[A-Za-z0-9_]\}"/>
<xs:pattern value="\{xpath%[A-Za-z0-9_\(\)\.\*\-/]+\}"/>
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>
</xs:element> </xs:element>
@ -43,6 +286,7 @@
<xs:element name="pname" maxOccurs="1" minOccurs="1"> <xs:element name="pname" maxOccurs="1" minOccurs="1">
<xs:simpleType> <xs:simpleType>
<xs:restriction base="xs:string"> <xs:restriction base="xs:string">
<!-- TODO: Can I use UTF-8 instead? -->
<!-- https://stackoverflow.com/a/9805789/733214 --> <!-- https://stackoverflow.com/a/9805789/733214 -->
<xs:pattern value="\p{IsBasicLatin}*"/> <xs:pattern value="\p{IsBasicLatin}*"/>
</xs:restriction> </xs:restriction>
@ -57,10 +301,30 @@
<xs:element name="desc" maxOccurs="1" minOccurs="1" type="xs:string"/> <xs:element name="desc" maxOccurs="1" minOccurs="1" type="xs:string"/>
<!-- END BDISK/PROFILE/META/DESC --> <!-- END BDISK/PROFILE/META/DESC -->
<!-- BDISK/PROFILE/META/DEV --> <!-- BDISK/PROFILE/META/DEV -->
<xs:element name="dev" maxOccurs="1" minOccurs="1" type="xs:string"/> <xs:element name="dev" maxOccurs="1" minOccurs="1">
<xs:complexType>
<xs:all>
<!-- BDISK/PROFILE/META/DEV/AUTHOR -->
<xs:element name="author" maxOccurs="1" minOccurs="1"
type="xs:string"/>
<!-- END BDISK/PROFILE/META/DEV/AUTHOR -->
<!-- BDISK/PROFILE/META/DEV/EMAIL -->
<!-- The following does NOT WORK. Shame, really. -->
<!-- It seems to be an invalid pattern per my XSD validator (xmllint). -->
<!--<xs:pattern value="([!#-&apos;*+/-9=?A-Z^-~-]+(\.[!#-&apos;*+/-9=?A-Z^-~-]+)*|&quot;([]!#-[^-~ \t]|(\\[\t -~]))+&quot;)@([!#-&apos;*+/-9=?A-Z^-~-]+(\.[!#-&apos;*+/-9=?A-Z^-~-]+)*|\[[\t -Z^-~]*])"/>-->
<xs:element name="email" maxOccurs="1" minOccurs="1"
type="xs:string"/>
<!-- END BDISK/PROFILE/META/DEV/EMAIL -->
<!-- BDISK/PROFILE/META/DEV/WEBSITE -->
<xs:element name="website" maxOccurs="1" minOccurs="1"
type="t_btag_uri"/>
<!-- END BDISK/PROFILE/META/DEV/WEBSITE -->
</xs:all>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/META/DEV --> <!-- END BDISK/PROFILE/META/DEV -->
<!-- BDISK/PROFILE/META/URI --> <!-- BDISK/PROFILE/META/URI -->
<xs:element name="uri" maxOccurs="1" minOccurs="1" type="xs:anyURI"/> <xs:element name="uri" maxOccurs="1" minOccurs="1" type="t_btag_uri"/>
<!-- END BDISK/PROFILE/META/URI --> <!-- END BDISK/PROFILE/META/URI -->
<!-- BDISK/PROFILE/META/VER --> <!-- BDISK/PROFILE/META/VER -->
<xs:element name="ver" maxOccurs="1" minOccurs="1" type="xs:string"/> <xs:element name="ver" maxOccurs="1" minOccurs="1" type="xs:string"/>
@ -114,29 +378,427 @@
</xs:element> </xs:element>
<!-- END BDISK/PROFILE/META --> <!-- END BDISK/PROFILE/META -->
<!-- BDISK/PROFILE/ACCOUNTS --> <!-- BDISK/PROFILE/ACCOUNTS -->
<xs:element name="accounts" maxOccurs="1" minOccurs="1"/> <xs:element name="accounts" maxOccurs="1" minOccurs="1">
<xs:complexType>
<xs:sequence>
<!-- BDISK/PROFILE/ACCOUNTS/ROOTPASS -->
<xs:element name="rootpass" maxOccurs="1" minOccurs="1" type="t_password"/>
<!-- END BDISK/PROFILE/ACCOUNTS/ROOTPASS -->
<!-- BDISK/PROFILE/ACCOUNTS/USER -->
<xs:element name="user" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:all>
<!-- BDISK/PROFILE/ACCOUNTS/USER/USERNAME -->
<xs:element name="username" type="t_username" minOccurs="1"
maxOccurs="1"/>
<!-- END BDISK/PROFILE/ACCOUNTS/USER/USERNAME -->
<!-- BDISK/PROFILE/ACCOUNTS/USER/COMMENT -->
<xs:element name="comment" type="xs:string" maxOccurs="1"
minOccurs="0"/>
<!-- END BDISK/PROFILE/ACCOUNTS/USER/COMMENT -->
<!-- BDISK/PROFILE/ACCOUNTS/USER/PASSWORD -->
<xs:element name="password" type="t_password" maxOccurs="1"
minOccurs="1"/>
<!-- END BDISK/PROFILE/ACCOUNTS/USER/PASSWORD -->
</xs:all>
<xs:attribute name="sudo" type="xs:boolean" use="optional"/>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/ACCOUNTS/USER -->
</xs:sequence>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/ACCOUNTS --> <!-- END BDISK/PROFILE/ACCOUNTS -->
<!-- BDISK/PROFILE/BUILD--> <!-- BDISK/PROFILE/SOURCES -->
<xs:element name="build" maxOccurs="1" minOccurs="1"/> <xs:element name="sources" maxOccurs="1" minOccurs="1">
<xs:complexType>
<xs:sequence>
<!-- BDisk only supports two different architectures (x86/i686 and x86_64, respectively) currently. -->
<!-- TODO: future improvements may let us include e.g. two different x86_64 environments (e.g. CentOS and Debian on the same media), but this is like, still in development stages. -->
<!-- BDISK/PROFILE/SOURCES/SOURCE -->
<xs:element name="source" minOccurs="1" maxOccurs="2">
<xs:complexType>
<xs:all>
<!-- We cheat here. TECHNICALLY it should ONLY be scheme://location (no /path...), but there isn't a data type for that. -->
<!-- Currently we enforce only one item. Future BDisk versions may be able to make use of multiple <mirror>s and select best one based on speed. -->
<!-- BDISK/PROFILE/SOURCES/SOURCE/MIRROR -->
<xs:element name="mirror" type="t_btag_uri" maxOccurs="1"
minOccurs="1"/>
<!-- END BDISK/PROFILE/SOURCES/SOURCE/MIRROR -->
<!-- BDISK/PROFILE/SOURCES/SOURCE/ROOTPATH -->
<xs:element name="rootpath" maxOccurs="1" minOccurs="1"
type="t_path"/>
<!-- END BDISK/PROFILE/SOURCES/SOURCE/ROOTPATH -->
<!-- BDISK/PROFILE/SOURCES/SOURCE/TARBALL -->
<xs:element name="tarball" maxOccurs="1" minOccurs="1"
type="t_remote_file"/>
<!-- END BDISK/PROFILE/SOURCES/SOURCE/TARBALL -->
<!-- BDISK/PROFILE/SOURCES/SOURCE/CHECKSUM -->
<xs:element name="checksum" maxOccurs="1" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="t_remote_file">
<!-- There is NO way we can validate this, because it will vary based on the algorithms supported by the build host. -->
<xs:attribute name="hash_algo" type="xs:string" use="required"/>
<xs:attribute name="explicit" type="xs:boolean" use="required"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/SOURCES/SOURCE/CHECKSUM -->
<!-- BDISK/PROFILE/SOURCES/SOURCE/SIG -->
<xs:element name="sig" maxOccurs="1" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="t_remote_file">
<!-- Required; otherwise there's no point using it. -->
<xs:attribute name="keys" type="t_gpg_keyid_list" use="required"/>
<xs:attribute name="keyserver" type="t_btag_uri"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/SOURCES/SOURCE/SIG-->
</xs:all>
<xs:attribute name="arch">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:pattern value="(i686|x86(_64)?|32|64)"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/SOURCES/SOURCE -->
</xs:sequence>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/SOURCES -->
<!-- BDISK/PROFILE/BUILD -->
<xs:element name="build" maxOccurs="1" minOccurs="1">
<xs:complexType>
<xs:all>
<!-- BDISK/PROFILE/BUILD/PATHS -->
<xs:element name="paths">
<xs:complexType>
<xs:all>
<!-- BDISK/PROFILE/BUILD/PATHS/BASE -->
<xs:element name="base" maxOccurs="1" minOccurs="1" type="t_path"/>
<!-- END BDISK/PROFILE/BUILD/PATHS/BASE -->
<!-- BDISK/PROFILE/BUILD/PATHS/CACHE -->
<xs:element name="cache" maxOccurs="1" minOccurs="1" type="t_path"/>
<!-- END BDISK/PROFILE/BUILD/PATHS/CACHE -->
<!-- BDISK/PROFILE/BUILD/PATHS/CHROOT -->
<xs:element name="chroot" maxOccurs="1" minOccurs="1"
type="t_path"/>
<!-- END BDISK/PROFILE/BUILD/PATHS/CHROOT -->
<!-- BDISK/PROFILE/BUILD/PATHS/OVERLAY -->
<xs:element name="overlay" maxOccurs="1" minOccurs="1"
type="t_path"/>
<!-- END BDISK/PROFILE/BUILD/PATHS/OVERLAY -->
<!-- BDISK/PROFILE/BUILD/PATHS/TEMPLATES -->
<xs:element name="templates" maxOccurs="1" minOccurs="1"
type="t_path"/>
<!-- END BDISK/PROFILE/BUILD/PATHS/TEMPLATES -->
<!-- BDISK/PROFILE/BUILD/PATHS/MOUNT -->
<xs:element name="mount" maxOccurs="1" minOccurs="1" type="t_path"/>
<!-- END BDISK/PROFILE/BUILD/PATHS/MOUNT -->
<!-- BDISK/PROFILE/BUILD/PATHS/DISTROS -->
<xs:element name="distros" maxOccurs="1" minOccurs="1"
type="t_path"/>
<!-- END BDISK/PROFILE/BUILD/PATHS/DISTROS -->
<!-- BDISK/PROFILE/BUILD/PATHS/DEST -->
<xs:element name="dest" maxOccurs="1" minOccurs="1" type="t_path"/>
<!-- END BDISK/PROFILE/BUILD/PATHS/DEST -->
<!-- BDISK/PROFILE/BUILD/PATHS/ISO -->
<xs:element name="iso" maxOccurs="1" minOccurs="1" type="t_path"/>
<!-- END BDISK/PROFILE/BUILD/PATHS/ISO -->
<!-- BDISK/PROFILE/BUILD/PATHS/HTTP -->
<xs:element name="http" maxOccurs="1" minOccurs="1" type="t_path"/>
<!-- END BDISK/PROFILE/BUILD/PATHS/HTTP -->
<!-- BDISK/PROFILE/BUILD/PATHS/TFTP -->
<xs:element name="tftp" maxOccurs="1" minOccurs="1" type="t_path"/>
<!-- END BDISK/PROFILE/BUILD/PATHS/TFTP -->
<!-- EBDISK/PROFILE/BUILD/PATHS/PKI -->
<xs:element name="pki" maxOccurs="1" minOccurs="1" type="t_path"/>
<!-- END BDISK/PROFILE/BUILD/PATHS/PKI -->
</xs:all>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/BUILD/PATHS -->
<!-- BDISK/PROFILE/BUILD/BASEDISTRO -->
<xs:element name="basedistro"/>
<!-- END BDISK/PROFILE/BUILD/BASEDISTRO -->
</xs:all>
<xs:attribute name="its_full_of_stars" type="xs:boolean"/>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/BUILD --> <!-- END BDISK/PROFILE/BUILD -->
<!-- BDISK/PROFILE/ISO --> <!-- BDISK/PROFILE/ISO -->
<xs:element name="iso" maxOccurs="1" minOccurs="1"/> <xs:element name="iso" maxOccurs="1" minOccurs="1">
<xs:complexType>
<xs:attribute name="sign" type="xs:boolean"/>
<xs:attribute name="multi_arch">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="yes"/>
<xs:enumeration value="no"/>
<xs:enumeration value="true"/>
<xs:enumeration value="false"/>
<xs:enumeration value="x86_64"/>
<xs:enumeration value="x86"/>
<xs:enumeration value="64"/>
<xs:enumeration value="32"/>
<xs:enumeration value="i686"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/ISO --> <!-- END BDISK/PROFILE/ISO -->
<!-- BDISK/PROFILE/IPXE --> <!-- BDISK/PROFILE/IPXE -->
<xs:element name="ipxe" maxOccurs="1" minOccurs="1"/> <xs:element name="ipxe" maxOccurs="1" minOccurs="1">
<xs:complexType>
<xs:all>
<!-- BDISK/PROFILE/IPXE/URI -->
<xs:element name="uri" type="t_btag_uri" maxOccurs="1" minOccurs="1"/>
<!-- END BDISK/PROFILE/IPXE/URI -->
</xs:all>
<xs:attribute name="sign" type="xs:boolean"/>
<xs:attribute name="iso" type="xs:boolean"/>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/IPXE --> <!-- END BDISK/PROFILE/IPXE -->
<!-- BDISK/PROFILE/GPG --> <!-- BDISK/PROFILE/GPG -->
<xs:element name="gpg" maxOccurs="1" minOccurs="1"/> <xs:element name="gpg" maxOccurs="1" minOccurs="1">
<xs:complexType>
<xs:sequence>
<!-- BDISK/PROFILE/GPG/KEY -->
<xs:element name="key" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:all>
<!-- BDISK/PROFILE/GPG/KEY/NAME -->
<xs:element name="name" type="xs:normalizedString" maxOccurs="1"
minOccurs="1"/>
<!-- END BDISK/PROFILE/GPG/KEY/NAME -->
<!-- BDISK/PROFILE/GPG/KEY/EMAIL -->
<xs:element name="email" type="xs:normalizedString" maxOccurs="1"
minOccurs="1"/>
<!-- END BDISK/PROFILE/GPG/KEY/EMAIL -->
<!-- BDISK/PROFILE/GPG/KEY/COMMENT -->
<xs:element name="comment" type="xs:string" maxOccurs="1"
minOccurs="0"/>
<!-- END BDISK/PROFILE/GPG/KEY/COMMENT -->
</xs:all>
<xs:attribute name="algo">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="rsa"/>
<xs:enumeration value="dsa"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<!-- We COULD constrain this further, but it's conditional upon the algo type. So we'll do that in BDisk itself. -->
<!-- But it may be possible? https://stackoverflow.com/a/39045446/733214 -->
<xs:attribute name="keysize" type="xs:positiveInteger"/>
<!-- XSD doesn't have a datatype for Epoch vs. 0 (for no expire). -->
<xs:attribute name="expire">
<xs:simpleType>
<!--This is xs:integer instead of xs:positiveInteger because 0 will fail validation then. -->
<xs:restriction base="xs:integer">
<xs:pattern value="(0|[0-9]{10})"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/GPG/KEY -->
</xs:sequence>
<xs:attribute name="keyid" type="t_gpg_keyid"/>
<xs:attribute name="publish" type="xs:boolean"/>
<xs:attribute name="prompt_passphrase" type="xs:boolean"/>
<xs:attribute name="gnupghome">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:pattern value="(.+)/([^/]+)"/>
<xs:pattern
value="((.+)/([^/]+))?\{variable%[A-Za-z0-9_]\}((.+)/([^/]+))?"/>
<xs:pattern
value="((.+)/([^/]+))?\{xpath%[A-Za-z0-9_\(\)\.\*\-/]+\}((.+)/([^/]+))?"/>
<xs:pattern value="(none|)"/>
<xs:pattern value="(auto|default)"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/GPG --> <!-- END BDISK/PROFILE/GPG -->
<!-- BDISK/PROFILE/PKI --> <!-- BDISK/PROFILE/PKI -->
<xs:element name="pki" maxOccurs="1" minOccurs="1"/> <xs:element name="pki" maxOccurs="1" minOccurs="0">
<xs:complexType>
<xs:sequence>
<!-- BDISK/PROFILE/PKI/CA -->
<xs:element name="ca" maxOccurs="1" minOccurs="1">
<xs:complexType>
<xs:all>
<!-- BDISK/PROFILE/PKI/CA/CERT -->
<xs:element name="cert" maxOccurs="1" minOccurs="1"
type="t_pki_cert"/>
<!-- END BDISK/PROFILE/PKI/CA/CERT -->
<!-- BDISK/PROFILE/PKI/CA/CSR -->
<xs:element name="csr" maxOccurs="1" minOccurs="0" type="t_path"/>
<!-- END BDISK/PROFILE/PKI/CA/CSR -->
<!-- BDISK/PROFILE/PKI/CA/INDEX -->
<xs:element name="index" maxOccurs="1" minOccurs="0" type="t_path"/>
<!-- END BDISK/PROFILE/PKI/CA/INDEX -->
<!-- BDISK/PROFILE/PKI/CA/SERIAL -->
<xs:element name="serial" maxOccurs="1" minOccurs="0"
type="t_path"/>
<!-- END BDISK/PROFILE/PKI/CA/SERIAL -->
<!-- BDISK/PROFILE/PKI/CA/KEY -->
<xs:element name="key" minOccurs="1" maxOccurs="1"
type="t_pki_key"/>
<!-- END BDISK/PROFILE/PKI/CA/CSR -->
<!-- BDISK/PROFILE/PKI/CA/SUBJECT -->
<xs:element name="subject" maxOccurs="1" minOccurs="0"
type="t_pki_subject"/>
<!-- END BDISK/PROFILE/PKI/CA/SUBJECT -->
</xs:all>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/PKI/CA -->
<!-- BDISK/PROFILE/PKI/CLIENT -->
<xs:element name="client" maxOccurs="1" minOccurs="1">
<xs:complexType>
<xs:all>
<!-- BDISK/PROFILE/PKI/CLIENT/CERT -->
<xs:element name="cert" maxOccurs="1" minOccurs="1"
type="t_pki_cert"/>
<!-- END BDISK/PROFILE/PKI/CLIENT/CERT -->
<!-- BDISK/PROFILE/PKI/CLIENT/CSR -->
<xs:element name="csr" maxOccurs="1" minOccurs="0" type="t_path"/>
<!-- END BDISK/PROFILE/PKI/CLIENT/CSR -->
<!-- BDISK/PROFILE/PKI/CLIENT/KEY -->
<xs:element name="key" minOccurs="1" maxOccurs="1"
type="t_pki_key"/>
<!-- END BDISK/PROFILE/PKI/CLIENT/CSR -->
<!-- BDISK/PROFILE/PKI/CLIENT/SUBJECT -->
<xs:element name="subject" maxOccurs="1" minOccurs="0"
type="t_pki_subject"/>
<!-- END BDISK/PROFILE/PKI/CLIENT/SUBJECT -->
</xs:all>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/PKI/CLIENT -->
</xs:sequence>
<xs:attribute name="overwrite" type="xs:boolean"/>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/PKI --> <!-- END BDISK/PROFILE/PKI -->
<!-- BDISK/PROFILE/SYNC --> <!-- BDISK/PROFILE/SYNC -->
<xs:element name="sync" maxOccurs="1" minOccurs="1"/> <xs:element name="sync" maxOccurs="1" minOccurs="1">
<xs:complexType>
<xs:all>
<!-- BDISK/PROFILE/SYNC/IPXE -->
<xs:element name="ipxe">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="t_path">
<xs:attribute name="enabled" type="xs:boolean"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/SYNC/IPXE -->
<!-- BDISK/PROFILE/SYNC/TFTP -->
<xs:element name="tftp">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="t_path">
<xs:attribute name="enabled" type="xs:boolean"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/SYNC/TFTP -->
<!-- BDISK/PROFILE/SYNC/ISO -->
<xs:element name="iso">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="t_path">
<xs:attribute name="enabled" type="xs:boolean"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/SYNC/ISO -->
<!-- BDISK/PROFILE/SYNC/GPG -->
<xs:element name="gpg">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="t_path">
<xs:attribute name="enabled" type="xs:boolean"/>
<xs:attribute name="format">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="asc"/>
<xs:enumeration value="bin"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/SYNC/GPG -->
<!-- BDISK/PROFILE/SYNC/RSYNC -->
<xs:element name="rsync">
<xs:complexType>
<xs:sequence>
<!-- BDISK/PROFILE/SYNC/RSYNC/USER -->
<xs:element name="user" type="t_username"/>
<!-- END BDISK/PROFILE/SYNC/RSYNC/USER -->
<!-- BDISK/PROFILE/SYNC/RSYNC/HOST -->
<xs:element name="host" type="t_net_loc"/>
<!-- END BDISK/PROFILE/SYNC/RSYNC/HOST -->
<!-- BDISK/PROFILE/SYNC/RSYNC/PORT -->
<xs:element name="port">
<xs:simpleType>
<xs:restriction base="xs:positiveInteger">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="65535"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<!-- END BDISK/PROFILE/SYNC/RSYNC/PORT -->
<xs:choice>
<!-- BDISK/PROFILE/SYNC/RSYNC/PUBKEY -->
<xs:element name="pubkey" type="t_path"/>
<!-- END BDISK/PROFILE/SYNC/RSYNC/PUBKEY -->
<!-- BDISK/PROFILE/SYNC/RSYNC/PUBKEY -->
<xs:element name="password"/>
<!-- END BDISK/PROFILE/SYNC/RSYNC/PUBKEY -->
</xs:choice>
</xs:sequence>
<xs:attribute name="enabled" type="xs:boolean"/>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/SYNC/IPXE -->
</xs:all>
</xs:complexType>
</xs:element>
<!-- END BDISK/PROFILE/SYNC --> <!-- END BDISK/PROFILE/SYNC -->
</xs:all> </xs:all>
<xs:attribute name="id" type="xs:positiveInteger"/> <xs:attribute name="id" type="xs:positiveInteger"/>
<xs:attribute name="name" type="xs:string"/> <xs:attribute name="name" type="xs:string"/>
<xs:attribute name="uuid">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:pattern
value="[0-9a-f]{8}\-[0-9a-f]{4}\-4[0-9a-f]{3}\-[89ab][0-9a-f]{3}\-[0-9a-f]{12}"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<!-- END BDISK/PROFILE --> <!-- END BDISK/PROFILE -->

View File

@ -4,7 +4,7 @@
# Go figure. # Go figure.


import confparse import confparse
import crypt import datetime
import getpass import getpass
import os import os
import utils import utils
@ -134,7 +134,12 @@ class ConfGenerator(object):
self.cfg = c.xml self.cfg = c.xml
self.append = True self.append = True
else: else:
self.cfg = lxml.etree.Element('bdisk') _ns = {None: 'http://bdisk.square-r00t.net/',
'xsi': 'http://www.w3.org/2001/XMLSchema-instance'}
_xsi = {
'{http://www.w3.org/2001/XMLSchema-instance}schemaLocation':
'http://bdisk.square-r00t.net bdisk.xsd'}
self.cfg = lxml.etree.Element('bdisk', nsmap = _ns, attrib = _xsi)
self.append = False self.append = False
self.profile = lxml.etree.Element('profile') self.profile = lxml.etree.Element('profile')
self.cfg.append(self.profile) self.cfg.append(self.profile)
@ -155,6 +160,13 @@ class ConfGenerator(object):
self.get_pki() self.get_pki()
self.get_gpg() self.get_gpg()
self.get_sync() self.get_sync()
# TODO: make this more specific (script? gui? web? etc.)
# and append comment to bdisk element
_comment = lxml.etree.Comment(
'Generated {0} by BDisk configuration generator'.format(
str(datetime.datetime.now())
)
)
except KeyboardInterrupt: except KeyboardInterrupt:
exit('\n\nCaught KeyboardInterrupt; quitting...') exit('\n\nCaught KeyboardInterrupt; quitting...')
return() return()
@ -472,7 +484,7 @@ class ConfGenerator(object):
print('Invalid selection. Starting over.') print('Invalid selection. Starting over.')
continue continue
chksum.attrib['hash_algo'] = checksum_type chksum.attrib['hash_algo'] = checksum_type
chksum.attrib['explicit'] = "no" chksum.attrib['explicit'] = "false"
chksum.text = checksum['full_url'] chksum.text = checksum['full_url']
else: else:
# Maybe it's a digest string. # Maybe it's a digest string.
@ -505,7 +517,7 @@ class ConfGenerator(object):
continue continue
else: else:
checksum_type = checksum_type[0] checksum_type = checksum_type[0]
chksum.attrib['explicit'] = "yes" chksum.attrib['explicit'] = "true"
chksum.text = checksum chksum.text = checksum
chksum.attrib['hash_algo'] = checksum_type chksum.attrib['hash_algo'] = checksum_type
print('\n++ SOURCES || {0} || GPG ++'.format(arch.upper())) print('\n++ SOURCES || {0} || GPG ++'.format(arch.upper()))
@ -597,7 +609,7 @@ class ConfGenerator(object):
usage = ( usage = (
'{0} for yes, {1} for no...\n')) '{0} for yes, {1} for no...\n'))
if _chk_optimizations: if _chk_optimizations:
build.attrib['its_full_of_stars'] = 'yes' build.attrib['its_full_of_stars'] = 'true'
print('\n++ BUILD || PATHS ++') print('\n++ BUILD || PATHS ++')
# Thankfully, we can simplify a lot of this. # Thankfully, we can simplify a lot of this.
_dir_strings = {'base': ('the base directory (used for files that are ' _dir_strings = {'base': ('the base directory (used for files that are '
@ -678,9 +690,9 @@ class ConfGenerator(object):
self.profile.append(iso) self.profile.append(iso)
# We have more than one arch, so we need to ask how they want to handle # We have more than one arch, so we need to ask how they want to handle
# it. # it.
_ma_strings = {'yes': ('a multi-arch ISO (both architectures on one ' _ma_strings = {'true': ('a multi-arch ISO (both architectures on one '
'ISO)'), 'ISO)'),
'no': ('separate image files for ' 'false': ('separate image files for '
'{0}').format(' and '.join(_arches))} '{0}').format(' and '.join(_arches))}
for a in _arches: for a in _arches:
_ma_strings[a] = 'only build an image file for {0}'.format(a) _ma_strings[a] = 'only build an image file for {0}'.format(a)
@ -712,7 +724,7 @@ class ConfGenerator(object):
'option to configure it a bit later).\nWould you like to sign ' 'option to configure it a bit later).\nWould you like to sign '
'the ISO/USB image files with GPG?\n'), usage = ( 'the ISO/USB image files with GPG?\n'), usage = (
'{0} for yes, {1} for no...\n')) '{0} for yes, {1} for no...\n'))
_gpg_sign = ('yes' if _gpg_input else 'no') _gpg_sign = ('true' if _gpg_input else 'false')
iso.attrib['sign'] = _gpg_sign iso.attrib['sign'] = _gpg_sign
self.profile.append(iso) self.profile.append(iso)
return() return()
@ -727,21 +739,21 @@ class ConfGenerator(object):
'see the manual for more information). Would you like to ' 'see the manual for more information). Would you like to '
'build iPXE support?\n'), usage = ( 'build iPXE support?\n'), usage = (
'{0} for yes, {1} for no...\n')) '{0} for yes, {1} for no...\n'))
_ipxe = ('yes' if _ipxe else 'no') _ipxe = ('true' if _ipxe else 'true')
if _ipxe == 'yes': if _ipxe == 'true':
print('\n++ iPXE || MINI-ISO ++') print('\n++ iPXE || MINI-ISO ++')
_iso = prompt.confirm_or_no(prompt = ( _iso = prompt.confirm_or_no(prompt = (
'\nWould you like to build a "mini-ISO" (see the manual) for ' '\nWould you like to build a "mini-ISO" (see the manual) for '
'bootstrapping iPXE booting from USB or optical media?\n'), 'bootstrapping iPXE booting from USB or optical media?\n'),
usage = ('{0} for yes, {1} for no...\n')) usage = ('{0} for yes, {1} for no...\n'))
ipxe.attrib['iso'] = ('yes' if _iso else 'no') ipxe.attrib['iso'] = ('true' if _iso else 'false')
print('\n++ iPXE || SIGNING ++') print('\n++ iPXE || SIGNING ++')
_sign = prompt.confirm_or_no(prompt = ( _sign = prompt.confirm_or_no(prompt = (
'\nBDisk can sign the mini-ISO and other relevant files for ' '\nBDisk can sign the mini-ISO and other relevant files for '
'iPXE builds using GPG. Would you like to sign the iPXE build ' 'iPXE builds using GPG. Would you like to sign the iPXE build '
'distributables? (You\'ll have the chance to configure GPG ' 'distributables? (You\'ll have the chance to configure GPG '
'later).\n'), usage = ('{0} for yes, {1} for no...\n')) 'later).\n'), usage = ('{0} for yes, {1} for no...\n'))
ipxe.attrib['sign'] = ('yes' if _sign else 'no') ipxe.attrib['sign'] = ('true' if _sign else 'false')
_uri = None _uri = None
while not _uri: while not _uri:
print('\n++ iPXE || URL ++') print('\n++ iPXE || URL ++')
@ -756,7 +768,7 @@ class ConfGenerator(object):
else: else:
uri = lxml.etree.SubElement(ipxe, 'uri') uri = lxml.etree.SubElement(ipxe, 'uri')
uri.text = _uri uri.text = _uri
if _ipxe == 'yes': if _ipxe == 'true':
self.profile.append(ipxe) self.profile.append(ipxe)
return() return()
@ -782,7 +794,7 @@ class ConfGenerator(object):
'wish to keep persistent keys and certs), you should ' 'wish to keep persistent keys and certs), you should '
'DEFINITELY answer no here.\n'), 'DEFINITELY answer no here.\n'),
usage = ('{0} for yes, {1} for no...\n')) usage = ('{0} for yes, {1} for no...\n'))
pki.attrib['overwrite'] = ('yes' if _overwrite else 'no') pki.attrib['overwrite'] = ('true' if _overwrite else 'false')
for x in ('ca', 'client'): for x in ('ca', 'client'):
print('\n++ SSL/TLS PKI || {0} ++'.format(x.upper())) print('\n++ SSL/TLS PKI || {0} ++'.format(x.upper()))
_x = None _x = None
@ -806,7 +818,7 @@ class ConfGenerator(object):
for x in _xpaths: for x in _xpaths:
_x = self.profile.xpath(x) _x = self.profile.xpath(x)
for a in _x: for a in _x:
if a == 'yes': if a == 'true':
_sigchk = True _sigchk = True
break break
if _sigchk: if _sigchk:
@ -850,7 +862,7 @@ class ConfGenerator(object):
'\nWould you like to push the key to the SKS keyserver pool ' '\nWould you like to push the key to the SKS keyserver pool '
'(making it much easier for end-users to look it up)?\n'), '(making it much easier for end-users to look it up)?\n'),
usage = ('{0} for yes, {1} for no...\n')) usage = ('{0} for yes, {1} for no...\n'))
gpg.attrib['publish'] = ('yes' if _gpgpublish else 'no') gpg.attrib['publish'] = ('true' if _gpgpublish else 'false')
print('\n++ GPG || PASSWORD HANDLING ++') print('\n++ GPG || PASSWORD HANDLING ++')
_gpgpass_prompt = prompt.confirm_or_no(prompt = ( _gpgpass_prompt = prompt.confirm_or_no(prompt = (
'\nWould you like BDisk to prompt you for a passphrase? If not, ' '\nWould you like BDisk to prompt you for a passphrase? If not, '
@ -858,7 +870,8 @@ class ConfGenerator(object):
'the configuration (HIGHLY unrecommended) or use a blank ' 'the configuration (HIGHLY unrecommended) or use a blank '
'passphrase (also HIGHLY unrecommended).\n'), 'passphrase (also HIGHLY unrecommended).\n'),
usage = ('{0} for yes, {1} for no...\n')) usage = ('{0} for yes, {1} for no...\n'))
gpg.attrib['prompt_passphrase'] = ('yes' if _gpgpass_prompt else 'no') gpg.attrib['prompt_passphrase'] = ('true' if _gpgpass_prompt else
'false')
_pass = None _pass = None
if not _gpgpass_prompt: if not _gpgpass_prompt:
while not _pass: while not _pass:
@ -923,7 +936,7 @@ class ConfGenerator(object):
'\nWould you like to sync {0}?\n'.format(_syncs[s])), '\nWould you like to sync {0}?\n'.format(_syncs[s])),
usage = ('{0} for yes, {1} for no...\n')) usage = ('{0} for yes, {1} for no...\n'))
elem = lxml.etree.SubElement(sync, s) elem = lxml.etree.SubElement(sync, s)
elem.attrib['enabled'] = ('yes' if _item_sync_chk else 'no') elem.attrib['enabled'] = ('true' if _item_sync_chk else 'false')
if not _item_sync_chk: if not _item_sync_chk:
continue continue
if s == 'gpg': if s == 'gpg':

View File

@ -168,7 +168,7 @@ class Conf(object):
## PROFILE/BUILD(/PATHS) ## PROFILE/BUILD(/PATHS)
self.cfg['build'] = {'paths': {}} self.cfg['build'] = {'paths': {}}
build = self.profile.xpath('./build')[0] build = self.profile.xpath('./build')[0]
_optimize = build.get('its_full_of_stars', 'no') _optimize = build.get('its_full_of_stars', 'false')
self.cfg['build']['optimize'] = transform.xml2py(_optimize) self.cfg['build']['optimize'] = transform.xml2py(_optimize)
for path in build.xpath('./paths/*'): for path in build.xpath('./paths/*'):
self.cfg['build']['paths'][path.tag] = path.text self.cfg['build']['paths'][path.tag] = path.text
@ -185,7 +185,7 @@ class Conf(object):
# We enable all features by default. # We enable all features by default.
elem = self.profile.xpath('./{0}'.format(x))[0] elem = self.profile.xpath('./{0}'.format(x))[0]
for a in self.cfg[x]: for a in self.cfg[x]:
self.cfg[x][a] = transform.xml2py(elem.get(a, 'yes')) self.cfg[x][a] = transform.xml2py(elem.get(a, 'true'))
if x == 'ipxe': if x == 'ipxe':
self.cfg[x]['uri'] = elem.xpath('./uri/text()')[0] self.cfg[x]['uri'] = elem.xpath('./uri/text()')[0]
return() return()

View File

@ -15,6 +15,7 @@ import uuid
import validators import validators
import zlib import zlib
import lxml.etree import lxml.etree
import lxml.objectify
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from collections import OrderedDict from collections import OrderedDict
from dns import resolver from dns import resolver
@ -446,12 +447,12 @@ class transform(object):
def py2xml(self, value, attrib = True): def py2xml(self, value, attrib = True):
if value in (False, ''): if value in (False, ''):
if attrib: if attrib:
return("no") return("false")
else: else:
return(None) return(None)
elif isinstance(value, bool): elif isinstance(value, bool):
# We handle the False case above. # We handle the False case above.
return("yes") return("true")
elif isinstance(value, str): elif isinstance(value, str):
return(value) return(value)
else: else:
@ -469,7 +470,6 @@ class transform(object):
text_out = re.sub('[^\w]', '', text_out) text_out = re.sub('[^\w]', '', text_out)
return(text_out) return(text_out)


# noinspection PyDictCreation
def url_to_dict(self, orig_url, no_None = False): def url_to_dict(self, orig_url, no_None = False):
def _getuserinfo(uinfo_str): def _getuserinfo(uinfo_str):
if len(uinfo_str) == 0: if len(uinfo_str) == 0:
@ -659,8 +659,8 @@ class transform(object):
return(acct) return(acct)


def xml2py(self, value, attrib = True): def xml2py(self, value, attrib = True):
yes = re.compile('^\s*(y(es)?|true|1)\s*$', re.IGNORECASE) yes = re.compile('^\s*(true|1)\s*$', re.IGNORECASE)
no = re.compile('^\s*(no?|false|0)\s*$', re.IGNORECASE) no = re.compile('^\s*(false|0)\s*$', re.IGNORECASE)
none = re.compile('^\s*(none|)\s*$', re.IGNORECASE) none = re.compile('^\s*(none|)\s*$', re.IGNORECASE)
if no.search(value): if no.search(value):
if attrib: if attrib:
@ -819,12 +819,18 @@ class xml_supplicant(object):
# This is retained so we can "refresh" the profile if needed. # This is retained so we can "refresh" the profile if needed.
self.orig_profile = profile self.orig_profile = profile
try: try:
self.xml = lxml.etree.fromstring(raw) self.orig_xml = lxml.etree.fromstring(raw)
# We need to strip the naked namespace for XPath to work.
self.xml = copy.deepcopy(self.orig_xml)
self.roottree = self.xml.getroottree()
self.tree = self.roottree.getroot()
self.strip_naked_ns()
except lxml.etree.XMLSyntaxError: except lxml.etree.XMLSyntaxError:
raise ValueError('The configuration provided does not seem to be ' raise ValueError('The configuration provided does not seem to be '
'valid') 'valid')
self.get_profile(profile = profile) self.get_profile(profile = profile)
self.xml = lxml.etree.fromstring(raw) # This is disabled; we set it above.
#self.xml = lxml.etree.fromstring(raw)
self.fmt = XPathFmt() self.fmt = XPathFmt()
self.max_recurse = int(self.profile.xpath( self.max_recurse = int(self.profile.xpath(
'//meta/max_recurse/text()')[0]) '//meta/max_recurse/text()')[0])
@ -969,6 +975,23 @@ class xml_supplicant(object):
).format(element.text)) ).format(element.text))
return(path) return(path)


def return_naked_ns(self):
# It's so stupid I have to do this.
return(self.orig_xml.nsmap)

def strip_naked_ns(self):
# I cannot *believe* that LXML doesn't have this built-in, considering
# how common naked namespaces are.
# https://stackoverflow.com/a/18160164/733214
for elem in self.roottree.getiterator():
if not hasattr(elem.tag, 'find'):
continue
i = elem.tag.find('}')
if i >= 0:
elem.tag = elem.tag[i + 1:]
lxml.objectify.deannotate(self.roottree, cleanup_namespaces = True)
return()

def substitute(self, element, recurse_count = 0): def substitute(self, element, recurse_count = 0):
if recurse_count >= self.max_recurse: if recurse_count >= self.max_recurse:
return(element) return(element)

View File

@ -1,286 +1,285 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<bdisk xmlns:bdisk="http://bdisk.square-r00t.net/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://bdisk.square-r00t.net bdisk.xsd"> <bdisk xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://bdisk.square-r00t.net/" xsi:schemaLocation="http://bdisk.square-r00t.net bdisk.xsd">
<profile name="default" id="1" uuid="8cdd6bcb-c147-4a63-9779-b5433c510dbc"> <profile name="default" id="1" uuid="8cdd6bcb-c147-4a63-9779-b5433c510dbc">
<meta> <meta>
<names> <names>
<name>BDisk</name> <name>BDISK</name>
<uxname>bdisk</uxname> <uxname>bdisk</uxname>
<!-- Just like with previous versions of BDisk, you can reference other values... <!-- Just like with previous versions of BDisk, you can reference other values...
but now with the neat benefits of XPath! Everything you could do in build.ini's and more. but now with the neat benefits of XPath! Everything you could do in build.ini's and more.
See https://www.w3schools.com/xml/xpath_syntax.asp See https://www.w3schools.com/xml/xpath_syntax.asp
If you need a literal curly brace, double them (e.g. for "{foo}", use "{{foo}}"), If you need a literal curly brace, double them (e.g. for "{foo}", use "{{foo}}"),
UNLESS it's in a <regexes><pattern> as part of the expression. Those are taken as literal strings. --> UNLESS it's in a <regexes><pattern> as part of the expression. Those are taken as literal strings. -->
<pname>{xpath%../name/text()}</pname> <pname>{xpath%../name/text()}</pname>
</names> </names>
<desc>A rescue/restore live environment.</desc> <desc>A rescue/restore live environment.</desc>
<dev> <dev>
<author>A. Dev Eloper</author> <author>A. Dev Eloper</author>
<email>dev@domain.tld</email> <email>dev@domain.tld</email>
<website>https://domain.tld/~dev</website> <website>https://domain.tld/~dev</website>
</dev> </dev>
<uri>https://domain.tld/projname</uri> <uri>https://domain.tld/projname</uri>
<ver>1.0.0</ver> <ver>1.0.0</ver>
<!-- This is the VERY FIRST value parsed, and is required. It controls how many levels of {xpath%...} to recurse. --> <!-- This is the VERY FIRST value parsed, and is required. It controls how many levels of {xpath%...} to recurse. -->
<!-- If the maximum level is reached, the substitution will evaluate as blank. --> <!-- If the maximum level is reached, the substitution will evaluate as blank. -->
<max_recurse>5</max_recurse> <max_recurse>5</max_recurse>
<!-- You need to store regex patterns here and reference them in a special way later, and it's only valid for certain <!-- You need to store regex patterns here and reference them in a special way later, and it's only valid for certain
items. See the manual for more information. NO btags within the patterns is allowed. --> items. See the manual for more information. NO btags within the patterns is allowed. -->
<regexes> <regexes>
<pattern id="tarball_x86_64">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz$</pattern> <pattern id="tarball_x86_64">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz$</pattern>
<pattern id="sig_x86_64">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz\.sig$</pattern> <pattern id="sig_x86_64">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz\.sig$</pattern>
<pattern id="tarball_i686">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz$</pattern> <pattern id="tarball_i686">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz$</pattern>
<pattern id="sig_i686">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz\.sig$</pattern> <pattern id="sig_i686">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz\.sig$</pattern>
</regexes> </regexes>
<!-- You can also define variables. NO xpath or regex btags, and they can't be used within other btags! --> <!-- You can also define variables. NO xpath or regex btags, and they can't be used within other btags! -->
<variables> <variables>
<variable id="bdisk_root">/var/tmp/BDisk</variable> <variable id="bdisk_root">/var/tmp/BDisk</variable>
</variables> </variables>
</meta> </meta>
<accounts> <accounts>
<!-- Salted/hashed password is "test" --> <!-- Salted/hashed password is "test" -->
<rootpass hashed="yes">$6$7KfIdtHTcXwVrZAC$LZGNeMNz7v5o/cYuA48FAxtZynpIwO5B1CPGXnOW5kCTVpXVt4SypRqfM.AoKkFt/O7MZZ8ySXJmxpELKmdlF1</rootpass> <rootpass hashed="true">$6$7KfIdtHTcXwVrZAC$LZGNeMNz7v5o/cYuA48FAxtZynpIwO5B1CPGXnOW5kCTVpXVt4SypRqfM.AoKkFt/O7MZZ8ySXJmxpELKmdlF1</rootpass>
<user sudo="yes"> <user sudo="true">
<username>{xpath%//meta/names/uxname/text()}</username> <username>{xpath%//meta/names/uxname/text()}</username>
<!-- You can also use substitution from different profiles in this same configuration: --> <!-- You can also use substitution from different profiles in this same configuration: -->
<!-- <username>{xpath%//profile[@name='another_profile']/meta/names/uxname"}</username> --> <!-- <username>{xpath%//profile[@name='another_profile']/meta/names/uxname"}</username> -->
<comment>{xpath%//meta/dev/author/text()}</comment> <comment>{xpath%//meta/dev/author/text()}</comment>
<password hashed="no" hash_algo="sha512" salt="auto">testpassword</password> <password hashed="false" hash_algo="sha512" salt="auto">testpassword</password>
</user> </user>
<user sudo="no"> <user sudo="false">
<username>testuser</username> <username>testuser</username>
<name>Test User</name> <comment>Test User</comment>
<password hashed="no" hash_algo="sha512" salt="auto">anothertestpassword</password> <password hashed="false" hash_algo="sha512" salt="auto">anothertestpassword</password>
</user> </user>
</accounts> </accounts>
<sources> <sources>
<source arch="x86_64"> <source arch="x86_64">
<mirror>http://archlinux.mirror.domain.tld</mirror> <mirror>http://archlinux.mirror.domain.tld</mirror>
<rootpath>/iso/latest</rootpath> <rootpath>/iso/latest</rootpath>
<tarball flags="regex,latest">{regex%tarball_x86_64}</tarball> <tarball flags="regex,latest">{regex%tarball_x86_64}</tarball>
<checksum hash_algo="sha1" explicit="no">sha1sums.txt</checksum> <checksum hash_algo="sha1" explicit="false">sha1sums.txt</checksum>
<sig keys="7F2D434B9741E8AC" keyserver="hkp://pool.sks-keyservers.net" flags="regex,latest">{regex%sig_x86_64}</sig> <sig keys="7F2D434B9741E8AC" keyserver="hkp://pool.sks-keyservers.net" flags="regex,latest">{regex%sig_x86_64}</sig>
</source> </source>
<source arch="i686"> <source arch="i686">
<mirror>http://archlinux32.mirror.domain.tld</mirror> <mirror>http://archlinux32.mirror.domain.tld</mirror>
<rootpath>/iso/latest</rootpath> <rootpath>/iso/latest</rootpath>
<tarball flags="regex,latest">{regex%tarball_i686}</tarball> <tarball flags="regex,latest">{regex%tarball_i686}</tarball>
<checksum hash_algo="sha512" explicit="yes">cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e</checksum> <checksum hash_algo="sha512" explicit="true">cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e</checksum>
<sig keys="248BF41F9BDD61D41D060AE774EDA3C6B06D0506" keyserver="hkp://pool.sks-keyservers.net" flags="regex,latest">{regex%sig_i686}</sig> <sig keys="248BF41F9BDD61D41D060AE774EDA3C6B06D0506" keyserver="hkp://pool.sks-keyservers.net" flags="regex,latest">{regex%sig_i686}</sig>
</source> </source>
</sources> </sources>
<build its_full_of_stars="yes"> <build its_full_of_stars="true">
<paths> <paths>
<base>{variable%bdisk_root}/base</base> <base>{variable%bdisk_root}/base</base>
<cache>{variable%bdisk_root}/cache</cache> <cache>{variable%bdisk_root}/cache</cache>
<chroot>{variable%bdisk_root}/chroots</chroot> <chroot>{variable%bdisk_root}/chroots</chroot>
<overlay>{variable%bdisk_root}/overlay</overlay> <overlay>{variable%bdisk_root}/overlay</overlay>
<templates>{variable%bdisk_root}/templates</templates> <templates>{variable%bdisk_root}/templates</templates>
<mount>/mnt/{xpath%//meta/names/uxname/text()}</mount> <mount>/mnt/{xpath%//meta/names/uxname/text()}</mount>
<distros>{variable%bdisk_root}/distros</distros> <distros>{variable%bdisk_root}/distros</distros>
<dest>{variable%bdisk_root}/results</dest> <dest>{variable%bdisk_root}/results</dest>
<iso>{variable%bdisk_root}/iso_overlay</iso> <iso>{variable%bdisk_root}/iso_overlay</iso>
<http>{variable%bdisk_root}/http</http> <http>{variable%bdisk_root}/http</http>
<tftp>{variable%bdisk_root}/tftp</tftp> <tftp>{variable%bdisk_root}/tftp</tftp>
<pki>{variable%bdisk_root}/pki</pki> <pki>{variable%bdisk_root}/pki</pki>
</paths> </paths>
<basedistro>archlinux</basedistro> <basedistro>archlinux</basedistro>
</build> </build>
<iso sign="yes" multi_arch="yes"/> <iso sign="true" multi_arch="true"/>
<ipxe sign="yes" iso="yes"> <ipxe sign="true" iso="true">
<uri>{xpath%//meta/dev/website/text()}/ipxe</uri> <uri>{xpath%//meta/dev/website/text()}/ipxe</uri>
</ipxe> </ipxe>
<pki overwrite="no"> <pki overwrite="no">
<!-- http://ipxe.org/crypto --> <!-- http://ipxe.org/crypto -->
<ca> <ca>
<cert hash_algo="sha512">{xpath%../../../build/paths/pki/text()}/ca.crt</cert> <cert hash_algo="sha512">{xpath%../../../build/paths/pki/text()}/ca.crt</cert>
<!-- If csr is self-enclosed (<csr />), we'll just generate and use a CSR in-memory. <!-- If csr is self-enclosed (<csr />), we'll just generate and use a CSR in-memory.
Assuming we need to generate a certificate, anyways. Assuming we need to generate a certificate, anyways.
If you want to write it out to disk (for debugging, etc.) OR use one already generated, If you want to write it out to disk (for debugging, etc.) OR use one already generated,
then provide a path. then provide a path.
e.g.: e.g.:
<csr>{xpath%build/paths/ssl/text()}/ca.csr</csr> --> <csr>{xpath%build/paths/ssl/text()}/ca.csr</csr> -->
<csr/> <csr/>
<!-- If you use an index file (or want to) to serialize client certificates, specify it here. --> <!-- If you use an index file (or want to) to serialize client certificates, specify it here. -->
<!-- It must conform to CADB spec (https://pki-tutorial.readthedocs.io/en/latest/cadb.html). --> <!-- It must conform to CADB spec (https://pki-tutorial.readthedocs.io/en/latest/cadb.html). -->
<!-- You should probably also specify a serial file if so. --> <!-- You should probably also specify a serial file if so. -->
<!-- Both of these are entirely optional if you aren't using an existing PKI. --> <!-- Both of these are entirely optional if you aren't using an existing PKI. -->
<index>{xpath%../../../build/paths/pki/text()}/index.txt</index> <index>{xpath%../../../build/paths/pki/text()}/index.txt</index>
<serial>{xpath%../../../build/paths/pki/text()}/serial</serial> <serial>{xpath%../../../build/paths/pki/text()}/serial</serial>
<!-- If you specify a cipher, the key will be encrypted to the passphrase provided by the passphrase attribute. <!-- If you specify a cipher, the key will be encrypted to the passphrase provided by the passphrase attribute.
If the key is encrypted (either a pre-existing or a created one) but passphrase is not provided, you will If the key is encrypted (either a pre-existing or a created one) but passphrase is not provided, you will
be (securely) prompted for the passphrase to unlock it/add a passphrase to it. --> be (securely) prompted for the passphrase to unlock it/add a passphrase to it. -->
<key cipher="none" passphrase="none" keysize="4096">{xpath%../../../build/paths/pki/text()}/ca.key</key> <key cipher="none" passphrase="none" keysize="4096">{xpath%../../../build/paths/pki/text()}/ca.key</key>
<subject> <subject>
<commonName>domain.tld</commonName> <commonName>domain.tld</commonName>
<countryName>XX</countryName> <countryName>XX</countryName>
<localityName>Some City</localityName> <localityName>Some City</localityName>
<stateOrProvinceName>Some State</stateOrProvinceName> <stateOrProvinceName>Some State</stateOrProvinceName>
<organization>Some Org, Inc.</organization> <organization>Some Org, Inc.</organization>
<organizationalUnitName>Department Name</organizationalUnitName> <organizationalUnitName>Department Name</organizationalUnitName>
<emailAddress>{xpath%../../../../meta/dev/email/text()}</emailAddress> <emailAddress>{xpath%../../../../meta/dev/email/text()}</emailAddress>
</subject> </subject>
</ca> </ca>
<client> <client>
<cert hash_algo="sha512">{xpath%../../../build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.crt</cert> <cert hash_algo="sha512">{xpath%../../../build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.crt</cert>
<csr/> <csr/>
<key cipher="none" passphrase="none" keysize="4096">{xpath%//build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.key</key> <key cipher="none" passphrase="none" keysize="4096">{xpath%//build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.key</key>
<subject> <subject>
<commonName>some client name</commonName> <commonName>some client name</commonName>
<countryName>XX</countryName> <countryName>XX</countryName>
<localityName>Some City</localityName> <localityName>Some City</localityName>
<stateOrProvinceName>Some State</stateOrProvinceName> <stateOrProvinceName>Some State</stateOrProvinceName>
<organization>Some Org, Inc.</organization> <organization>Some Org, Inc.</organization>
<organizationalUnitName>Department Name</organizationalUnitName> <organizationalUnitName>Department Name</organizationalUnitName>
<emailAddress>{xpath%../../../../meta/dev/email/text()}</emailAddress> <emailAddress>{xpath%../../../../meta/dev/email/text()}</emailAddress>
</subject> </subject>
</client> </client>
</pki> </pki>
<!-- If prompt_passphrase is "no" and passphrase attribute is not given for a gpg element, we will try to use a <!-- If prompt_passphrase is "no" and passphrase attribute is not given for a gpg element, we will try to use a
blank passphrase for all operations. --> blank passphrase for all operations. -->
<gpg keyid="none" gnupghome="none" publish="no" prompt_passphrase="no"> <gpg keyid="none" gnupghome="none" publish="no" prompt_passphrase="no">
<!-- The below is only used if we are generating a key (i.e. keyid="none"). --> <!-- The below is only used if we are generating a key (i.e. keyid="none"). -->
<key algo="rsa" keysize="4096" expire="0"> <key algo="rsa" keysize="4096" expire="0">
<name>{xpath%../../../meta/dev/author/text()}</name> <name>{xpath%../../../meta/dev/author/text()}</name>
<email>{xpath%../../../meta/dev/email/text()}</email> <email>{xpath%../../../meta/dev/email/text()}</email>
<comment>for {xpath%../../../meta/names/pname/text()} [autogenerated] | {xpath%../../../meta/uri/text()} | {xpath%../../../meta/desc/text()}</comment> <comment>for {xpath%../../../meta/names/pname/text()} [autogenerated] | {xpath%../../../meta/uri/text()} | {xpath%../../../meta/desc/text()}</comment>
</key> </key>
</gpg> </gpg>
<sync> <sync>
<!-- ipxe includes the http directory. or should, anyways. --> <!-- ipxe includes the http directory. or should, anyways. -->
<ipxe enabled="yes">/srv/http/{xpath%../../meta/names/uxname/text()}</ipxe> <ipxe enabled="true">/srv/http/{xpath%../../meta/names/uxname/text()}</ipxe>
<tftp enabled="yes">/tftproot/{xpath%../../meta/names/uxname/text()}</tftp> <tftp enabled="true">/tftproot/{xpath%../../meta/names/uxname/text()}</tftp>
<iso enabled="yes">/srv/http/isos/{xpath%../../meta/names/uxname/text()}</iso> <iso enabled="true">/srv/http/isos/{xpath%../../meta/names/uxname/text()}</iso>
<gpg enabled="yes" format="asc">/srv/http/{xpath%../../meta/names/uxname/text()}/pubkey.asc</gpg> <gpg enabled="true" format="asc">/srv/http/{xpath%../../meta/names/uxname/text()}/pubkey.asc</gpg>
<rsync enabled="yes"> <rsync enabled="true">
<user>root</user> <user>root</user>
<host>mirror.domain.tld</host> <host>mirror.domain.tld</host>
<port>22</port> <port>22</port>
<pubkey>~/.ssh/id_ed25519</pubkey> <pubkey>~/.ssh/id_ed25519</pubkey>
</rsync> </rsync>
</sync> </sync>
</profile> </profile>
<profile name="alternate" id="2" uuid="2ed07c19-2071-4d66-8569-da40475ba716"> <profile name="alternate" id="2" uuid="2ed07c19-2071-4d66-8569-da40475ba716">
<meta> <meta>
<names> <names>
<name>AnotherCD</name> <name>AnotherCD</name>
<uxname>bdisk_alt</uxname> <uxname>bdisk_alt</uxname>
<pname>{xpath%../name/text()}</pname> <pname>{xpath%../name/text()}</pname>
</names> </names>
<desc>Another rescue/restore live environment.</desc> <desc>Another rescue/restore live environment.</desc>
<dev> <dev>
<author>Another Dev Eloper</author> <author>Another Dev Eloper</author><!-- You can reference other profiles within the same configuration. -->
<!-- You can reference other profiles within the same configuration. --> <email>{xpath%//profile[@name="default"]/meta/dev/email/text()}</email>
<email>{xpath%//profile[@name="default"]/meta/dev/email/text()}</email> <website>{xpath%//profile[@name="default"]/meta/dev/website/text()}</website>
<website>{xpath%//profile[@name="default"]/meta/dev/website/text()}</website> </dev>
</dev> <uri>https://domain.tld/projname</uri>
<uri>https://domain.tld/projname</uri> <ver>0.0.1</ver>
<ver>0.0.1</ver> <max_recurse>5</max_recurse>
<max_recurse>5</max_recurse> <regexes>
<regexes> <pattern id="tarball_x86_64">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz$</pattern>
<pattern id="tarball_x86_64">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz$</pattern> <pattern id="sig_x86_64">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz\.sig$</pattern>
<pattern id="sig_x86_64">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz\.sig$</pattern> <pattern id="tarball_i686">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz$</pattern>
<pattern id="tarball_i686">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz$</pattern> <pattern id="sig_i686">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz\.sig$</pattern>
<pattern id="sig_i686">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz\.sig$</pattern> </regexes>
</regexes> <variables>
<variables> <variable id="bdisk_root">/var/tmp/BDisk</variable>
<variable id="bdisk_root">/var/tmp/BDisk</variable> </variables>
</variables> </meta>
</meta> <accounts>
<accounts> <rootpass hashed="false">atotallyinsecurepassword</rootpass>
<rootpass hashed="no">atotallyinsecurepassword</rootpass> <user sudo="false">
<user sudo="no"> <username>testuser</username>
<username>testuser</username> <comment>Test User</comment>
<comment>Test User</comment> <password hashed="false" hash_algo="sha512" salt="auto">atestpassword</password>
<password hashed="no" hash_algo="sha512" salt="auto">atestpassword</password> </user>
</user> </accounts>
</accounts> <sources>
<sources> <source arch="x86_64">
<source arch="x86_64"> <mirror>http://archlinux.mirror.domain.tld</mirror>
<mirror>http://archlinux.mirror.domain.tld</mirror> <rootpath>/iso/latest</rootpath>
<rootpath>/iso/latest</rootpath> <tarball flags="regex,latest">{regex%tarball_x86_64}</tarball>
<tarball flags="regex,latest">{regex%tarball_x86_64}</tarball> <checksum hash_algo="sha1" explicit="false">sha1sums.txt</checksum>
<checksum hash_algo="sha1" explicit="no">sha1sums.txt</checksum> <sig keys="7F2D434B9741E8AC" keyserver="hkp://pool.sks-keyservers.net" flags="regex,latest">{regex%sig_x86_64}</sig>
<sig keys="7F2D434B9741E8AC" keyserver="hkp://pool.sks-keyservers.net" flags="regex,latest">{regex%sig_x86_64}</sig> </source>
</source> <source arch="i686">
<source arch="i686"> <mirror>http://archlinux32.mirror.domain.tld</mirror>
<mirror>http://archlinux32.mirror.domain.tld</mirror> <rootpath>/iso/latest</rootpath>
<rootpath>/iso/latest</rootpath> <tarball flags="regex,latest">{regex%tarball_i686}</tarball>
<tarball flags="regex,latest">{regex%tarball_i686}</tarball> <checksum hash_algo="sha512" explicit="true">cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e</checksum>
<checksum hash_algo="sha512" explicit="yes">cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e</checksum> <sig keys="248BF41F9BDD61D41D060AE774EDA3C6B06D0506" keyserver="hkp://pool.sks-keyservers.net" flags="regex,latest">{regex%sig_i686}</sig>
<sig keys="248BF41F9BDD61D41D060AE774EDA3C6B06D0506" keyserver="hkp://pool.sks-keyservers.net" flags="regex,latest">{regex%sig_i686}</sig> </source>
</source> </sources>
</sources> <build its_full_of_stars="true">
<build its_full_of_stars="yes"> <paths>
<paths> <base>{variable%bdisk_root}/base</base>
<base>{variable%bdisk_root}/base</base> <cache>{variable%bdisk_root}/cache</cache>
<cache>{variable%bdisk_root}/cache</cache> <chroot>{variable%bdisk_root}/chroots</chroot>
<chroot>{variable%bdisk_root}/chroots</chroot> <overlay>{variable%bdisk_root}/overlay</overlay>
<overlay>{variable%bdisk_root}/overlay</overlay> <templates>{variable%bdisk_root}/templates</templates>
<templates>{variable%bdisk_root}/templates</templates> <mount>/mnt/{xpath%//meta/names/uxname/text()}</mount>
<mount>/mnt/{xpath%//meta/names/uxname/text()}</mount> <distros>{variable%bdisk_root}/distros</distros>
<distros>{variable%bdisk_root}/distros</distros> <dest>{variable%bdisk_root}/results</dest>
<dest>{variable%bdisk_root}/results</dest> <iso>{variable%bdisk_root}/iso_overlay</iso>
<iso>{variable%bdisk_root}/iso_overlay</iso> <http>{variable%bdisk_root}/http</http>
<http>{variable%bdisk_root}/http</http> <tftp>{variable%bdisk_root}/tftp</tftp>
<tftp>{variable%bdisk_root}/tftp</tftp> <pki>{variable%bdisk_root}/pki</pki>
<pki>{variable%bdisk_root}/pki</pki> </paths>
</paths> <basedistro>archlinux</basedistro>
<basedistro>archlinux</basedistro> </build>
</build> <iso sign="true" multi_arch="true"/>
<iso sign="yes" multi_arch="yes"/> <ipxe sign="true" iso="true">
<ipxe sign="yes" iso="yes"> <uri>{xpath%//meta/dev/website/text()}/ipxe</uri>
<uri>{xpath%//meta/dev/website/text()}/ipxe</uri> </ipxe>
</ipxe> <pki overwrite="no">
<pki overwrite="no"> <ca>
<ca> <cert hash_algo="sha512">{xpath%../../../build/paths/pki/text()}/ca.crt</cert>
<cert hash_algo="sha512">{xpath%../../../build/paths/pki/text()}/ca.crt</cert> <csr/>
<csr/> <index>{xpath%../../../build/paths/pki/text()}/index.txt</index>
<index>{xpath%../../../build/paths/pki/text()}/index.txt</index> <serial>{xpath%../../../build/paths/pki/text()}/serial</serial>
<serial>{xpath%../../../build/paths/pki/text()}/serial</serial> <key cipher="none" passphrase="none" keysize="4096">{xpath%../../../build/paths/pki/text()}/ca.key</key>
<key cipher="none" passphrase="none" keysize="4096">{xpath%../../../build/paths/pki/text()}/ca.key</key> <subject>
<subject> <commonName>domain.tld</commonName>
<commonName>domain.tld</commonName> <countryName>XX</countryName>
<countryName>XX</countryName> <localityName>Some City</localityName>
<localityName>Some City</localityName> <stateOrProvinceName>Some State</stateOrProvinceName>
<stateOrProvinceName>Some State</stateOrProvinceName> <organization>Some Org, Inc.</organization>
<organization>Some Org, Inc.</organization> <organizationalUnitName>Department Name</organizationalUnitName>
<organizationalUnitName>Department Name</organizationalUnitName> <emailAddress>{xpath%../../../../meta/dev/email/text()}</emailAddress>
<emailAddress>{xpath%../../../../meta/dev/email/text()}</emailAddress> </subject>
</subject> </ca>
</ca> <client>
<client> <cert hash_algo="sha512">{xpath%../../../build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.crt</cert>
<cert hash_algo="sha512">{xpath%../../../build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.crt</cert> <csr/>
<csr/> <key cipher="none" passphrase="none" keysize="4096">{xpath%//build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.key</key>
<key cipher="none" passphrase="none" keysize="4096">{xpath%//build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.key</key> <subject>
<subject> <commonName>some client name</commonName>
<commonName>some client name</commonName> <countryName>XX</countryName>
<countryName>XX</countryName> <localityName>Some City</localityName>
<localityName>Some City</localityName> <stateOrProvinceName>Some State</stateOrProvinceName>
<stateOrProvinceName>Some State</stateOrProvinceName> <organization>Some Org, Inc.</organization>
<organization>Some Org, Inc.</organization> <organizationalUnitName>Department Name</organizationalUnitName>
<organizationalUnitName>Department Name</organizationalUnitName> <emailAddress>{xpath%../../../../meta/dev/email/text()}</emailAddress>
<emailAddress>{xpath%../../../../meta/dev/email/text()}</emailAddress> </subject>
</subject> </client>
</client> </pki>
</pki> <gpg keyid="none" gnupghome="none" publish="no" prompt_passphrase="no">
<gpg keyid="none" gnupghome="none" publish="no" prompt_passphrase="no"> <key algo="rsa" keysize="4096" expire="0">
<key algo="rsa" keysize="4096" expire="0"> <name>{xpath%../../../meta/dev/author/text()}</name>
<name>{xpath%../../../meta/dev/author/text()}</name> <email>{xpath%../../../meta/dev/email/text()}</email>
<email>{xpath%../../../meta/dev/email/text()}</email> <comment>for {xpath%../../../meta/names/pname/text()} [autogenerated] | {xpath%../../../meta/uri/text()} | {xpath%../../../meta/desc/text()}</comment>
<comment>for {xpath%../../../meta/names/pname/text()} [autogenerated] | {xpath%../../../meta/uri/text()} | {xpath%../../../meta/desc/text()}</comment> </key>
</key> </gpg>
</gpg> <sync>
<sync> <ipxe enabled="true">/srv/http/{xpath%../../meta/names/uxname/text()}</ipxe>
<ipxe enabled="yes">/srv/http/{xpath%../../meta/names/uxname/text()}</ipxe> <tftp enabled="true">/tftproot/{xpath%../../meta/names/uxname/text()}</tftp>
<tftp enabled="yes">/tftproot/{xpath%../../meta/names/uxname/text()}</tftp> <iso enabled="true">/srv/http/isos/{xpath%../../meta/names/uxname/text()}</iso>
<iso enabled="yes">/srv/http/isos/{xpath%../../meta/names/uxname/text()}</iso> <gpg enabled="true" format="asc">/srv/http/{xpath%../../meta/names/uxname/text()}/pubkey.asc</gpg>
<gpg enabled="yes" format="asc">/srv/http/{xpath%../../meta/names/uxname/text()}/pubkey.asc</gpg> <rsync enabled="true">
<rsync enabled="yes"> <user>root</user>
<user>root</user> <host>mirror.domain.tld</host>
<host>mirror.domain.tld</host> <port>22</port>
<port>22</port> <pubkey>~/.ssh/id_ed25519</pubkey>
<pubkey>~/.ssh/id_ed25519</pubkey> </rsync>
</rsync> </sync>
</sync> </profile>
</profile>
</bdisk> </bdisk>

View File

@ -1,13 +1,34 @@
#!/usr/bin/env python3.6 #!/usr/bin/env python3.6


import copy import copy
from lxml import etree from lxml import etree, objectify


parser = etree.XMLParser(remove_blank_text = True) #parser = etree.XMLParser(remove_blank_text = True)
parser = etree.XMLParser(remove_blank_text = False)

# We need to append to a new root because you can't edit nsmap, and you can't
# xpath on an element with a naked namespace (e.g. 'xlmns="..."').
ns = {None: 'http://bdisk.square-r00t.net/',
'xsi': 'http://www.w3.org/2001/XMLSchema-instance'}
xsi = {'{http://www.w3.org/2001/XMLSchema-instance}schemaLocation':
'http://bdisk.square-r00t.net bdisk.xsd'}
new_cfg = etree.Element('bdisk', nsmap = ns, attrib = xsi)
new_cfg.text = '\n '


with open('single_profile.xml', 'rb') as f: with open('single_profile.xml', 'rb') as f:
xml = etree.fromstring(f.read(), parser) xml = etree.fromstring(f.read(), parser)



roottree = xml.getroottree()
for elem in roottree.getiterator():
if not hasattr(elem.tag, 'find'):
continue
i = elem.tag.find('}')
if i >= 0:
elem.tag = elem.tag[i + 1:]
objectify.deannotate(roottree, cleanup_namespaces = True)


single_profile = xml.xpath('/bdisk/profile[1]')[0] single_profile = xml.xpath('/bdisk/profile[1]')[0]
alt_profile = copy.deepcopy(single_profile) alt_profile = copy.deepcopy(single_profile)
for c in alt_profile.xpath('//comment()'): for c in alt_profile.xpath('//comment()'):
@ -42,18 +63,22 @@ for e in accounts.iter():
if e.tag in accounts_tags: if e.tag in accounts_tags:
e.text = accounts_tags[e.tag] e.text = accounts_tags[e.tag]
if e.tag == 'rootpass': if e.tag == 'rootpass':
e.attrib['hashed'] = 'no' e.attrib['hashed'] = 'false'
elif e.tag == 'user': elif e.tag == 'user':
e.attrib['sudo'] = 'no' e.attrib['sudo'] = 'false'
# Delete the second user # Delete the second user
accounts.remove(accounts[2]) accounts.remove(accounts[2])
author = alt_profile.xpath('/profile/meta/dev/author')[0] author = alt_profile.xpath('/profile/meta/dev/author')[0]
author.addnext(etree.Comment( author.addnext(etree.Comment(
' You can reference other profiles within the same configuration. ')) ' You can reference other profiles within the same configuration. '))
xml.append(alt_profile) #xml.append(alt_profile)

for child in xml.xpath('/bdisk/profile'):
new_cfg.append(copy.deepcopy(child))
new_cfg.append(alt_profile)


with open('multi_profile.xml', 'wb') as f: with open('multi_profile.xml', 'wb') as f:
f.write(etree.tostring(xml, f.write(etree.tostring(new_cfg,
pretty_print = True, pretty_print = True,
encoding = 'UTF-8', encoding = 'UTF-8',
xml_declaration = True)) xml_declaration = True))

View File

@ -1,11 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<bdisk xmlns:bdisk="http://bdisk.square-r00t.net/" <bdisk xmlns="http://bdisk.square-r00t.net/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://bdisk.square-r00t.net bdisk.xsd"> xsi:schemaLocation="http://bdisk.square-r00t.net bdisk.xsd">
<profile name="default" id="1" uuid="8cdd6bcb-c147-4a63-9779-b5433c510dbc"> <profile name="default" id="1" uuid="8cdd6bcb-c147-4a63-9779-b5433c510dbc">
<meta> <meta>
<names> <names>
<name>BDisk</name> <name>BDISK</name>
<!--<name>{xpath%../uxname/text()}</name>-->
<uxname>bdisk</uxname> <uxname>bdisk</uxname>
<!-- Just like with previous versions of BDisk, you can reference other values... <!-- Just like with previous versions of BDisk, you can reference other values...
but now with the neat benefits of XPath! Everything you could do in build.ini's and more. but now with the neat benefits of XPath! Everything you could do in build.ini's and more.
@ -29,8 +30,7 @@
items. See the manual for more information. NO btags within the patterns is allowed. --> items. See the manual for more information. NO btags within the patterns is allowed. -->
<regexes> <regexes>
<pattern id="tarball_x86_64">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz$</pattern> <pattern id="tarball_x86_64">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz$</pattern>
<pattern id="sig_x86_64">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz\.sig$ <pattern id="sig_x86_64">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz\.sig$</pattern>
</pattern>
<pattern id="tarball_i686">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz$</pattern> <pattern id="tarball_i686">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz$</pattern>
<pattern id="sig_i686">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz\.sig$</pattern> <pattern id="sig_i686">archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz\.sig$</pattern>
</regexes> </regexes>
@ -41,56 +41,48 @@
</meta> </meta>
<accounts> <accounts>
<!-- Salted/hashed password is "test" --> <!-- Salted/hashed password is "test" -->
<rootpass hashed="yes"> <rootpass hashed="true">$6$7KfIdtHTcXwVrZAC$LZGNeMNz7v5o/cYuA48FAxtZynpIwO5B1CPGXnOW5kCTVpXVt4SypRqfM.AoKkFt/O7MZZ8ySXJmxpELKmdlF1</rootpass>
$6$7KfIdtHTcXwVrZAC$LZGNeMNz7v5o/cYuA48FAxtZynpIwO5B1CPGXnOW5kCTVpXVt4SypRqfM.AoKkFt/O7MZZ8ySXJmxpELKmdlF1 <user sudo="true">
</rootpass>
<user sudo="yes">
<username>{xpath%//meta/names/uxname/text()}</username> <username>{xpath%//meta/names/uxname/text()}</username>
<!-- You can also use substitution from different profiles in this same configuration: --> <!-- You can also use substitution from different profiles in this same configuration: -->
<!-- <username>{xpath%//profile[@name='another_profile']/meta/names/uxname"}</username> --> <!-- <username>{xpath%//profile[@name='another_profile']/meta/names/uxname"}</username> -->
<comment>{xpath%//meta/dev/author/text()}</comment> <comment>{xpath%//meta/dev/author/text()}</comment>
<password hashed="no" <password hashed="false"
hash_algo="sha512" hash_algo="sha512"
salt="auto">testpassword salt="auto">testpassword</password>
</password>
</user> </user>
<user sudo="no"> <user sudo="false">
<username>testuser</username> <username>testuser</username>
<name>Test User</name> <comment>Test User</comment>
<password hashed="no" <password hashed="false"
hash_algo="sha512" hash_algo="sha512"
salt="auto">anothertestpassword salt="auto">anothertestpassword</password>
</password>
</user> </user>
</accounts> </accounts>
<sources> <sources>
<source arch="x86_64"> <source arch="x86_64">
<mirror>http://archlinux.mirror.domain.tld</mirror> <mirror>http://archlinux.mirror.domain.tld</mirror>
<rootpath>/iso/latest</rootpath> <rootpath>/iso/latest</rootpath>
<tarball flags="regex,latest">{regex%tarball_x86_64}</tarball> <tarball flags="regex latest">{regex%tarball_x86_64}</tarball>
<checksum hash_algo="sha1" <checksum hash_algo="sha1"
explicit="no">sha1sums.txt explicit="false"
</checksum> flags="latest">sha1sums.txt</checksum>
<sig keys="7F2D434B9741E8AC" <sig keys="7F2D434B9741E8AC"
keyserver="hkp://pool.sks-keyservers.net" keyserver="hkp://pool.sks-keyservers.net"
flags="regex,latest">{regex%sig_x86_64} flags="regex latest">{regex%sig_x86_64}</sig>
</sig>
</source> </source>
<source arch="i686"> <source arch="i686">
<mirror>http://archlinux32.mirror.domain.tld</mirror> <mirror>http://archlinux32.mirror.domain.tld</mirror>
<rootpath>/iso/latest</rootpath> <rootpath>/iso/latest</rootpath>
<tarball flags="regex,latest">{regex%tarball_i686}</tarball> <tarball flags="regex latest">{regex%tarball_i686}</tarball>
<checksum hash_algo="sha512" <checksum hash_algo="sha512"
explicit="yes"> explicit="true">cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e</checksum>
cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
</checksum>
<sig keys="248BF41F9BDD61D41D060AE774EDA3C6B06D0506" <sig keys="248BF41F9BDD61D41D060AE774EDA3C6B06D0506"
keyserver="hkp://pool.sks-keyservers.net" keyserver="hkp://pool.sks-keyservers.net"
flags="regex,latest">{regex%sig_i686} flags="regex latest">{regex%sig_i686}</sig>
</sig>
</source> </source>
</sources> </sources>
<build its_full_of_stars="yes"> <build its_full_of_stars="true">
<paths> <paths>
<base>{variable%bdisk_root}/base</base> <base>{variable%bdisk_root}/base</base>
<cache>{variable%bdisk_root}/cache</cache> <cache>{variable%bdisk_root}/cache</cache>
@ -107,11 +99,11 @@
</paths> </paths>
<basedistro>archlinux</basedistro> <basedistro>archlinux</basedistro>
</build> </build>
<iso sign="yes" multi_arch="yes"/> <iso sign="true" multi_arch="true"/>
<ipxe sign="yes" iso="yes"> <ipxe sign="true" iso="true">
<uri>{xpath%//meta/dev/website/text()}/ipxe</uri> <uri>{xpath%//meta/dev/website/text()}/ipxe</uri>
</ipxe> </ipxe>
<pki overwrite="no"> <pki overwrite="false">
<!-- http://ipxe.org/crypto --> <!-- http://ipxe.org/crypto -->
<ca> <ca>
<cert hash_algo="sha512">{xpath%../../../build/paths/pki/text()}/ca.crt</cert> <cert hash_algo="sha512">{xpath%../../../build/paths/pki/text()}/ca.crt</cert>
@ -133,8 +125,7 @@
be (securely) prompted for the passphrase to unlock it/add a passphrase to it. --> be (securely) prompted for the passphrase to unlock it/add a passphrase to it. -->
<key cipher="none" <key cipher="none"
passphrase="none" passphrase="none"
keysize="4096">{xpath%../../../build/paths/pki/text()}/ca.key keysize="4096">{xpath%../../../build/paths/pki/text()}/ca.key</key>
</key>
<subject> <subject>
<commonName>domain.tld</commonName> <commonName>domain.tld</commonName>
<countryName>XX</countryName> <countryName>XX</countryName>
@ -146,16 +137,13 @@
</subject> </subject>
</ca> </ca>
<client> <client>
<cert hash_algo="sha512"> <cert hash_algo="sha512">{xpath%../../../build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.crt</cert>
{xpath%../../../build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.crt
</cert>
<csr/> <csr/>
<key cipher="none" <key cipher="none"
passphrase="none" passphrase="none"
keysize="4096">{xpath%//build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.key keysize="4096">{xpath%//build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.key</key>
</key>
<subject> <subject>
<commonName>some client name</commonName> <commonName>website.tld</commonName>
<countryName>XX</countryName> <countryName>XX</countryName>
<localityName>Some City</localityName> <localityName>Some City</localityName>
<stateOrProvinceName>Some State</stateOrProvinceName> <stateOrProvinceName>Some State</stateOrProvinceName>
@ -169,26 +157,23 @@
blank passphrase for all operations. --> blank passphrase for all operations. -->
<gpg keyid="none" <gpg keyid="none"
gnupghome="none" gnupghome="none"
publish="no" publish="false"
prompt_passphrase="no"> prompt_passphrase="false">
<!-- The below is only used if we are generating a key (i.e. keyid="none"). --> <!-- The below is only used if we are generating a key (i.e. keyid="none"). -->
<key algo="rsa" keysize="4096" expire="0"> <key algo="rsa" keysize="4096" expire="0">
<name>{xpath%../../../meta/dev/author/text()}</name> <name>{xpath%../../../meta/dev/author/text()}</name>
<email>{xpath%../../../meta/dev/email/text()}</email> <email>{xpath%../../../meta/dev/email/text()}</email>
<comment>for {xpath%../../../meta/names/pname/text()} [autogenerated] | {xpath%../../../meta/uri/text()} <comment>for {xpath%../../../meta/names/pname/text()} [autogenerated] | {xpath%../../../meta/uri/text()} | {xpath%../../../meta/desc/text()}</comment>
| {xpath%../../../meta/desc/text()}
</comment>
</key> </key>
</gpg> </gpg>
<sync> <sync>
<!-- ipxe includes the http directory. or should, anyways. --> <!-- ipxe includes the http directory. or should, anyways. -->
<ipxe enabled="yes">/srv/http/{xpath%../../meta/names/uxname/text()}</ipxe> <ipxe enabled="true">/srv/http/{xpath%../../meta/names/uxname/text()}</ipxe>
<tftp enabled="yes">/tftproot/{xpath%../../meta/names/uxname/text()}</tftp> <tftp enabled="true">/tftproot/{xpath%../../meta/names/uxname/text()}</tftp>
<iso enabled="yes">/srv/http/isos/{xpath%../../meta/names/uxname/text()}</iso> <iso enabled="true">/srv/http/isos/{xpath%../../meta/names/uxname/text()}</iso>
<gpg enabled="yes" <gpg enabled="true"
format="asc">/srv/http/{xpath%../../meta/names/uxname/text()}/pubkey.asc format="asc">/srv/http/{xpath%../../meta/names/uxname/text()}/pubkey.asc</gpg>
</gpg> <rsync enabled="true">
<rsync enabled="yes">
<user>root</user> <user>root</user>
<host>mirror.domain.tld</host> <host>mirror.domain.tld</host>
<port>22</port> <port>22</port>