holy cats. docs are finally done

and packaging commands/alternate packager
reconfigured- though untested.  bumping tag out of
beta because nothing should(????) break.
This commit is contained in:
brent s 2017-05-05 01:40:28 -04:00
parent fa61ea6400
commit bad590518a
5 changed files with 51 additions and 115 deletions

8
HOWTO
View File

@ -1,8 +0,0 @@
The following kernel parameters are supported:

aif aif=True do the same thing. if aif is False, it behaves as if aif is not specified. Enable AIF.
aif_url path to install XML document. can be e.g.: http://domain.tld/aif.xml https://domain.tld/aif.xml ftp://domain.tld/aif.xml file:///tmp/aif.xml (note that local filesystem references are in relation to the system running the client) (note: HTTPS must be signed by a valid root CA)
aif_username the username to use for HTTP/HTTPS Basic auth, HTTP/HTTPS Digest auth, or FTP/FTPS auth (must be specified to use Basic/Digest auth)
aif_password the password to use for HTTP/HTTPS Basic auth, HTTP/HTTPS Digest auth, or FTP/FTPS auth (must be specified to use Basic/Digest auth)
aif_auth either 'basic' or 'digest', for HTTP/HTTPS auth (ignored for other types). default, if others are specified, is basic.
aif_realm the realm name for HTTP/HTTPS Digest auth (ignored for other types). leave unset to try whatever default realm is presented

10
aif.xsd
View File

@ -108,6 +108,12 @@
<xs:pattern value="(file|https?)://.*" /> <xs:pattern value="(file|https?)://.*" />
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>

<xs:simpleType name="scripttype">
<xs:restriction base="xs:token">
<xs:pattern value="(pre|post|pkg)" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="bootloaders"> <xs:simpleType name="bootloaders">
<xs:restriction base="xs:token"> <xs:restriction base="xs:token">
@ -266,7 +272,6 @@
<xs:element name="pacman" maxOccurs="1" minOccurs="1"> <xs:element name="pacman" maxOccurs="1" minOccurs="1">
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>
<xs:element name="command" maxOccurs="1" minOccurs="0" />
<xs:element name="repos" maxOccurs="1" minOccurs="1"> <xs:element name="repos" maxOccurs="1" minOccurs="1">
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>
@ -305,6 +310,7 @@
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
</xs:sequence> </xs:sequence>
<xs:attribute name="command" type="xs:string" />
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<!-- END PACMAN --> <!-- END PACMAN -->
@ -325,7 +331,7 @@
<xs:complexType> <xs:complexType>
<xs:attribute name="uri" type="scripturi" use="required" /> <xs:attribute name="uri" type="scripturi" use="required" />
<xs:attribute name="order" type="xs:integer" use="required" /> <xs:attribute name="order" type="xs:integer" use="required" />
<xs:attribute name="bootstrap" type="xs:boolean" use="required" /> <xs:attribute name="execution" type="xs:scripttype" use="required" />
<xs:attribute name="user" type="xs:string" /> <xs:attribute name="user" type="xs:string" />
<xs:attribute name="password" type="xs:string" /> <xs:attribute name="password" type="xs:string" />
<xs:attribute name="realm" type="xs:string" /> <xs:attribute name="realm" type="xs:string" />

View File

@ -306,10 +306,10 @@ class aif(object):
for i in x: for i in x:
aifdict['software']['mirrors'].append(i.text) aifdict['software']['mirrors'].append(i.text)
# Then the command # Then the command
if xmlobj.find('pacman/command') is None: if 'command' in xmlobj.find('pacman').attrib:
aifdict['software']['command'] = False aifdict['software']['command'] = xmlobj.find('pacman').attrib['command']
else: else:
aifdict['software']['command'] = xmlobj.find('pacman/command').text aifdict['software']['command'] = False
# And then the repo list. # And then the repo list.
for x in xmlobj.findall('pacman/repos/repo'): for x in xmlobj.findall('pacman/repos/repo'):
repo = x.attrib['name'] repo = x.attrib['name']
@ -348,11 +348,8 @@ class aif(object):
scriptcontents = self.webFetch(x.attrib['uri'], auth).decode('utf-8') scriptcontents = self.webFetch(x.attrib['uri'], auth).decode('utf-8')
else: else:
scriptcontents = self.webFetch(x.attrib['uri']).decode('utf-8') scriptcontents = self.webFetch(x.attrib['uri']).decode('utf-8')
if x.attrib['bootstrap'].lower() in ('true', '1'): tempscriptdict[x.attrib['execution']][x.attrib['order']] = scriptcontents
tempscriptdict['pre'][x.attrib['order']] = scriptcontents for d in ('pre', 'post', 'pkg'):
else:
tempscriptdict['post'][x.attrib['order']] = scriptcontents
for d in ('pre', 'post'):
keylst = list(tempscriptdict[d].keys()) keylst = list(tempscriptdict[d].keys())
keylst.sort() keylst.sort()
for s in keylst: for s in keylst:
@ -782,7 +779,6 @@ class archInstall(object):
return(bootcmds) return(bootcmds)


def scriptcmds(self, scripttype): def scriptcmds(self, scripttype):
# Pre-run/"booststrap" scripts
t = scripttype t = scripttype
if t in self.scripts.keys(): if t in self.scripts.keys():
for i, s in enumerate(self.scripts[t]): for i, s in enumerate(self.scripts[t]):
@ -793,11 +789,11 @@ class archInstall(object):
f.write(s) f.write(s)
os.chmod(filepath, 0o700) os.chmod(filepath, 0o700)
os.chown(filepath, 0, 0) # shouldn't be necessary, but just in case the umask's messed up or something. os.chown(filepath, 0, 0) # shouldn't be necessary, but just in case the umask's messed up or something.
if t == 'pre': if t in ('pre', 'pkg'):
# We want to run these right away. # We want to run these right away.
with open(logfile, 'a') as log: with open(logfile, 'a') as log:
for i, s in enumerate(self.scripts['pre']): for i, s in enumerate(self.scripts[t]):
subprocess.call('/root/scripts/pre/{0}'.format(i), subprocess.call('/root/scripts/{0}/{1}'.format(t, i),
stdout = log, stdout = log,
stderr = subprocess.STDOUT) stderr = subprocess.STDOUT)
return() return()
@ -847,12 +843,9 @@ class archInstall(object):
# This should be run in the chroot, unless we find a way to pacstrap # This should be run in the chroot, unless we find a way to pacstrap
# packages separate from chrooting # packages separate from chrooting
if self.software['command']: if self.software['command']:
pkgr = self.software['command'] pkgr = shlex.split(self.software['command'])
else: else:
pkgr = 'pacman' pkgr = ['pacman', '--needed', '--noconfirm', '-S']
pkgropts = ['--needed', '--noconfirm']
if pkgr == 'apacman':
pkgropts.extend(['--noedit', '--skipinteg'])
if self.software['packages']: if self.software['packages']:
for p in self.software['packages'].keys(): for p in self.software['packages'].keys():
if self.software['packages'][p]['repo']: if self.software['packages'][p]['repo']:
@ -860,11 +853,8 @@ class archInstall(object):
self.software['packages'][p]) self.software['packages'][p])
else: else:
pkgname = p pkgname = p
cmd = [pkgr] pkgr.append(pkgname)
for o in pkgropts: pkgcmds.append(pkgr)
cmd.append(o)
cmd.extend(['-S', pkgname])
pkgcmds.append(cmd)
return(pkgcmds) return(pkgcmds)


def serviceSetup(self): def serviceSetup(self):
@ -903,6 +893,12 @@ class archInstall(object):
with open(logfile, 'a') as log: with open(logfile, 'a') as log:
for c in chrootcmds: for c in chrootcmds:
subprocess.call(c, stdout = log, stderr = subprocess.STDOUT) subprocess.call(c, stdout = log, stderr = subprocess.STDOUT)
if scripts['pkg']:
self.scriptcmds('pkg')
for i, s in enumerate(scripts['pkg']):
subprocess.call('/root/scripts/pkg/{0}'.format(i),
stdout = log,
stderr = subprocess.STDOUT)
for p in pkgcmds: for p in pkgcmds:
subprocess.call(p, stdout = log, stderr = subprocess.STDOUT) subprocess.call(p, stdout = log, stderr = subprocess.STDOUT)
for b in bootcmds: for b in bootcmds:
@ -946,6 +942,7 @@ def main():
with open(logfile, 'a') as log: with open(logfile, 'a') as log:
pprint.pprint(instconf, stream = log) pprint.pprint(instconf, stream = log)
runInstall(instconf) runInstall(instconf)
subprocess.call(['reboot'])


if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -409,12 +409,22 @@ The `/aif/system/service` element holds information about services that should e
|====================== |======================


=== `<pacman>` === `<pacman>`
The `/aif/pacman` element contains the <<code_repos_code, repos>>, <<code_repo_code, repos/repo>>, <<code_mirrorlist_code, mirrorlist>>, <<code_mirror_code, mirrorlist/mirror>>, <<code_software_code, software>>, <<code_package_code, software/packages>>, and <<code_command_code, command>> elements. The `/aif/pacman` element contains the <<code_repos_code, repos>>, <<code_repo_code, repos/repo>>, <<code_mirrorlist_code, mirrorlist>>, <<code_mirror_code, mirrorlist/mirror>>, <<code_software_code, software>>, and <<code_package_code, software/packages>> elements.


==== `<command>` [options="header"]
NOTE: This is currently kind of useless. I need to implement a pre-package-installation <<code_scripts_code, hook script>> first. I promise it's coming. |======================
^|Attribute ^|Value
^m|command |The command to use to install a package
|======================


If you configured an alternate package utility, you can specify the command here. Note that it should be configured/called with necessary options to avoid the necessity of user involvement (since that's the entire point of AIF-NG). [[command]]
If you configured an alternate package utility (using a `execution="pkg"` <<code_script_code, script>> entry), you can specify the command here. Note that it should be configured/called with necessary options to avoid the necessity of user involvement (since that's the entire point of AIF-NG). e.g.:

<aif ... >
...
<pacman command="apacman --needed --noconfirm --noedit --skipinteg -S">
...
</aif>


==== `<repos>` ==== `<repos>`
The `/aif/pacman/repos` element contains one (or more) <<code_repo_code, repo>> element(s). The `/aif/pacman/repos` element contains one (or more) <<code_repo_code, repo>> element(s).
@ -476,7 +486,15 @@ The `/aif/scripts/script` elements specify scripts to be run at different stages
^m|user |Same behavior as <<starting_an_install, `aif_user`>> but for fetching this script (see also <<aif_url, further notes>> on this) ^m|user |Same behavior as <<starting_an_install, `aif_user`>> but for fetching this script (see also <<aif_url, further notes>> on this)
^m|password |Same behavior as <<starting_an_install, `aif_password`>> but for fetching this script (see also <<aif_url, further notes>> on this) ^m|password |Same behavior as <<starting_an_install, `aif_password`>> but for fetching this script (see also <<aif_url, further notes>> on this)
^m|realm |Same behavior as <<starting_an_install, `aif_realm`>> but for fetching this script (see also <<aif_url, further notes>> on this) ^m|realm |Same behavior as <<starting_an_install, `aif_realm`>> but for fetching this script (see also <<aif_url, further notes>> on this)
^m|bootstrap |A boolean; if `1`/`true` then we will run this script before even formatting <<code_disk_code, disks>>; otherwise if it's `0`/`false` then we would run it *inside* the chroot environment as the very last thing ^m|execution |(see <<script_types, below>>)
|====================== |======================


NOTE: The `bootstrap` attribute is subject to change to something more flexible to allow more flexibility in when the scripts are executed. Expect this to happen soon, so be aware.
[[script_types]]
There are several script types availabe for `execution`. Currently, these are:

* pre
* pkg
* post

*pre* scripts are run (in numerical `order`) before the disks are even formatted. *pkg* scripts are run (in numerical `order`) right before the <<code_package_code, packages>> are installed (this allows you to configure an <<command, alternate packager>> such as https://aur.archlinux.org/packages/apacman/[apacman^]) - these are run *inside* the chroot of the new install. *pre* scripts are run inside the chroot like *pkg*, but are executed very last thing, just before the reboot.

View File

@ -1,77 +0,0 @@
{'disk': {'/dev/sda': {'fmt': 'gpt',
'parts': {'1': {'fstype': 'ef00',
'num': '1',
'size': '10%',
'start': '0%'},
'2': {'fstype': '8300',
'num': '2',
'size': '80%',
'start': '10%'},
'3': {'fstype': '8200',
'num': '3',
'size': '10%',
'start': '80%'}}}},
'mount': {'1': {'device': '/dev/sda2',
'fstype': None,
'mountpt': '/mnt',
'opts': None},
'2': {'device': '/dev/sda1',
'fstype': None,
'mountpt': '/mnt/boot',
'opts': None},
'3': {'device': '/dev/sda3',
'fstype': None,
'mountpt': 'swap',
'opts': None}},
'network': {'hostname': 'aiftest.square-r00t.net',
'ifaces': {'auto': {'ipv4': {'addresses': ['auto'],
'gw': False,
'resolvers': False},
'resolvers': []}}},
'scripts': {'post': {}, 'pre': {}},
'software': {'mirrors': ['http://mirrors.advancedhosters.com/archlinux/$repo/os/$arch',
'http://mirrors.advancedhosters.com/archlinux/$repo/os/$arch',
'http://mirror.us.leaseweb.net/archlinux/$repo/os/$arch',
'http://ftp.osuosl.org/pub/archlinux/$repo/os/$arch',
'http://arch.mirrors.ionfish.org/$repo/os/$arch',
'http://mirrors.gigenet.com/archlinux/$repo/os/$arch',
'http://mirror.jmu.edu/pub/archlinux/$repo/os/$arch'],
'packages': {'sed': {'repo': 'core'}},
'repos': {'archlinuxfr': {'enabled': False,
'mirror': 'http://repo.archlinux.fr/$arch',
'siglevel': 'Optional TrustedOnly'},
'community': {'enabled': True,
'mirror': 'file:///etc/pacman.d/mirrorlist',
'siglevel': 'default'},
'core': {'enabled': True,
'mirror': 'file:///etc/pacman.d/mirrorlist',
'siglevel': 'default'},
'extra': {'enabled': True,
'mirror': 'file:///etc/pacman.d/mirrorlist',
'siglevel': 'default'},
'multilib': {'enabled': True,
'mirror': 'file:///etc/pacman.d/mirrorlist',
'siglevel': 'default'},
'multilib-testing': {'enabled': False,
'mirror': 'file:///etc/pacman.d/mirrorlist',
'siglevel': 'default'},
'testing': {'enabled': False,
'mirror': 'file:///etc/pacman.d/mirrorlist',
'siglevel': 'default'}}},
'system': {'bootloader': {'efi': 'true', 'target': '/boot', 'type': 'grub'},
'chrootpath': '/mnt',
'kbd': False,
'locale': 'en_US.UTF-8',
'services': False,
'timezone': 'EST5EDT'},
'users': {'aifusr': {'comment': 'A test user for AIF.',
'gid': None,
'group': None,
'home': {'create': True, 'path': '/opt/aifusr'},
'password': '$6$WtxZKOyaahvvWQRG$TUys60kQhF0ffBdnDSJVTA.PovwCOajjMz8HEHL2H0ZMi0bFpDTQvKA7BqzM3nA.ZMAUxNjpJP1dG/eA78Zgw0',
'sudo': True,
'uid': None,
'xgroup': {'admins': {'create': True, 'gid': False},
'users': {'create': False, 'gid': False},
'wheel': {'create': False, 'gid': False}}},
'root': {'password': '$6$3YPpiS.l3SQC6ELe$NQ4qMvcDpv5j1cCM6AGNc5Hyg.rsvtzCt2VWlSbuZXCGg2GB21CMUN8TMGS35tdUezZ/n9y3UFGlmLRVWXvZR.'}}}