2
0
mirror of https://github.com/xcat2/confluent.git synced 2026-09-29 00:31:09 +00:00

Compare commits

...

337 Commits

Author SHA1 Message Date
Jarrod Johnson 49a504972f Fix syntax error in confignet 2023-10-25 14:21:55 -04:00
Jarrod Johnson 9c9d71882c Disable keepalive
Unfortunately, apache can get a bit odd over how it
reports a non-viable open socket for keepalive, which
can happen in certain windows.

Disable the keepalive feature and take some performance penalty in
browsers for the sake of more consistent return behavior and
fewer idle greenthreads doing nothing.
2023-10-19 15:51:40 -04:00
Jarrod Johnson 913a26aec9 Change to consistent CWD for osdeploy arm build 2023-10-19 10:42:39 -04:00
Jarrod Johnson 063bfc17a5 Start using container for final build process
Makes supporting the base platform easier by largely ignoring the
base platform.
2023-10-19 10:40:57 -04:00
Jarrod Johnson 8b150a9047 Fix for post group failures
A node failure after group failure would
erase the group from range.

Further, correct an issue where an empty nodeset
would trigger
a bad behavior.
2023-10-19 09:25:57 -04:00
Jarrod Johnson b91a194184 Improve selfselfice performance with yaml
The yaml python default behavior is 'pure python' and is
tortuously slow.

As a test, yaml dump of a 17,000 element list took 70 seconds in default configuration.

Opting into the C functions, that time comes down to 10 seconds, a
nice and easy improvement for generic yaml.

For dumping a simple dumb list (e.g. the nodelist for ssh), a special
case yaml-looking result is done, which hits 0.4 seconds on that same
test. So this special case is added to nodelist, which can be very long
and very in demand at the same time.
2023-10-17 16:29:30 -04:00
Jarrod Johnson 06d18cec63 Fix abbreviation when pad decreases
This is a bizarre way to work, but it should be valid.
2023-10-16 08:29:45 -04:00
Jarrod Johnson 0434f38ea1 Add iterm and kitty image support to stats
This delivers improved graphics
speed and quality for selected terminals.
2023-10-13 15:25:08 -04:00
Jarrod Johnson bfbb7c2843 Handle mid-range pad changing, and identical names with only pad difference
This would be painful to operate, but if done at least
reverse noderange will
faithfully honor it now.
2023-10-12 16:09:40 -04:00
Jarrod Johnson 3a6932ea6d Start tracking padding during abbreviation
This will take care of padding when
padding is consistent across a range.

However, we still have a problem with a progression like:
01
02
...
98
099
100

Where numbers in the middle start getting padding unexpectedly without a leading digit.
2023-10-12 15:28:54 -04:00
Jarrod Johnson 6e4d9d9eb4 Address potential slowdowns by misbehaving DNS
For one, shorten the DNS timeout, if the DNS server is completely out, give up quickly.

For another, if a host has a large number of net.X.hostnames, the sequential nature
was intolerable.
Have each network be evaluated in a greenthread concurrently to serve
the DNS latency concurrently.
2023-10-12 14:46:09 -04:00
Jarrod Johnson 2d906e1886 Fix handling of pre-existing array 2023-10-11 10:15:24 -04:00
Jarrod Johnson e9a2f57ad8 Simplify the noderange abbreviation
Since the multi-iterator ambition is out,
ditch the expensive set wrangling step.

Now the procedure is:
-Suck nodes into groups, as possible
-Separately for groups and nodes:
     -Sort the elements
     -Chunk the elements based on 'non-numberical' situation matching
     -analyze the iterators to apply [] to shorten the name
     -Multi-iterator will cause a discontinuity, and a new ',' delimited name gets constructed
2023-10-10 16:56:32 -04:00
Jarrod Johnson c254564f02 Fully give up on multi-iterator abbreviation
There's too many cases that can go wrong.

Note that with this lower ambition, it would be possible to
significantly streamline the implementation.

Notably, the 'find discontinuities' approach
was selected to *try* to
support multiple iterators,
but since that didn't pan out,
a more straightforward
numerical strategy can
be used from the onset.
2023-10-10 12:47:19 -04:00
Jarrod Johnson fe27cdea4a Abbreviate harder, using brackets
Add a round that collapses as is
convenient to bracketed range.
2023-10-09 17:18:44 -04:00
Jarrod Johnson a4ea5e5c4b Abbreviate sequential nodes
When we have sequential nodes, collapse to ':' delimited range.
2023-10-07 09:51:32 -04:00
Jarrod Johnson 06ee48f702 Merge pull request #135 from tkucherera-lenovo/Nodeattrib
missing_shlex import in nodeattrib
2023-10-05 12:53:16 -04:00
tkucherera 77eec1a791 missing_shlex import in nodeattrib 2023-10-05 11:44:04 -04:00
Jarrod Johnson b60b78327f Merge pull request #134 from tkucherera-lenovo/Nodeattrib
Nodeattrib
2023-10-04 16:32:32 -04:00
tkucherera 2e84c73baa '' 2023-10-04 16:27:05 -04:00
tkucherera 67f607a8f1 fix to synopsis 2023-10-04 16:26:20 -04:00
tkucherera eca1854d56 fix to env doc 2023-10-04 10:37:41 -04:00
tkucherera ba90609f3b documentation for nodeattrib -s 2023-10-04 10:36:58 -04:00
tkucherera c8094276d0 typ0_fix 2023-10-04 10:34:07 -04:00
tkucherera d299db3442 doc 2023-10-04 10:31:24 -04:00
tkucherera 9f168aee73 docs- batch file systax 2023-10-04 10:28:16 -04:00
Jarrod Johnson ee19386d8c Export nodename in ubuntu pre 2023-10-04 09:49:09 -04:00
Jarrod Johnson ef9083062b Make multiple attempts to fetch networking configuration
Since confignet runs early in startup, the networking can be a bit fickle.

Tolerate outages during early use.
2023-10-03 10:13:53 -04:00
Jarrod Johnson cca0c57e90 Merge pull request #132 from tkucherera-lenovo/nodersync
node rsync -s switch
2023-10-02 12:57:19 -04:00
Jarrod Johnson 79e3ad53f8 Add server side rack layout organization
The info is hard to put together client side, but
supremely easy server side.

Provide a nice call to
get the layout for a noderange, similar to (but better than) current
GUI code.

Now GUI can get a nice canned JSON
description of the layout.
2023-09-29 16:23:59 -04:00
tkucherera b63d75f2bb change to remove to many conditionals 2023-09-29 12:07:38 -04:00
tkucherera 378929579f Allow to be able to specify prefix as well 2023-09-28 08:56:52 -04:00
tkucherera eee8bbb498 node rsync -s switch 2023-09-27 17:52:15 -04:00
Jarrod Johnson a00fd325aa Export variables for ubuntu pre.d run 2023-09-27 13:09:23 -04:00
Jarrod Johnson 3624013889 Merge pull request #130 from tkucherera-lenovo/Nodeattrib
Nodeattrib
2023-09-20 15:07:02 -04:00
tkucherera bd0b16992d man page 2023-09-20 14:42:17 -04:00
tkucherera 4ecbbdfd9a nodeattrib -s use with batch file 2023-09-20 14:37:07 -04:00
tkucherera 5768514ba9 nodeattrib -s attrib.batch 2023-09-20 14:29:21 -04:00
Jarrod Johnson f88b44dee2 Fix issues with imgutil 2023-09-20 10:13:34 -04:00
Jarrod Johnson d0c97b7623 Add pieces of EL profiles 2023-09-19 13:14:07 -04:00
Jarrod Johnson 04505e1bbb Break out partitioning and pagkacelist for EL profiles 2023-09-19 13:01:10 -04:00
Jarrod Johnson d613d0f546 Add openbmc plugin for console 2023-09-18 16:03:48 -04:00
Jarrod Johnson 47fc233cce Fix debian packaging for confluent 2023-09-18 15:48:38 -04:00
Jarrod Johnson 8f80add0f1 Enhance debian packaging for confluent 2023-09-18 15:19:10 -04:00
Jarrod Johnson 0a527f5f39 Add environment to firstboot ubuntu 2023-09-18 11:38:41 -04:00
Jarrod Johnson 3e8c6d1ea6 Correct syntax issue in el7 image2disk 2023-09-18 11:04:50 -04:00
Jarrod Johnson a01b7c6503 Revamp and add missing bits to scripted ubuntu install 2023-09-18 10:30:52 -04:00
Jarrod Johnson 83e3627b47 Add pre.d to ubuntu 22 diskful 2023-09-18 10:19:50 -04:00
Jarrod Johnson 37b75ba777 Correct variable name on commit clear 2023-09-15 15:54:35 -04:00
Jarrod Johnson aa5de3c6a3 Suspend handling of new socket connections while configmanager down 2023-09-15 15:48:37 -04:00
Jarrod Johnson d4c535d038 Halt autonomous discovery handling while configmanager is down
This avoids triggering a potential large amount of churn on transiently
"unknown" systems
that are actually discovered.
2023-09-15 15:32:33 -04:00
Jarrod Johnson 94b8559777 Declare ready on becoming leader
Provide for leader scenario to correctly
flag configmanager as ready.
2023-09-15 15:28:16 -04:00
Jarrod Johnson f2f25fe912 Implement ready tracking
When going through the
dramatic scenario of initializing collective,
take _ready down
so that other code can
pause operation appropriately.
2023-09-15 15:25:26 -04:00
Jarrod Johnson c0629fcce5 Fix invocation of json restore change 2023-09-15 11:41:12 -04:00
Jarrod Johnson 4952e87309 Undo collective manager changes
Abort attempt to avoid duplicate startups, it was incorrect.
2023-09-15 10:52:13 -04:00
Jarrod Johnson 533244458d Do not count as 'initting' until collective starts. 2023-09-15 10:37:51 -04:00
Jarrod Johnson 20f02b5ef7 Avoid searching switches for foreign nodes
Consult collective.manager
to decide to skip
consideration of a node, if
that node shouldn't be managed anyway.

This should avoid "cross-island" behavior for such
environments.
2023-09-15 10:07:14 -04:00
Jarrod Johnson df47c6d0fd Disable attribute notify during json restore
This is guaranteed to be a lot of churn very quickly, disable it for
now.
2023-09-13 17:03:05 -04:00
Jarrod Johnson 97ee8e2372 Cerrect the logic of duplicate discovery protection 2023-09-13 10:50:21 -04:00
Jarrod Johnson 74c6848a0b Avoid redundant setting of known data
Setting attributes can be a touch expensive, since
there's a high risk
of this being old news,
check that discovery hasn't already set values
before trying to set them again.
2023-09-13 09:59:03 -04:00
Jarrod Johnson b75979f3ec Insulate confluent from fatal errors from discovery subscription errors 2023-09-12 16:59:53 -04:00
Jarrod Johnson 50d5cead06 Add prereq checks to EL cloning 2023-09-12 16:55:19 -04:00
Jarrod Johnson e6b0b235e9 Fix image2disk for nvme clone targets 2023-09-12 16:53:32 -04:00
Jarrod Johnson 00eb9e3c9d Fix full_net_config with missing address info 2023-09-12 16:49:15 -04:00
Jarrod Johnson b77d8b1f21 Make yaml import conditional
Only Ubuntu requires it, but tends to have it.

Other distributions do not tend to have it.
2023-09-12 10:45:15 -04:00
Jarrod Johnson d7190c893f Correct networkmanager entries for boot over infiniband
When booting and infiniband comes up as the 'get started' nic,
make the entry use correct type so as to avoid
confusion later, particularly when confignet comes along to fixup
the configuration.
2023-09-11 13:11:17 -04:00
Jarrod Johnson f82829aa0c Add dependency checking to imgutil capture
This will more quickly indicate problems in a profile trying to capture.

First iteration will address Ubuntu.
2023-09-08 17:10:27 -04:00
Jarrod Johnson 203dabfb0b Place nameservers on every NIC in netplan
netplan, like others, makes the questionable choice to designate DNS
as a NIC specific setting, despite not mapping well
to a NIC.

Since we model DNS like NTP, a global, just repeat the DNS config for
every interface.  This redundancy is fine in testing multiple
interfaces.
2023-09-08 16:56:58 -04:00
Jarrod Johnson 9441221150 Have cooltera plugin adapt
As new sensors appear, be more adaptive
to continue tracking existing sensors.
2023-09-08 11:30:57 -04:00
Jarrod Johnson 8de6f4356d Fix sense of new flag
Accidently made flag exactly opposite of intended
2023-09-07 15:12:43 -04:00
Jarrod Johnson fe78034eaa Add '-y' to imgutil build
Allow non-interactive imgutil build.
2023-09-07 14:56:07 -04:00
Jarrod Johnson 691d92f735 Avoid calling implicit nic config if nowhere to put it
If 'None' attributes are in use,
we'd have no where to
stick implicit configuration anyway.
2023-09-07 14:41:16 -04:00
Jarrod Johnson 8ca1f80ef6 Fix implicit nic in confignet
If the implicit IP
is not in any of the
attribute groups of net,
then auto-vivify from the normal place.
2023-09-07 14:36:56 -04:00
Jarrod Johnson 3cacbf283a Fix cloning to NVME boot
The partition device names
have a different scheme
for nvme v. other devices.
2023-09-07 10:09:19 -04:00
Jarrod Johnson 89e573207c Remove irrelevant command from ubuntu cloning firstboot 2023-09-01 16:55:01 -04:00
Jarrod Johnson f16cf4387f Further Ubuntu enhancements
Add confignet to Ubuntu 20 and 22
Add syncfile to the ubuntu diskless/cloning
2023-09-01 16:40:02 -04:00
Jarrod Johnson fa60a9dc9f Add IPv6 support to confignet 2023-09-01 16:34:30 -04:00
Jarrod Johnson 2268d7f65a Fix hotplug firmware in suse diskless 2023-09-01 13:51:17 -04:00
Jarrod Johnson abd5f4e9f2 Fix shebang in firstboot on ubuntu cloning 2023-09-01 13:51:02 -04:00
Jarrod Johnson f6e658c341 Add site CA to ubuntu profiles on install 2023-09-01 13:25:20 -04:00
Jarrod Johnson 44ec390f40 Add post.sh to ubuntu cloning 2023-09-01 12:29:27 -04:00
Jarrod Johnson 6ab91b50af Add missing bits of Ubuntu diskless 2023-09-01 10:55:18 -04:00
Jarrod Johnson 1f32ef2310 Implement basic netplan support
Start with single links, ipv4 only for ubuntu.
2023-09-01 10:07:51 -04:00
Jarrod Johnson 22cb2bdc40 Handle Ubuntu hardcoded grub cfg
Ubuntu hardcodes grub.cfg to
another location.

Make a stub file as a flag to guide osimage
to know where grub.cfg goes.
2023-08-29 10:57:25 -04:00
Jarrod Johnson 610bc793b7 Merge branch 'master' into ubuntucloning 2023-08-24 10:53:33 -04:00
Jarrod Johnson 85375cc733 Fix hotplug firmware to use rootfs after boot 2023-08-24 10:53:25 -04:00
Jarrod Johnson af4ca64da8 Fix hotplug firmware to use rootfs after boot 2023-08-24 10:53:00 -04:00
Jarrod Johnson 439143115e Merge branch 'master' into ubuntucloning 2023-08-22 12:28:36 -04:00
Jarrod Johnson b14b34bdbd Add limited sensor support for Eaton PDUs 2023-08-22 12:28:07 -04:00
Jarrod Johnson 899ce7f055 Correct spelling of hooks directory in Ubuntu cloning 2023-08-17 16:27:45 -04:00
Jarrod Johnson 7e209e412a Make confluent hook executable in ubuntu diskless 2023-08-17 16:16:36 -04:00
Jarrod Johnson 7051f467bb Avoid a deprectationwarning in copytree handling
While trying to address one
deprecationwarning, we
hit another.  Check if the
new function exists and use it,
falling back to distutils if
everything fails.
2023-08-17 14:49:44 -04:00
Jarrod Johnson b88ccc292c Avoid deprecation on distutils with newer python
Unfortunately, python 3.6 needs the distutils version, but we should avoid it altogether
by python 3.10, but by 3.10 the shutil.copytree can do it.
2023-08-17 14:36:38 -04:00
Jarrod Johnson c47066d713 Include ubuntu material in packaging 2023-08-17 14:11:41 -04:00
Jarrod Johnson 8ddcf45e1d Create links for ubuntu20.04 and ubuntu22.04 2023-08-17 14:03:55 -04:00
Jarrod Johnson 53d2b873a2 Package ubuntu 22.04 diskless 2023-08-17 11:28:29 -04:00
Jarrod Johnson bc7dbeebea Add ubuntu 22.04 diskless 2023-08-17 11:16:32 -04:00
Jarrod Johnson 1b2d8a0596 Merge branch 'ubuntucloning' of github.com:lenovo/confluent into ubuntucloning 2023-08-17 11:16:01 -04:00
Jarrod Johnson f3e7d4ab67 Merge pull request #92 from sjtstg/nmcli-autoconnect
Confignet does not set autoconnect with network manager
2023-08-17 08:06:54 -04:00
Simon Thompson b27542ec00 Confignet does not set autoconnect with network manager so disk installed images do not bring up interface on reboot 2023-08-17 10:30:36 +02:00
Jarrod Johnson 58cc9840b3 Prune out any netplan configuration, if exists
To mitigate chance of network configuration
being tanked by image based
net config, mask it when capturing.
2023-08-16 14:28:10 -04:00
Jarrod Johnson 84d23bb1fd Begin work on Ubuntu cloning 2023-08-16 12:00:50 -04:00
Jarrod Johnson ae915cd735 Merge pull request #126 from weragrzeda/master
nodelist delimiters
2023-08-15 11:03:48 -04:00
weragrzeda c7a323b370 nodelist delimiters fixed for py2 compatibility 2023-08-15 16:31:38 +02:00
root 9e070a14d4 nodelist delimiters 2023-08-15 15:58:10 +02:00
Jarrod Johnson 189ba525d3 Merge pull request #91 from sjtstg/ansible-play-fix
fix ansible support when multi stage plays are in playbook
2023-08-15 08:38:56 -04:00
Jarrod Johnson 5068cda2cf Catch another sort of exception for non-rpm distributions
subprocess may produce a different sort of exception if
rpm doesn't exist at all
2023-08-14 09:23:00 -04:00
Jarrod Johnson 95c5253944 Remove CIDR prefix length in ubuntu 20 deployment
This produces invalid configuration for subiquity otherwise.
2023-08-11 15:01:55 -04:00
Jarrod Johnson ca2dcd2dbe Reference identity network in ubuntu 20.04
When using identity image, also use identity image
for network configuration.
2023-08-11 14:34:12 -04:00
Jarrod Johnson dba6e7f378 Change Ubuntu 20.04 to be consistent to 22.04
This aims to bring
identity image deployment fully to ubuntu 20.0.4.
2023-08-11 13:44:37 -04:00
Jarrod Johnson 0b7247d386 Fix CentOS 7 routed deployment with identity image
Numerous issues prevented the identity image support from actually running,
correct them.
2023-08-10 16:27:42 -04:00
Jarrod Johnson 75add230b6 Skip API key init on checkonly runs
Checkonly does not require API key, and makes apiclient more dependent
on material that is unlikely to exist early in a deployment.
2023-08-09 11:13:09 -04:00
tkucherera 2c90227f63 "Firmware Update " 2023-08-09 10:48:09 -04:00
tkucherera 0cff70c607 firmware update 2023-08-09 10:37:35 -04:00
Jarrod Johnson 75082c4418 Move up creation of ca.pem 2023-08-03 14:03:36 -04:00
Jarrod Johnson 9a1c9eb43f Improve ssh concurrency on websocket
ssh module was pausing input for the
entire websocket while doing the simple 'write' operation.

Change to background the actual
logon processing,
rather than blocking what should be a fairly trivial write operation.
2023-08-03 09:56:36 -04:00
Jarrod Johnson 89bd798f8b Increasing time again, outlet count didn't factor 2023-08-02 15:20:29 -04:00
Jarrod Johnson bf10e58f00 Bump version
With recent collective changes, bump the version to block connection with
older collective members until upgraded.
2023-08-02 13:43:41 -04:00
Jarrod Johnson cbf2cdcdc5 Scale timeout with number of outlets
Delta PDUs seem to serialize outlet operation.
2023-08-01 16:08:51 -04:00
Jarrod Johnson 987587aaf8 Allow custom auth file to define valid roles 2023-07-26 16:37:55 -04:00
Jarrod Johnson ad25c31d3f Correct error in check_for_yaml function in auth 2023-07-26 16:15:36 -04:00
Jarrod Johnson b1018d648e Hook loading of /etc/confluent/authorization.yaml
This should permit custom roles to be defined.
2023-07-26 16:05:29 -04:00
Jarrod Johnson a18d0f10b7 Clean up stale lvm devices files
During cloning, stale lvm devices file may cause
ugly output.  Remove stale files before proceeding down steps
that trigger lvm warnings.
2023-07-26 07:54:41 -04:00
Jarrod Johnson 65ac3de21b Take EL9 version of image2disk for improvements with parted supervision 2023-07-26 07:26:49 -04:00
Jarrod Johnson c9d9a3cc54 Add EL9 cloning support
Main difference from EL8 is different grub strategy.  To cope, capture
the uuid of new /boot and manipulate the
stub grub.cfg with the right uuid.

In EL8, the efi has the main grub, EL9 changes to have /boot host the 'real' grub,
causing us to have to modify the stub grub.
2023-07-25 17:09:37 -04:00
Jarrod Johnson 957b979dde Reorder imports in configmanager to mitigate circular import 2023-07-24 13:38:44 -04:00
Jarrod Johnson 48c4a2e062 Have reconnects use new TCP connections
Current code was trying to reuse connections that would be useless,
explicitly go to new TCP connections for reconnection.
2023-07-24 12:31:32 -04:00
Jarrod Johnson 285a159ba5 Implement a number of improvements for collective
For one, remove 'non-voting' members from being leaders.
Large number of leader candidates create long delays for
converging on a valid organization.  Further, some treat 'non-voting'
more roughly, inducing the worst case convergence scenario of unclean
shutdown of leader.
Convergence now happens fairly quickly for collectives with large
number of non-voting members.

During initial DB transfer, the leader would be tied up unreasonably
long handling the jsonification of a large configuration.  Offload to a worker
process to allow the leader to continue operation while this intensive, rare
operation occurs.

Reliably run a reassimilation procedure for the lifetime of the leader.
This allows orphaned members to be prompted to join the correct leader.

Serialize the onboarding of a connecting member, and have redundancy more gracefully
paused. This avoids excessive waiting in lock and more deterministic timing
with respect to timeout expectations by the connecting system.
2023-07-24 11:11:39 -04:00
Jarrod Johnson 8ea2ba046e Sort the IP addresses in nodediscover for consistent UI 2023-07-19 16:16:27 -04:00
Jarrod Johnson f16daa44dd Handle older python with addrinfo
While newer python omits '%',
older python includes.  Change to handle
either form.
2023-07-19 16:04:25 -04:00
Jarrod Johnson 03fce4f762 Adjust sys.path logic in macmap and osimage
Ensure the sys.path logic
is before attempting
the relevant imports.
2023-07-19 12:15:01 -04:00
Jarrod Johnson 809099c8f8 Specifically wait for /dev/disk/by-label
When udev is populating the disk hierarchy, it can be a long time
before the 'by-label' is specifically ready.

Wait for that specific entry to come along before continuing to
check if there's an identity image.
2023-07-07 15:32:47 -04:00
Jarrod Johnson a875f0d3e1 Correct syntax error in selfservice 2023-07-06 14:04:49 -04:00
Simon Thompson 6ee9f96e08 fix ansible support when multi stage plays are in playbook 2023-07-06 09:34:38 +02:00
Jarrod Johnson fcc62b7cb7 Improve confluent scanning on newer python
Newer python changed the format of peer[0], adapt to the change
to use the socket info if not available in the peer[0] string.
2023-07-05 16:34:37 -04:00
Jarrod Johnson 11cb47c03e Use natural sort on some self service calls 2023-07-05 16:18:49 -04:00
Jarrod Johnson afc78513a1 Merge pull request #90 from sjtstg/ansible-fixes
Ansible fixes
2023-07-05 16:15:30 -04:00
Simon Thompson 45f22c3e31 when host is not in hosts file, group_vars is not loaded, change logic to emulate host being in hosts file with no groups to ensure group_vars is loaded which permits use of dynamic grouping in plays 2023-07-05 21:25:25 +02:00
Simon Thompson d0f978548e sort directory listing to make ansible plays and script order deterministic 2023-07-05 21:23:55 +02:00
Jarrod Johnson 052d16aa49 Avoid modifying PYTHONPATH
Since there's a possibility of cross-python invocation,
avoid modifying PYTHONPATH
2023-07-05 11:40:00 -04:00
Jarrod Johnson 7ddd2c2e6e Correct mistakes in shebang adaptive behavior 2023-07-05 11:14:32 -04:00
Jarrod Johnson 9186c8142c Fix incorrect reference in the smm validation by certificate 2023-06-28 13:13:26 -04:00
Jarrod Johnson c07248d58e Fix outlet control on Geist PDUs. 2023-06-27 08:04:16 -04:00
Jarrod Johnson 013de4f881 Adapt to ansible python runtime
Unfortunately, python being python, ansible may elect to install under a
different python runtime than confluent.

In such a case, hope that the ansible python can work.

Remove eventlet as a hard requirement, as
that is unlikely to be in ansible python.

This leaves msgpack, which is unavoidable, for now. But if it's in ansible python,
it's fine.
2023-06-26 15:41:44 -04:00
Jarrod Johnson 795b4c513d Rework for connected temperature sensors
PDUs behave differently when a sensor module is
connected. Handle
that difference and
provide the relevant data.
2023-06-26 12:32:45 -04:00
Jarrod Johnson 4056264991 Correct keyname from previous fix 2023-06-23 17:01:50 -04:00
Jarrod Johnson 77c8e93a8d Fix terminal actions on shared websocket
The full complement of functionality was not
interpreted in shared context
2023-06-23 16:33:30 -04:00
Jarrod Johnson 1695e222ec Rename command to nodeapply, by popular demand 2023-06-22 14:16:54 -04:00
Jarrod Johnson b2a793568a Merge pull request #125 from tkucherera-lenovo/master
change timestamp log option from -d to -T
2023-06-22 14:14:59 -04:00
Jarrod Johnson 3ebd43fe0c Bump genesis base version 2023-06-15 09:35:37 -04:00
Jarrod Johnson 2e20e0303f Fix libbpf link 2023-06-15 09:22:52 -04:00
Jarrod Johnson da2df63498 Update location of krb5 2023-06-15 09:20:37 -04:00
Jarrod Johnson 896a4ff1ff Fix spec format 2023-06-14 16:05:08 -04:00
Jarrod Johnson a14effa4f2 Undo change
Realized we need to install related rpm for efivar
2023-06-14 15:57:27 -04:00
Jarrod Johnson 66c79a5f42 Fixup handling of efivar license 2023-06-14 15:52:52 -04:00
Jarrod Johnson 389c37659e Refresh more licensing material in genesis rpm 2023-06-14 15:47:17 -04:00
tkucherera 89af8661da change timestamp log option from -d to -T 2023-06-12 10:51:29 -04:00
Jarrod Johnson 41437c511b Fix when networkmanager breaks one of our connections
This usually happens with ipv6 link local used
in initramfs stage, after networkmanager may
mutilate the ipv6 connectivity.
2023-06-12 08:49:13 -04:00
Jarrod Johnson 75f0aaeee9 Allow session id through header
This permits a client to exert finer grained control
over the session id
than provided by cookie.
2023-06-08 11:30:32 -04:00
Jarrod Johnson 68f9688292 Drop SLP packets with error
Some implementations send
error for services they do not provide.
2023-06-08 08:02:59 -04:00
Jarrod Johnson 67204f79a1 Fix bug where dispatching a request could block all other activity 2023-06-02 11:06:44 -04:00
Jarrod Johnson e9dd7da775 Fix syntax error in el7 identity image support 2023-06-02 08:55:27 -04:00
Jarrod Johnson 8f1be7c905 Fix Python2 compatibility issue with port forwarder 2023-06-01 16:50:06 -04:00
Jarrod Johnson bc684b82b4 Implement identity image based deployment for EL7
Though older, it is still popularly used.
2023-06-01 16:49:17 -04:00
Jarrod Johnson 5e72d40c03 Fix compatibility issue with python2 2023-06-01 13:31:32 -04:00
Jarrod Johnson 7ab2aff7f2 Restore syntax of EL7 deployment
Inadvertent incomplete checkin
broke syntax of EL7, fix to have it
work as-is for now.
2023-06-01 09:20:17 -04:00
Jarrod Johnson c3fc931ba4 Fix python2 compatibility issue for port forwarding
The measure for predictable port numbering
was done with python3 in mind, without consideration
of python2.
2023-06-01 09:18:36 -04:00
Jarrod Johnson 2c61cee72d Merge pull request #124 from Tkucherera/nodeconsole_timestamp
Nodeconsole timestamp
2023-06-01 09:08:33 -04:00
Tinashe 190ec2473b dump log to stfout with timestamps 2023-05-31 17:39:53 -04:00
Tkucherera 9ebb8f27ec Merge branch 'xcat2:master' into master 2023-05-31 17:34:52 -04:00
Jarrod Johnson 0db7d4f9d2 Stall readback of PDU after outlet control
There is some lag after requesting an outlet change and
the outlet state actually changing.
2023-05-26 10:43:04 -04:00
Jarrod Johnson 5d1315098f Enhance and extend check of node relations 2023-05-25 11:14:58 -04:00
Jarrod Johnson fc29ddb913 Improve routed EL8 deployment and add debug shell on tty2 2023-05-24 11:02:23 -04:00
Jarrod Johnson b06b77f5a5 Fix issues with confluent media deployment on multi-nics in routed env 2023-05-23 17:22:38 -04:00
Jarrod Johnson 97a5bf0806 Correct typo in suse 15 diskless boot 2023-05-19 14:50:04 -04:00
Jarrod Johnson 36e61f301a Add a nodefreshen command
This aims to provide the same shortcuts as 'updatenode'
2023-05-18 15:03:29 -04:00
Jarrod Johnson e476c7b9e6 Avoid deprecationwarning in python 3.10+
Newer python is not backwards compatible with
a constant.  Attempt to use new
constant and fallback to teh old one
if unavilable.
2023-05-18 09:20:52 -04:00
Jarrod Johnson a523df80e8 Handle newer SuSE
After SP4, suse drops mkinird requirement.

Switch to dracut -f in such a scenario.
2023-05-16 14:51:27 -04:00
Jarrod Johnson 8f4982e850 Fix build mistake in the cooltera plugin 2023-05-15 08:30:44 -04:00
Jarrod Johnson a167d19441 Add module for cooltera nodesensors 2023-05-10 13:24:20 -04:00
Jarrod Johnson 2237e0e173 Add a retry mechanism for connecting socket
Timing is sensitive during the handshake, catch and retry
if it should fail.
2023-05-10 11:12:29 -04:00
Jarrod Johnson b08b62614a Have proxydhcp recover from faults 2023-05-10 08:44:31 -04:00
Jarrod Johnson e93e4abd83 Add clear error when base profile doesn't exist
If the user specifies a wrong '-b',
indicate clearly that is the case,
and do so early.
2023-05-10 08:40:45 -04:00
Jarrod Johnson 430b24081c Have apiclient timeout if IO hangs up 2023-05-09 16:04:24 -04:00
Jarrod Johnson ec54ecc9cd Fix tiling with different gravity
In some environments, the coordinates may be reported in a
different format.  Handle the different context.
2023-04-28 09:20:31 -04:00
Jarrod Johnson f787461759 Merge pull request #123 from Tkucherera/tmux_reuse
Tmux reuse
2023-04-28 09:18:44 -04:00
Jarrod Johnson 7312d8e092 Provide commented hints for mdns integration
mdns protocol is not currently used, but
put in breadcrumbs for
bringing it alive if
we have an openbmc handler.
2023-04-27 15:51:28 -04:00
Tkucherera 884a6be68c Wkill like command (#1)
* wkill like command fix

* tmux session resuse

---------

Co-authored-by: Tinashe <tkucherera@lenovo.com>
2023-04-27 15:46:40 -04:00
Tinashe a35a7e74c3 tmux session resuse 2023-04-27 15:39:32 -04:00
Jarrod Johnson ffdf799713 Advance mdns support
At this point, the protocol handler
seems up to the task of describing openbmcs
2023-04-27 08:59:39 -04:00
Jarrod Johnson b9d0da0416 Correct mistake in the gathering of valid nodenames 2023-04-26 15:37:08 -04:00
Jarrod Johnson 3fd930137d Begin work on mdns protocol support 2023-04-21 16:14:25 -04:00
Tinashe 71a263366d wkill like command fix 2023-04-21 10:22:10 -04:00
Jarrod Johnson 7b150773df Extend multi-nic guessing to Ubuntu 20/22 2023-04-20 15:45:32 -04:00
Jarrod Johnson 53f4665358 Correct issues in Ubuntu 18 deployment 2023-04-20 14:48:39 -04:00
Jarrod Johnson e5fff430be Explicitly clear logonwaiters on discard of a session
When a session is being discarded, it
may inadvertently hold onto logonwaiters.

The IPMI session may be reused, but the context is new and those
dead contexts can consume memory unreasonably.
2023-04-19 10:22:33 -04:00
Jarrod Johnson 55da173b27 Correct missing parameter in Geist
Geist support was missing a variable in the refactor.
2023-04-19 10:20:34 -04:00
Jarrod Johnson 55a796af82 Correct some errors in the Ubuntu 18 support
An ommited end clause as well
as some bashisms.
2023-04-12 13:23:39 -04:00
Jarrod Johnson 123d190f12 Extend network and deployment server checking for Ubuntu 18.04
When doing network evaluation in ambiguous contexts,
spend some time checking each nic and each candidate target ip address.

This may take longer, but options are limited in a routed context.
2023-04-12 13:04:08 -04:00
Jarrod Johnson 305a3a06d2 Ensure $HOME is set during firstboot
systemd tends not to set environment variables.  However some firstboot
scripts generally expect $HOME to be correct.
2023-04-12 11:22:27 -04:00
Jarrod Johnson 024677d7de Try EL7 to build the old addons 2023-04-07 16:50:20 -04:00
Jarrod Johnson fb31a68818 Add profile.yaml to ubuntu18.04 stock profile 2023-04-07 16:26:32 -04:00
Jarrod Johnson 526a248963 Add ubuntu18.04 to build script in other location 2023-04-07 16:17:37 -04:00
Jarrod Johnson 86d9d6fc2f Add ubuntu18.04 to build 2023-04-07 15:46:29 -04:00
Jarrod Johnson 2bdc53722b Further advance ubuntu 18.04 support 2023-04-07 15:45:31 -04:00
Jarrod Johnson 25b0f45e6f Merge remote-tracking branch 'lenovo/master' 2023-04-07 13:53:44 -04:00
Jarrod Johnson f5b3682c08 Merge pull request #89 from erderial/patch-8
added functionality to check for net.*switch
2023-04-07 13:52:01 -04:00
Jarrod Johnson b7ea27b939 Advance draft Ubuntu 18 support
Get most things automated for the targeted use case.

Still need to handle partitioning and end of install question, add firstboot and add
staged and complete step.
2023-04-06 16:07:55 -04:00
Jarrod Johnson 1fff15677d Add el9bin correctly into build process 2023-04-04 11:55:23 -04:00
Jarrod Johnson 556d858d33 Address extraneous errors during build 2023-04-04 11:27:50 -04:00
Jarrod Johnson 0a02b010c9 Fix esxi build for new build strategy 2023-04-04 11:24:10 -04:00
Jarrod Johnson 08e19fbf6e Provide a sample for fuse3 urlmount
When the time comes to transition, this will be useful.

The challenge is that existing images will likely have a 'distribution'
with fuse2 libs, so this isn't a transition to make lightly.

Definitely should be done for new distributions at least, current
distributions pending further investigation
2023-04-04 10:39:12 -04:00
Jarrod Johnson 2d16d5558c Rework to build everything under el8 or el9 containers specifically
Make the build host less critical of an implementation detail
2023-04-04 10:19:13 -04:00
Jarrod Johnson 7f15e4af27 Change back to fedora
We need fuse-devel for now, since urlmount is written against older fuse
2023-04-04 09:44:04 -04:00
Jarrod Johnson 34313f4041 Change to EL9 for the new-wave util builds 2023-04-04 09:32:25 -04:00
erderial 9bb402a1b8 Update confluent_selfcheck 2023-04-03 10:27:07 +03:00
erderial 13d4c57ee2 changes done as per request 2023-03-31 19:32:43 +03:00
erderial 88c47c9254 added functionality to check for net.*switch
added functionality to check for net.*switch
2023-03-31 16:43:15 +03:00
Jarrod Johnson 181aa876a7 Draft initramfs addons for Ubuntu 18
For older Ubuntu 18, the automated installer is debian-installer.  Derive from the
prototype debian work, with same limitation about more limited network bringup that
we are stuck with from Debian limitations.
2023-03-30 16:36:40 -04:00
Jarrod Johnson a0dbb90c77 Handle mismatched alpha and numeric in hyphenated string
If 123abc-abc123 were attempted, it would produce
a strange error
when it encounters a string compare to number.

Detect the scenario and treat it like similar situations.
2023-03-30 14:21:22 -04:00
Jarrod Johnson cb129789b8 Properly recognize old ubuntu server install media
Older media designed around
debian installer requires
different handling.
2023-03-30 08:33:18 -04:00
Jarrod Johnson 7ac778106e Also skip over failure to broadcast SSDP 2023-03-29 16:55:12 -04:00
Jarrod Johnson f808c542e4 Ignore forbidden transmits on multicast 2023-03-29 16:53:40 -04:00
Jarrod Johnson 2a3bc61be3 Avoid overwriting groups on a redefine
When a node is being redefined, do
not populate groups.

That is only needed when truly defining for first time.
2023-03-29 09:28:52 -04:00
Jarrod Johnson 73fb54ccbc Add more manual licenses to the kernel 2023-03-28 17:02:53 -04:00
Jarrod Johnson 578bd9702a Sample script to install a cert into an XCC 2023-03-24 15:56:26 -04:00
Jarrod Johnson ca5f19a4f1 Sample script for getting a CSR from an XCC 2023-03-24 15:46:21 -04:00
Jarrod Johnson 717df579aa Add firmware to Geist support 2023-03-17 16:02:55 -04:00
Jarrod Johnson 70b973b1cf Refactor measurements in Geist
Use common code
for sensor translation.
2023-03-17 15:34:26 -04:00
Jarrod Johnson 48696ef63d Begin adding sensors to Geist PDUs 2023-03-17 14:37:03 -04:00
Jarrod Johnson ff025989c6 Restore spacing around float in nodesensors
The managed formatting needs
to be padded in the non-csv output.
2023-03-16 17:29:36 -04:00
Jarrod Johnson 872718c658 Add notation about alternate location of ansible plays
Make it known that plays may now be private.
2023-03-16 15:19:15 -04:00
Jarrod Johnson 47af869360 Allow ansible plays to be private
Since the node need not have access,
the ansible plays may be made private instead.

This enables potentially sensitive plays
to be protected.
2023-03-16 15:15:46 -04:00
Jarrod Johnson f256b1cd4e Handle more complex ansible configuration
Some plays expect the
inventory from /etc/ansible, detect
if that inventory *could* apply, use if it can.

ansible users generally anticipate leveraging the implicit '.' in the role
path,
chdir to meet that expectation.

'become' in the play without 'become_user' can upset ansible runtime.

Since we are already root, we will just ignore the implicit 'become', since we already
match that behavior.
2023-03-16 13:24:46 -04:00
Jarrod Johnson bfe03e6e01 Fix erronously dragging in CIDR to IPv4 configuration 2023-03-14 16:55:20 -04:00
Jarrod Johnson 8dc3dfd20c Limit TRYNIC to only one NIC in ubuntu deployment 2023-03-14 15:36:24 -04:00
Jarrod Johnson 0cc588f8e9 Carry nic detection through to bottom of Ubuntu 2023-03-14 15:24:37 -04:00
Jarrod Johnson e12578b6ac Use media net config when media deployed 2023-03-14 13:32:20 -04:00
Jarrod Johnson 0366bbd26f Place apikey where expected 2023-03-13 17:00:35 -04:00
Jarrod Johnson 5f4ab5ff80 Fix path to hmacfile
Since we are running
outside of chroot, need to adjust the $()
substitution.
2023-03-13 16:21:25 -04:00
Jarrod Johnson 88a6bccf12 Use b64 alphabet for b64
While POSIX hates +, b64 needs +
2023-03-13 16:20:17 -04:00
Jarrod Johnson 52c3e9d515 Do not care about port, let kernel decide 2023-03-13 11:19:11 -04:00
Jarrod Johnson 50a4ee2c6d Have a quick sample script to get LLA of USB nic peer 2023-03-13 11:15:31 -04:00
Jarrod Johnson 15ff24fccd Correct syntax errors in auth.py 2023-03-10 16:38:47 -05:00
Jarrod Johnson d9cc9112f4 Add identity image deployment to Ubuntu
Support the api arm token
and media network
config for Ubuntu.
2023-03-10 16:23:48 -05:00
Jarrod Johnson 5418d9ea97 Place a common script for setupssh 2023-03-10 16:05:29 -05:00
Jarrod Johnson 2aeade1e74 Merge pull request #88 from erderial/patch-6
updated with custom yaml file for auth
2023-03-09 15:48:12 -05:00
erderial 85f9dc12fb Update auth.py 2023-03-09 22:38:37 +02:00
erderial 56dea2422a Update auth.py 2023-03-07 21:08:01 +02:00
Jarrod Johnson 8b89232922 Do not get collective member when collective doesn't exist 2023-03-06 16:59:07 -05:00
Jarrod Johnson 22c464e092 Only add self to collective if self not yet in collective
Previously, it was safe to just do all the time, but now it may lose
the role.
2023-03-06 16:49:03 -05:00
Jarrod Johnson 4d9b11bc55 Fix quorum when there is no collective yet 2023-03-06 16:38:09 -05:00
Jarrod Johnson baa365fcac Implement non-voting collective members
Provide for applications
where only a small subset of collective
members should be
considered to count
toward whether the collective
can proceed.

Commonly, 'service' nodes may
be numerous to do work, but may all want to go offline
during a maintenance window.
2023-03-06 11:56:15 -05:00
Jarrod Johnson a385b1e93d Try strategy to have confignet run
confignet is special, it is designed
to work when networking
isn't right.  So have it run during firstboot
in case post fouled up
the network for firstboot.
2023-02-28 12:12:36 -05:00
Jarrod Johnson 733b6853dd Up newly added interfaces as a matter of course 2023-02-28 12:04:20 -05:00
Jarrod Johnson b4182cd4b5 Fix formation of error message
Use format to take in the parameters regardless of type
2023-02-27 14:55:01 -05:00
erderial cf2f5aac7b Merge branch 'lenovo:master' into patch-6 2023-02-27 18:27:39 +02:00
Jarrod Johnson 9f7e53701e Avoid latching onto USB nic in a vswitch as 'the nic'
In esxi, some builds may have USB nic brought up in a vswitch.

Detect and avoid that scenario.
2023-02-27 10:43:40 -05:00
erderial 3b9f9abdd9 Merge pull request #2 from erderial/erderial-patch-1
updated auth.py with some changes
2023-02-27 17:36:20 +02:00
erderial b800aa032e updated auth.py with some changes
updated auth.py with some changes. Need to add the check_for_yaml() function to main.py as well
2023-02-27 17:10:17 +02:00
Jarrod Johnson 70d8a1059c Consistently treat bytes as bytes in ssh
In Python3 systems,
there would be confusion
about bytes versus str.

Fix this so that ssh can work more consistently.
2023-02-24 15:47:20 -05:00
Jarrod Johnson 59b07665ab Modify float formatting again
Make sure at least one decimal is in a float.

Maximum precision of 5 past.
2023-02-24 12:03:43 -05:00
Jarrod Johnson 5ea214a726 Use eventlet subprocess
sshutil uses eventlet subprocess,
making calledprocesserror
hard to catch.

Adjust to consistently use same
subprocesss module.
2023-02-22 16:34:13 -05:00
Jarrod Johnson b99034f539 Improve reliability of collective join
While servicing an enrollment,
there's a window for a collective
member to be 'defined' but not
yet active, meaning quorum may transiently be lost as multiple enrollments progress.

Serialize enrollments by holding the enrollment process open.

Also, there is a chance that a transient transfer error may occur during loading
of the DB.  In such a case, restart
the connection rather thn aborting.
2023-02-22 16:11:38 -05:00
Jarrod Johnson 6df2e822a5 Correct api call in discovery 2023-02-22 09:34:32 -05:00
Jarrod Johnson 2379f6f90f Change nodesensors format of float
Floats are either unnecessarily long
in normal output, or too unconstrained in CSV output.

Normalize to as many digits as 'makes sense' up to 5 digits.

5 miight seem a bit much, but one common metric is kWh, which may need
that precision over short intervals.
2023-02-22 08:41:46 -05:00
erderial 8940247164 updated with custom yaml file for auth
Added 2 new function to check if the custom yaml file exists - /etc/confluent/authorize.yaml - and one to update the _allowbyrole and _deniedbyrole vars accordingly.
2023-02-21 15:13:17 +02:00
Jarrod Johnson 77ba0acee6 Merge pull request #122 from Tkucherera/nodeconsole-kill
nodeconsole <noderange> kill: added functionality for closing open win…
2023-02-16 16:37:07 -05:00
Tinashe b2c773bb84 nodeconsole <noderange> kill:added functionality for closing open windowed consoles 2023-02-16 15:54:21 -05:00
Jarrod Johnson 241800b1c9 Restore filename-only import
The open file handle as implemented
could not pass to the subprocess.

Rather than figure out how to open
and pass the filehandle,
simply let the subprocess
independently open the file
if it isn't passed.
2023-02-16 09:13:05 -05:00
Jarrod Johnson abc639e32b Preferentially support HTTPS on Eaton PDU
While Eaton does not do HTTPS by default,
it can be configured to do so.

Support when available.

Mitigate downgrade attack by
stickying the cert fingerprint.
If fingerprint is present, then refuse
to even think about port 80.
2023-02-15 17:03:35 -05:00
Jarrod Johnson 90af99e864 Add more clear error on syncfile mistake
If a bad node was included in
a syncfile, the error was highly misleading.

Provide a more clear indicaiton of the problem on failure.
2023-02-14 14:53:40 -05:00
Jarrod Johnson 09ce824c85 Fix bad lookup attempts on slashed addr
While this should in theory be
harmless, it exacerbates some
DNS setups that would look
up the normal result quickly,
but would stall on
a bad lookup.
2023-02-14 14:53:40 -05:00
Jarrod Johnson 9c1e7a7142 Allow interfaces to supersede default
In some scenarios, the 'default'
interface is overlapped by another connection, either
identical or as a superset in a bond.

Whittle down the default
interface if superseded
to mitigate duplicate interface setup.
2023-02-14 14:53:40 -05:00
Jarrod Johnson 36195198a6 Add fallback for newer msgpack
Newer msgpack refuses the encoding argument, use raw=False instead.

Further, newer msgpack refuses to accept int as key by default.
Opt into it as the risk is hash collision due to msgpack int being used directly, and
we aren't dealing with untrusted
peer (we only talk to ourselves).
2023-02-14 14:53:40 -05:00
Jarrod Johnson 3798a33213 Merge pull request #121 from Tkucherera/nodeconsole
nodeconsole documentation: passthrough options
2023-02-14 08:45:43 -05:00
Tinashe 251b307bd7 nodeconsole documentation: passthrough options 2023-02-14 08:27:25 -05:00
Jarrod Johnson bb7a72db65 Fix for ipv6 deployment
Need to avoid double-bracketing of the server and also disable globbing
so curl does not mistake the ip address for a glob attempt.
2023-02-13 09:36:42 -05:00
Jarrod Johnson fcde113e08 Add a check of dns.domain to selfcheck for node 2023-02-08 14:45:16 -05:00
Jarrod Johnson a02f617b3d Add DDR5 dimm to nodeinventory CLI output 2023-02-07 14:01:18 -05:00
Jarrod Johnson 7f1ac92fc9 Store mgr from confluent= specificate 2023-02-01 16:51:21 -05:00
Jarrod Johnson 8cf97833ab Fixes for certificate directed discovery 2023-02-01 13:09:40 -05:00
Jarrod Johnson 3e747069d9 Try to get verified bay from SMMs
With V3 systems, we can now ask
the SMMs for the certificates
and use that for a verified
measurement, regardless of
whether the XCC is returning
the correct bay number.
2023-02-01 12:57:27 -05:00
Jarrod Johnson c687da4d5f Tweak architecture override on import 2023-01-31 15:57:41 -05:00
Jarrod Johnson 340ccc422c Specify check for arch override of addons.cpio
For now, keep using x86_64 as
default, but allow overrides
for other architectures.

One day it may be cleaner to move all addons.cpio to
arch specific subdirs.
2023-01-31 15:27:45 -05:00
Jarrod Johnson 2c3afac576 Restructure aarch64 addons
Avoid tripping over current copy over, prepare
for smarter selection by architecture.
2023-01-31 15:10:49 -05:00
Jarrod Johnson 8e1cc63ac0 Correct spelling of keyword argument in ipmi 2023-01-31 15:00:22 -05:00
Jarrod Johnson dc6c7c1acc Make sure both el8 and el9 binaries are packed 2023-01-31 13:29:24 -05:00
Jarrod Johnson 5c309db47c Further ARMv8 support
Handle aarch64 differences in
at least some distributions.
2023-01-31 11:20:40 -05:00
Jarrod Johnson 976e9ef563 Bump version on genesis 2023-01-31 09:10:23 -05:00
Jarrod Johnson 0efd2a4d74 Fix the amended license gathering 2023-01-31 08:58:56 -05:00
Jarrod Johnson 424830471d Note how to fetch srpms associated with genesis 2023-01-31 08:54:03 -05:00
Jarrod Johnson 23f33a8420 Revamp license gathering for genesis 2023-01-31 08:52:32 -05:00
Jarrod Johnson 521a58c1d9 Have a utility to generate NOTICE from tmux
tmux basically defers to the c files, so
generate a NOTICE file from c files.
2023-01-31 08:37:42 -05:00
Jarrod Johnson ce375a1162 Merge pull request #120 from Tkucherera/master
Adding missing imports
2023-01-30 14:48:05 -05:00
Tkucherera caee136012 Merge branch 'xcat2:master' into master 2023-01-30 14:15:53 -05:00
Tinashe 2e283f3442 nodeconsole: missing imports time and socket 2023-01-30 14:13:44 -05:00
Jarrod Johnson 2b01d9fbfa Properly store all candidate host ip addresses
This is needed to ensure that mis-detected primary ip
falls through to another viable ip
2023-01-30 12:40:40 -05:00
Jarrod Johnson 627bc9ffe3 Modify pkglist for aarch64 2023-01-27 12:14:37 -05:00
Jarrod Johnson 3e71e103b1 Fix unpacking of el8 and el9 built sources 2023-01-27 10:47:27 -05:00
Jarrod Johnson a90cd8515e Tweak osdeploy for ARM setup 2023-01-27 10:43:29 -05:00
Jarrod Johnson 284d042afe Merge pull request #119 from Tkucherera/master
nodeconsole windowed and tiled functionality
2023-01-27 09:33:45 -05:00
Tinashe 2cc134adeb nodeconsole: allow for passthrough args 2023-01-27 09:30:46 -05:00
Jarrod Johnson 02e242ec4e Restore link local cert in apiclient 2023-01-27 09:13:47 -05:00
Jarrod Johnson 1777223232 Fixes for osdeploy arm ipxe init 2023-01-27 08:40:31 -05:00
Jarrod Johnson 648290ffbc Begin implementing aarch64 deploy support 2023-01-27 08:00:38 -05:00
Tinashe c9b72225a9 nodeeventlog timeframe documentation 2023-01-26 10:37:30 -05:00
Tinashe 3433635e9b nodeeventlog: timeframe option 2023-01-26 10:16:33 -05:00
Tkucherera 7a6c4fc5b2 Merge branch 'xcat2:master' into master 2023-01-26 10:05:04 -05:00
Tinashe f176a836ae nodeecentlog: add timeframe option 2023-01-26 10:01:02 -05:00
Jarrod Johnson ce324e90f7 Draft spec to generate addons-aarch64 files 2023-01-25 12:54:03 -05:00
Tinashe 23ea53ab55 console geometry 100x31 2023-01-24 11:18:21 -05:00
Jarrod Johnson d14d28caf8 Confirm TLS connectivity when scanning hosts
In certain environments, Confluent may have an IP address that
is fake, but then there is elsewhere with that same IP for real.

To mitigate this, follow up basic connectivity with proof of having
an associated certificate.
2023-01-24 08:22:00 -05:00
Jarrod Johnson 0008998680 Add api method to request all mac data
This will provide easy way for
client to get FDB data, potentially
for use in conjunction with discovery data.

For now, leave LLDP out, as that isn't currently cached
at the confluent layer.
2023-01-23 13:37:29 -05:00
Jarrod Johnson 2e059b5887 Make an API for getting full discovery data in one fetch
This makes for faster nodediscover being possible, also
makes web management of the data easier
2023-01-23 11:47:33 -05:00
Jarrod Johnson 792e6472e4 Fix IPv6 addresses_match
fe80:: could be submitted during
collective startup, handle that problem appropriately.
2023-01-23 11:24:25 -05:00
Tinashe b965f9b758 nodeconsole windowed and tiled functionality 2023-01-20 16:41:56 -05:00
Jarrod Johnson a522e17a63 Merge pull request #118 from Tkucherera/master
nodeeventlog man page -l option
2023-01-20 14:49:11 -05:00
Tinashe 9f3b934ea4 nodeeventlog man page -l option 2023-01-20 14:24:32 -05:00
Jarrod Johnson 680ca2c4a2 Merge pull request #117 from Tkucherera/master
nodeeventlog: return last n entries
2023-01-20 12:51:16 -05:00
Tinashe c3d0d255d3 nodeeventlog: -l return last n lines for each node 2023-01-20 12:13:15 -05:00
Tinashe 46d0a8d222 nodeeventlog: return last n entries 2023-01-20 10:09:52 -05:00
Jarrod Johnson 75f020f53c Have apiarmed continuous be properly respected for shared secret
Remote media was erroneously being invalidated, despite user opting
out of the strict security.
2023-01-19 14:54:18 -05:00
Jarrod Johnson c09e8448c2 Change to POSIX compliant range
POSIX allows ., but does not allow +.  This was a problem with EL 8.4 libxcrypt,
though is not a problem otherwise.
2023-01-19 14:53:35 -05:00
Jarrod Johnson 01f939b871 Have SuSE path also not be bothered by inability to restart web service 2023-01-18 08:50:30 -05:00
Jarrod Johnson 1f23750356 Add affluent detection to confluent
Affluent agent will now have an SSDP
response.  Add support for at
least recognizing and presenting
this in the discovery data.
2023-01-17 15:11:12 -05:00
Jarrod Johnson d1265af828 Handle more errors
subprocess may throw other errors that aren't calledprocesserrors,
in newer python versions.  Handle the case more broadly.
2023-01-17 10:04:10 -05:00
Jarrod Johnson 0929f059e2 Increase track size in dir2img
Larger images still run afoul of track limits
in mtools.  Make tracks 4 times as big
to lower number of required tracks.
2023-01-17 10:02:51 -05:00
Jarrod Johnson 40c3f2da53 Actually display deployment state, when available 2023-01-13 13:02:17 -05:00
Jarrod Johnson 51e53405d8 Add attributes for profiles to report state
Profiles may want to report things
like success and error
2023-01-13 12:54:21 -05:00
Jarrod Johnson d644d34b60 Add '-s' to nodeinventory
This allows a quick command to
get attributes into confluent
for manually added nodes,
without having to go through 'discovery' process.
2023-01-13 12:29:36 -05:00
Jarrod Johnson 7f31ae5b57 Fix syntax error 2023-01-13 11:15:51 -05:00
Jarrod Johnson a09e1a3f8b Handle IPv6 not set on IPMI nodes 2023-01-13 11:07:13 -05:00
Jarrod Johnson 50c073670d Explicitly declare Textmode during autoconsole
This enables a workable console during text install,
while also allowing graphical to run
2023-01-13 10:54:29 -05:00
Jarrod Johnson bc452b9b9a Restore role-less group
If a group is missing a role,
coerce it to administrator
2023-01-13 10:01:52 -05:00
Jarrod Johnson 453d1f9ceb Add IPv6 configuration support
For redfish and IPMI devices,
support new IPv6 static configuration
controls
2023-01-13 10:01:28 -05:00
Jarrod Johnson feed125c86 Fix restoration of old confluent db
Old confluent DB may have None in role. This is no longer
allowed.  Restore such entries by coercing them to 'Administrator'
which is how old confluent treated such users.
2023-01-12 08:38:55 -05:00
161 changed files with 6503 additions and 627 deletions
+4 -4
View File
@@ -21,17 +21,17 @@ def create_image(directory, image, label=None):
currsz = (currsz // 512 +1) * 512
datasz += currsz
datasz += ents * 32768
datasz = datasz // 4096 + 1
datasz = datasz // 16384 + 1
with open(image, 'wb') as imgfile:
imgfile.seek(datasz * 4096 - 1)
imgfile.seek(datasz * 16384 - 1)
imgfile.write(b'\x00')
if label:
subprocess.check_call(['mformat', '-i', image, '-v', label,
'-r', '16', '-d', '1', '-t', str(datasz),
'-s', '4','-h', '2', '::'])
'-s', '16','-h', '2', '::'])
else:
subprocess.check_call(['mformat', '-i', image, '-r', '16', '-d', '1', '-t',
str(datasz), '-s', '4','-h', '2', '::'])
str(datasz), '-s', '16','-h', '2', '::'])
# Some clustered filesystems will have the lock from mformat
# linger after close (mformat doesn't unlock)
# do a blocking wait for shared lock and then explicitly
+166
View File
@@ -0,0 +1,166 @@
#!/usr/bin/python3
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2016-2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from collections import deque
import optparse
import os
import select
import signal
import subprocess
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
import confluent.sortutil as sortutil
devnull = None
def run():
global devnull
devnull = open(os.devnull, 'rb')
argparser = optparse.OptionParser(
usage="Usage: %prog [options] noderange commandexpression",
epilog="Expressions are the same as in attributes, e.g. "
"'ipmitool -H {hardwaremanagement.manager}' will be expanded.")
argparser.add_option('-f', '-c', '--count', type='int', default=168,
help='Number of commands to run at a time')
argparser.add_option('-k', '--security', action='store_true',
help='Update SSH setup')
argparser.add_option('-F', '--sync', action='store_true',
help='Run the syncfiles associated with the currently completed OS profile on the noderange')
argparser.add_option('-P', '--scripts',
help='Re-run specified scripts, with full path under scripts, e.g. post.d/first,firstboot.d/second')
argparser.add_option('-m', '--maxnodes', type='int',
help='Specify a maximum number of '
'nodes to run remote ssh command to, '
'prompting if over the threshold')
# among other things, FD_SETSIZE limits. Besides, spawning too many
# processes can be unkind for the unaware on memory pressure and such...
#argparser.disable_interspersed_args()
(options, args) = argparser.parse_args()
if len(args) < 1:
argparser.print_help()
sys.exit(1)
client.check_globbing(args[0])
concurrentprocs = options.count
c = client.Command()
currprocs = 0
all = set([])
pipedesc = {}
pendingexecs = deque()
exitcode = 0
c.stop_if_noderange_over(args[0], options.maxnodes)
nodemap = {}
cmdparms = []
nodes = []
for res in c.read('/noderange/{0}/nodes/'.format(args[0])):
if 'error' in res:
sys.stderr.write(res['error'] + '\n')
exitcode |= res.get('errorcode', 1)
break
node = res['item']['href'][:-1]
nodes.append(node)
cmdstorun = []
if options.security:
cmdstorun.append(['run_remote', 'setupssh'])
if options.sync:
cmdstorun.append(['run_remote_python', 'syncfileclient'])
if options.scripts:
for script in options.scripts.split(','):
cmdstorun.append(['run_remote', script])
if not cmdstorun:
argparser.print_help()
sys.exit(1)
idxbynode = {}
cmdvbase = ['bash', '/etc/confluent/functions']
for sshnode in nodes:
idxbynode[sshnode] = 1
cmdv = ['ssh', sshnode] + cmdvbase + cmdstorun[0]
if currprocs < concurrentprocs:
currprocs += 1
run_cmdv(node, cmdv, all, pipedesc)
else:
pendingexecs.append((node, cmdv))
if not all or exitcode:
sys.exit(exitcode)
rdy, _, _ = select.select(all, [], [], 10)
while all:
pernodeout = {}
for r in rdy:
desc = pipedesc[r]
node = desc['node']
data = True
while data and select.select([r], [], [], 0)[0]:
data = r.readline()
if data:
if desc['type'] == 'stdout':
if node not in pernodeout:
pernodeout[node] = []
pernodeout[node].append(data)
else:
data = client.stringify(data)
sys.stderr.write('{0}: {1}'.format(node, data))
sys.stderr.flush()
else:
pop = desc['popen']
ret = pop.poll()
if ret is not None:
exitcode = exitcode | ret
all.discard(r)
r.close()
if desc['type'] == 'stdout':
if idxbynode[node] < len(cmdstorun):
cmdv = ['ssh', sshnode] + cmdvbase + cmdstorun[idxbynode[node]]
idxbynode[node] += 1
run_cmdv(node, cmdv, all, pipedesc)
elif pendingexecs:
node, cmdv = pendingexecs.popleft()
run_cmdv(node, cmdv, all, pipedesc)
for node in sortutil.natural_sort(pernodeout):
for line in pernodeout[node]:
line = client.stringify(line)
line = line.lstrip('\x08')
sys.stdout.write('{0}: {1}'.format(node, line))
sys.stdout.flush()
if all:
rdy, _, _ = select.select(all, [], [], 10)
sys.exit(exitcode)
def run_cmdv(node, cmdv, all, pipedesc):
nopen = subprocess.Popen(
cmdv, stdin=devnull, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
pipedesc[nopen.stdout] = {'node': node, 'popen': nopen,
'type': 'stdout'}
pipedesc[nopen.stderr] = {'node': node, 'popen': nopen,
'type': 'stderr'}
all.add(nopen.stdout)
all.add(nopen.stderr)
if __name__ == '__main__':
run()
+20
View File
@@ -22,6 +22,7 @@ import optparse
import os
import signal
import sys
import shlex
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
@@ -53,6 +54,8 @@ argparser.add_option('-p', '--prompt', action='store_true',
argparser.add_option('-m', '--maxnodes', type='int',
help='Prompt if trying to set attributes on more '
'than specified number of nodes')
argparser.add_option('-s', '--set', dest='set', metavar='settings.batch',
default=False, help='set attributes using a batch file')
(options, args) = argparser.parse_args()
@@ -109,6 +112,23 @@ elif options.clear or options.environment or options.prompt:
sys.stderr.write('Attribute names required with specified options\n')
argparser.print_help()
exitcode = 400
elif options.set:
arglist = [noderange]
showtype='current'
argfile = open(options.set, 'r')
argset = argfile.readline()
while argset:
try:
argset = argset[:argset.index('#')]
except ValueError:
pass
argset = argset.strip()
if argset:
arglist += shlex.split(argset)
argset = argfile.readline()
session.stop_if_noderange_over(noderange, options.maxnodes)
exitcode=client.updateattrib(session,arglist,nodetype, noderange, options, None)
if exitcode != 0:
sys.exit(exitcode)
+6
View File
@@ -90,6 +90,12 @@ cfgpaths = {
'bmc.ipv4_gateway': (
'configuration/management_controller/net_interfaces/management',
'ipv4_gateway'),
'bmc.static_ipv6_addresses': (
'configuration/management_controller/net_interfaces/management',
'static_v6_addresses'),
'bmc.static_ipv6_gateway': (
'configuration/management_controller/net_interfaces/management',
'static_v6_gateway'),
'bmc.hostname': (
'configuration/management_controller/hostname', 'hostname'),
}
+206 -7
View File
@@ -1,4 +1,4 @@
#!/usr/bin/python2
#!/usr/libexec/platform-python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015 Lenovo
@@ -23,13 +23,17 @@ path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
import confluent.sortutil as sortutil
import confluent.logreader as logreader
import time
import socket
import re
confettypath = os.path.join(os.path.dirname(sys.argv[0]), 'confetty')
argparser = optparse.OptionParser(
usage="Usage: %prog [options] node",
usage="Usage: %prog [options] <noderange> [kill][-- [passthroughoptions]]",
epilog="Command sequences are available while connected to a console, hit "
"ctrl-'e', then release ctrl, then 'c', then '?' for a full list. "
"For example, ctrl-'e', then 'c', then '.' will exit the current "
@@ -38,6 +42,10 @@ argparser.add_option('-t', '--tile', action='store_true', default=False,
help='Tile console windows in the terminal')
argparser.add_option('-l', '--log', action='store_true', default=False,
help='Enter log replay mode instead of showing a live console')
argparser.add_option('-T', '--Timestamp', action='store_true', default=False,
help= 'Dump log in stdout with timestamps')
argparser.add_option('-w','--windowed', action='store_true', default=False,
help='Open terminal windows for each node. The '
'environment variable NODECONSOLE_WINDOWED_COMMAND '
@@ -58,10 +66,26 @@ argparser.add_option('-w','--windowed', action='store_true', default=False,
'--shell-type login". If the NODECONSOLE_WINDOWED_COMMAND '
'environment variable isn\'t set, xterm will be used by'
'default.')
(options, args) = argparser.parse_args()
pass_through_args = []
killcon = False
try:
noderange = args[0]
if len(args) > 1:
if args[1] == 'kill':
killcon = True
pass_through_args = args[1:]
args = args[:1]
except IndexError:
argparser.print_help()
sys.exit(1)
if len(args) != 1:
argparser.print_help()
sys.exit(1)
if options.log:
logname = args[0]
if not os.path.exists(logname) and logname[0] != '/':
@@ -71,14 +95,105 @@ if options.log:
sys.exit(1)
logreader.replay_to_console(logname)
sys.exit(0)
#added functionality for wcons
if options.windowed:
if options.Timestamp:
logname = args[0]
if not os.path.exists(logname) and logname[0] != '/':
logname = os.path.join('/var/log/confluent/consoles', logname)
if not os.path.exists(logname):
sys.stderr.write('Unable to locate {0} on local system\n'.format(logname))
sys.exit(1)
logreader.dump_to_console(logname)
sys.exit(0)
def kill(noderange):
sess = client.Command()
envstring=os.environ.get('NODECONSOLE_WINDOWED_COMMAND')
if not envstring:
envlist=["xterm", "-e"]
envstring = 'xterm'
nodes = []
for res in sess.read('/noderange/{0}/nodes/'.format(args[0])):
node = res.get('item', {}).get('href', '/').replace('/', '')
if not node:
sys.stderr.write(res.get('error', repr(res)) + '\n')
sys.exit(1)
nodes.append(node)
for node in nodes:
s=socket.socket(socket.AF_UNIX)
winid=None
try:
win=subprocess.Popen(['xwininfo', '-tree', '-root'], stdout=subprocess.PIPE)
wintr=win.communicate()[0]
for line in wintr.decode('utf-8').split('\n'):
if 'console: {0}'.format(node) in line or 'confetty' in line:
win_obj = [ele for ele in line.split(' ') if ele.strip()]
winid = win_obj[0]
except:
print("Error: cannot retrieve window id of node {}".format(node))
if winid:
ps_data=subprocess.Popen(['xkill', '-id', winid ], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
sys.exit(0)
def handle_geometry(envlist, sizegeometry, side_pad=0, top_pad=0, first=False):
if '-geometry' in envlist:
g_index = envlist.index('-geometry')
elif '-g' in envlist:
g_index = envlist.index('-g')
else:
g_index = 0
if g_index:
if first:
envlist[g_index+1] = '{0}+{1}+{2}'.format(envlist[g_index+1],side_pad, top_pad)
else:
envlist[g_index+1] = '{0}+{1}+{2}'.format(sizegeometry,side_pad, top_pad)
else:
envlist.insert(1, '-geometry')
envlist.insert(2, '{0}+{1}+{2}'.format(sizegeometry,side_pad, top_pad))
g_index = 1
return envlist
# add funcltionality to close/kill all open consoles
if killcon:
kill(noderange)
#added functionality for wcons
if options.windowed:
result=subprocess.Popen(['xwininfo', '-root'], stdout=subprocess.PIPE)
rootinfo=result.communicate()[0]
result.wait()
for line in rootinfo.decode('utf-8').split('\n'):
if 'Width' in line:
screenwidth = int(line.split(':')[1])
if 'Height' in line:
screenheight = int(line.split(':')[1])
envstring=os.environ.get('NODECONSOLE_WINDOWED_COMMAND')
if not envstring:
sizegeometry='100x31'
corrected_x, corrected_y = (13,84)
envlist = handle_geometry(['xterm'] + pass_through_args + ['-e'],sizegeometry, first=True)
#envlist=['xterm', '-bg', 'black', '-fg', 'white', '-geometry', '{sizegeometry}+0+0'.format(sizegeometry=sizegeometry), '-e']
else:
envlist=os.environ.get('NODECONSOLE_WINDOWED_COMMAND').split(' ')
if envlist[0] == 'xterm':
if '-geometry' in envlist:
g_index = envlist.index('-geometry')
elif '-g' in envlist:
g_index = envlist.index('-g')
else:
g_index = 0
if g_index:
envlist[g_index+1] = envlist[g_index+1] + '+0+0'
else:
envlist.insert(1, '-geometry')
envlist.insert(2, '100x31+0+0')
g_index = 1
nodes = []
sess = client.Command()
for res in sess.read('/noderange/{0}/nodes/'.format(args[0])):
@@ -87,9 +202,87 @@ if options.windowed:
sys.stderr.write(res.get('error', repr(res)) + '\n')
sys.exit(1)
nodes.append(node)
if options.tile and not envlist[0] == 'xterm':
sys.stderr.write('[ERROR] UNSUPPORTED OPTIONS. \nWindowed and tiled consoles are only supported when using xterm \n')
sys.exit(1)
firstnode=nodes[0]
nodes.pop(0)
with open(os.devnull, 'wb') as devnull:
xopen=subprocess.Popen(envlist + [confettypath, '-c', '/tmp/controlpath-{0}'.format(firstnode), '-m', '5', 'start', '/nodes/{0}/console/session'.format(firstnode) ] , stdin=devnull)
time.sleep(2)
s=socket.socket(socket.AF_UNIX)
winid=''
try:
s.connect('/tmp/controlpath-{firstnode}'.format(firstnode=firstnode))
s.recv(64)
s.send(b'GETWINID')
winid=s.recv(64).decode('utf-8')
except:
time.sleep(2)
# try to get id of first panel/xterm window using name
win=subprocess.Popen(['xwininfo', '-tree', '-root'], stdout=subprocess.PIPE)
wintr=win.communicate()[0]
for line in wintr.decode('utf-8').split('\n'):
if 'console: {firstnode}'.format(firstnode=firstnode) in line or 'confetty' in line:
win_obj = [ele for ele in line.split(' ') if ele.strip()]
winid = win_obj[0]
if winid:
firstnode_window=subprocess.Popen(['xwininfo', '-id', '{winid}'.format(winid=winid)], stdout=subprocess.PIPE)
xinfo=firstnode_window.communicate()[0]
xinfl = xinfo.decode('utf-8').split('\n')
for line in xinfl:
if 'Absolute upper-left X:' in line:
side_pad = int(line.split(':')[1])
elif 'Absolute upper-left Y:' in line:
top_pad = int(line.split(':')[1])
elif 'Width:' in line:
window_width = int(line.split(':')[1])
elif 'Height' in line:
window_height = int(line.split(':')[1])
elif '-geometry' in line:
l = re.split(' |x|-|\+', line)
l_nosp = [ele for ele in l if ele.strip()]
wmxo = int(l_nosp[1])
wmyo = int(l_nosp[2])
sizegeometry = str(wmxo) + 'x' + str(wmyo)
else:
pass
window_width += side_pad*2
window_height += side_pad+top_pad
screenwidth -= wmxo
screenheight -= wmyo
currx = window_width
curry = 0
maxcol = int(screenwidth/window_width)
for node in sortutil.natural_sort(nodes):
if options.tile and envlist[0] == 'xterm':
corrected_x = currx
corrected_y = curry
xgeometry = '{0}+{1}+{2}'.format(sizegeometry, corrected_x, corrected_y)
currx += window_width
if currx >= screenwidth:
currx=0
curry += window_height
if curry > screenheight:
curry =top_pad
if not envstring:
envlist= handle_geometry(envlist, sizegeometry, corrected_x, corrected_y)
else:
if g_index:
envlist[g_index+1] = xgeometry
elif envlist[0] == 'xterm':
envlist=handle_geometry(envlist, sizegeometry, side_pad, top_pad)
side_pad+=(side_pad+1)
top_pad+=(top_pad+30)
else:
pass
with open(os.devnull, 'wb') as devnull:
subprocess.Popen(envlist + [confettypath, '-m', '5', 'start', '/nodes/{0}/console/session'.format(node)], stdin=devnull)
xopen=subprocess.Popen(envlist + [confettypath, '-c', '/tmp/controlpath-{0}'.format(node), '-m', '5', 'start', '/nodes/{0}/console/session'.format(node)] , stdin=devnull)
sys.exit(0)
#end of wcons
if options.tile:
@@ -103,8 +296,13 @@ if options.tile:
sys.exit(1)
nodes.append(node)
initial = True
in_tmux = False
pane = 0
sessname = 'nodeconsole_{0}'.format(os.getpid())
if os.environ.get("TMUX"):
initial = False
in_tmux = True
subprocess.call(['tmux', 'rename-session', sessname])
for node in sortutil.natural_sort(nodes):
panename = '{0}:{1}'.format(sessname, pane)
if initial:
@@ -125,7 +323,8 @@ if options.tile:
pane += 1
subprocess.call(['tmux', 'select-pane', '-t', sessname])
subprocess.call(['tmux', 'set-option', '-t', panename, 'pane-border-status', 'top'], stderr=null)
os.execlp('tmux', 'tmux', 'attach', '-t', sessname)
if not in_tmux:
os.execlp('tmux', 'tmux', 'attach', '-t', sessname)
else:
os.execl(confettypath, confettypath, 'start',
'/nodes/{0}/console/session'.format(args[0]))
+14 -3
View File
@@ -49,7 +49,7 @@ def armonce(nr, cli):
def setpending(nr, profile, cli):
args = {'deployment.pendingprofile': profile}
args = {'deployment.pendingprofile': profile, 'deployment.state': '', 'deployment.state_detail': ''}
if not profile.startswith('genesis-'):
args['deployment.stagedprofile'] = ''
args['deployment.profile'] = ''
@@ -132,7 +132,7 @@ def main(args):
if node not in databynode:
databynode[node] = {}
for attr in dbn[node]:
if attr in ('deployment.pendingprofile', 'deployment.apiarmed', 'deployment.stagedprofile', 'deployment.profile'):
if attr in ('deployment.pendingprofile', 'deployment.apiarmed', 'deployment.stagedprofile', 'deployment.profile', 'deployment.state', 'deployment.state_detail'):
databynode[node][attr] = dbn[node][attr].get('value', '')
for node in sortutil.natural_sort(databynode):
profile = databynode[node].get('deployment.pendingprofile', '')
@@ -153,7 +153,18 @@ def main(args):
armed = ' (node authentication armed)'
else:
armed = ''
print('{0}: {1}{2}'.format(node, profile, armed))
stateinfo = ''
deploymentstate = databynode[node].get('deployment.state', '')
if deploymentstate:
statedetails = databynode[node].get('deployment.state_detail', '')
if statedetails:
stateinfo = '{}: {}'.format(deploymentstate, statedetails)
else:
stateinfo = deploymentstate
if stateinfo:
print('{0}: {1} ({2})'.format(node, profile, stateinfo))
else:
print('{0}: {1}{2}'.format(node, profile, armed))
sys.exit(0)
if args.network and not args.prepareonly:
return rc
+64 -5
View File
@@ -17,6 +17,7 @@
import codecs
from datetime import datetime as dt
from datetime import timedelta
import optparse
import os
import signal
@@ -41,7 +42,18 @@ argparser = optparse.OptionParser(
argparser.add_option('-m', '--maxnodes', type='int',
help='Specify a maximum number of '
'nodes to clear if clearing log, '
'prompting if over the threshold')
'prompting if over the threshold')
argparser.add_option('-l', '--lines', type='int',
help='return the last <n> entries '
'for each node in the eventlog. '
)
argparser.add_option('-t', '--timeframe', type='string',
help='return entries within a specified timeframe '
'for each node in the eventlog. This will return '
'entries from the last hours or days. '
'1h would be one hour, 4d would be four days. '
'format <num>h or <num>d'
)
(options, args) = argparser.parse_args()
try:
noderange = args[0]
@@ -89,12 +101,34 @@ def format_event(evt):
msg = ''
return ' '.join(retparts) + msg
if deletemode:
func = session.delete
session.stop_if_noderange_over(noderange, options.maxnodes)
else:
func = session.read
if options.timeframe:
try:
delta = int(options.timeframe[:-1])
except ValueError:
argparser.print_help()
sys.exit(1)
if options.timeframe[-1].lower() == 'd':
tdelta = timedelta(days=delta)
elif options.timeframe[-1].lower() == 'h':
tdelta = timedelta(hours=delta)
else:
argparser.print_help()
sys.exit(1)
timeframe = dt.now() - tdelta
event_dict = {}
nodes = []
for res in session.read('/noderange/{0}/nodes/'.format(args[0])):
node = res.get('item', {}).get('href', '/').replace('/', '')
nodes.append(node)
event_dict[node] = []
for rsp in func('/noderange/{0}/events/hardware/log'.format(noderange)):
if 'error' in rsp:
sys.stderr.write(rsp['error'] + '\n')
@@ -107,6 +141,31 @@ for rsp in func('/noderange/{0}/events/hardware/log'.format(noderange)):
sys.stderr.write('{0}: {1}\n'.format(node, thisdata['error']))
exitcode |= 1
if 'events' in thisdata:
evtdata = thisdata['events']
for evt in evtdata:
print('{0}: {1}'.format(node, format_event(evt)))
evtdata = thisdata['events']
if options.lines:
event_dict[node].extend(evtdata)
else:
for evt in evtdata:
if options.timeframe:
# check if line is in timeframe
if 'timestamp' in evt and evt['timestamp'] is not None:
display = dt.strptime(evt['timestamp'], '%Y-%m-%dT%H:%M:%S')
if display > timeframe:
print('{0}: {1}'.format(node, format_event(evt)))
else:
print('{0}: {1}'.format(node, format_event(evt)))
if options.lines:
for node in nodes:
evtdata_list = event_dict[node]
if len(evtdata_list) != 0:
if len(evtdata_list) > options.lines:
evtdata_list = evtdata_list[-abs(options.lines):]
for evt in evtdata_list:
if options.timeframe:
if 'timestamp' in evt and evt['timestamp'] is not None:
display = dt.strptime(evt['timestamp'], '%Y-%m-%dT%H:%M:%S')
if display > timeframe:
print('{0}: {1}'.format(node, format_event(evt)))
else:
print('{0}: {1}'.format(node, format_event(evt)))
+32 -4
View File
@@ -53,6 +53,8 @@ def print_mem_info(node, prefix, meminfo):
memdescfmt += '3-{1} '
elif 'DDR4' in meminfo['memory_type']:
memdescfmt += '4-{1} '
elif 'DDR5' in meminfo['memory_type']:
memdescfmt += '5-{1} '
elif 'DCPMM' in meminfo['memory_type']:
memdescfmt = '{0}GB {1} '
meminfo['module_type'] = 'DCPMM'
@@ -99,6 +101,7 @@ usedprefixes = set([])
argparser = optparse.OptionParser(
usage="Usage: %prog <noderange> [serial|model|uuid|mac]")
argparser.add_option('-j', '--json', action='store_true', help='Output JSON')
argparser.add_option('-s', '--store', action='store_true', help='Store serial, model, and uuid into id.serial, id.model, and id.uuid')
(options, args) = argparser.parse_args()
try:
noderange = args[0]
@@ -126,17 +129,36 @@ if len(args) > 1:
try:
if options.json:
databynode = {}
if options.store and len(args) <= 1:
url = '/noderange/{0}/inventory/hardware/all/system'
pushattribs = {}
session = client.Command()
for res in session.read(url.format(noderange)):
printerror(res)
if 'databynode' not in res:
continue
for node in res['databynode']:
if options.store and node not in pushattribs:
pushattribs[node] = {}
printerror(res['databynode'][node], node)
if 'inventory' not in res['databynode'][node]:
continue
for inv in res['databynode'][node]['inventory']:
prefix = inv['name']
if options.store and prefix == 'System':
currinfo = inv.get('information', {})
curruuid = currinfo.get('UUID', '')
if curruuid:
curruuid = curruuid.lower()
pushattribs[node]['id.uuid'] = curruuid
currserial = currinfo.get('Serial Number', '')
if currserial:
currserial = currserial.strip()
pushattribs[node]['id.serial'] = currserial
currmodelnum = currinfo.get('Model', '')
if currmodelnum:
currmodelnum = currmodelnum.strip()
pushattribs[node]['id.model'] = currmodelnum
idx = 2
while (node, prefix) in usedprefixes:
prefix = '{0} {1}'.format(inv['name'], idx)
@@ -148,7 +170,7 @@ try:
if node not in databynode:
databynode[node] = {}
databynode[node][prefix] = inv
else:
elif not options.store:
print('{0}: {1}: Not Present'.format(node, prefix))
continue
info = inv['information']
@@ -179,12 +201,18 @@ try:
databynode[node] = {}
databynode[node][prefix] = inv
break
print(u'{0}: {1} {2}: {3}'.format(node, prefix,
pretty(datum),
info[datum]))
elif not options.store:
print(u'{0}: {1} {2}: {3}'.format(node, prefix,
pretty(datum),
info[datum]))
if options.json:
print(json.dumps(databynode, sort_keys=True, indent=4,
separators=(',', ': ')))
if pushattribs:
for node in pushattribs:
for rsp in session.update('/nodes/{0}/attributes/current'.format(node), pushattribs[node]):
if 'error' in rsp:
sys.stderr.write(rsp['error'] + '\n')
except KeyboardInterrupt:
print('')
sys.exit(exitcode)
+10 -3
View File
@@ -1,4 +1,4 @@
#!/usr/bin/python2
#!/usr/libexec/platform-python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015-2017 Lenovo
@@ -15,13 +15,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
__author__ = 'jjohnson2,alin37'
__author__ = 'jjohnson2,alin37,wgrzeda'
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
@@ -39,9 +41,12 @@ def main():
" or: %prog [options] noderange <nodeattribute>...")
argparser.add_option('-b', '--blame', action='store_true',
help='Show information about how attributes inherited')
argparser.add_option('-d', '--delim', metavar="STRING", default = "\n",
help='Delimiter separating the values')
(options, args) = argparser.parse_args()
noderange=""
nodelist=""
list = []
try:
noderange = args[0]
nodelist = '/noderange/{0}/nodes/'.format(noderange)
@@ -61,7 +66,9 @@ def main():
sys.stderr.write(res['error'] + '\n')
exitcode = 1
else:
print(res['item']['href'].replace('/', ''))
elem=(res['item']['href'].replace('/', ''))
list.append(elem)
print(options.delim.join(list))
sys.exit(exitcode)
+15 -3
View File
@@ -48,6 +48,8 @@ def run():
'prompting if over the threshold')
argparser.add_option('-l', '--loginname', type='str',
help='Username to use when connecting, defaults to current user.')
argparser.add_option('-s', '--substitutename',
help='Use a different name other than the nodename for rsync')
argparser.add_option('-f', '-c', '--count', type='int', default=168,
help='Number of nodes to concurrently rsync')
# among other things, FD_SETSIZE limits. Besides, spawning too many
@@ -63,10 +65,20 @@ def run():
c = client.Command()
cmdstr = ' '.join(args[:-1])
cmdstr = 'rsync -av --info=progress2 ' + cmdstr
if options.loginname:
cmdstr += ' {}@'.format(options.loginname) + '{node}:' + targpath
targname = options.substitutename
if targname and '{' in targname:
targname = targname + ':'
elif targname:
targname = '{node}' + targname + ':'
else:
cmdstr += ' {node}:' + targpath
targname = '{node}:'
if options.loginname:
cmdstr += ' {}@'.format(options.loginname) + targname + targpath
else:
cmdstr += ' {}'.format(targname) + targpath
currprocs = 0
all = set([])
+9 -1
View File
@@ -37,6 +37,12 @@ class hybridcsv(csv.excel):
lineterminator = '\n'
def floatformat(num):
fm = u'{:.5f}'.format(num).rstrip('0')
if fm[-1:] == u'.':
return fm + u'0'
return fm
csv.register_dialect('hybrid', hybridcsv)
import confluent.client as client
@@ -135,7 +141,7 @@ def sensorpass(showout=True, appendtime=False):
if sensedata['value'] is None:
showval = ''
elif isinstance(sensedata['value'], float):
showval = u' {0:.5f} '.format(sensedata['value'])
showval = u' {0} '.format(floatformat(sensedata['value']))
else:
showval = u' {0} '.format(sensedata['value'])
if sensedata['units'] not in (None, u''):
@@ -191,6 +197,8 @@ def format_csv(csvwriter, orderedsensors, resdata, showtime=True):
datum = ','.join([datum, healthstates])
else:
datum = healthstates
if isinstance(datum, float):
datum = floatformat(datum)
rowdata.append(datum)
except KeyError:
rowdata.append('N/A')
+36 -9
View File
@@ -16,13 +16,10 @@
# limitations under the License.
import argparse
import base64
import csv
import fcntl
import io
import numpy as np
import os
import subprocess
import sys
try:
@@ -35,7 +32,31 @@ except ImportError:
pass
def plot(gui, output, plotdata, bins):
def iterm_draw(data):
databuf = data.getbuffer()
datalen = len(databuf)
data = base64.b64encode(databuf).decode('utf8')
sys.stdout.write(
'\x1b]1337;File=inline=1;size={}:'.format(datalen))
sys.stdout.write(data)
sys.stdout.write('\a')
sys.stdout.write('\n')
sys.stdout.flush()
def kitty_draw(data):
data = base64.b64encode(data.getbuffer())
while data:
chunk, data = data[:4096], data[4096:]
m = 1 if data else 0
sys.stdout.write('\x1b_Ga=T,f=100,m={};'.format(m))
sys.stdout.write(chunk.decode('utf8'))
sys.stdout.write('\x1b\\')
sys.stdout.flush()
sys.stdout.write('\n')
def plot(gui, output, plotdata, bins, fmt):
import matplotlib as mpl
if gui and mpl.get_backend() == 'agg':
sys.stderr.write('Error: No GUI backend available and -g specified!\n')
@@ -51,8 +72,13 @@ def plot(gui, output, plotdata, bins):
tdata = io.BytesIO()
plt.savefig(tdata)
if not gui and not output:
writer = DumbWriter()
writer.draw(tdata)
if fmt == 'sixel':
writer = DumbWriter()
writer.draw(tdata)
elif fmt == 'kitty':
kitty_draw(tdata)
elif fmt == 'iterm':
iterm_draw(tdata)
return n, bins
def textplot(plotdata, bins):
@@ -81,7 +107,8 @@ histogram = False
aparser = argparse.ArgumentParser(description='Quick access to common statistics')
aparser.add_argument('-c', type=int, default=0, help='Column number to analyze (default is last column)')
aparser.add_argument('-d', default=None, help='Value used to separate columns')
aparser.add_argument('-x', default=False, action='store_true', help='Output histogram in sixel format')
aparser.add_argument('-x', default=False, action='store_true', help='Output histogram in graphical format')
aparser.add_argument('-f', default='sixel', help='Format for histogram output (sixel/iterm/kitty)')
aparser.add_argument('-s', default=0, help='Number of header lines to skip before processing')
aparser.add_argument('-g', default=False, action='store_true', help='Open histogram in separate graphical window')
aparser.add_argument('-o', default=None, help='Output histogram to the specified filename in PNG format')
@@ -138,7 +165,7 @@ while data:
data = list(csv.reader([data], delimiter=delimiter))[0]
n = None
if args.g or args.o or args.x:
n, bins = plot(args.g, args.o, plotdata, bins=args.b)
n, bins = plot(args.g, args.o, plotdata, bins=args.b, fmt=args.f)
if args.t:
n, bins = textplot(plotdata, bins=args.b)
print('Samples: {5} Min: {3} Median: {0} Mean: {1} Max: {4} StandardDeviation: {2} Sum: {6}'.format(np.median(plotdata), np.mean(plotdata), np.std(plotdata), np.min(plotdata), np.max(plotdata), len(plotdata), np.sum(plotdata)))
+42
View File
@@ -296,5 +296,47 @@ def replay_to_console(txtfile):
sys.exit(1)
_replay_to_console(txtfile, binfile)
def dump_to_console(txtfile):
if os.path.exists(txtfile + '.cbl'):
binfile = txtfile + '.cbl'
elif '.' not in txtfile:
if '/' not in txtfile:
txtfile = os.getcwd() + '/' + txtfile
sys.stderr.write('Unable to locate cbl file: "{0}"\n'.format(txtfile + '.cbl'))
sys.exit(1)
else:
fileparts = txtfile.split('.')
prefix = '.'.join(fileparts[:-1])
binfile = prefix + '.cbl.' + fileparts[-1]
if not os.path.exists(binfile):
sys.stderr.write('Unable to locate cbl file: "{0}"\n'.format(binfile))
sys.exit(1)
replay = LogReplay(txtfile, binfile)
quitit = False
writeout('\x1b[2J\x1b[;H')
prepend = ''
try:
while not quitit:
newdata, delay = replay.get_output(False)
if newdata:
if prepend:
newdata = prepend + newdata
prepend = b''
writeout(newdata.replace(b'\r\n', '\r\n[ {0} ] '.format(time.strftime('%m/%d %H:%M:%S', time.localtime(replay.laststamp))).encode('utf8')))
newdata = ''
try:
if hasattr(sys.stdout, 'buffer'):
sys.stdout.buffer.flush()
else:
sys.stdout.flush()
except IOError:
pass
else:
break
except Exception:
writeout('\x1b[m\x1b[?25h\n')
raise
writeout('\x1b[m\x1b[?25h\n')
if __name__ == '__main__':
replay_to_console(sys.argv[1])
+29 -3
View File
@@ -7,7 +7,8 @@ nodeattrib(8) -- List or change confluent nodes attributes
`nodeattrib <noderange> [<nodeattribute1=value1> <nodeattribute2=value2> ...]`
`nodeattrib -c <noderange> <nodeattribute1> <nodeattribute2> ...`
`nodeattrib -e <noderange> <nodeattribute1> <nodeattribute2> ...`
`nodeattrib -p <noderange> <nodeattribute1> <nodeattribute2> ...`
`nodeattrib -p <noderange> <nodeattribute1> <nodeattribute2> ...`
`nodeattrib <noderange> -s <attributes.batch> ...`
## DESCRIPTION
@@ -53,12 +54,18 @@ to a blank value will allow masking a group defined attribute with an empty valu
* `-e`, `--environment`:
Set specified attributes based on exported environment variable of matching name.
Environment variable names may be lower case or all upper case.
Replace . with _ as needed (e.g. info.note may be specified as either $info_note or $INFO_NOTE
Replace . with _ as needed (e.g. info.note may be specified as either $info_note or $INFO_NOTE)
* `-p`, `--prompt`:
Request interactive prompting to provide values rather than the command line
or environment variables.
* `-s`, `--set`:
Set attributes using a batch file rather than the command line. The attributes in the batch file
can be specified as one line of key=value pairs simmilar to command line or each attribute can
be in its own line. Lines that start with # sign will be read as a comment. See EXAMPLES for batch
file syntax.
* `-m MAXNODES`, `--maxnodes=MAXNODES`:
Prompt if trying to set attributes on more than
specified number of nodes.
@@ -116,6 +123,25 @@ to a blank value will allow masking a group defined attribute with an empty valu
`d1: net.pxe.switch: pxeswitch1`
`d1: net.switch:`
* Setting attributes using a batch file with syntax similar to command line:
`# cat nodeattributes.batch`
`# power`
`power.psu1.outlet=3 power.psu1.pdu=pdu2`
`# nodeattrib n41 -s nodeattributes.batch`
`n41: 3`
`n41: pdu2`
* Setting attributes using a batch file with syntax where each attribute is in its own line:
`# cat nodeattributes.batch`
`# management`
`custom.mgt.switch=switch_main`
`custom.mgt.switch.port=swp4`
`# nodeattrib n41 -s nodeattributes.batch`
`n41: switch_main`
`n41: swp4`
## SEE ALSO
nodegroupattrib(8), nodeattribexpressions(5)
+20 -1
View File
@@ -2,7 +2,7 @@ nodeconsole(8) -- Open a console to a confluent node
=====================================================
## SYNOPSIS
`nodeconsole [options] <noderange>`
`nodeconsole [options] <noderange> [kill][-- [passthroughoptions]]`
## DESCRIPTION
@@ -16,6 +16,9 @@ will initiate an automatic retry interval that is randomized between 2 and 4 min
The reopen escape sequence below requests an immediate retry, as does connecting
a new session.
When a windowed console is open the `nodeconsole <noderange> kill` command will kill the
console process which will result in the console window closing.
## OPTIONS
* `-t`, `--tile`:
@@ -26,6 +29,11 @@ a new session.
Perform a log reply on the current, local log in /var/log/confluent/consoles.
If in collective mode, this only makes sense to use on the current collective
manager at this time.
* `-T`, `--Timestamp`:
Dump the log with Timpstamps on the current, local log in /var/log/confluent/consoles.
If in collective mode, this only makes sense to use on the current collective
manager at this time.
* `-w`, `--windowed`:
Open terminal windows for each node. The
@@ -86,3 +94,14 @@ keystroke will be interpreted as a command. The following commands are availabl
Get a list of supported commands
* `<ent>`:
Hit enter to skip entering a command at the escape prompt.
## PASSTHROUGH OPTIONS
While opening a windowed console with xterm or any other console of choice. The
nodeconsole command gives capality to specify passthrough options targeted at
the console. All options after the -- will be parsed the console program. For
example, opening a windowed console using xterm with a black background.
`nodeconconsole -w n1 -- -bg black`
@@ -15,6 +15,15 @@ noderange.
* `-m MAXNODES`, `--maxnodes=MAXNODES`:
Specify a maximum number of nodes to clear if clearing log, prompting if
over the threshold
* `-l LINES`, `--lines=LINES`:
return the last <n> entries for each node in the eventlog.
* `-t TIMEFRAME`, `--timeframe=TIMEFRAME`:
return entries within a specified timeframe for each node's event log.
This will return entries from the last <n> hours or days. 1h would be
entries from with the last one hour.
* `-h`, `--help`:
Show help message and exit
+3 -2
View File
@@ -4,7 +4,7 @@ nodelist(8) -- List confluent nodes and their attributes
## SYNOPSIS
`nodelist <noderange>`
`nodelist <noderange> [-b] <nodeattribute>...`
`nodelist <noderange> [-b] [-d] {string} <nodeattribute>...`
## DESCRIPTION
@@ -24,7 +24,8 @@ all attributes that begin with `net.` and end with `switch`.
* `-b`, `--blame`:
Annotate inherited and expression based attributes to show their base value.
* `-d`, `--delim`:
Choose a delimiter to separat the values. Default - ENTER.
## EXAMPLES
* Listing matching nodes of a simple noderange:
`# nodelist n1-n4`
+3
View File
@@ -16,6 +16,9 @@ noderange. This will present progress as percentage for all nodes.
Specify how many rsync executions to do concurrently. If noderange
exceeds the count, then excess nodes will wait until one of the
active count completes.
* `-s`, `--substitutename`:
'Use a different name other than the nodename for rsync'
* `-m MAXNODES`, `--maxnodes=MAXNODES`:
Specify a maximum number of nodes to run rsync to, prompting if over the
+14 -3
View File
@@ -11,13 +11,24 @@ mv confluent_osdeploy.tar.xz ~/rpmbuild/SOURCES/
cd -
mkdir -p el9bin/opt/confluent/bin
mkdir -p el9bin/stateless-bin
podman run --privileged --rm -v $(pwd)/utils:/buildutils -i -t fedorabuilder make -C /buildutils
podman run --privileged --rm -v $(pwd)/utils:/buildutils -i -t fedorabuild make -C /buildutils
cd utils
mv confluent_imginfo copernicus clortho autocons ../el9bin/opt/confluent/bin
mv start_root urlmount ../el9bin/stateless-bin/
cp confluent_imginfo copernicus clortho autocons ../el9bin/opt/confluent/bin
cp start_root urlmount ../el9bin/stateless-bin/
make clean
cd ..
mkdir -p el8bin/opt/confluent/bin
mkdir -p el8bin/stateless-bin
podman run --privileged --rm -v $(pwd)/utils:/buildutils -i -t el7build make -C /buildutils
cd utils
cp confluent_imginfo copernicus clortho autocons ../el8bin/opt/confluent/bin
cp start_root urlmount ../el8bin/stateless-bin/
make clean
cd ..
tar Jcvf confluent_el9bin.tar.xz el9bin/
tar Jcvf confluent_el8bin.tar.xz el8bin/
mv confluent_el8bin.tar.xz ~/rpmbuild/SOURCES/
mv confluent_el9bin.tar.xz ~/rpmbuild/SOURCES/
rm -rf el9bin
rm -rf el8bin
rpmbuild -ba confluent_osdeploy.spec
+34
View File
@@ -0,0 +1,34 @@
cd $(dirname $0)
VERSION=`git describe|cut -d- -f 1`
NUMCOMMITS=`git describe|cut -d- -f 2`
if [ "$NUMCOMMITS" != "$VERSION" ]; then
VERSION=$VERSION.dev$NUMCOMMITS.g`git describe|cut -d- -f 3`
fi
sed -e "s/#VERSION#/$VERSION/" confluent_osdeploy-aarch64.spec.tmpl > confluent_osdeploy-aarch64.spec
cd ..
cp ../LICENSE .
tar Jcvf confluent_osdeploy.tar.xz confluent_osdeploy
mv confluent_osdeploy.tar.xz ~/rpmbuild/SOURCES/
cd -
mkdir -p el9bin/opt/confluent/bin
mkdir -p el9bin/stateless-bin
mkdir -p el8bin/opt/confluent/bin
mkdir -p el8bin/stateless-bin
podman run --privileged --rm -v $(pwd)/utils:/buildutils -i -t el9builder make -C /buildutils
cd utils
mv confluent_imginfo copernicus clortho autocons ../el9bin/opt/confluent/bin
mv start_root urlmount ../el9bin/stateless-bin/
cd ..
podman run --privileged --rm -v $(pwd)/utils:/buildutils -i -t el8builder make -C /buildutils
cd utils
mv confluent_imginfo copernicus clortho autocons ../el8bin/opt/confluent/bin
mv start_root urlmount ../el8bin/stateless-bin/
cd ..
tar Jcvf confluent_el9bin.tar.xz el9bin/
tar Jcvf confluent_el8bin.tar.xz el8bin/
mv confluent_el8bin.tar.xz ~/rpmbuild/SOURCES/
mv confluent_el9bin.tar.xz ~/rpmbuild/SOURCES/
rm -rf el9bin
rm -rf el8bin
podman run --privileged --rm -v $HOME:/root el8builder rpmbuild -ba /root/confluent/confluent_osdeploy/confluent_osdeploy-aarch64.spec
@@ -21,6 +21,10 @@ class InvalidApiKey(Exception):
def msg_align(len):
return (len + 3) & ~3
try:
_protoparm = ssl.PROTOCOL_TLS_CLIENT
except AttributeError:
_protoparm = ssl.PROTOCOL_SSLv23
cryptname = ctypes.util.find_library('crypt')
if not cryptname:
if os.path.exists('/lib64/libcrypt.so.2') or os.path.exists('/usr/lib64/libcrypt.so.2'):
@@ -223,7 +227,7 @@ def get_apikey(nodename, hosts, errout=None):
return apikey
class HTTPSClient(client.HTTPConnection, object):
def __init__(self, usejson=False, port=443, host=None, errout=None, phmac=None):
def __init__(self, usejson=False, port=443, host=None, errout=None, phmac=None, checkonly=False):
self.phmac = phmac
self.errout = None
if errout:
@@ -253,6 +257,7 @@ class HTTPSClient(client.HTTPConnection, object):
self.stdheaders['CONFLUENT_NODENAME'] = node
if line.startswith('MANAGER:') and not host:
host = line.split(' ')[1]
self.hosts.append(host)
if not plainhost:
plainhost = host
if line.startswith('EXTMGRINFO:'):
@@ -286,7 +291,7 @@ class HTTPSClient(client.HTTPConnection, object):
if self.phmac:
with open(phmac, 'r') as hmacin:
self.stdheaders['CONFLUENT_CRYPTHMAC'] = hmacin.read()
else:
elif not checkonly:
self.stdheaders['CONFLUENT_APIKEY'] = get_apikey(node, self.hosts, errout=self.errout)
if mgtiface:
self.stdheaders['CONFLUENT_MGTIFACE'] = mgtiface
@@ -304,6 +309,10 @@ class HTTPSClient(client.HTTPConnection, object):
def check_connections(self):
foundsrv = None
hosts = self.hosts
ctx = ssl.SSLContext(_protoparm)
ctx.load_verify_locations('/etc/confluent/ca.pem')
ctx.verify_mode = ssl.CERT_REQUIRED
ctx.check_hostname = True
for timeo in (0.1, 5):
for host in hosts:
try:
@@ -311,10 +320,16 @@ class HTTPSClient(client.HTTPConnection, object):
psock = socket.socket(addrinf[0])
psock.settimeout(timeo)
psock.connect(addrinf[4])
chost = host.split('%', 1)[0]
ctx.wrap_socket(psock, server_hostname=chost)
foundsrv = host
psock.close()
break
except OSError:
except (OSError, socket.error):
continue
except ssl.SSLError:
continue
except ssl.CertificateError:
continue
else:
continue
@@ -342,11 +357,12 @@ class HTTPSClient(client.HTTPConnection, object):
raise Exception('Unable to reach any hosts')
return foundsrv
def connect(self):
def connect(self, tries=3):
addrinf = socket.getaddrinfo(self.host, self.port)[0]
psock = socket.socket(addrinf[0])
psock.settimeout(15)
psock.connect(addrinf[4])
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
ctx = ssl.SSLContext(_protoparm)
ctx.load_verify_locations('/etc/confluent/ca.pem')
host = self.host.split('%', 1)[0]
if '[' not in host and ':' in host:
@@ -364,6 +380,10 @@ class HTTPSClient(client.HTTPConnection, object):
self.errout.write(errmsg)
self.errout.flush()
sys.exit(1)
except socket.timeout:
if not tries:
raise
return self.connect(tries=tries-1)
def grab_url(self, url, data=None, returnrsp=False):
return self.grab_url_with_status(url, data, returnrsp)[1]
@@ -448,7 +468,7 @@ if __name__ == '__main__':
outf.write(chunk)
chunk = reader.read(16384)
sys.exit(0)
client = HTTPSClient(usejson, errout=errout, phmac=phmac)
client = HTTPSClient(usejson, errout=errout, phmac=phmac, checkonly=checkonly)
if waitfor:
status = 201
while status != waitfor:
@@ -8,6 +8,10 @@ import sys
import time
import shlex
import subprocess
try:
import yaml
except ImportError:
pass
try:
from importlib.machinery import SourceFileLoader
def load_source(mod, path):
@@ -107,6 +111,103 @@ def get_interface_name(iname, settings):
return iname
return None
class NetplanManager(object):
def __init__(self, deploycfg):
self.cfgbydev = {}
self.read_connections()
self.deploycfg = deploycfg
def read_connections(self):
for plan in glob.glob('/etc/netplan/*.y*ml'):
with open(plan) as planfile:
planinfo = yaml.safe_load(planfile)
if not planinfo:
continue
nicinfo = planinfo.get('network', {}).get('ethernets', {})
for devname in nicinfo:
if devname == 'lo':
continue
if 'gateway4' in nicinfo[devname]:
# normalize deprecated syntax on read in
gw4 = nicinfo[devname]['gateway4']
del nicinfo[devname]['gateway4']
routeinfo = nicinfo[devname].get('routes', [])
for ri in routeinfo:
if ri.get('via', None) == gw4 and ri.get('to', None) in ('default', '0.0.0.0/0', '0/0'):
break
else:
routeinfo.append({
'to': 'default',
'via': gw4
})
nicinfo[devname]['routes'] = routeinfo
self.cfgbydev[devname] = nicinfo[devname]
def apply_configuration(self, cfg):
devnames = cfg['interfaces']
if len(devnames) != 1:
raise Exception('Multi-nic team/bonds not yet supported')
stgs = cfg['settings']
needcfgapply = False
for devname in devnames:
needcfgwrite = False
if stgs['ipv6_method'] == 'static':
curraddr = stgs['ipv6_address']
currips = self.getcfgarrpath([devname, 'addresses'])
if curraddr not in currips:
needcfgwrite = True
currips.append(curraddr)
if stgs['ipv4_method'] == 'static':
curraddr = stgs['ipv4_address']
currips = self.getcfgarrpath([devname, 'addresses'])
if curraddr not in currips:
needcfgwrite = True
currips.append(curraddr)
gws = []
gws.append(stgs.get('ipv4_gateway', None))
gws.append(stgs.get('ipv6_gateway', None))
for gwaddr in gws:
if gwaddr:
cfgroutes = self.getcfgarrpath([devname, 'routes'])
for rinfo in cfgroutes:
if rinfo.get('via', None) == gwaddr:
break
else:
needcfgwrite = True
cfgroutes.append({'via': gwaddr, 'to': 'default'})
dnsips = self.deploycfg.get('nameservers', [])
dnsdomain = self.deploycfg.get('dnsdomain', '')
if dnsips:
currdnsips = self.getcfgarrpath([devname, 'nameservers', 'addresses'])
for dnsip in dnsips:
if dnsip not in currdnsips:
needcfgwrite = True
currdnsips.append(dnsip)
if dnsdomain:
currdnsdomain = self.getcfgarrpath([devname, 'nameservers', 'search'])
if dnsdomain not in currdnsdomain:
needcfgwrite = True
currdnsdomain.append(dnsdomain)
if needcfgwrite:
needcfgapply = True
newcfg = {'network': {'version': 2, 'ethernets': {devname: self.cfgbydev[devname]}}}
with open('/etc/netplan/{0}-confluentcfg.yaml'.format(devname), 'w') as planout:
planout.write(yaml.dump(newcfg))
if needcfgapply:
subprocess.call(['netplan', 'apply'])
def getcfgarrpath(self, devpath):
currptr = self.cfgbydev
for k in devpath[:-1]:
if k not in currptr:
currptr[k] = {}
currptr = currptr[k]
if devpath[-1] not in currptr:
currptr[devpath[-1]] = []
return currptr[devpath[-1]]
class WickedManager(object):
def __init__(self):
self.teamidx = 0
@@ -253,6 +354,7 @@ class NetworkManager(object):
def apply_configuration(self, cfg):
cmdargs = {}
cmdargs['connection.autoconnect'] = 'yes'
stgs = cfg['settings']
cmdargs['ipv6.method'] = stgs.get('ipv6_method', 'link-local')
if stgs.get('ipv6_address', None):
@@ -296,6 +398,10 @@ class NetworkManager(object):
subprocess.check_call(['nmcli', 'c', 'u', u])
else:
subprocess.check_call(['nmcli', 'c', 'add', 'type', self.devtypes[iname], 'con-name', cname, 'connection.interface-name', iname] + cargs)
self.read_connections()
u = self.uuidbyname.get(cname, None)
if u:
subprocess.check_call(['nmcli', 'c', 'u', u])
@@ -311,8 +417,12 @@ if __name__ == '__main__':
myaddrs = apiclient.get_my_addresses()
srvs, _ = apiclient.scan_confluents()
doneidxs = set([])
dc = None
for srv in srvs:
s = socket.create_connection((srv, 443))
try:
s = socket.create_connection((srv, 443))
except socket.error:
continue
myname = s.getsockname()
s.close()
if len(myname) == 4:
@@ -325,8 +435,27 @@ if __name__ == '__main__':
curridx = addr[-1]
if curridx in doneidxs:
continue
status, nc = apiclient.HTTPSClient(usejson=True, host=srv).grab_url_with_status('/confluent-api/self/netcfg')
for tries in (1, 2, 3):
try:
status, nc = apiclient.HTTPSClient(usejson=True, host=srv).grab_url_with_status('/confluent-api/self/netcfg')
break
except Exception:
if tries == 3:
raise
time.sleep(1)
continue
nc = json.loads(nc)
if not dc:
for tries in (1, 2, 3):
try:
status, dc = apiclient.HTTPSClient(usejson=True, host=srv).grab_url_with_status('/confluent-api/self/deploycfg2')
break
except Exception:
if tries == 3:
raise
time.sleep(1)
continue
dc = json.loads(dc)
iname = get_interface_name(idxmap[curridx], nc.get('default', {}))
if iname:
for iname in iname.split(','):
@@ -344,7 +473,16 @@ if __name__ == '__main__':
else:
netname_to_interfaces[uname] = {'interfaces': set([iname]), 'settings': nc['extranets'][netname]}
doneidxs.add(curridx)
if 'default' in netname_to_interfaces:
for netn in netname_to_interfaces:
if netn == 'default':
continue
netname_to_interfaces['default']['interfaces'] -= netname_to_interfaces[netn]['interfaces']
if not netname_to_interfaces['default']['interfaces']:
del netname_to_interfaces['default']
rm_tmp_llas(tmpllas)
if os.path.exists('/usr/sbin/netplan'):
nm = NetplanManager(dc)
if os.path.exists('/usr/bin/nmcli'):
nm = NetworkManager(devtypes)
elif os.path.exists('/usr/sbin/wicked'):
@@ -0,0 +1,31 @@
[ -f /lib/confluent/functions ] && . /lib/confluent/functions
[ -f /etc/confluent/functions ] && . /etc/confluent/functions
[ -f /opt/confluent/bin/apiclient ] && confapiclient=/opt/confluent/bin/apiclient
[ -f /etc/confluent/apiclient ] && confapiclient=/etc/confluent/apiclient
for pubkey in /etc/ssh/ssh_host*key.pub; do
certfile=${pubkey/.pub/-cert.pub}
rm $certfile
confluentpython $confapiclient /confluent-api/self/sshcert $pubkey -o $certfile
done
TMPDIR=$(mktemp -d)
cd $TMPDIR
confluentpython $confapiclient /confluent-public/site/initramfs.tgz -o initramfs.tgz
tar xf initramfs.tgz
for ca in ssh/*.ca; do
LINE=$(cat $ca)
cp -af /etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts.new
grep -v "$LINE" /etc/ssh/ssh_known_hosts > /etc/ssh/ssh_known_hosts.new
echo '@cert-authority *' $LINE >> /etc/ssh/ssh_known_hosts.new
mv /etc/ssh/ssh_known_hosts.new /etc/ssh/ssh_known_hosts
done
for pubkey in ssh/*.*pubkey; do
LINE=$(cat $pubkey)
cp -af /root/.ssh/authorized_keys /root/.ssh/authorized_keys.new
grep -v "$LINE" /root/.ssh/authorized_keys > /root/.ssh/authorized_keys.new
echo "$LINE" >> /root/.ssh/authorized_keys.new
mv /root/.ssh/authorized_keys.new /root/.ssh/authorized_keys
done
confluentpython $confapiclient /confluent-api/self/nodelist | sed -e 's/^- //' > /etc/ssh/shosts.equiv
cat /etc/ssh/shosts.equiv > /root/.shosts
cd -
rm -rf $TMPDIR
@@ -0,0 +1,91 @@
Name: confluent_osdeploy-aarch64
Version: #VERSION#
Release: 1
Summary: OS Deployment support for confluent
License: Apache2
URL: https://hpc.lenovo.com/
Source0: confluent_osdeploy.tar.xz
Source1: confluent_el9bin.tar.xz
Source2: confluent_el8bin.tar.xz
BuildArch: noarch
Requires: confluent_ipxe mtools tar
BuildRoot: /tmp
%description
This contains support utilities for enabling deployment of aarch64 architecture systems
%define debug_package %{nil}
%prep
%setup -n confluent_osdeploy -a 2 -a 1
%build
mkdir -p opt/confluent/bin
mkdir -p stateless-bin
cp -a el8bin/* .
ln -s el8 el9
for os in rhvh4 el7 genesis el8 suse15 ubuntu20.04 ubuntu22.04 coreos el9; do
mkdir ${os}out
cd ${os}out
if [ -d ../${os}bin ]; then
cp -a ../${os}bin/opt .
else
cp -a ../opt .
fi
cp -a ../${os}/initramfs/* .
cp -a ../common/initramfs/* .
find . | cpio -H newc -o > ../addons.cpio
mv ../addons.cpio .
cd ..
done
for os in el7 el8 suse15 el9 ubuntu20.04; do
mkdir ${os}disklessout
cd ${os}disklessout
if [ -d ../${os}bin ]; then
cp -a ../${os}bin/opt .
else
cp -a ../opt .
fi
cp -a ../${os}-diskless/initramfs/* .
cp -a ../common/initramfs/* .
if [ -d ../${os}bin ]; then
cp -a ../${os}bin/stateless-bin/* opt/confluent/bin
else
cp -a ../stateless-bin/* opt/confluent/bin
fi
find . | cpio -H newc -o > ../addons.cpio
mv ../addons.cpio .
cd ..
done
mkdir esxi7out
cd esxi7out
cp -a ../opt .
cp -a ../esxi7/initramfs/* .
cp -a ../common/initramfs/* .
chmod +x bin/* opt/confluent/bin/*
tar zcvf ../addons.tgz *
mv ../addons.tgz .
cd ..
cp -a esxi7out esxi6out
cp -a esxi7 esxi6
cp -a esxi7out esxi8out
cp -a esxi7 esxi8
%install
mkdir -p %{buildroot}/opt/confluent/share/licenses/confluent_osdeploy/
#cp LICENSE %{buildroot}/opt/confluent/share/licenses/confluent_osdeploy/
for os in rhvh4 el7 el8 el9 genesis suse15 ubuntu20.04 ubuntu22.04 esxi6 esxi7 esxi8 coreos; do
mkdir -p %{buildroot}/opt/confluent/lib/osdeploy/$os/initramfs/aarch64/
cp ${os}out/addons.* %{buildroot}/opt/confluent/lib/osdeploy/$os/initramfs/aarch64/
if [ -d ${os}disklessout ]; then
mkdir -p %{buildroot}/opt/confluent/lib/osdeploy/${os}-diskless/initramfs/aarch64/
cp ${os}disklessout/addons.* %{buildroot}/opt/confluent/lib/osdeploy/${os}-diskless/initramfs/aarch64/
fi
done
find %{buildroot}/opt/confluent/lib/osdeploy/ -name .gitignore -exec rm -f {} +
%files
/opt/confluent/lib/osdeploy
#%license /opt/confluent/share/licenses/confluent_osdeploy/LICENSE
+14 -15
View File
@@ -7,6 +7,7 @@ License: Apache2
URL: https://hpc.lenovo.com/
Source0: confluent_osdeploy.tar.xz
Source1: confluent_el9bin.tar.xz
Source2: confluent_el8bin.tar.xz
BuildArch: noarch
Requires: confluent_ipxe mtools tar
BuildRoot: /tmp
@@ -18,24 +19,22 @@ This contains support utilities for enabling deployment of x86_64 architecture s
%define debug_package %{nil}
%prep
%setup -n confluent_osdeploy -a 1
%setup -n confluent_osdeploy -a 2 -a 1
%build
mkdir -p opt/confluent/bin
mkdir -p stateless-bin
cd utils
make all
cp confluent_imginfo copernicus clortho autocons ../opt/confluent/bin
cp start_root urlmount ../stateless-bin/
cd ..
#cd utils
#make all
#cp confluent_imginfo copernicus clortho autocons ../opt/confluent/bin
#cp start_root urlmount ../stateless-bin/
#cd ..
ln -s el8 el9
for os in rhvh4 el7 genesis el8 suse15 ubuntu20.04 ubuntu22.04 coreos el9; do
for os in rhvh4 el7 genesis el8 suse15 ubuntu18.04 ubuntu20.04 ubuntu22.04 coreos el9; do
mkdir ${os}out
cd ${os}out
if [ -d ../${os}bin ]; then
cp -a ../${os}bin/opt .
else
cp -a ../opt .
cp -a ../el8bin/opt .
fi
cp -a ../${os}/initramfs/* .
cp -a ../common/initramfs/* .
@@ -43,20 +42,20 @@ for os in rhvh4 el7 genesis el8 suse15 ubuntu20.04 ubuntu22.04 coreos el9; do
mv ../addons.cpio .
cd ..
done
for os in el7 el8 suse15 el9 ubuntu20.04; do
for os in el7 el8 suse15 el9 ubuntu20.04 ubuntu22.04; do
mkdir ${os}disklessout
cd ${os}disklessout
if [ -d ../${os}bin ]; then
cp -a ../${os}bin/opt .
else
cp -a ../opt .
cp -a ../el8bin/opt .
fi
cp -a ../${os}-diskless/initramfs/* .
cp -a ../common/initramfs/* .
if [ -d ../${os}bin ]; then
cp -a ../${os}bin/stateless-bin/* opt/confluent/bin
else
cp -a ../stateless-bin/* opt/confluent/bin
cp -a ../el8bin/stateless-bin/* opt/confluent/bin
fi
find . | cpio -H newc -o > ../addons.cpio
mv ../addons.cpio .
@@ -64,7 +63,7 @@ for os in el7 el8 suse15 el9 ubuntu20.04; do
done
mkdir esxi7out
cd esxi7out
cp -a ../opt .
cp -a ../el8bin/opt .
cp -a ../esxi7/initramfs/* .
cp -a ../common/initramfs/* .
chmod +x bin/* opt/confluent/bin/*
@@ -79,7 +78,7 @@ cp -a esxi7 esxi8
%install
mkdir -p %{buildroot}/opt/confluent/share/licenses/confluent_osdeploy/
cp LICENSE %{buildroot}/opt/confluent/share/licenses/confluent_osdeploy/
for os in rhvh4 el7 el8 el9 genesis suse15 ubuntu20.04 ubuntu22.04 esxi6 esxi7 esxi8 coreos; do
for os in rhvh4 el7 el8 el9 genesis suse15 ubuntu20.04 ubuntu18.04 ubuntu22.04 esxi6 esxi7 esxi8 coreos; do
mkdir -p %{buildroot}/opt/confluent/lib/osdeploy/$os/initramfs
mkdir -p %{buildroot}/opt/confluent/lib/osdeploy/$os/profiles
cp ${os}out/addons.* %{buildroot}/opt/confluent/lib/osdeploy/$os/initramfs
@@ -69,7 +69,7 @@ if [ "$v4cfgmeth" = "static" ]; then
for namesrv in "$namesrvs"; do
setdebopt netcfg/get_nameservers $namesrv string
done
elif [ "$vpcfgmeth" = "dhcp" ]; then
elif [ "$v4cfgmeth" = "dhcp" ]; then
setdebopt netcfg/disable_dhcp false boolean
setdebopt netcfg/confirm_static false boolean
fi
@@ -5,6 +5,8 @@
# noted below so custom commands are executed before
# the script notifies confluent that install is fully complete.
HOME=$(getent passwd $(whoami)|cut -d: -f 6)
export HOME
nodename=$(grep ^NODENAME /etc/confluent/confluent.info|awk '{print $2}')
confluent_apikey=$(cat /etc/confluent/confluent.apikey)
confluent_mgr=$(grep ^deploy_server: /etc/confluent/confluent.deploycfg|awk '{print $2}')
@@ -1,10 +1,10 @@
#!/bin/bash
function test_mgr() {
whost=$1
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
if curl -s https://${whost}/confluent-api/ > /dev/null; then
if curl -gs https://${whost}/confluent-api/ > /dev/null; then
return 0
fi
return 1
@@ -63,10 +63,10 @@ fetch_remote() {
set_confluent_vars
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -f -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo $1 failed to download; return 1; fi
}
@@ -174,10 +174,10 @@ run_remote_python() {
cd $confluentscripttmpdir
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -f -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo "'$*'" failed to download; return 1; fi
confluentpython $*
retcode=$?
@@ -11,6 +11,13 @@ import struct
import sys
import subprocess
def get_partname(devname, idx):
if devname[-1] in '0123456789':
return '{}p{}'.format(devname, idx)
else:
return '{}{}'.format(devname, idx)
def get_next_part_meta(img, imgsize):
if img.tell() == imgsize:
return None
@@ -53,10 +60,13 @@ class PartedRunner():
def __init__(self, disk):
self.disk = disk
def run(self, command):
def run(self, command, check=True):
command = command.split()
command = ['parted', '-a', 'optimal', '-s', self.disk] + command
return subprocess.check_output(command).decode('utf8')
if check:
return subprocess.check_output(command).decode('utf8')
else:
return subprocess.run(command, stdout=subprocess.PIPE).stdout.decode('utf8')
def fixup(rootdir, vols):
devbymount = {}
@@ -166,6 +176,8 @@ def fixup(rootdir, vols):
partnum = re.search('(\d+)$', targdev).group(1)
targblock = re.search('(.*)\d+$', targdev).group(1)
if targblock:
if targblock.endswith('p') and 'nvme' in targblock:
targblock = targblock[:-1]
shimpath = subprocess.check_output(['find', os.path.join(rootdir, 'boot/efi'), '-name', 'shimx64.efi']).decode('utf8').strip()
shimpath = shimpath.replace(rootdir, '/').replace('/boot/efi', '').replace('//', '/').replace('/', '\\')
subprocess.check_call(['efibootmgr', '-c', '-d', targblock, '-l', shimpath, '--part', partnum])
@@ -224,7 +236,8 @@ def install_to_disk(imgpath):
instdisk = diskin.read()
instdisk = '/dev/' + instdisk
parted = PartedRunner(instdisk)
dinfo = parted.run('unit s print')
# do this safer, unit s print might bomb
dinfo = parted.run('unit s print', check=False)
dinfo = dinfo.split('\n')
sectors = 0
sectorsize = 0
@@ -258,7 +271,7 @@ def install_to_disk(imgpath):
if end > sectors:
end = sectors
parted.run('mkpart primary {}s {}s'.format(curroffset, end))
vol['targetdisk'] = instdisk + '{0}'.format(volidx)
vol['targetdisk'] = get_partname(instdisk , volidx)
curroffset += size + 1
if not lvmvols:
if swapsize:
@@ -268,10 +281,10 @@ def install_to_disk(imgpath):
if end > sectors:
end = sectors
parted.run('mkpart swap {}s {}s'.format(curroffset, end))
subprocess.check_call(['mkswap', instdisk + '{}'.format(volidx + 1)])
subprocess.check_call(['mkswap', get_partname(instdisk, volidx + 1)])
else:
parted.run('mkpart lvm {}s 100%'.format(curroffset))
lvmpart = instdisk + '{}'.format(volidx + 1)
lvmpart = get_partname(instdisk, volidx + 1)
subprocess.check_call(['pvcreate', '-ff', '-y', lvmpart])
subprocess.check_call(['vgcreate', 'localstorage', lvmpart])
vginfo = subprocess.check_output(['vgdisplay', 'localstorage', '--units', 'b']).decode('utf8')
@@ -125,4 +125,6 @@ if grep installtodisk /proc/cmdline > /dev/null; then
fi
mv /lib/modules/$(uname -r) /lib/modules/$(uname -r)-ramfs
ln -s /sysroot/lib/modules/$(uname -r) /lib/modules/
mv /lib/firmware /lib/firmware-ramfs
ln -s /sysroot/lib/firmware /lib/firmware
exec /opt/confluent/bin/start_root
@@ -7,41 +7,127 @@ if [ -f /tmp/dd_disk ]; then
fi
done
fi
mkdir -p /etc/confluent
cat /tls/*.pem > /etc/confluent/ca.pem
TRIES=0
echo -n > /etc/confluent/confluent.info
cd /sys/class/net
while ! awk -F'|' '{print $3}' /etc/confluent/confluent.info |grep 1 >& /dev/null && [ "$TRIES" -lt 60 ]; do
TRIES=$((TRIES + 1))
for currif in *; do
ip link set $currif up
done
/opt/confluent/bin/copernicus -t > /etc/confluent/confluent.info
done
cd /
grep ^EXTMGRINFO: /etc/confluent/confluent.info || return 0 # Do absolutely nothing if no data at all yet
echo -n "" > /tmp/confluent.initq
# restart cmdline
echo -n "" > /etc/cmdline.d/01-confluent.conf
nodename=$(grep ^NODENAME /etc/confluent/confluent.info|awk '{print $2}')
#TODO: blkid --label <whatever> to find mounted api
shutdownnic=""
oum=$(umask)
python /opt/confluent/bin/apiclient /confluent-api/self/deploycfg > /etc/confluent/confluent.deploycfg
ifidx=$(cat /tmp/confluent.ifidx)
ifname=$(ip link |grep ^$ifidx:|awk '{print $2}')
ifname=${ifname%:}
echo $ifname > /tmp/net.ifaces
umask 0077
mkdir -p /etc/confluent
echo -n > /etc/confluent/confluent.info
cat /tls/*.pem > /etc/confluent/ca.pem
TRIES=5
while [ ! -e /dev/disk ] && [ $TRIES -gt 0 ]; do
sleep 2
TRIES=$((TRIES - 1))
done
if [ -e /dev/disk/by-label/CNFLNT_IDNT ]; then
tmnt=/tmp/idntmnt
mkdir -p $tmnt
tcfg=/tmp/idnttmp
mount /dev/disk/by-label/CNFLNT_IDNT $tmnt
cd $tmnt
deploysrvs=$(sed -n '/^deploy_servers:/, /^[^-]/p' cnflnt.yml |grep ^-|sed -e 's/^- //'|grep -v :)
nodename=$(grep ^nodename: cnflnt.yml|awk '{print $2}')
ln -s /opt/confluent/bin/clortho /opt/confluent/bin/genpasshmac
hmackeyfile=/tmp/hmackeyfile
passfile=/etc/confluent/confluent.apikey
passcrypt=/tmp/passcrypt
hmacfile=/tmp/hmacfile
echo -n $(grep ^apitoken: cnflnt.yml|awk '{print $2}') > $hmackeyfile;
/opt/confluent/bin/genpasshmac $passfile $passcrypt $hmacfile $hmackeyfile
echo "NODENAME: "$nodename > /etc/confluent/confluent.info
for dsrv in $deploysrvs; do
echo 'MANAGER: '$dsrv >> /etc/confluent/confluent.info
done
sed -n '/^net_cfgs:/, /^[^- ]/{/^[^- ]/!p}' cnflnt.yml |sed -n '/^-/, /^-/{/^-/!p}'| sed -e 's/^[- ]*//'> $tcfg
autoconfigmethod=$(grep ^ipv4_method: $tcfg)
autoconfigmethod=${autoconfigmethod#ipv4_method: }
for i in /sys/class/net/*; do
ip link set $(basename $i) down
udevadm info $i | grep ID_NET_DRIVER=cdc_ether > /dev/null && continue
ip link set $(basename $i) up
done
sleep 10
usedhcp=0
for NICGUESS in $(ip link|grep LOWER_UP|grep -v LOOPBACK| awk '{print $2}' | sed -e 's/:$//'); do
if [ "$autoconfigmethod" = "dhcp" ]; then
usedhcp=1
else
v4addr=$(grep ^ipv4_address: $tcfg)
v4addr=${v4addr#ipv4_address: }
v4plen=${v4addr#*/}
v4addr=${v4addr%/*}
v4gw=$(grep ^ipv4_gateway: $tcfg)
v4gw=${v4gw#ipv4_gateway: }
ip addr add dev $NICGUESS $v4addr/$v4plen
if [ "$v4gw" = "null" ]; then
v4gw=""
fi
if [ ! -z "$v4gw" ]; then
ip route add default via $v4gw
fi
v4nm=$(grep ipv4_netmask: $tcfg)
v4nm=${v4nm#ipv4_netmask: }
TESTSRV=$(python /opt/confluent/bin/apiclient -c 2> /dev/null)
if [ ! -z "$TESTSRV" ]; then
python /opt/confluent/bin/apiclient -p $hmacfile /confluent-api/self/registerapikey $passcrypt
mgr=$TESTSRV
ifname=$NICGUESS
shutdownnic=$ifname
break
fi
if [ ! -z "$v4gw" ]; then
ip route del default via $v4gw
fi
ip -4 addr flush dev $NICGUESS
fi
done
fi
TRIES=0
if [ "$usedhcp" = 1 ]; then
echo ip=$ifname:dhcp >> /etc/cmdline.d/01-confluent.conf
elif [ -z "$ifname" ]; then
cd /sys/class/net
while ! awk -F'|' '{print $3}' /etc/confluent/confluent.info |grep 1 >& /dev/null && [ "$TRIES" -lt 60 ]; do
TRIES=$((TRIES + 1))
for currif in *; do
ip link set $currif up
done
/opt/confluent/bin/copernicus -t > /etc/confluent/confluent.info
done
cd /
grep ^EXTMGRINFO: /etc/confluent/confluent.info || return 0 # Do absolutely nothing if no data at all yet
echo -n "" > /etc/cmdline.d/01-confluent.conf
else
echo ip=$v4addr::$v4gw:$v4nm:$hostname:$ifname:none > /etc/cmdline.d/01-confluent.conf
fi
python /opt/confluent/bin/apiclient /confluent-api/self/deploycfg > /etc/confluent/confluent.deploycfg
if [ ! -z "$shutdownnic" ]; then
if [ ! -z "$v4gw" ]; then
ip route del default via $v4gw
fi
ip -4 addr flush dev $shutdownnic
fi
# restart cmdline
nodename=$(grep ^NODENAME /etc/confluent/confluent.info|awk '{print $2}')
echo -n "" > /tmp/confluent.initq
if [ -z "$ifname" ]; then
ifidx=$(cat /tmp/confluent.ifidx)
ifname=$(ip link |grep ^$ifidx:|awk '{print $2}')
ifname=${ifname%:}
fi
if [ ! -z "$ifname" ]; then
echo $ifname > /tmp/net.ifaces
fi
dnsdomain=$(grep ^dnsdomain: /etc/confluent/confluent.deploycfg)
dnsdomain=${dnsdomain#dnsdomain: }
hostname=$nodename
if [ ! -z "$dnsdomain" ] && [ "$dnsdomain" != "null" ]; then
hostname=$hostname.$dnsdomain
fi
mgr=$(grep ^deploy_server: /etc/confluent/confluent.deploycfg)
mgr=${mgr#deploy_server: }
if [ -z "$mgr" ]; then
mgr=$(grep ^deploy_server: /etc/confluent/confluent.deploycfg)
mgr=${mgr#deploy_server: }
fi
profilename=$(grep ^profile: /etc/confluent/confluent.deploycfg)
profilename=${profilename#profile: }
proto=$(grep ^protocol: /etc/confluent/confluent.deploycfg)
@@ -65,21 +151,23 @@ kickstart=$proto://$mgr/confluent-public/os/$profilename/kickstart
root=anaconda-net:$proto://$mgr/confluent-public/os/$profilename/distribution
export kickstart
export root
autoconfigmethod=$(grep ipv4_method /etc/confluent/confluent.deploycfg)
autoconfigmethod=${autoconfigmethod#ipv4_method: }
if [ "$autoconfigmethod" = "dhcp" ]; then
echo ip=$ifname:dhcp >> /etc/cmdline.d/01-confluent.conf
else
v4addr=$(grep ^ipv4_address: /etc/confluent/confluent.deploycfg)
v4addr=${v4addr#ipv4_address: }
v4gw=$(grep ^ipv4_gateway: /etc/confluent/confluent.deploycfg)
v4gw=${v4gw#ipv4_gateway: }
if [ "$v4gw" = "null" ]; then
v4gw=""
if [ -z "$autoconfigmethod" ]; then
autoconfigmethod=$(grep ipv4_method /etc/confluent/confluent.deploycfg)
autoconfigmethod=${autoconfigmethod#ipv4_method: }
if [ "$autoconfigmethod" = "dhcp" ]; then
echo ip=$ifname:dhcp >> /etc/cmdline.d/01-confluent.conf
else
v4addr=$(grep ^ipv4_address: /etc/confluent/confluent.deploycfg)
v4addr=${v4addr#ipv4_address: }
v4gw=$(grep ^ipv4_gateway: /etc/confluent/confluent.deploycfg)
v4gw=${v4gw#ipv4_gateway: }
if [ "$v4gw" = "null" ]; then
v4gw=""
fi
v4nm=$(grep ipv4_netmask: /etc/confluent/confluent.deploycfg)
v4nm=${v4nm#ipv4_netmask: }
echo ip=$v4addr::$v4gw:$v4nm:$hostname:$ifname:none >> /etc/cmdline.d/01-confluent.conf
fi
v4nm=$(grep ipv4_netmask: /etc/confluent/confluent.deploycfg)
v4nm=${v4nm#ipv4_netmask: }
echo ip=$v4addr::$v4gw:$v4nm:$hostname:$ifname:none >> /etc/cmdline.d/01-confluent.conf
fi
nameserversec=0
while read -r entry; do
@@ -1,6 +1,10 @@
Ansible playbooks ending in .yml or .yaml that are placed into this directory will be executed at the
appropriate phase of the install process.
Alternatively, plays may be placed in /var/lib/confluent/private/os/<profilename>/ansible/<directory>.
This prevents public clients from being able to read the plays, which is not necessary for them to function,
and may protect them from divulging material contained in the plays or associated roles.
The 'hosts' may be omitted, and if included will be ignored, replaced with the host that is specifically
requesting the playbooks be executed.
@@ -1,6 +1,10 @@
Ansible playbooks ending in .yml or .yaml that are placed into this directory will be executed at the
appropriate phase of the install process.
Alternatively, plays may be placed in /var/lib/confluent/private/os/<profilename>/ansible/<directory>.
This prevents public clients from being able to read the plays, which is not necessary for them to function,
and may protect them from divulging material contained in the plays or associated roles.
The 'hosts' may be omitted, and if included will be ignored, replaced with the host that is specifically
requesting the playbooks be executed.
@@ -1,4 +1,6 @@
#!/bin/sh
HOME=$(getent passwd $(whoami)|cut -d: -f 6)
export HOME
# This script is executed on the first boot after install has
# completed. It is best to edit the middle of the file as
@@ -1,10 +1,10 @@
#!/bin/bash
function test_mgr() {
whost=$1
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
if curl -s https://${whost}/confluent-api/ > /dev/null; then
if curl -gs https://${whost}/confluent-api/ > /dev/null; then
return 0
fi
return 1
@@ -63,10 +63,10 @@ fetch_remote() {
set_confluent_vars
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -f -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo $1 failed to download; return 1; fi
}
@@ -174,10 +174,10 @@ run_remote_python() {
cd $confluentscripttmpdir
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -f -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo "'$*'" failed to download; return 1; fi
confluentpython $*
retcode=$?
@@ -189,8 +189,15 @@ cat > /run/NetworkManager/system-connections/$ifname.nmconnection << EOC
EOC
echo id=${ifname} >> /run/NetworkManager/system-connections/$ifname.nmconnection
echo uuid=$(uuidgen) >> /run/NetworkManager/system-connections/$ifname.nmconnection
linktype=$(ip link |grep -A2 ${ifname}|tail -n 1|awk '{print $1}')
if [ "$linktype" = link/infiniband ]; then
linktype="infiniband"
else
linktype="ethernet"
fi
echo type=$linktype >> /run/NetworkManager/system-connections/$ifname.nmconnection
cat >> /run/NetworkManager/system-connections/$ifname.nmconnection << EOC
type=ethernet
autoconnect-retries=1
EOC
echo interface-name=$ifname >> /run/NetworkManager/system-connections/$ifname.nmconnection
@@ -199,9 +206,6 @@ multi-connect=1
permissions=
wait-device-timeout=60000
[ethernet]
mac-address-blacklist=
EOC
autoconfigmethod=$(grep ^ipv4_method: /etc/confluent/confluent.deploycfg |awk '{print $2}')
auto6configmethod=$(grep ^ipv6_method: /etc/confluent/confluent.deploycfg |awk '{print $2}')
@@ -5,6 +5,8 @@
# noted below so custom commands are executed before
# the script notifies confluent that install is fully complete.
HOME=$(getent passwd $(whoami)|cut -d: -f 6)
export HOME
nodename=$(grep ^NODENAME /etc/confluent/confluent.info|awk '{print $2}')
confluent_apikey=$(cat /etc/confluent/confluent.apikey)
confluent_mgr=$(grep ^deploy_server: /etc/confluent/confluent.deploycfg|awk '{print $2}')
@@ -1,10 +1,10 @@
#!/bin/bash
function test_mgr() {
whost=$1
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
if curl -s https://${whost}/confluent-api/ > /dev/null; then
if curl -gs https://${whost}/confluent-api/ > /dev/null; then
return 0
fi
return 1
@@ -63,10 +63,10 @@ fetch_remote() {
set_confluent_vars
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -f -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo $1 failed to download; return 1; fi
}
@@ -174,10 +174,10 @@ run_remote_python() {
cd $confluentscripttmpdir
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -f -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo "'$*'" failed to download; return 1; fi
confluentpython $*
retcode=$?
@@ -11,6 +11,14 @@ import struct
import sys
import subprocess
bootuuid = None
def get_partname(devname, idx):
if devname[-1] in '0123456789':
return '{}p{}'.format(devname, idx)
else:
return '{}{}'.format(devname, idx)
def get_next_part_meta(img, imgsize):
if img.tell() == imgsize:
return None
@@ -53,10 +61,13 @@ class PartedRunner():
def __init__(self, disk):
self.disk = disk
def run(self, command):
def run(self, command, check=True):
command = command.split()
command = ['parted', '-a', 'optimal', '-s', self.disk] + command
return subprocess.check_output(command).decode('utf8')
if check:
return subprocess.check_output(command).decode('utf8')
else:
return subprocess.run(command, stdout=subprocess.PIPE).stdout.decode('utf8')
def fixup(rootdir, vols):
devbymount = {}
@@ -125,9 +136,14 @@ def fixup(rootdir, vols):
sys.stdout.flush()
for metafs in ('proc', 'sys', 'dev'):
subprocess.check_call(['mount', '-o', 'bind', '/{}'.format(metafs), os.path.join(rootdir, metafs)])
with open(os.path.join(rootdir, 'etc/sysconfig/grub')) as defgrubin:
if os.path.exists(os.path.join(rootdir, 'etc/lvm/devices/system.devices')):
os.remove(os.path.join(rootdir, 'etc/lvm/devices/system.devices'))
grubsyscfg = os.path.join(rootdir, 'etc/sysconfig/grub')
if not os.path.exists(grubsyscfg):
grubsyscfg = os.path.join(rootdir, 'etc/default/grub')
with open(grubsyscfg) as defgrubin:
defgrub = defgrubin.read().split('\n')
with open(os.path.join(rootdir, 'etc/sysconfig/grub'), 'w') as defgrubout:
with open(grubsyscfg, 'w') as defgrubout:
for gline in defgrub:
gline = gline.split()
newline = []
@@ -136,8 +152,34 @@ def fixup(rootdir, vols):
continue
newline.append(ent)
defgrubout.write(' '.join(newline) + '\n')
grubcfg = subprocess.check_output(['find', os.path.join(rootdir, 'boot'), '-name', 'grub.cfg']).decode('utf8').strip().replace(rootdir, '/')
subprocess.check_call(['chroot', rootdir, 'grub2-mkconfig', '-o', grubcfg])
grubcfg = subprocess.check_output(['find', os.path.join(rootdir, 'boot'), '-name', 'grub.cfg']).decode('utf8').strip().replace(rootdir, '/').replace('//', '/')
grubcfg = grubcfg.split('\n')
if not grubcfg[-1]:
grubcfg = grubcfg[:-1]
if len(grubcfg) == 1:
grubcfg = grubcfg[0]
else:
for gcfg in grubcfg:
rgcfg = os.path.join(rootdir, gcfg[1:]) # gcfg has a leading / to get rid of
if os.stat(rgcfg).st_size > 256:
grubcfg = gcfg
else:
with open(rgcfg, 'r') as gin:
tgrubcfg = gin.read()
tgrubcfg = tgrubcfg.split('\n')
if 'search --no-floppy --fs-uuid --set=dev' in tgrubcfg[0]:
tgrubcfg[0] = 'search --no-floppy --fs-uuid --set=dev ' + bootuuid
with open(rgcfg, 'w') as gout:
for gcline in tgrubcfg:
gout.write(gcline)
gout.write('\n')
try:
subprocess.check_call(['chroot', rootdir, 'grub2-mkconfig', '-o', grubcfg])
except Exception as e:
print(repr(e))
print(rootdir)
print(grubcfg)
time.sleep(86400)
newroot = None
with open('/etc/shadow') as shadowin:
shents = shadowin.read().split('\n')
@@ -166,6 +208,8 @@ def fixup(rootdir, vols):
partnum = re.search('(\d+)$', targdev).group(1)
targblock = re.search('(.*)\d+$', targdev).group(1)
if targblock:
if 'nvme' in targblock and targblock[-1] == 'p':
targblock = targblock[:-1]
shimpath = subprocess.check_output(['find', os.path.join(rootdir, 'boot/efi'), '-name', 'shimx64.efi']).decode('utf8').strip()
shimpath = shimpath.replace(rootdir, '/').replace('/boot/efi', '').replace('//', '/').replace('/', '\\')
subprocess.check_call(['efibootmgr', '-c', '-d', targblock, '-l', shimpath, '--part', partnum])
@@ -184,6 +228,7 @@ def had_swap():
return False
def install_to_disk(imgpath):
global bootuuid
lvmvols = {}
deftotsize = 0
mintotsize = 0
@@ -224,7 +269,7 @@ def install_to_disk(imgpath):
instdisk = diskin.read()
instdisk = '/dev/' + instdisk
parted = PartedRunner(instdisk)
dinfo = parted.run('unit s print')
dinfo = parted.run('unit s print', check=False)
dinfo = dinfo.split('\n')
sectors = 0
sectorsize = 0
@@ -258,7 +303,7 @@ def install_to_disk(imgpath):
if end > sectors:
end = sectors
parted.run('mkpart primary {}s {}s'.format(curroffset, end))
vol['targetdisk'] = instdisk + '{0}'.format(volidx)
vol['targetdisk'] = get_partname(instdisk, volidx)
curroffset += size + 1
if not lvmvols:
if swapsize:
@@ -268,10 +313,10 @@ def install_to_disk(imgpath):
if end > sectors:
end = sectors
parted.run('mkpart swap {}s {}s'.format(curroffset, end))
subprocess.check_call(['mkswap', instdisk + '{}'.format(volidx + 1)])
subprocess.check_call(['mkswap', get_partname(instdisk, volidx + 1)])
else:
parted.run('mkpart lvm {}s 100%'.format(curroffset))
lvmpart = instdisk + '{}'.format(volidx + 1)
lvmpart = get_partname(instdisk, volidx + 1)
subprocess.check_call(['pvcreate', '-ff', '-y', lvmpart])
subprocess.check_call(['vgcreate', 'localstorage', lvmpart])
vginfo = subprocess.check_output(['vgdisplay', 'localstorage', '--units', 'b']).decode('utf8')
@@ -366,6 +411,14 @@ def install_to_disk(imgpath):
sys.stdout.write('\x1b[1K\rDone writing {0}'.format(vol['mount']))
sys.stdout.write('\n')
sys.stdout.flush()
if vol['mount'] == '/boot':
tbootuuid = subprocess.check_output(['blkid', vol['targetdisk']])
if b'UUID="' in tbootuuid:
bootuuid = tbootuuid.split(b'UUID="', 1)[1].split(b'"')[0].decode('utf8')
subprocess.check_call(['umount', '/run/imginst/targ'])
for vol in allvols:
subprocess.check_call(['mount', vol['targetdisk'], '/run/imginst/targ/' + vol['mount']])
@@ -373,4 +426,4 @@ def install_to_disk(imgpath):
if __name__ == '__main__':
install_to_disk(os.environ['mountsrc'])
install_to_disk(os.environ['mountsrc'])
@@ -127,5 +127,7 @@ if grep installtodisk /proc/cmdline > /dev/null; then
fi
mv /lib/modules/$(uname -r) /lib/modules/$(uname -r)-ramfs
ln -s /sysroot/lib/modules/$(uname -r) /lib/modules/
mv /lib/firmware /lib/firmware-ramfs
ln -s /sysroot/lib/firmware /lib/firmware
kill $(grep -l ^/usr/lib/systemd/systemd-udevd /proc/*/cmdline|cut -d/ -f 3)
exec /opt/confluent/bin/start_root
@@ -31,6 +31,9 @@ if [ ! -f /sysroot/tmp/installdisk ]; then
fi
lvm vgchange -a n
udevadm control -e
if [ -f /sysroot/etc/lvm/devices/system.devices ]; then
rm /sysroot/etc/lvm/devices/system.devices
fi
chroot /sysroot /usr/lib/systemd/systemd-udevd --daemon
chroot /sysroot bash -c "source /etc/confluent/functions; run_remote_python image2disk.py"
echo "Port 22" >> /etc/ssh/sshd_config
@@ -1,6 +1,7 @@
#!/bin/sh
[ -e /tmp/confluent.initq ] && return 0
. /lib/dracut-lib.sh
setsid sh -c 'exec bash <> /dev/tty2 >&0 2>&1' &
udevadm trigger
udevadm trigger --type=devices --action=add
udevadm settle
@@ -40,7 +41,7 @@ mkdir -p /etc/confluent
echo -n > /etc/confluent/confluent.info
umask $oum
TRIES=5
while [ ! -e /dev/disk ] && [ $TRIES -gt 0 ]; do
while [ ! -e /dev/disk/by-label ] && [ $TRIES -gt 0 ]; do
sleep 2
TRIES=$((TRIES - 1))
done
@@ -55,21 +56,49 @@ if [ -e /dev/disk/by-label/CNFLNT_IDNT ]; then
sed -n '/^net_cfgs:/, /^[^- ]/{/^[^- ]/!p}' cnflnt.yml |sed -n '/^-/, /^-/{/^-/!p}'| sed -e 's/^[- ]*//'> $tcfg
autoconfigmethod=$(grep ^ipv4_method: $tcfg)
autoconfigmethod=${autoconfigmethod#ipv4_method: }
if [ "$autoconfigmethod" = "dhcp" ]; then
/usr/libexec/nm-initrd-generator ip=:dhcp
else
v4addr=$(grep ^ipv4_address: $tcfg)
v4addr=${v4addr#ipv4_address: }
v4addr=${v4addr%/*}
v4gw=$(grep ^ipv4_gateway: $tcfg)
v4gw=${v4gw#ipv4_gateway: }
if [ "$v4gw" = "null" ]; then
v4gw=""
for i in /sys/class/net/*; do
ip link set $(basename $i) down
udevadm info $i | grep ID_NET_DRIVER=cdc_ether > /dev/null && continue
ip link set $(basename $i) up
done
for NICGUESS in $(ip link|grep LOWER_UP|grep -v LOOPBACK| awk '{print $2}' | sed -e 's/:$//'); do
if [ "$autoconfigmethod" = "dhcp" ]; then
/usr/libexec/nm-initrd-generator ip=$NICGUESS:dhcp
else
v4addr=$(grep ^ipv4_address: $tcfg)
v4addr=${v4addr#ipv4_address: }
v4plen=${v4addr#*/}
v4addr=${v4addr%/*}
v4gw=$(grep ^ipv4_gateway: $tcfg)
v4gw=${v4gw#ipv4_gateway: }
ip addr add dev $NICGUESS $v4addr/$v4plen
if [ "$v4gw" = "null" ]; then
v4gw=""
fi
if [ ! -z "$v4gw" ]; then
ip route add default via $v4gw
fi
v4nm=$(grep ipv4_netmask: $tcfg)
v4nm=${v4nm#ipv4_netmask: }
DETECTED=0
for dsrv in $deploysrvs; do
if curl --capath /tls/ -s --connect-timeout 3 https://$dsrv/confluent-public/ > /dev/null; then
rm /run/NetworkManager/system-connections/*
/usr/libexec/nm-initrd-generator ip=$v4addr::$v4gw:$v4nm:$hostname:$NICGUESS:none
DETECTED=1
ifname=$NICGUESS
break
fi
done
if [ ! -z "$v4gw" ]; then
ip route del default via $v4gw
fi
ip addr flush dev $NICGUESS
if [ $DETECTED = 1 ]; then
break
fi
fi
v4nm=$(grep ipv4_netmask: $tcfg)
v4nm=${v4nm#ipv4_netmask: }
/usr/libexec/nm-initrd-generator ip=$v4addr::$v4gw:$v4nm:$hostname::none
fi
done
NetworkManager --configure-and-quit=initrd --no-daemon
hmackeyfile=/tmp/cnflnthmackeytmp
echo -n $(grep ^apitoken: cnflnt.yml|awk '{print $2}') > $hmackeyfile
@@ -85,10 +114,10 @@ if [ -e /dev/disk/by-label/CNFLNT_IDNT ]; then
echo 'MANAGER: '$deploysrv >> /etc/confluent/confluent.info
done
for deployer in $deploysrvs; do
if curl -f -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_CRYPTHMAC: $(cat $hmacfile)" -d@$passcrypt -k https://$deployer/confluent-api/self/registerapikey; then
if curl --capath /tls/ -f -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_CRYPTHMAC: $(cat $hmacfile)" -d@$passcrypt -k https://$deployer/confluent-api/self/registerapikey; then
cp $passfile /etc/confluent/confluent.apikey
confluent_apikey=$(cat /etc/confluent/confluent.apikey)
curl -sf -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $confluent_apikey" https://$deployer/confluent-api/self/deploycfg2 > /etc/confluent/confluent.deploycfg
curl --capath /tls/ -sf -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $confluent_apikey" https://$deployer/confluent-api/self/deploycfg2 > /etc/confluent/confluent.deploycfg
confluent_profile=$(grep ^profile: /etc/confluent/confluent.deploycfg)
confluent_profile=${confluent_profile#profile: }
mgr=$deployer
@@ -100,7 +129,9 @@ cd /sys/class/net
if ! grep MANAGER: /etc/confluent/confluent.info; then
confluentsrv=$(getarg confluent)
if [ ! -z "$confluentsrv" ]; then
mgr=$confluentsrv
if [[ "$confluentsrv" = *":"* ]]; then
mgr="[$mgr]"
confluenthttpsrv=[$confluentsrv]
/usr/libexec/nm-initrd-generator ip=:dhcp6
else
@@ -112,7 +143,7 @@ if ! grep MANAGER: /etc/confluent/confluent.info; then
for mac in $(ip -br link|grep -v LOOPBACK|awk '{print $3}'); do
myids=$myids"/mac="$mac
done
myname=$(curl -sH "CONFLUENT_IDS: $myids" https://$confluenthttpsrv/confluent-api/self/whoami)
myname=$(curl --capath /tls/ -sH "CONFLUENT_IDS: $myids" https://$confluenthttpsrv/confluent-api/self/whoami)
if [ ! -z "$myname" ]; then
echo NODENAME: $myname > /etc/confluent/confluent.info
echo MANAGER: $confluentsrv >> /etc/confluent/confluent.info
@@ -146,15 +177,17 @@ fi
while ! confluentpython /opt/confluent/bin/apiclient $errout /confluent-api/self/deploycfg2 > /etc/confluent/confluent.deploycfg; do
sleep 10
done
ifidx=$(cat /tmp/confluent.ifidx)
if [ ! -z "$ifidx" ]; then
ifname=$(ip link |grep ^$ifidx:|awk '{print $2}')
ifname=${ifname%:}
ifname=${ifname%@*}
echo $ifname > /tmp/net.ifaces
else
ip -br a|grep UP|awk '{print $1}' > /tmp/net.ifaces
ifname=$(cat /tmp/net.ifaces)
ifidx=$(cat /tmp/confluent.ifidx 2> /dev/null)
if [ -z "$ifname" ]; then
if [ ! -z "$ifidx" ]; then
ifname=$(ip link |grep ^$ifidx:|awk '{print $2}')
ifname=${ifname%:}
ifname=${ifname%@*}
echo $ifname > /tmp/net.ifaces
else
ip -br a|grep UP|awk '{print $1}' > /tmp/net.ifaces
ifname=$(cat /tmp/net.ifaces)
fi
fi
dnsdomain=$(grep ^dnsdomain: /etc/confluent/confluent.deploycfg)
@@ -1,6 +1,10 @@
Ansible playbooks ending in .yml or .yaml that are placed into this directory will be executed at the
appropriate phase of the install process.
Alternatively, plays may be placed in /var/lib/confluent/private/os/<profilename>/ansible/<directory>.
This prevents public clients from being able to read the plays, which is not necessary for them to function,
and may protect them from divulging material contained in the plays or associated roles.
The 'hosts' may be omitted, and if included will be ignored, replaced with the host that is specifically
requesting the playbooks be executed.
@@ -1,6 +1,10 @@
Ansible playbooks ending in .yml or .yaml that are placed into this directory will be executed at the
appropriate phase of the install process.
Alternatively, plays may be placed in /var/lib/confluent/private/os/<profilename>/ansible/<directory>.
This prevents public clients from being able to read the plays, which is not necessary for them to function,
and may protect them from divulging material contained in the plays or associated roles.
The 'hosts' may be omitted, and if included will be ignored, replaced with the host that is specifically
requesting the playbooks be executed.
@@ -2,6 +2,10 @@
sed -i 's/centos/CentOS/; s/rhel/Red Hat Enterprise Linux/; s/oraclelinux/Oracle Linux/; s/alma/AlmaLinux/' $2/profile.yaml
ln -s $1/images/pxeboot/vmlinuz $2/boot/kernel && \
ln -s $1/images/pxeboot/initrd.img $2/boot/initramfs/distribution
mkdir -p $2/boot/efi/boot && \
ln -s $1/EFI/BOOT/BOOTX64.EFI $1/EFI/BOOT/grubx64.efi $2/boot/efi/boot/
mkdir -p $2/boot/efi/boot
if [ -e $1/EFI/BOOT/BOOTAA64.EFI ]; then
ln -s $1/EFI/BOOT/BOOTAA64.EFI $1/EFI/BOOT/grubaa64.efi $2/boot/efi/boot/
else
ln -s $1/EFI/BOOT/BOOTX64.EFI $1/EFI/BOOT/grubx64.efi $2/boot/efi/boot/
fi
@@ -33,15 +33,7 @@
reboot
%packages
@^minimal-environment
#-kernel-uek # This can opt out of the UEK for the relevant distribution
bind-utils
chrony
pciutils
python3
rsync
tar
-iwl*-firmware
%include /tmp/pkglist
%include /tmp/addonpackages
%include /tmp/cryptpkglist
%end
@@ -0,0 +1,9 @@
@^minimal-environment
#-kernel-uek # This can opt out of the UEK for the relevant distribution
bind-utils
chrony
pciutils
python3
rsync
tar
-iwl*-firmware
@@ -0,0 +1,4 @@
clearpart --all --initlabel
ignoredisk --only-use %%INSTALLDISK%%
autopart --nohome %%LUKSHOOK%%
@@ -1,4 +1,6 @@
#!/bin/sh
HOME=$(getent passwd $(whoami)|cut -d: -f 6)
export HOME
# This script is executed on the first boot after install has
# completed. It is best to edit the middle of the file as
@@ -33,16 +35,21 @@ export nodename confluent_mgr confluent_profile
exec >> /var/log/confluent/confluent-firstboot.log
exec 2>> /var/log/confluent/confluent-firstboot.log
chmod 600 /var/log/confluent/confluent-firstboot.log
if [ ! -f /etc/confluent/firstboot.ran ]; then
cat /etc/confluent/tls/*.pem >> /etc/pki/tls/certs/ca-bundle.crt
confluentpython /root/confignet
rm /root/confignet
fi
while ! ping -c 1 $confluent_pingtarget >& /dev/null; do
sleep 1
done
if [ ! -f /etc/confluent/firstboot.ran ]; then
touch /etc/confluent/firstboot.ran
cat /etc/confluent/tls/*.pem >> /etc/pki/tls/certs/ca-bundle.crt
run_remote_python confignet
run_remote firstboot.custom
# Firstboot scripts may be placed into firstboot.d, e.g. firstboot.d/01-firstaction.sh, firstboot.d/02-secondaction.sh
run_remote_parts firstboot.d
@@ -1,10 +1,10 @@
#!/bin/bash
function test_mgr() {
whost=$1
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
if curl -s https://${whost}/confluent-api/ > /dev/null; then
if curl -gs https://${whost}/confluent-api/ > /dev/null; then
return 0
fi
return 1
@@ -63,10 +63,10 @@ fetch_remote() {
set_confluent_vars
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -f -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo $1 failed to download; return 1; fi
}
@@ -174,10 +174,10 @@ run_remote_python() {
cd $confluentscripttmpdir
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -f -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo "'$*'" failed to download; return 1; fi
confluentpython $*
retcode=$?
@@ -47,5 +47,8 @@ run_remote_parts post.d
# Induce execution of remote configuration, e.g. ansible plays in ansible/post.d/
run_remote_config post.d
cd /root
fetch_remote confignet
cd -
curl -sf -X POST -d 'status: staged' -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $apikey" https://$confluent_mgr/confluent-api/self/updatestatus
kill $logshowpid
@@ -87,6 +87,7 @@ done
cryptboot=$(grep ^encryptboot: /etc/confluent/confluent.deploycfg | awk '{print $2}')
LUKSPARTY=''
touch /tmp/cryptpkglist
touch /tmp/pkglist
touch /tmp/addonpackages
if [ "$cryptboot" == "tpm2" ]; then
LUKSPARTY="--encrypted --passphrase=$(cat /etc/confluent/confluent.apikey)"
@@ -102,15 +103,18 @@ confluentpython /opt/confluent/bin/apiclient /confluent-public/os/$confluent_pro
run_remote pre.custom
run_remote_parts pre.d
confluentpython /etc/confluent/apiclient /confluent-public/os/$confluent_profile/kickstart -o /tmp/kickstart.base
if grep '^%include /tmp/pkglist' /tmp/kickstart.* > /dev/null; then
confluentpython /etc/confluent/apiclient /confluent-public/os/$confluent_profile/packagelist -o /tmp/pkglist
fi
grep '^%include /tmp/partitioning' /tmp/kickstart.* > /dev/null || touch /tmp/installdisk
if [ ! -e /tmp/installdisk ]; then
run_remote_python getinstalldisk
fi
confluentpython /etc/confluent/apiclient /confluent-public/os/$confluent_profile/partitioning -o /tmp/partitioning.template
grep '^%include /tmp/partitioning' /tmp/kickstart.* > /dev/null || rm /tmp/installdisk
if [ -e /tmp/installdisk -a ! -e /tmp/partitioning ]; then
echo clearpart --all --initlabel >> /tmp/partitioning
echo ignoredisk --only-use $(cat /tmp/installdisk) >> /tmp/partitioning
echo autopart --nohome $LUKSPARTY >> /tmp/partitioning
INSTALLDISK=$(cat /tmp/installdisk)
sed -e s/%%INSTALLDISK%%/$INSTALLDISK/ -e s/%%LUKSHOOK%%/$LUKSPARTY/ /tmp/partitioning.template > /tmp/partitioning
dd if=/dev/zero of=/dev/$(cat /tmp/installdisk) bs=1M count=1 >& /dev/null
vgchange -a n >& /dev/null
fi
@@ -154,8 +154,14 @@ cat > /run/NetworkManager/system-connections/$ifname.nmconnection << EOC
EOC
echo id=${ifname} >> /run/NetworkManager/system-connections/$ifname.nmconnection
echo uuid=$(uuidgen) >> /run/NetworkManager/system-connections/$ifname.nmconnection
linktype=$(ip link |grep -A2 ${ifname}|tail -n 1|awk '{print $1}')
if [ "$linktype" = link/infiniband ]; then
linktype="infiniband"
else
linktype="ethernet"
fi
echo type=$linktype >> /run/NetworkManager/system-connections/$ifname.nmconnection
cat >> /run/NetworkManager/system-connections/$ifname.nmconnection << EOC
type=ethernet
autoconnect-retries=1
EOC
echo interface-name=$ifname >> /run/NetworkManager/system-connections/$ifname.nmconnection
@@ -164,9 +170,6 @@ multi-connect=1
permissions=
wait-device-timeout=60000
[ethernet]
mac-address-blacklist=
EOC
autoconfigmethod=$(grep ^ipv4_method: /etc/confluent/confluent.deploycfg |awk '{print $2}')
auto6configmethod=$(grep ^ipv6_method: /etc/confluent/confluent.deploycfg |awk '{print $2}')
@@ -5,6 +5,8 @@
# noted below so custom commands are executed before
# the script notifies confluent that install is fully complete.
HOME=$(getent passwd $(whoami)|cut -d: -f 6)
export HOME
nodename=$(grep ^NODENAME /etc/confluent/confluent.info|awk '{print $2}')
confluent_apikey=$(cat /etc/confluent/confluent.apikey)
confluent_mgr=$(grep ^deploy_server: /etc/confluent/confluent.deploycfg|awk '{print $2}')
@@ -1,10 +1,10 @@
#!/bin/bash
function test_mgr() {
whost=$1
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
if curl -s https://${whost}/confluent-api/ > /dev/null; then
if curl -gs https://${whost}/confluent-api/ > /dev/null; then
return 0
fi
return 1
@@ -63,10 +63,10 @@ fetch_remote() {
set_confluent_vars
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -f -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo $1 failed to download; return 1; fi
}
@@ -174,10 +174,10 @@ run_remote_python() {
cd $confluentscripttmpdir
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -f -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo "'$*'" failed to download; return 1; fi
confluentpython $*
retcode=$?
@@ -11,6 +11,14 @@ import struct
import sys
import subprocess
bootuuid = None
def get_partname(devname, idx):
if devname[-1] in '0123456789':
return '{}p{}'.format(devname, idx)
else:
return '{}{}'.format(devname, idx)
def get_next_part_meta(img, imgsize):
if img.tell() == imgsize:
return None
@@ -53,10 +61,13 @@ class PartedRunner():
def __init__(self, disk):
self.disk = disk
def run(self, command):
def run(self, command, check=True):
command = command.split()
command = ['parted', '-a', 'optimal', '-s', self.disk] + command
return subprocess.check_output(command).decode('utf8')
if check:
return subprocess.check_output(command).decode('utf8')
else:
return subprocess.run(command, stdout=subprocess.PIPE).stdout.decode('utf8')
def fixup(rootdir, vols):
devbymount = {}
@@ -125,9 +136,14 @@ def fixup(rootdir, vols):
sys.stdout.flush()
for metafs in ('proc', 'sys', 'dev'):
subprocess.check_call(['mount', '-o', 'bind', '/{}'.format(metafs), os.path.join(rootdir, metafs)])
with open(os.path.join(rootdir, 'etc/sysconfig/grub')) as defgrubin:
if os.path.exists(os.path.join(rootdir, 'etc/lvm/devices/system.devices')):
os.remove(os.path.join(rootdir, 'etc/lvm/devices/system.devices'))
grubsyscfg = os.path.join(rootdir, 'etc/sysconfig/grub')
if not os.path.exists(grubsyscfg):
grubsyscfg = os.path.join(rootdir, 'etc/default/grub')
with open(grubsyscfg) as defgrubin:
defgrub = defgrubin.read().split('\n')
with open(os.path.join(rootdir, 'etc/sysconfig/grub'), 'w') as defgrubout:
with open(grubsyscfg, 'w') as defgrubout:
for gline in defgrub:
gline = gline.split()
newline = []
@@ -136,8 +152,34 @@ def fixup(rootdir, vols):
continue
newline.append(ent)
defgrubout.write(' '.join(newline) + '\n')
grubcfg = subprocess.check_output(['find', os.path.join(rootdir, 'boot'), '-name', 'grub.cfg']).decode('utf8').strip().replace(rootdir, '/')
subprocess.check_call(['chroot', rootdir, 'grub2-mkconfig', '-o', grubcfg])
grubcfg = subprocess.check_output(['find', os.path.join(rootdir, 'boot'), '-name', 'grub.cfg']).decode('utf8').strip().replace(rootdir, '/').replace('//', '/')
grubcfg = grubcfg.split('\n')
if not grubcfg[-1]:
grubcfg = grubcfg[:-1]
if len(grubcfg) == 1:
grubcfg = grubcfg[0]
else:
for gcfg in grubcfg:
rgcfg = os.path.join(rootdir, gcfg[1:]) # gcfg has a leading / to get rid of
if os.stat(rgcfg).st_size > 256:
grubcfg = gcfg
else:
with open(rgcfg, 'r') as gin:
tgrubcfg = gin.read()
tgrubcfg = tgrubcfg.split('\n')
if 'search --no-floppy --fs-uuid --set=dev' in tgrubcfg[0]:
tgrubcfg[0] = 'search --no-floppy --fs-uuid --set=dev ' + bootuuid
with open(rgcfg, 'w') as gout:
for gcline in tgrubcfg:
gout.write(gcline)
gout.write('\n')
try:
subprocess.check_call(['chroot', rootdir, 'grub2-mkconfig', '-o', grubcfg])
except Exception as e:
print(repr(e))
print(rootdir)
print(grubcfg)
time.sleep(86400)
newroot = None
with open('/etc/shadow') as shadowin:
shents = shadowin.read().split('\n')
@@ -166,6 +208,8 @@ def fixup(rootdir, vols):
partnum = re.search('(\d+)$', targdev).group(1)
targblock = re.search('(.*)\d+$', targdev).group(1)
if targblock:
if targblock.endswith('p') and 'nvme' in targblock:
targblock = targblock[:-1]
shimpath = subprocess.check_output(['find', os.path.join(rootdir, 'boot/efi'), '-name', 'shimx64.efi']).decode('utf8').strip()
shimpath = shimpath.replace(rootdir, '/').replace('/boot/efi', '').replace('//', '/').replace('/', '\\')
subprocess.check_call(['efibootmgr', '-c', '-d', targblock, '-l', shimpath, '--part', partnum])
@@ -184,6 +228,7 @@ def had_swap():
return False
def install_to_disk(imgpath):
global bootuuid
lvmvols = {}
deftotsize = 0
mintotsize = 0
@@ -224,7 +269,7 @@ def install_to_disk(imgpath):
instdisk = diskin.read()
instdisk = '/dev/' + instdisk
parted = PartedRunner(instdisk)
dinfo = parted.run('unit s print')
dinfo = parted.run('unit s print', check=False)
dinfo = dinfo.split('\n')
sectors = 0
sectorsize = 0
@@ -258,7 +303,7 @@ def install_to_disk(imgpath):
if end > sectors:
end = sectors
parted.run('mkpart primary {}s {}s'.format(curroffset, end))
vol['targetdisk'] = instdisk + '{0}'.format(volidx)
vol['targetdisk'] = get_partname(instdisk, volidx)
curroffset += size + 1
if not lvmvols:
if swapsize:
@@ -268,10 +313,10 @@ def install_to_disk(imgpath):
if end > sectors:
end = sectors
parted.run('mkpart swap {}s {}s'.format(curroffset, end))
subprocess.check_call(['mkswap', instdisk + '{}'.format(volidx + 1)])
subprocess.check_call(['mkswap', get_partname(instdisk, volidx + 1)])
else:
parted.run('mkpart lvm {}s 100%'.format(curroffset))
lvmpart = instdisk + '{}'.format(volidx + 1)
lvmpart = get_partname(instdisk, volidx + 1)
subprocess.check_call(['pvcreate', '-ff', '-y', lvmpart])
subprocess.check_call(['vgcreate', 'localstorage', lvmpart])
vginfo = subprocess.check_output(['vgdisplay', 'localstorage', '--units', 'b']).decode('utf8')
@@ -366,6 +411,14 @@ def install_to_disk(imgpath):
sys.stdout.write('\x1b[1K\rDone writing {0}'.format(vol['mount']))
sys.stdout.write('\n')
sys.stdout.flush()
if vol['mount'] == '/boot':
tbootuuid = subprocess.check_output(['blkid', vol['targetdisk']])
if b'UUID="' in tbootuuid:
bootuuid = tbootuuid.split(b'UUID="', 1)[1].split(b'"')[0].decode('utf8')
subprocess.check_call(['umount', '/run/imginst/targ'])
for vol in allvols:
subprocess.check_call(['mount', vol['targetdisk'], '/run/imginst/targ/' + vol['mount']])
@@ -373,4 +426,4 @@ def install_to_disk(imgpath):
if __name__ == '__main__':
install_to_disk(os.environ['mountsrc'])
install_to_disk(os.environ['mountsrc'])
@@ -127,5 +127,7 @@ if grep installtodisk /proc/cmdline > /dev/null; then
fi
mv /lib/modules/$(uname -r) /lib/modules/$(uname -r)-ramfs
ln -s /sysroot/lib/modules/$(uname -r) /lib/modules/
mv /lib/firmware /lib/firmware-ramfs
ln -s /sysroot/lib/firmware /lib/firmware
kill $(grep -l ^/usr/lib/systemd/systemd-udevd /proc/*/cmdline|cut -d/ -f 3)
exec /opt/confluent/bin/start_root
@@ -31,6 +31,9 @@ if [ ! -f /sysroot/tmp/installdisk ]; then
fi
lvm vgchange -a n
udevadm control -e
if [ -f /sysroot/etc/lvm/devices/system.devices ]; then
rm /sysroot/etc/lvm/devices/system.devices
fi
chroot /sysroot /usr/lib/systemd/systemd-udevd --daemon
chroot /sysroot bash -c "source /etc/confluent/functions; run_remote_python image2disk.py"
echo "Port 22" >> /etc/ssh/sshd_config
@@ -94,6 +94,7 @@ while ! grep NODENAME /etc/confluent/confluent.info; do
fi
done
node=$(grep NODENAME: /etc/confluent/confluent.info|head -n 1|awk '{print $2}')
cat /tls/*.pem > /etc/confluent/ca.pem
mgr=$(python /opt/confluent/bin/apiclient -c)
APIKEY=$(cat /etc/confluent/confluent.apikey)
@@ -108,7 +109,6 @@ while [ -z "$APIKEY" ]; do
(/clortho $node $mgr || /opt/confluent/bin/clortho $node $mgr) > /etc/confluent/confluent.apikey
APIKEY=$(cat /etc/confluent/confluent.apikey)
done
cat /tls/*.pem > /etc/confluent/ca.pem
/opt/confluent/bin/apiclient /confluent-api/self/deploycfg > /etc/confluent/confluent.deploycfg.new
profile=$(grep ^profile: /etc/confluent/confluent.deploycfg.new | sed -e 's/^profile: //')
/opt/confluent/bin/apiclient /confluent-public/os/$profile/kickstart > /etc/confluent/ks.cfg
@@ -33,6 +33,8 @@ for info in vswinfo.split('\n'):
upinfo = uplinkmatch.match(info)
if upinfo:
vmnic = upinfo.group(1)
if vmnic and 'vusb0' not in vmnic:
break
try:
with open('/tmp/confluentident/cnflnt.jsn') as identin:
identcfg = json.load(identin)
@@ -1,6 +1,10 @@
Ansible playbooks ending in .yml or .yaml that are placed into this directory will be executed at the
appropriate phase of the install process.
Alternatively, plays may be placed in /var/lib/confluent/private/os/<profilename>/ansible/<directory>.
This prevents public clients from being able to read the plays, which is not necessary for them to function,
and may protect them from divulging material contained in the plays or associated roles.
The 'hosts' may be omitted, and if included will be ignored, replaced with the host that is specifically
requesting the playbooks be executed.
@@ -161,7 +161,7 @@ else
echo -e "BOOTPROTO='static'\nSTARTMODE='auto'" >> /run/confluent/ifcfg-$ifname
echo "IPADDR='$v4addr/$v4nm'" >> /run/confluent/ifcfg-$ifname
if [ ! -z "$v4gw" ]; then
echo defafult $v4gw - $ifname > /run/confluent/ifroute-$ifname
echo default $v4gw - $ifname > /run/confluent/ifroute-$ifname
fi
fi
@@ -1,10 +1,10 @@
#!/bin/bash
function test_mgr() {
whost=$1
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
if curl -s https://${whost}/confluent-api/ > /dev/null; then
if curl -gs https://${whost}/confluent-api/ > /dev/null; then
return 0
fi
return 1
@@ -63,10 +63,10 @@ fetch_remote() {
set_confluent_vars
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -f -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo $1 failed to download; return 1; fi
}
@@ -174,10 +174,10 @@ run_remote_python() {
cd $confluentscripttmpdir
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -f -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo "'$*'" failed to download; return 1; fi
confluentpython $*
retcode=$?
@@ -138,4 +138,6 @@ if grep installtodisk /proc/cmdline > /dev/null; then
fi
mv /lib/modules/$(uname -r) /lib/modules/$(uname -r)-ramfs
ln -s /sysroot/lib/modules/$(uname -r) /lib/modules/
mv /lib/firmware /lib/firmware-ramfs
ln -s /sysroot/lib/firmware /lib/firmware
exec /opt/confluent/bin/start_root
@@ -77,6 +77,7 @@ if [ "$textconsole" = "true" ] && ! grep console= /proc/cmdline > /dev/null && [
sed -e s'/$/ 'console=${autocons#*/dev/}/ /proc/cmdline > /etc/fakecmdline
mount -o bind /etc/fakecmdline /proc/cmdline
echo "ConsoleDevice: ${autocons%,*}" >> /etc/linuxrc.d/01-confluent
echo "Textmode: 1" >> /etc/linuxrc.d/01-confluent
fi
tz=$(grep timezone: /etc/confluent/confluent.deploycfg | awk '{print $2}')
@@ -1,6 +1,10 @@
Ansible playbooks ending in .yml or .yaml that are placed into this directory will be executed at the
appropriate phase of the install process.
Alternatively, plays may be placed in /var/lib/confluent/private/os/<profilename>/ansible/<directory>.
This prevents public clients from being able to read the plays, which is not necessary for them to function,
and may protect them from divulging material contained in the plays or associated roles.
The 'hosts' may be omitted, and if included will be ignored, replaced with the host that is specifically
requesting the playbooks be executed.
@@ -1,6 +1,10 @@
Ansible playbooks ending in .yml or .yaml that are placed into this directory will be executed at the
appropriate phase of the install process.
Alternatively, plays may be placed in /var/lib/confluent/private/os/<profilename>/ansible/<directory>.
This prevents public clients from being able to read the plays, which is not necessary for them to function,
and may protect them from divulging material contained in the plays or associated roles.
The 'hosts' may be omitted, and if included will be ignored, replaced with the host that is specifically
requesting the playbooks be executed.
@@ -1,4 +1,6 @@
#!/bin/bash
HOME=$(getent passwd $(whoami)|cut -d: -f 6)
export HOME
# This script runs at the end of the final boot, updating status
exec >> /var/log/confluent/confluent-firstboot.log
@@ -1,10 +1,10 @@
#!/bin/bash
function test_mgr() {
whost=$1
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
if curl -s https://${whost}/confluent-api/ > /dev/null; then
if curl -gs https://${whost}/confluent-api/ > /dev/null; then
return 0
fi
return 1
@@ -63,10 +63,10 @@ fetch_remote() {
set_confluent_vars
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -f -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo $1 failed to download; return 1; fi
}
@@ -174,10 +174,10 @@ run_remote_python() {
cd $confluentscripttmpdir
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -f -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo "'$*'" failed to download; return 1; fi
confluentpython $*
retcode=$?
@@ -1,6 +1,10 @@
Ansible playbooks ending in .yml or .yaml that are placed into this directory will be executed at the
appropriate phase of the install process.
Alternatively, plays may be placed in /var/lib/confluent/private/os/<profilename>/ansible/<directory>.
This prevents public clients from being able to read the plays, which is not necessary for them to function,
and may protect them from divulging material contained in the plays or associated roles.
The 'hosts' may be omitted, and if included will be ignored, replaced with the host that is specifically
requesting the playbooks be executed.
@@ -1,6 +1,10 @@
Ansible playbooks ending in .yml or .yaml that are placed into this directory will be executed at the
appropriate phase of the install process.
Alternatively, plays may be placed in /var/lib/confluent/private/os/<profilename>/ansible/<directory>.
This prevents public clients from being able to read the plays, which is not necessary for them to function,
and may protect them from divulging material contained in the plays or associated roles.
The 'hosts' may be omitted, and if included will be ignored, replaced with the host that is specifically
requesting the playbooks be executed.
@@ -1,4 +1,6 @@
#!/bin/bash
HOME=$(getent passwd $(whoami)|cut -d: -f 6)
export HOME
# This script runs at the end of the final boot, updating status
exec >> /var/log/confluent/confluent-firstboot.log
@@ -1,10 +1,10 @@
#!/bin/bash
function test_mgr() {
whost=$1
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
if curl -s https://${whost}/confluent-api/ > /dev/null; then
if curl -gs https://${whost}/confluent-api/ > /dev/null; then
return 0
fi
return 1
@@ -63,10 +63,10 @@ fetch_remote() {
set_confluent_vars
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -f -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo $1 failed to download; return 1; fi
}
@@ -174,10 +174,10 @@ run_remote_python() {
cd $confluentscripttmpdir
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -f -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo "'$*'" failed to download; return 1; fi
confluentpython $*
retcode=$?
@@ -0,0 +1,205 @@
reverse_uuid() {
echo $1 | head -c 8 | tail -c 2
echo $1 | head -c 6 | tail -c 2
echo $1 | head -c 4 | tail -c 2
echo $1 | head -c 2 | tail -c 2
echo $1 | head -c 13 | tail -c 2
echo $1 | head -c 11 | tail -c 2
echo $1 | head -c 18 | tail -c 2
echo $1 | head -c 16 | tail -c 2
echo $1 | tail -c 18 | sed -e s/-//
}
setdebopt() {
debconf-set $1 $2
echo d-i $1 $3 $2 >> /preseed.cfg
}
mkdir -p /etc/confluent
for i in /sys/class/net/*; do
ip link set $(basename $i) up
done
TRIES=5
while [ ! -e /dev/disk ] && [ $TRIES -gt 0 ]; do
sleep 2
TRIES=$((TRIES - 1))
done
for i in /sys/class/net/*; do
ip link set $(basename $i) down
udevadm info $i | grep ID_NET_DRIVER=cdc_ether > /dev/null && continue
ip link set $(basename $i) up
done
cp -a /tls/* /etc/ssl/certs/
mkdir -p /etc/confluent
if [ -e /dev/disk/by-label/CNFLNT_IDNT ]; then
tmnt=$(mktemp -d)
tcfg=$(mktemp)
mount /dev/disk/by-label/CNFLNT_IDNT $tmnt
cd $tmnt
deploysrvs=$(sed -n '/^deploy_servers:/,/^[^-]/p' cnflnt.yml |grep ^-|sed -e 's/^- //'|grep -v :)
nodename=$(grep ^nodename: cnflnt.yml|cut -f 2 -d ' ')
echo NODENAME: $nodename > /etc/confluent/confluent.info
sed -n '/^net_cfgs:/,/^[^- ]/{/^[^- ]/!p}' cnflnt.yml |sed -n '/^-/,/^-/{/^-/!p}'| sed -e 's/^[- ]*//'> $tcfg
autoconfigmethod=$(grep ^ipv4_method: $tcfg)
autoconfigmethod=${autoconfigmethod#ipv4_method: }
if [ "$autoconfigmethod" = "static" ]; then
setdebopt netcfg/disable_dhcp true boolean
v4addr=$(grep ^ipv4_address: $tcfg|cut -d: -f 2|sed -e 's/ //')
v4gw=$(grep ^ipv4_gateway: $tcfg|cut -d: -f 2| sed -e 's/ //')
if [ "$v4gw" = "null" ]; then
v4gw=""
fi
v4nm=$(grep ^ipv4_netmask: $tcfg|cut -d: -f 2|sed -e 's/ //')
setdebopt netcfg/get_netmask $v4nm string
setdebopt netcfg/get_ipaddress ${v4addr%/*} string
setdebopt netcfg/confirm_static true boolean
if [ ! -z "$v4gw" ]; then
setdebopt netcfg/get_gateway $v4gw string
fi
for NICGUESS in $(ip link|grep LOWER_UP|grep -v LOOPBACK|cut -d ' ' -f 2 | sed -e 's/:$//'); do
ip addr add dev $NICGUESS $v4addr
if [ ! -z "$v4gw" ]; then
ip route add default via $v4gw
fi
for dsrv in $deploysrvs; do
if wget https://$dsrv/confluent-public/ --tries=1 --timeout=1 -O /dev/null > /dev/null 2>&1; then
deploysrvs=$dsrv
NIC=$NICGUESS
setdebopt netcfg/choose_interface $NIC select
break
fi
done
if [ -z "$NIC" ]; then
ip -4 a flush dev $NICGUESS
else
break
fi
done
#TODO: nameservers
elif [ "$v4cfgmeth" = "dhcp" ]; then
setdebopt netcfg/disable_dhcp false boolean
setdebopt netcfg/confirm_static false boolean
for NICGUESS in $(ip link|grep LOWER_UP|grep -v LOOPBACK|cut -d ' ' -f 2 | sed -e 's/:$//'); do
udhcpc $NICGUESS
done
for dsrv in $deploysrvs; do
if wget https://$dsrv/confluent-public/ --tries=1 --timeout=1 -O /dev/null > /dev/null 2>&1; then
deploysrvs=$dsrv
fi
done
fi
mgr=$deploysrvs
ln -s /opt/confluent/bin/clortho /opt/confluent/bin/genpasshmac
hmackeyfile=/tmp/cnflnthmackeytmp
passfile=/tmp/cnflnttmppassfile
passcrypt=/tmp/cnflntcryptfile
hmacfile=/tmp/cnflnthmacfile
echo -n $(grep ^apitoken: cnflnt.yml|cut -d ' ' -f 2) > $hmackeyfile
/opt/confluent/bin/genpasshmac $passfile $passcrypt $hmacfile $hmackeyfile
wget --header="CONFLUENT_NODENAME: $nodename" --header="CONFLUENT_CRYPTHMAC: $(cat $hmacfile)" --post-file=$passcrypt https://$mgr/confluent-api/self/registerapikey -O - --quiet
cp $passfile /etc/confluent/confluent.apikey
nic=$NIC
else
dhuuid=$(reverse_uuid $(cat /sys/devices/virtual/dmi/id/product_uuid))
dhcpid=$(mktemp)
mkdir -p /etc/confluent
cp /tls/* /etc/ssl/certs/
cat /tls/*.pem >> /etc/confluent/ca.pem
for nic in $(ip link | grep mtu|grep -v LOOPBACK|cut -d: -f 2|sed -e 's/ //'); do
ip link set $nic up
done
for nic in $(ip link | grep mtu|grep -v LOOPBACK|grep LOWER_UP|cut -d: -f 2|sed -e 's/ //'); do
if udhcpc -i $nic -p $dhcpid -t 2 -T 2 -n -x 93:0007 -x 97:00$dhuuid -q; then
/opt/confluent/bin/copernicus > /etc/confluent/confluent.info
if grep ^MANAGER:.*\\. /etc/confluent/confluent.info ; then
break
fi
fi
ip -4 flush dev $nic
done
mgr=$(grep ^MANAGER:.*\\. /etc/confluent/confluent.info|head -n 1|cut -d: -f 2|sed -e 's/ //')
nodename=$(grep ^NODENAME: /etc/confluent/confluent.info|head -n 1|cut -d: -f 2|sed -e 's/ //')
/opt/confluent/bin/clortho $nodename $mgr > /etc/confluent/confluent.apikey
fi
apikey=$(cat /etc/confluent/confluent.apikey)
cd /etc/confluent
wget --header="CONFLUENT_NODENAME: $nodename" --header="CONFLUENT_APIKEY: $apikey" https://$mgr/confluent-api/self/deploycfg
cd -
predir=$(mktemp -d)
cd $predir
cp /etc/confluent/deploycfg /etc/confluent/confluent.deploycfg
profile=$(grep ^profile: /etc/confluent/deploycfg|cut -d ' ' -f 2)
namesrvs=$(sed -n '/^nameservers:/,/^[^-]/p' /etc/confluent/deploycfg|grep ^- | cut -d ' ' -f 2|sed -e 's/ //')
for namesrv in "$namesrvs"; do
setdebopt netcfg/get_nameservers $namesrv string
done
rootpass=$(grep ^rootpassword: /etc/confluent/deploycfg|cut -d ' ' -f 2|sed -e 's/ //')
if [ "$rootpass" = null ] || [ -z "$rootpass" ]; then
setdebopt passwd/root-login false boolean
else
setdebopt passwd/root-login true boolean
setdebopt passwd/root-password-crypted $rootpass string
fi
setdebopt time/zone $(grep ^timezone: /etc/confluent/deploycfg|cut -d ' ' -f 2|sed -e 's/ //') string
ntpsrvs=$(sed -n '/^ntpservers:/,/^[^-]/p' /etc/confluent/deploycfg|grep ^- | cut -d ' ' -f 2|sed -e 's/ //')
for ntpsrv in "$ntpsrvs"; do
setdebopt clock-setup/ntp true boolean
setdebopt clock-setup/ntp-server $ntpsrv string
done
setdebopt debian-installer/locale $(grep ^locale: /etc/confluent/deploycfg|cut -d ' ' -f 2) select
domainname=$(grep ^dnsdomain: /etc/confluent/deploycfg|cut -d ' ' -f 2)
if [ ! -z "$domainname" ] && [ "$domainname" != "null" ]; then
setdebopt netcfg/get_domain $domainname string
fi
wget https://$mgr/confluent-public/os/$profile/scripts/pre.sh
chmod u+x pre.sh
wget https://$mgr/confluent-public/os/$profile/scripts/prechroot.sh
chmod u+x prechroot.sh
wget https://$mgr/confluent-public/os/$profile/scripts/post.sh
chmod u+x post.sh
wget https://$mgr/confluent-public/os/$profile/preseed.cfg
cat preseed.cfg >> /preseed.cfg
echo $mgr > /etc/confluent/deployer
setdebopt auto-install/enable true boolean
setdebopt partman/early_command $predir/pre.sh string
setdebopt preseed/late_command $predir/prechroot.sh string
mv $predir/post.sh /tmp/
cd -
ip -4 a flush dev $nic
setdebopt netcfg/choose_interface $nic select
setdebopt netcfg/get_hostname $nodename string
setdebopt mirror/protocol https string
setdebopt mirror/country manual string
setdebopt mirror/https/hostname $mgr string
setdebopt mirror/https/directory /confluent-public/os/$profile/distribution string
setdebopt mirror/protocol https string
setdebopt mirror/https/proxy "" string
setdebopt apt-setup/security_host $mgr string
if [ ! -e /dev/disk/by-label/CNFLNT_IDNT ]; then
v4cfgmeth=$(grep ipv4_method: /etc/confluent/deploycfg |cut -d: -f 2|sed -e 's/ //')
if [ "$v4cfgmeth" = "static" ]; then
setdebopt netcfg/disable_dhcp true boolean
v4addr=$(grep ^ipv4_address: /etc/confluent/deploycfg|cut -d: -f 2|sed -e 's/ //')
v4gw=$(grep ^ipv4_gateway: /etc/confluent/deploycfg|cut -d: -f 2| sed -e 's/ //')
if [ "$v4gw" = "null" ]; then
v4gw=""
fi
v4nm=$(grep ^ipv4_netmask: /etc/confluent/deploycfg|cut -d: -f 2|sed -e 's/ //')
setdebopt netcfg/get_netmask $v4nm string
setdebopt netcfg/get_ipaddress $v4addr string
setdebopt netcfg/confirm_static true boolean
if [ ! -z "$v4gw" ]; then
setdebopt netcfg/get_gateway $v4gw string
fi
namesrvs=$(sed -n '/^nameservers:/,/^[^-]/p' /etc/confluent/deploycfg|grep ^- | cut -d ' ' -f 2|sed -e 's/ //')
for namesrv in "$namesrvs"; do
setdebopt netcfg/get_nameservers $namesrv string
done
elif [ "$vpcfgmeth" = "dhcp" ]; then
setdebopt netcfg/disable_dhcp false boolean
setdebopt netcfg/confirm_static false boolean
fi
fi
@@ -0,0 +1,7 @@
#!/bin/sh
sed -i 's/label: ubuntu/label: Ubuntu/' $2/profile.yaml && \
ln -s $1/install/hwe-netboot/ubuntu-installer/amd64/linux $2/boot/kernel && \
ln -s $1/install/hwe-netboot/ubuntu-installer/amd64/initrd.gz $2/boot/initramfs/distribution && \
mkdir -p $2/boot/efi/boot && \
ln -s $1/EFI/BOOT/* $2/boot/efi/boot
@@ -0,0 +1,21 @@
d-i anna/choose_modules string openssh-server-udeb
d-i partman-auto/method string regular
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-md/device_remove_md boolean true
d-i partman-auto/expert_recipe_file string /tmp/partitionfile
d-i partman/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
d-i passwd/make-user boolean false
d-i clock-setup/utc boolean true
d-i apt-setup/multiverse boolean false
d-i apt-setup/universe boolean false
d-i apt-setup/backports boolean false
d-i apt-setup/updates boolean false
d-i grub-installer/only_debian boolean true
tasksel tasksel/first multiselect standard
d-i pkgsel/include string openssh-server curl
d-i pkgsel/update-policy select none
d-i pkgsel/updatedb boolean false
d-i finish-install/reboot_in_progress note
@@ -0,0 +1,3 @@
label: %%DISTRO%% %%VERSION%% %%ARCH%% (Default Profile)
kernelargs: quiet osprofile=%%PROFILE%%
#installedargs: example # These arguments would be added to the installed system
@@ -0,0 +1,11 @@
[Unit]
Description=First Boot Process
Requires=network-online.target
After=network-online.target
[Service]
ExecStart=/opt/confluent/bin/firstboot.sh
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,22 @@
#!/bin/bash
echo "Confluent first boot is running"
HOME=$(getent passwd $(whoami)|cut -d: -f 6)
export HOME
#cp -a /etc/confluent/ssh/* /etc/ssh/
#systemctl restart sshd
rootpw=$(grep ^rootpassword: /etc/confluent/confluent.deploycfg |awk '{print $2}')
if [ ! -z "$rootpw" -a "$rootpw" != "null" ]; then
echo root:$rootpw | chpasswd -e
fi
nodename=$(grep ^NODENAME: /etc/confluent/confluent.info | awk '{print $2}')
confluent_apikey=$(cat /etc/confluent/confluent.apikey)
confluent_mgr=$(grep ^deploy_server: /etc/confluent/confluent.deploycfg |awk '{print $2}')
while ! ping -c 1 $confluent_mgr >& /dev/null; do
sleep 1
done
source /etc/confluent/functions
run_remote_parts firstboot.d
run_remote_config firstboot.d
systemctl disable firstboot
curl -f -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $confluent_apikey" -X POST -d "status: complete" https://$confluent_mgr/confluent-api/self/updatestatus
@@ -0,0 +1,208 @@
#!/bin/bash
function test_mgr() {
whost=$1
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
if curl -gs https://${whost}/confluent-api/ > /dev/null; then
return 0
fi
return 1
}
function confluentpython() {
if [ -x /usr/libexec/platform-python ]; then
/usr/libexec/platform-python $*
elif [ -x /usr/bin/python3 ]; then
/usr/bin/python3 $*
elif [ -x /usr/bin/python ]; then
/usr/bin/python $*
elif [ -x /usr/bin/python2 ]; then
/usr/bin/python2 $*
fi
}
function set_confluent_vars() {
if [ -z "$nodename" ]; then
nodename=$(grep ^NODENAME: /etc/confluent/confluent.info | awk '{print $2}')
fi
if [[ "$confluent_mgr" == *"%"* ]]; then
confluent_mgr=""
fi
if [ -z "$confluent_mgr" ]; then
confluent_mgr=$(grep ^deploy_server: /etc/confluent/confluent.deploycfg | sed -e 's/[^ ]*: //')
if ! test_mgr $confluent_mgr; then
confluent_mgr=$(grep ^deploy_server_v6: /etc/confluent/confluent.deploycfg | sed -e 's/[^ ]*: //')
if [[ "$confluent_mgr" = *":"* ]]; then
confluent_mgr="[$confluent_mgr]"
fi
fi
if ! test_mgr $confluent_mgr; then
BESTMGRS=$(grep ^EXTMGRINFO: /etc/confluent/confluent.info | grep '|1$' | sed -e 's/EXTMGRINFO: //' -e 's/|.*//')
OKMGRS=$(grep ^EXTMGRINFO: /etc/confluent/confluent.info | grep '|0$' | sed -e 's/EXTMGRINFO: //' -e 's/|.*//')
for confluent_mgr in $BESTMGRS $OKMGRS; do
if [[ $confluent_mgr == *":"* ]]; then
confluent_mgr="[$confluent_mgr]"
fi
if test_mgr $confluent_mgr; then
break
fi
done
fi
fi
if [ -z "$confluent_profile" ]; then
confluent_profile=$(grep ^profile: /etc/confluent/confluent.deploycfg | sed -e 's/[^ ]*: //')
fi
}
fetch_remote() {
curlargs=""
if [ -f /etc/confluent/ca.pem ]; then
curlargs=" --cacert /etc/confluent/ca.pem"
fi
set_confluent_vars
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo $1 failed to download; return 1; fi
}
source_remote_parts() {
confluentscripttmpdir=$(mktemp -d /tmp/confluentscripts.XXXXXXXXX)
apiclient=/opt/confluent/bin/apiclient
if [ -f /etc/confluent/apiclient ]; then
apiclient=/etc/confluent/apiclient
fi
scriptlist=$(confluentpython $apiclient /confluent-api/self/scriptlist/$1|sed -e 's/^- //')
for script in $scriptlist; do
source_remote $1/$script
done
rm -rf $confluentscripttmpdir
unset confluentscripttmpdir
}
run_remote_parts() {
confluentscripttmpdir=$(mktemp -d /tmp/confluentscripts.XXXXXXXXX)
apiclient=/opt/confluent/bin/apiclient
if [ -f /etc/confluent/apiclient ]; then
apiclient=/etc/confluent/apiclient
fi
scriptlist=$(confluentpython $apiclient /confluent-api/self/scriptlist/$1|sed -e 's/^- //')
for script in $scriptlist; do
run_remote $1/$script
done
rm -rf $confluentscripttmpdir
unset confluentscripttmpdir
}
source_remote() {
set_confluent_vars
unsettmpdir=0
echo
echo '---------------------------------------------------------------------------'
echo Sourcing $1 from https://$confluent_mgr/confluent-public/os/$confluent_profile/scripts/
if [ -z "$confluentscripttmpdir" ]; then
confluentscripttmpdir=$(mktemp -d /tmp/confluentscripts.XXXXXXXXX)
unsettmpdir=1
fi
echo Sourcing from $confluentscripttmpdir
cd $confluentscripttmpdir
fetch_remote $1
if [ $? != 0 ]; then echo $1 failed to download; return 1; fi
chmod +x $1
cmd=$1
shift
source ./$cmd
cd - > /dev/null
if [ "$unsettmpdir" = 1 ]; then
rm -rf $confluentscripttmpdir
unset confluentscripttmpdir
unsettmpdir=0
fi
rm -rf $confluentscripttmpdir
return $retcode
}
run_remote() {
requestedcmd="'$*'"
unsettmpdir=0
set_confluent_vars
echo
echo '---------------------------------------------------------------------------'
echo Running $requestedcmd from https://$confluent_mgr/confluent-public/os/$confluent_profile/scripts/
if [ -z "$confluentscripttmpdir" ]; then
confluentscripttmpdir=$(mktemp -d /tmp/confluentscripts.XXXXXXXXX)
unsettmpdir=1
fi
echo Executing in $confluentscripttmpdir
cd $confluentscripttmpdir
fetch_remote $1
if [ $? != 0 ]; then echo $requestedcmd failed to download; return 1; fi
chmod +x $1
cmd=$1
if [ -x /usr/bin/chcon ]; then
chcon system_u:object_r:bin_t:s0 $cmd
fi
shift
./$cmd $*
retcode=$?
if [ $retcode -ne 0 ]; then
echo "$requestedcmd exited with code $retcode"
fi
cd - > /dev/null
if [ "$unsettmpdir" = 1 ]; then
rm -rf $confluentscripttmpdir
unset confluentscripttmpdir
unsettmpdir=0
fi
return $retcode
}
run_remote_python() {
echo
set_confluent_vars
if [ -f /etc/confluent/ca.pem ]; then
curlargs=" --cacert /etc/confluent/ca.pem"
fi
echo '---------------------------------------------------------------------------'
echo Running python script "'$*'" from https://$confluent_mgr/confluent-public/os/$confluent_profile/scripts/
confluentscripttmpdir=$(mktemp -d /tmp/confluentscripts.XXXXXXXXX)
echo Executing in $confluentscripttmpdir
cd $confluentscripttmpdir
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo "'$*'" failed to download; return 1; fi
confluentpython $*
retcode=$?
echo "'$*' exited with code $retcode"
cd - > /dev/null
rm -rf $confluentscripttmpdir
unset confluentscripttmpdir
return $retcode
}
run_remote_config() {
echo
set_confluent_vars
apiclient=/opt/confluent/bin/apiclient
if [ -f /etc/confluent/apiclient ]; then
apiclient=/etc/confluent/apiclient
fi
echo '---------------------------------------------------------------------------'
echo Requesting to run remote configuration for "'$*'" from $confluent_mgr under profile $confluent_profile
confluentpython $apiclient /confluent-api/self/remoteconfig/"$*" -d {}
confluentpython $apiclient /confluent-api/self/remoteconfig/status -w 204
echo
echo 'Completed remote configuration'
echo '---------------------------------------------------------------------------'
return
}
#If invoked as a command, use the arguments to actually run a function
(return 0 2>/dev/null) || $1 "${@:2}"
@@ -0,0 +1,67 @@
#!/bin/bash
mkdir -p /run/sshd
mkdir -p /root/.ssh
cat /tmp/ssh/*pubkey >> /root/.ssh/authorized_keys
cat /tmp/ssh/*.ca | sed -e s/^/'@cert-authority * '/ >> /etc/ssh/ssh_known_hosts
chmod 700 /etc/confluent
chmod go-rwx /etc/confluent/*
sshconf=/etc/ssh/ssh_config
if [ -d /etc/ssh/ssh_config.d/ ]; then
sshconf=/etc/ssh/ssh_config.d/01-confluent.conf
fi
echo 'Host *' >> $sshconf
echo ' HostbasedAuthentication yes' >> $sshconf
echo ' EnableSSHKeysign yes' >> $sshconf
echo ' HostbasedKeyTypes *ed25519*' >> $sshconf
/usr/sbin/sshd
confluent_profile=$(grep ^profile: /etc/confluent/confluent.deploycfg | awk '{print $2}')
mkdir -p /opt/confluent/bin
python3 /opt/confluent/bin/apiclient /confluent-public/os/$confluent_profile/scripts/firstboot.sh > /opt/confluent/bin/firstboot.sh
chmod +x /opt/confluent/bin/firstboot.sh
python3 /opt/confluent/bin/apiclient /confluent-public/os/$confluent_profile/scripts/firstboot.service > /etc/systemd/system/firstboot.service
systemctl enable firstboot
python3 /opt/confluent/bin/apiclient /confluent-public/os/$confluent_profile/scripts/functions > /etc/confluent/functions
source /etc/confluent/functions
python3 /opt/confluent/bin/apiclient /confluent-api/self/nodelist | sed -e s/'^- //' > /tmp/allnodes
cp /tmp/allnodes /root/.shosts
cp /tmp/allnodes /etc/ssh/shosts.equiv
if grep ^ntpservers: /etc/confluent/confluent.deploycfg > /dev/null; then
ntps=$(sed -n '/^ntpservers:/,/^[^-]/p' /etc/confluent/confluent.deploycfg|sed 1d|sed '$d' | sed -e 's/^- //' | paste -sd ' ')
sed -i "s/#NTP=/NTP=$ntps/" /etc/systemd/timesyncd.conf
fi
textcons=$(grep ^textconsole: /etc/confluent/confluent.deploycfg |awk '{print $2}')
updategrub=0
if [ "$textcons" = "true" ] && ! grep console= /proc/cmdline > /dev/null; then
cons=""
if [ -f /tmp/autocons.info ]; then
cons=$(cat /tmp/autocons.info)
fi
if [ ! -z "$cons" ]; then
sed -i 's/GRUB_CMDLINE_LINUX="\([^"]*\)"/GRUB_CMDLINE_LINUX="\1 console='${cons#/dev/}'"/' /etc/default/grub
updategrub=1
fi
fi
kargs=$(python3 /opt/confluent/bin/apiclient /confluent-public/os/$confluent_profile/profile.yaml | grep ^installedargs: | sed -e 's/#.*//')
if [ ! -z "$kargs" ]; then
sed -i 's/GRUB_CMDLINE_LINUX="\([^"]*\)"/GRUB_CMDLINE_LINUX="\1 '"${kargs}"'"/' /etc/default/grub
fi
if [ 1 = $updategrub ]; then
update-grub
fi
if [ -e /sys/firmware/efi ]; then
bootnum=$(efibootmgr | grep ubuntu | sed -e 's/ .*//' -e 's/\*//' -e s/Boot//)
if [ ! -z "$bootnum" ]; then
currboot=$(efibootmgr | grep ^BootOrder: | awk '{print $2}')
nextboot=$(echo $currboot| awk -F, '{print $1}')
[ "$nextboot" = "$bootnum" ] || efibootmgr -o $bootnum,$currboot
efibootmgr -D
fi
fi
run_remote_python syncfileclient
run_remote_parts post.d
run_remote_config post
python3 /opt/confluent/bin/apiclient /confluent-api/self/updatestatus -d 'status: staged'
@@ -0,0 +1,87 @@
#!/bin/sh
## Use the following option to add additional boot parameters for the
## installed system (if supported by the bootloader installer).
## Note: options passed to the installer will be added automatically.
#d-i debian-installer/add-kernel-opts string [from profile.yaml]
deploycfg=/etc/confluent/confluent.deploycfg
mgr=$(cat /etc/confluent/deployer)
cryptboot=$(grep encryptboot: $deploycfg|sed -e 's/^encryptboot: //')
if [ "$cryptboot" != "" ] && [ "$cryptboot" != "none" ] && [ "$cryptboot" != "null" ]; then
echo "****Encrypted boot requested, but not implemented for this OS, halting install" > /dev/console
[ -f '/tmp/autoconsdev' ] && (echo "****Encryptod boot requested, but not implemented for this OS,halting install" >> $(cat /tmp/autoconsdev))
while :; do sleep 86400; done
fi
cat > /usr/lib/live-installer.d/confluent-certs << EOF
#!/bin/sh
cp /tls/* /target/etc/ssl/certs/
cat /tls/*.pem >> /target/etc/ssl/certs/ca-certificates.crt
EOF
chmod a+x /usr/lib/live-installer.d/confluent-certs
mkdir -p /.ssh/
cat /ssh/*pubkey > /.ssh/authorized_keys
mkdir -p /etc/ssh
nodename=$(grep ^NODENAME: /etc/confluent/confluent.info|cut -d ' ' -f 2)
apikey=$(cat /etc/confluent/confluent.apikey)
ssh-keygen -A
for pubkey in /etc/ssh/ssh_host*key.pub; do
certfile=$(echo $pubkey | sed -e s/.pub/-cert.pub/)
keyfile=${pubkey%.pub}
wget --header="CONFLUENT_NODENAME: $nodename" --header="CONFLUENT_APIKEY: $apikey" --post-file=$pubkey https://$mgr/confluent-api/self/sshcert -O $certfile --quiet
echo HostKey $keyfile >> /etc/ssh/sshd_config
echo HostCertificate $certfile >> /etc/ssh/sshd_config
done
if [ -e /tmp/installdisk ]; then
instdisk=$(cat /tmp/installdisk)
else
for blockdev in $(ls /sys/class/block/); do
shortname=$(basename $blockdev)
if [ "$shortname" != "${shortname%loop*}" ]; then
continue
fi
udevadm info --query=property /dev/$shortname |grep DEVTYPE=disk > /dev/null || continue # ignore partitions
udevadm info --query=property /dev/$shortname |grep DM_NAME > /dev/null && continue # not a real disk
sz=$(cat /sys/block/$shortname/size 2> /dev/null)
[ -z "$sz" ] && continue
[ $sz -lt 1048576 ] && continue # Too small
[ -z "$firstdisk" ] && firstdisk=$shortname
if udevadm info --query=property /dev/$shortname|grep ID_MODEL=| sed -e s/' '/_/g | grep -iE '(thinksystem_m.2|m.2_nvme_2-bay_raid_kit)' > /dev/null; then
instdisk=$shortname
break
fi
if udevadm info --query=property /dev/$shortname|grep MD_CONTAINER=imsm; then
sraid=$sortname
else
drv=$(udevadm info -a /dev/sdb|grep DRIVERS==|grep -Ev '""|"sd"' | sed -e s/.*=// -e s/'"'//g)
if [ "ahci" = "$drv" -a -z "$onbdisk" ]; then
onbdisk=$shortname
elif [ "megaraid" = "$drv" -a -z "$rdisk" ]; then
rdisk=$shortname
fi
fi
done
fi
if [ -z "$instdisk" ]; then
if [ ! -z "$sraid"]; then
instdisk=$sraid
elif [ ! -z "$onbdisk" ]; then
instdisk=$onbdisk
elif [ ! -z "$rdisk" ]; then
instdisk=$rdisk
else
instdisk=$firstdisk
fi
fi
if [ ! -z "$instdisk" ]; then
debconf-set partman-auto/disk /dev/$instdisk
fi
echo HostbasedAuthentication yes >> /etc/ssh/sshd_config
echo HostbasedUsesNameFromPacketOnly yes >> /etc/ssh/sshd_config
echo IgnoreRhosts no >> /etc/ssh/sshd_config
echo sshd:x:1:1::/run/sshd:/bin/false >> /etc/passwd
/usr/sbin/sshd
wget --header="CONFLUENT_NODENAME: $nodename" --header="CONFLUENT_APIKEY: $apikey" https://$mgr/confluent-api/self/nodelist -O /tmp/allnodes --quiet
#kill -HUP $(ps | grep -v grep | grep /usr/sbin/sshd | sed -e 's/^ *//'|cut -d ' ' -f 1)
#curl -f https://$confluent_mgr/confluent-public/os/$confluent_profile/scripts/getinstalldisk > /tmp/getinstalldisk
#python3 /tmp/getinstalldisk
#sed -i s!%%INSTALLDISK%%!/dev/$(cat /tmp/installdisk)! /autoinstall.yaml
@@ -0,0 +1,17 @@
#!/bin/sh
mount -o bind /sys /target/sys
mount -o bind /dev /target/dev
mount -o bind /dev/pts /target/dev/pts
mount -o bind /proc /target/proc
mount -o bind /dev/pts /target/dev/pts
mount -o bind /run /target/run
cp -a /etc/confluent /target/etc/confluent
cp -a /opt/confluent /target/opt/confluent
mv /tmp/post.sh /target/tmp/
cp -a /ssh /tls /target/tmp
cat /tls/*.pem >> /target/etc/confluent/ca.pem
cp -a /etc/ssh/ssh_host_* /target/etc/ssh/
grep HostCertificate /etc/ssh/sshd_config >> /target/etc/ssh/sshd_config
echo Port 2222 >> /etc/ssh/sshd_config
kill -HUP $(ps |grep -v grep|grep sshd|grep /usr|sed -e s/' root.*//')
chroot /target bash /tmp/post.sh
@@ -107,7 +107,7 @@ if [ "$v6meth" = static ]; then
ip route add default via $v6gw
fi
fi
v4meth=$(grep ^ipv6_method: /etc/confluent/confluent.deploycfg|awk '{print $2}')
v4meth=$(grep ^ipv4_method: /etc/confluent/confluent.deploycfg|awk '{print $2}')
if [ "$v4meth" = static ]; then
v4addr=$(grep ^ipv4_address: /etc/confluent/confluent.deploycfg | awk '{print $2}')
v4prefix=$(grep ^prefix: /etc/confluent/confluent.deploycfg | awk '{print $2}')
@@ -0,0 +1,11 @@
[Unit]
Description=First Boot Process
Requires=network-online.target
After=network-online.target
[Service]
ExecStart=/opt/confluent/bin/firstboot.sh
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,40 @@
#!/bin/bash
# This script is executed on the first boot after install has
# completed. It is best to edit the middle of the file as
# noted below so custom commands are executed before
# the script notifies confluent that install is fully complete.
HOME=$(getent passwd $(whoami)|cut -d: -f 6)
export HOME
nodename=$(grep ^NODENAME /etc/confluent/confluent.info|awk '{print $2}')
confluent_apikey=$(cat /etc/confluent/confluent.apikey)
confluent_mgr=$(grep ^deploy_server: /etc/confluent/confluent.deploycfg|awk '{print $2}')
confluent_profile=$(grep ^profile: /etc/confluent/confluent.deploycfg|awk '{print $2}')
export nodename confluent_mgr confluent_profile
. /etc/confluent/functions
(
exec >> /var/log/confluent/confluent-firstboot.log
exec 2>> /var/log/confluent/confluent-firstboot.log
chmod 600 /var/log/confluent/confluent-firstboot.log
while ! ping -c 1 $confluent_mgr >& /dev/null; do
sleep 1
done
if [ ! -f /etc/confluent/firstboot.ran ]; then
touch /etc/confluent/firstboot.ran
run_remote firstboot.custom
# Firstboot scripts may be placed into firstboot.d, e.g. firstboot.d/01-firstaction.sh, firstboot.d/02-secondaction.sh
run_remote_parts firstboot.d
# Induce execution of remote configuration, e.g. ansible plays in ansible/firstboot.d/
run_remote_config firstboot.d
fi
curl -X POST -d 'status: complete' -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $confluent_apikey" https://$confluent_mgr/confluent-api/self/updatestatus
systemctl disable firstboot
rm /etc/systemd/system/firstboot.service
rm /etc/confluent/firstboot.ran
) &
tail --pid $! -F /var/log/confluent/confluent-firstboot.log > /dev/console
@@ -0,0 +1,93 @@
import subprocess
import os
class DiskInfo(object):
def __init__(self, devname):
self.name = devname
self.wwn = None
self.path = None
self.model = ''
self.size = 0
self.driver = None
self.mdcontainer = ''
devnode = '/dev/{0}'.format(devname)
qprop = subprocess.check_output(
['udevadm', 'info', '--query=property', devnode])
if not isinstance(qprop, str):
qprop = qprop.decode('utf8')
for prop in qprop.split('\n'):
if '=' not in prop:
continue
k, v = prop.split('=', 1)
if k == 'DEVTYPE' and v != 'disk':
raise Exception('Not a disk')
elif k == 'DM_NAME':
raise Exception('Device Mapper')
elif k == 'ID_MODEL':
self.model = v
elif k == 'DEVPATH':
self.path = v
elif k == 'ID_WWN':
self.wwn = v
elif k == 'MD_CONTAINER':
self.mdcontainer = v
attrs = subprocess.check_output(['udevadm', 'info', '-a', devnode])
if not isinstance(attrs, str):
attrs = attrs.decode('utf8')
for attr in attrs.split('\n'):
if '==' not in attr:
continue
k, v = attr.split('==', 1)
k = k.strip()
if k == 'ATTRS{size}':
self.size = v.replace('"', '')
elif (k == 'DRIVERS' and not self.driver
and v not in ('"sd"', '""')):
self.driver = v.replace('"', '')
if not self.driver and 'imsm' not in self.mdcontainer:
raise Exception("No driver detected")
if os.path.exists('/sys/block/{0}/size'.format(self.name)):
with open('/sys/block/{0}/size'.format(self.name), 'r') as sizesrc:
self.size = int(sizesrc.read()) * 512
if int(self.size) < 536870912:
raise Exception("Device too small for install")
@property
def priority(self):
if self.model.lower() in ('m.2 nvme 2-bay raid kit', 'thinksystem_m.2_vd', 'thinksystem m.2', 'thinksystem_m.2'):
return 0
if 'imsm' in self.mdcontainer:
return 1
if self.driver == 'ahci':
return 2
if self.driver.startswith('megaraid'):
return 3
if self.driver.startswith('mpt'):
return 4
return 99
def __repr__(self):
return repr({
'name': self.name,
'path': self.path,
'wwn': self.wwn,
'driver': self.driver,
'size': self.size,
'model': self.model,
})
def main():
disks = []
for disk in sorted(os.listdir('/sys/class/block')):
try:
disk = DiskInfo(disk)
disks.append(disk)
except Exception as e:
print("Skipping {0}: {1}".format(disk, str(e)))
nd = [x.name for x in sorted(disks, key=lambda x: x.priority)]
if nd:
open('/tmp/installdisk', 'w').write(nd[0])
if __name__ == '__main__':
main()
@@ -0,0 +1,426 @@
#!/usr/bin/python3
import glob
import json
import os
import re
import time
import shutil
import socket
import stat
import struct
import sys
import subprocess
bootuuid = None
def get_partname(devname, idx):
if devname[-1] in '0123456789':
return '{}p{}'.format(devname, idx)
else:
return '{}{}'.format(devname, idx)
def get_next_part_meta(img, imgsize):
if img.tell() == imgsize:
return None
pathlen = struct.unpack('!H', img.read(2))[0]
mountpoint = img.read(pathlen).decode('utf8')
jsonlen = struct.unpack('!I', img.read(4))[0]
metadata = json.loads(img.read(jsonlen).decode('utf8'))
img.seek(16, 1) # skip the two 64-bit values we don't use, they are in json
nextlen = struct.unpack('!H', img.read(2))[0]
img.seek(nextlen, 1) # skip filesystem type
nextlen = struct.unpack('!H', img.read(2))[0]
img.seek(nextlen, 1) # skip orig devname (redundant with json)
nextlen = struct.unpack('!H', img.read(2))[0]
img.seek(nextlen, 1) # skip padding
nextlen = struct.unpack('!Q', img.read(8))[0]
img.seek(nextlen, 1) # go to next section
return metadata
def get_multipart_image_meta(img):
img.seek(0, 2)
imgsize = img.tell()
img.seek(16)
seekamt = img.read(1)
img.seek(struct.unpack('B', seekamt)[0], 1)
partinfo = get_next_part_meta(img, imgsize)
while partinfo:
yield partinfo
partinfo = get_next_part_meta(img, imgsize)
def get_image_metadata(imgpath):
with open(imgpath, 'rb') as img:
header = img.read(16)
if header == b'\x63\x7b\x9d\x26\xb7\xfd\x48\x30\x89\xf9\x11\xcf\x18\xfd\xff\xa1':
for md in get_multipart_image_meta(img):
yield md
else:
raise Exception('Installation from single part image not supported')
class PartedRunner():
def __init__(self, disk):
self.disk = disk
def run(self, command, check=True):
command = command.split()
command = ['parted', '-a', 'optimal', '-s', self.disk] + command
if check:
return subprocess.check_output(command).decode('utf8')
else:
return subprocess.run(command, stdout=subprocess.PIPE).stdout.decode('utf8')
def fixup(rootdir, vols):
devbymount = {}
for vol in vols:
devbymount[vol['mount']] = vol['targetdisk']
fstabfile = os.path.join(rootdir, 'etc/fstab')
with open(fstabfile) as tfile:
fstab = tfile.read().split('\n')
while not fstab[0]:
fstab = fstab[1:]
if os.path.exists(os.path.join(rootdir, '.autorelabel')):
os.unlink(os.path.join(rootdir, '.autorelabel'))
with open(fstabfile, 'w') as tfile:
for tab in fstab:
entry = tab.split()
if tab.startswith('#ORIGFSTAB#'):
if entry[1] in devbymount:
targetdev = devbymount[entry[1]]
if targetdev.startswith('/dev/localstorage/'):
entry[0] = targetdev
else:
uuid = subprocess.check_output(['blkid', '-s', 'UUID', '-o', 'value', targetdev]).decode('utf8')
uuid = uuid.strip()
entry[0] = 'UUID={}'.format(uuid)
elif entry[2] == 'swap':
entry[0] = '/dev/mapper/localstorage-swap'
entry[0] = entry[0].ljust(42)
entry[1] = entry[1].ljust(16)
entry[3] = entry[3].ljust(28)
tab = '\t'.join(entry)
tfile.write(tab + '\n')
with open(os.path.join(rootdir, 'etc/hostname'), 'w') as nameout:
nameout.write(socket.gethostname() + '\n')
selinuxconfig = os.path.join(rootdir, 'etc/selinux/config')
policy = None
if os.path.exists(selinuxconfig):
with open(selinuxconfig) as cfgin:
sec = cfgin.read().split('\n')
for l in sec:
l = l.split('#', 1)[0]
if l.startswith('SELINUXTYPE='):
_, policy = l.split('=')
for sshkey in glob.glob(os.path.join(rootdir, 'etc/ssh/*_key*')):
os.unlink(sshkey)
for sshkey in glob.glob('/etc/ssh/*_key*'):
newkey = os.path.join(rootdir, sshkey[1:])
shutil.copy2(sshkey, newkey)
finfo = os.stat(sshkey)
os.chown(newkey, finfo[stat.ST_UID], finfo[stat.ST_GID])
# Will use confignet to handle networking for ubuntu
shutil.rmtree(os.path.join(rootdir, 'etc/confluent/'))
shutil.copytree('/etc/confluent', os.path.join(rootdir, 'etc/confluent'))
if policy:
sys.stdout.write('Applying SELinux labeling...')
sys.stdout.flush()
subprocess.check_call(['setfiles', '-r', rootdir, os.path.join(rootdir, 'etc/selinux/{}/contexts/files/file_contexts'.format(policy)), os.path.join(rootdir, 'etc')])
subprocess.check_call(['setfiles', '-r', rootdir, os.path.join(rootdir, 'etc/selinux/{}/contexts/files/file_contexts'.format(policy)), os.path.join(rootdir, 'opt')])
sys.stdout.write('Done\n')
sys.stdout.flush()
for metafs in ('proc', 'sys', 'dev'):
subprocess.check_call(['mount', '-o', 'bind', '/{}'.format(metafs), os.path.join(rootdir, metafs)])
if os.path.exists(os.path.join(rootdir, 'etc/lvm/devices/system.devices')):
os.remove(os.path.join(rootdir, 'etc/lvm/devices/system.devices'))
grubsyscfg = os.path.join(rootdir, 'etc/sysconfig/grub')
if not os.path.exists(grubsyscfg):
grubsyscfg = os.path.join(rootdir, 'etc/default/grub')
with open(grubsyscfg) as defgrubin:
defgrub = defgrubin.read().split('\n')
with open(grubsyscfg, 'w') as defgrubout:
for gline in defgrub:
gline = gline.split()
newline = []
for ent in gline:
if ent.startswith('resume=') or ent.startswith('rd.lvm.lv'):
continue
newline.append(ent)
defgrubout.write(' '.join(newline) + '\n')
grubcfg = subprocess.check_output(['find', os.path.join(rootdir, 'boot'), '-name', 'grub.cfg']).decode('utf8').strip().replace(rootdir, '/').replace('//', '/')
grubcfg = grubcfg.split('\n')
if not grubcfg[-1]:
grubcfg = grubcfg[:-1]
if len(grubcfg) == 1:
grubcfg = grubcfg[0]
else:
for gcfg in grubcfg:
rgcfg = os.path.join(rootdir, gcfg[1:]) # gcfg has a leading / to get rid of
if os.stat(rgcfg).st_size > 256:
grubcfg = gcfg
else:
with open(rgcfg, 'r') as gin:
tgrubcfg = gin.read()
tgrubcfg = tgrubcfg.split('\n')
if 'search --no-floppy --fs-uuid --set=dev' in tgrubcfg[0]:
tgrubcfg[0] = 'search --no-floppy --fs-uuid --set=dev ' + bootuuid
elif 'search.fs_uuid ' in tgrubcfg[0] and 'root' in tgrubcfg[0]:
tgrubcfg[0] = 'search.fs_uuid ' + bootuuid + ' root'
with open(rgcfg, 'w') as gout:
for gcline in tgrubcfg:
gout.write(gcline)
gout.write('\n')
try:
# must fixup root@d2:/boot/efi/EFI# cat ubuntu/grub.cfg ... uuid
subprocess.check_call(['chroot', rootdir, 'grub-mkconfig', '-o', grubcfg])
except Exception as e:
print(repr(e))
print(rootdir)
print(grubcfg)
time.sleep(86400)
newroot = None
with open('/etc/shadow') as shadowin:
shents = shadowin.read().split('\n')
for shent in shents:
shent = shent.split(':')
if not shent:
continue
if shent[0] == 'root' and shent[1] not in ('*', '!!', ''):
newroot = shent[1]
if newroot:
shlines = None
with open(os.path.join(rootdir, 'etc/shadow')) as oshadow:
shlines = oshadow.read().split('\n')
with open(os.path.join(rootdir, 'etc/shadow'), 'w') as oshadow:
for line in shlines:
if line.startswith('root:'):
line = line.split(':')
line[1] = newroot
line = ':'.join(line)
oshadow.write(line + '\n')
partnum = None
targblock = None
for vol in vols:
if vol['mount'] == '/boot/efi':
targdev = vol['targetdisk']
partnum = re.search('(\d+)$', targdev).group(1)
targblock = re.search('(.*)\d+$', targdev).group(1)
if targblock:
shimpath = subprocess.check_output(['find', os.path.join(rootdir, 'boot/efi'), '-name', 'shimx64.efi']).decode('utf8').strip()
shimpath = shimpath.replace(rootdir, '/').replace('/boot/efi', '').replace('//', '/').replace('/', '\\')
subprocess.check_call(['efibootmgr', '-c', '-d', targblock, '-l', shimpath, '--part', partnum])
#other network interfaces
def had_swap():
with open('/etc/fstab') as tabfile:
tabs = tabfile.read().split('\n')
for tab in tabs:
tab = tab.split()
if len(tab) < 3:
continue
if tab[2] == 'swap':
return True
return False
def install_to_disk(imgpath):
global bootuuid
lvmvols = {}
deftotsize = 0
mintotsize = 0
deflvmsize = 0
minlvmsize = 0
biggestsize = 0
biggestfs = None
plainvols = {}
allvols = []
swapsize = 0
if had_swap():
with open('/proc/meminfo') as meminfo:
swapsize = meminfo.read().split('\n')[0]
swapsize = int(swapsize.split()[1])
if swapsize < 2097152:
swapsize = swapsize * 2
elif swapsize > 8388608 and swapsize < 67108864:
swapsize = swapsize * 0.5
elif swapsize >= 67108864:
swapsize = 33554432
swapsize = int(swapsize * 1024)
deftotsize = swapsize
mintotsize = swapsize
for fs in get_image_metadata(imgpath):
allvols.append(fs)
deftotsize += fs['initsize']
mintotsize += fs['minsize']
if fs['initsize'] > biggestsize:
biggestfs = fs
biggestsize = fs['initsize']
if fs['device'].startswith('/dev/mapper'):
lvmvols[fs['device'].replace('/dev/mapper/', '')] = fs
deflvmsize += fs['initsize']
minlvmsize += fs['minsize']
else:
plainvols[int(re.search('(\d+)$', fs['device'])[0])] = fs
with open('/tmp/installdisk') as diskin:
instdisk = diskin.read()
instdisk = '/dev/' + instdisk
parted = PartedRunner(instdisk)
dinfo = parted.run('unit s print', check=False)
dinfo = dinfo.split('\n')
sectors = 0
sectorsize = 0
for inf in dinfo:
if inf.startswith('Disk {0}:'.format(instdisk)):
_, sectors = inf.split(': ')
sectors = int(sectors.replace('s', ''))
if inf.startswith('Sector size (logical/physical):'):
_, sectorsize = inf.split(':')
sectorsize = sectorsize.split('/')[0]
sectorsize = sectorsize.replace('B', '')
sectorsize = int(sectorsize)
# for now, only support resizing/growing the largest partition
minexcsize = deftotsize - biggestfs['initsize']
mintotsize = deftotsize - biggestfs['initsize'] + biggestfs['minsize']
minsectors = mintotsize // sectorsize
if sectors < (minsectors + 65536):
raise Exception('Disk too small to fit image')
biggestsectors = sectors - (minexcsize // sectorsize)
biggestsize = sectorsize * biggestsectors
parted.run('mklabel gpt')
curroffset = 2048
for volidx in sorted(plainvols):
vol = plainvols[volidx]
if vol is not biggestfs:
size = vol['initsize'] // sectorsize
else:
size = biggestsize // sectorsize
size += 2047 - (size % 2048)
end = curroffset + size
if end > sectors:
end = sectors
parted.run('mkpart primary {}s {}s'.format(curroffset, end))
vol['targetdisk'] = get_partname(instdisk, volidx)
curroffset += size + 1
if not lvmvols:
if swapsize:
swapsize = swapsize // sectorsize
swapsize += 2047 - (size % 2048)
end = curroffset + swapsize
if end > sectors:
end = sectors
parted.run('mkpart swap {}s {}s'.format(curroffset, end))
subprocess.check_call(['mkswap', get_partname(instdisk, volidx + 1)])
else:
parted.run('mkpart lvm {}s 100%'.format(curroffset))
lvmpart = get_partname(instdisk, volidx + 1)
subprocess.check_call(['pvcreate', '-ff', '-y', lvmpart])
subprocess.check_call(['vgcreate', 'localstorage', lvmpart])
vginfo = subprocess.check_output(['vgdisplay', 'localstorage', '--units', 'b']).decode('utf8')
vginfo = vginfo.split('\n')
pesize = 0
pes = 0
for infline in vginfo:
infline = infline.split()
if len(infline) >= 3 and infline[:2] == ['PE', 'Size']:
pesize = int(infline[2])
if len(infline) >= 5 and infline[:2] == ['Free', 'PE']:
pes = int(infline[4])
takeaway = swapsize // pesize
for volidx in lvmvols:
vol = lvmvols[volidx]
if vol is biggestfs:
continue
takeaway += vol['initsize'] // pesize
takeaway += 1
biggestextents = pes - takeaway
for volidx in lvmvols:
vol = lvmvols[volidx]
if vol is biggestfs:
extents = biggestextents
else:
extents = vol['initsize'] // pesize
extents += 1
if vol['mount'] == '/':
lvname = 'root'
else:
lvname = vol['mount'].replace('/', '_')
subprocess.check_call(['lvcreate', '-l', '{}'.format(extents), '-y', '-n', lvname, 'localstorage'])
vol['targetdisk'] = '/dev/localstorage/{}'.format(lvname)
if swapsize:
subprocess.check_call(['lvcreate', '-y', '-l', '{}'.format(swapsize // pesize), '-n', 'swap', 'localstorage'])
subprocess.check_call(['mkswap', '/dev/localstorage/swap'])
os.makedirs('/run/imginst/targ')
for vol in allvols:
with open(vol['targetdisk'], 'wb') as partition:
partition.write(b'\x00' * 1 * 1024 * 1024)
subprocess.check_call(['mkfs.{}'.format(vol['filesystem']), vol['targetdisk']])
subprocess.check_call(['mount', vol['targetdisk'], '/run/imginst/targ'])
source = vol['mount'].replace('/', '_')
source = '/run/imginst/sources/' + source
blankfsstat = os.statvfs('/run/imginst/targ')
blankused = (blankfsstat.f_blocks - blankfsstat.f_bfree) * blankfsstat.f_bsize
sys.stdout.write('\nWriting {0}: '.format(vol['mount']))
with subprocess.Popen(['cp', '-ax', source + '/.', '/run/imginst/targ']) as copier:
stillrunning = copier.poll()
lastprogress = 0.0
while stillrunning is None:
currfsstat = os.statvfs('/run/imginst/targ')
currused = (currfsstat.f_blocks - currfsstat.f_bfree) * currfsstat.f_bsize
currused -= blankused
with open('/proc/meminfo') as meminf:
for line in meminf.read().split('\n'):
if line.startswith('Dirty:'):
_, dirty, _ = line.split()
dirty = int(dirty) * 1024
progress = (currused - dirty) / vol['minsize']
if progress < lastprogress:
progress = lastprogress
if progress > 0.99:
progress = 0.99
lastprogress = progress
progress = progress * 100
sys.stdout.write('\x1b[1K\rWriting {0}: {1:3.2f}%'.format(vol['mount'], progress))
sys.stdout.flush()
time.sleep(0.5)
stillrunning = copier.poll()
if stillrunning != 0:
raise Exception("Error copying volume")
with subprocess.Popen(['sync']) as syncrun:
stillrunning = syncrun.poll()
while stillrunning is None:
with open('/proc/meminfo') as meminf:
for line in meminf.read().split('\n'):
if line.startswith('Dirty:'):
_, dirty, _ = line.split()
dirty = int(dirty) * 1024
progress = (vol['minsize'] - dirty) / vol['minsize']
if progress < lastprogress:
progress = lastprogress
if progress > 0.99:
progress = 0.99
lastprogress = progress
progress = progress * 100
sys.stdout.write('\x1b[1K\rWriting {0}: {1:3.2f}%'.format(vol['mount'], progress))
sys.stdout.flush()
time.sleep(0.5)
stillrunning = syncrun.poll()
sys.stdout.write('\x1b[1K\rDone writing {0}'.format(vol['mount']))
sys.stdout.write('\n')
sys.stdout.flush()
if vol['mount'] == '/boot':
tbootuuid = subprocess.check_output(['blkid', vol['targetdisk']])
if b'UUID="' in tbootuuid:
bootuuid = tbootuuid.split(b'UUID="', 1)[1].split(b'"')[0].decode('utf8')
subprocess.check_call(['umount', '/run/imginst/targ'])
for vol in allvols:
subprocess.check_call(['mount', vol['targetdisk'], '/run/imginst/targ/' + vol['mount']])
fixup('/run/imginst/targ', allvols)
if __name__ == '__main__':
install_to_disk(os.environ['mountsrc'])
@@ -127,11 +127,13 @@ chmod +x /sysroot/opt/confluent/bin/onboot.sh
cp /opt/confluent/bin/apiclient /sysroot/opt/confluent/bin
ln -s /etc/systemd/system/onboot.service /sysroot/etc/systemd/system/multi-user.target.wants/onboot.service
cp /etc/confluent/functions /sysroot/etc/confluent/functions
mv /lib/modules/$(uname -r) /lib/modules/$(uname -r)-ramfs
ln -s /sysroot/lib/modules/$(uname -r) /lib/modules/
mv /lib/firmware /lib/firmware-ramfs
ln -s /sysroot/lib/firmware /lib/firmware
if grep installtodisk /proc/cmdline > /dev/null; then
. /etc/confluent/functions
run_remote installimage
exec reboot -f
fi
mv /lib/modules/$(uname -r) /lib/modules/$(uname -r)-ramfs
ln -s /sysroot/lib/modules/$(uname -r) /lib/modules/
exec /opt/confluent/bin/start_root
@@ -0,0 +1,48 @@
#!/bin/bash
. /etc/confluent/functions
# the image will be used to deploy itself
# provide both access to image (for parsing metadata)
# and existing mounts of image (to take advantage of caching)
mount -o bind /sys /sysroot/sys
mount -o bind /dev /sysroot/dev
mount -o bind /proc /sysroot/proc
mount -o bind /run /sysroot/run
if [ ! -f /tmp/mountparts.sh ]; then
mkdir -p /sysroot/run/imginst/sources/_
mount -o bind /mnt/remote /sysroot/run/imginst/sources/_
else
for srcmount in $(cat /tmp/mountparts.sh | awk '{print $2}'); do
srcname=${srcmount#/dev/mapper/mproot}
srcdir=$(echo $srcmount | sed -e 's!/dev/mapper/mproot!/mnt/remote!' -e 's!_!/!g')
mkdir -p /sysroot/run/imginst/sources/$srcname
mount -o bind $srcdir /sysroot/run/imginst/sources/$srcname
done
fi
cd /sysroot/run
chroot /sysroot/ bash -c "source /etc/confluent/functions; run_remote_python getinstalldisk"
chroot /sysroot/ bash -c "source /etc/confluent/functions; run_remote_parts pre.d"
if [ ! -f /sysroot/tmp/installdisk ]; then
echo 'Unable to find a suitable installation target device, ssh to port 2222 to investigate'
while [ ! -f /sysroot/tmp/installdisk ]; do
sleep 1
done
fi
lvm vgchange -a n
udevadm control -e
if [ -f /sysroot/etc/lvm/devices/system.devices ]; then
rm /sysroot/etc/lvm/devices/system.devices
fi
chroot /sysroot /usr/lib/systemd/systemd-udevd --daemon
chroot /sysroot bash -c "source /etc/confluent/functions; run_remote_python image2disk.py"
echo "Port 22" >> /etc/ssh/sshd_config
echo 'Match LocalPort 22' >> /etc/ssh/sshd_config
echo ' ChrootDirectory /sysroot/run/imginst/targ' >> /etc/ssh/sshd_config
kill -HUP $(cat /run/sshd.pid)
cat /tls/*.pem > /sysroot/run/imginst/targ/usr/local/share/ca-certificates/confluent.crt
chroot /sysroot/run/imginst/targ update-ca-certificates
chroot /sysroot/run/imginst/targ bash -c "source /etc/confluent/functions; run_remote post.sh"
chroot /sysroot bash -c "umount \$(tac /proc/mounts|awk '{print \$2}'|grep ^/run/imginst/targ)"
@@ -0,0 +1,37 @@
#!/bin/bash
# This script is executed 'chrooted' into a cloned disk target before rebooting
#
nodename=$(grep ^NODENAME /etc/confluent/confluent.info|awk '{print $2}')
confluent_apikey=$(cat /etc/confluent/confluent.apikey)
confluent_mgr=$(grep ^deploy_server: /etc/confluent/confluent.deploycfg|awk '{print $2}')
confluent_profile=$(grep ^profile: /etc/confluent/confluent.deploycfg|awk '{print $2}')
export nodename confluent_mgr confluent_profile
. /etc/confluent/functions
mkdir -p /var/log/confluent
chmod 700 /var/log/confluent
exec >> /var/log/confluent/confluent-post.log
exec 2>> /var/log/confluent/confluent-post.log
chmod 600 /var/log/confluent/confluent-post.log
tail -f /var/log/confluent/confluent-post.log > /dev/console &
logshowpid=$!
curl -f https://$confluent_mgr/confluent-public/os/$confluent_profile/scripts/firstboot.service > /etc/systemd/system/firstboot.service
mkdir -p /opt/confluent/bin
curl -f https://$confluent_mgr/confluent-public/os/$confluent_profile/scripts/firstboot.sh > /opt/confluent/bin/firstboot.sh
chmod +x /opt/confluent/bin/firstboot.sh
systemctl enable firstboot
run_remote_python syncfileclient
run_remote_python confignet
run_remote post.custom
# post scripts may be placed into post.d, e.g. post.d/01-firstaction.sh, post.d/02-secondaction.sh
run_remote_parts post.d
# Induce execution of remote configuration, e.g. ansible plays in ansible/post.d/
run_remote_config post.d
curl -sf -X POST -d 'status: staged' -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $confluent_apikey" https://$confluent_mgr/confluent-api/self/updatestatus
kill $logshowpid
@@ -0,0 +1,286 @@
#!/usr/bin/python3
import subprocess
import importlib
import tempfile
import json
import os
import shutil
import pwd
import grp
from importlib.machinery import SourceFileLoader
try:
apiclient = SourceFileLoader('apiclient', '/opt/confluent/bin/apiclient').load_module()
except FileNotFoundError:
apiclient = SourceFileLoader('apiclient', '/etc/confluent/apiclient').load_module()
def partitionhostsline(line):
comment = ''
try:
cmdidx = line.index('#')
comment = line[cmdidx:]
line = line[:cmdidx].strip()
except ValueError:
pass
if not line:
return '', [], comment
ipaddr, names = line.split(maxsplit=1)
names = names.split()
return ipaddr, names, comment
class HostMerger(object):
def __init__(self):
self.byip = {}
self.byname = {}
self.sourcelines = []
self.targlines = []
def read_source(self, sourcefile):
with open(sourcefile, 'r') as hfile:
self.sourcelines = hfile.read().split('\n')
while not self.sourcelines[-1]:
self.sourcelines = self.sourcelines[:-1]
for x in range(len(self.sourcelines)):
line = self.sourcelines[x]
currip, names, comment = partitionhostsline(line)
if currip:
self.byip[currip] = x
for name in names:
self.byname[name] = x
def read_target(self, targetfile):
with open(targetfile, 'r') as hfile:
lines = hfile.read().split('\n')
if not lines[-1]:
lines = lines[:-1]
for y in range(len(lines)):
line = lines[y]
currip, names, comment = partitionhostsline(line)
if currip in self.byip:
x = self.byip[currip]
if self.sourcelines[x] is None:
# have already consumed this enntry
continue
self.targlines.append(self.sourcelines[x])
self.sourcelines[x] = None
continue
for name in names:
if name in self.byname:
x = self.byname[name]
if self.sourcelines[x] is None:
break
self.targlines.append(self.sourcelines[x])
self.sourcelines[x] = None
break
else:
self.targlines.append(line)
def write_out(self, targetfile):
while not self.targlines[-1]:
self.targlines = self.targlines[:-1]
if not self.targlines:
break
while not self.sourcelines[-1]:
self.sourcelines = self.sourcelines[:-1]
if not self.sourcelines:
break
with open(targetfile, 'w') as hosts:
for line in self.targlines:
hosts.write(line + '\n')
for line in self.sourcelines:
if line is not None:
hosts.write(line + '\n')
class CredMerger:
def __init__(self):
try:
with open('/etc/login.defs', 'r') as ldefs:
defs = ldefs.read().split('\n')
except FileNotFoundError:
defs = []
lkup = {}
self.discardnames = {}
self.shadowednames = {}
for line in defs:
try:
line = line[:line.index('#')]
except ValueError:
pass
keyval = line.split()
if len(keyval) < 2:
continue
lkup[keyval[0]] = keyval[1]
self.uidmin = int(lkup.get('UID_MIN', 1000))
self.uidmax = int(lkup.get('UID_MAX', 60000))
self.gidmin = int(lkup.get('GID_MIN', 1000))
self.gidmax = int(lkup.get('GID_MAX', 60000))
self.shadowlines = None
def read_passwd(self, source, targfile=False):
self.read_generic(source, self.uidmin, self.uidmax, targfile)
def read_group(self, source, targfile=False):
self.read_generic(source, self.gidmin, self.gidmax, targfile)
def read_generic(self, source, minid, maxid, targfile):
if targfile:
self.targdata = []
else:
self.sourcedata = []
with open(source, 'r') as inputfile:
for line in inputfile.read().split('\n'):
try:
name, _, uid, _ = line.split(':', 3)
uid = int(uid)
except ValueError:
continue
if targfile:
if uid < minid or uid > maxid:
self.targdata.append(line)
else:
self.discardnames[name] = 1
else:
if name[0] in ('+', '#', '@'):
self.sourcedata.append(line)
elif uid >= minid and uid <= maxid:
self.sourcedata.append(line)
def read_shadow(self, source):
self.shadowlines = []
try:
with open(source, 'r') as inshadow:
for line in inshadow.read().split('\n'):
try:
name, _ = line.split(':' , 1)
except ValueError:
continue
if name in self.discardnames:
continue
self.shadowednames[name] = 1
self.shadowlines.append(line)
except FileNotFoundError:
return
def write_out(self, outfile):
with open(outfile, 'w') as targ:
for line in self.targdata:
targ.write(line + '\n')
for line in self.sourcedata:
targ.write(line + '\n')
if outfile == '/etc/passwd':
if self.shadowlines is None:
self.read_shadow('/etc/shadow')
with open('/etc/shadow', 'w') as shadout:
for line in self.shadowlines:
shadout.write(line + '\n')
for line in self.sourcedata:
name, _ = line.split(':', 1)
if name[0] in ('+', '#', '@'):
continue
if name in self.shadowednames:
continue
shadout.write(name + ':!:::::::\n')
if outfile == '/etc/group':
if self.shadowlines is None:
self.read_shadow('/etc/gshadow')
with open('/etc/gshadow', 'w') as shadout:
for line in self.shadowlines:
shadout.write(line + '\n')
for line in self.sourcedata:
name, _ = line.split(':' , 1)
if name in self.shadowednames:
continue
shadout.write(name + ':!::\n')
def appendonce(basepath, filename):
with open(filename, 'rb') as filehdl:
thedata = filehdl.read()
targname = filename.replace(basepath, '')
try:
with open(targname, 'rb') as filehdl:
targdata = filehdl.read()
except IOError:
targdata = b''
if thedata in targdata:
return
with open(targname, 'ab') as targhdl:
targhdl.write(thedata)
def synchronize():
tmpdir = tempfile.mkdtemp()
appendoncedir = tempfile.mkdtemp()
try:
ac = apiclient.HTTPSClient()
myips = []
ipaddrs = subprocess.check_output(['ip', '-br', 'a']).split(b'\n')
for line in ipaddrs:
isa = line.split()
if len(isa) < 3 or isa[1] != b'UP':
continue
for addr in isa[2:]:
if addr.startswith(b'fe80::') or addr.startswith(b'169.254'):
continue
addr = addr.split(b'/')[0]
if not isinstance(addr, str):
addr = addr.decode('utf8')
myips.append(addr)
data = json.dumps({'merge': tmpdir, 'appendonce': appendoncedir, 'myips': myips})
status, rsp = ac.grab_url_with_status('/confluent-api/self/remotesyncfiles', data)
if status == 202:
lastrsp = ''
while status != 204:
status, rsp = ac.grab_url_with_status('/confluent-api/self/remotesyncfiles')
if not isinstance(rsp, str):
rsp = rsp.decode('utf8')
if status == 200:
lastrsp = rsp
pendpasswd = os.path.join(tmpdir, 'etc/passwd')
if os.path.exists(pendpasswd):
cm = CredMerger()
cm.read_passwd(pendpasswd, targfile=False)
cm.read_passwd('/etc/passwd', targfile=True)
cm.write_out('/etc/passwd')
pendgroup = os.path.join(tmpdir, 'etc/group')
if os.path.exists(pendgroup):
cm = CredMerger()
cm.read_group(pendgroup, targfile=False)
cm.read_group('/etc/group', targfile=True)
cm.write_out('/etc/group')
pendhosts = os.path.join(tmpdir, 'etc/hosts')
if os.path.exists(pendhosts):
cm = HostMerger()
cm.read_source(pendhosts)
cm.read_target('/etc/hosts')
cm.write_out('/etc/hosts')
for dirn in os.walk(appendoncedir):
for filen in dirn[2]:
appendonce(appendoncedir, os.path.join(dirn[0], filen))
if lastrsp:
lastrsp = json.loads(lastrsp)
opts = lastrsp.get('options', {})
for fname in opts:
uid = -1
gid = -1
for opt in opts[fname]:
if opt == 'owner':
try:
uid = pwd.getpwnam(opts[fname][opt]['name']).pw_uid
except KeyError:
uid = opts[fname][opt]['id']
elif opt == 'group':
try:
gid = grp.getgrnam(opts[fname][opt]['name']).gr_gid
except KeyError:
gid = opts[fname][opt]['id']
elif opt == 'permissions':
os.chmod(fname, int(opts[fname][opt], 8))
if uid != -1 or gid != -1:
os.chown(fname, uid, gid)
finally:
shutil.rmtree(tmpdir)
shutil.rmtree(appendoncedir)
if __name__ == '__main__':
synchronize()
@@ -9,33 +9,49 @@ MGR=$(grep ^EXTMGRINFO: /custom-installation/confluent/confluent.info |awk -F'|'
MGR=$(grep ^MANAGER: /custom-installation/confluent/confluent.info|head -n 1| awk '{print $2}')
MGTIFACE=$(grep $MGR /custom-installation/confluent/confluent.info | grep ^EXTMGRINFO: | head -n 1 | awk -F'|' '{print $2}')
oum=$(umask)
umask 077
chroot . custom-installation/confluent/bin/clortho $NODENAME $MGR > /root/custom-installation/confluent/confluent.apikey
MGR=[$MGR]
deploycfg=/root/custom-installation/confluent/confluent.deploycfg
netcfgfile=$deploycfg
umask 077
if [ -e /tmp/cnflnthmackeytmp ]; then
netcfgfile=/tmp/idnttmp
hmackeyfile=/tmp/cnflnthmackeytmp
#echo -n $(grep ^apitoken: /tmp/identdata/cnflnt.yml|awk '{print $2}') > $hmackeyfile
passfile=/tmp/cnflnttmppassfile
passcrypt=/tmp/cnflntcryptfile
hmacfile=/tmp/cnflnthmacfile
chroot . ln -sf /custom-installation/confluent/bin/clortho custom-installation/confluent/bin/genpasshmac
cp $hmackeyfile tmp
chroot . custom-installation/confluent/bin/genpasshmac $passfile $passcrypt $hmacfile $hmackeyfile
chroot . curl -f -H "CONFLUENT_NODENAME: $NODENAME" -H "CONFLUENT_CRYPTHMAC: $(cat /root/$hmacfile)" -d @/tmp/cnflntcryptfile https://$MGR/confluent-api/self/registerapikey
cp /root/$passfile /root/custom-installation/confluent/confluent.apikey
DEVICE=$(cat /tmp/autodetectnic)
else
chroot . custom-installation/confluent/bin/clortho $NODENAME $MGR > /root/custom-installation/confluent/confluent.apikey
MGR=[$MGR]
nic=$(grep ^MANAGER /custom-installation/confluent/confluent.info|grep fe80::|sed -e s/.*%//|head -n 1)
nic=$(ip link |grep ^$nic:|awk '{print $2}')
DEVICE=${nic%:}
fi
if [ -z "$MGTIFACE" ]; then
chroot . usr/bin/curl -f -H "CONFLUENT_NODENAME: $NODENAME" -H "CONFLUENT_APIKEY: $(cat /root//custom-installation/confluent/confluent.apikey)" https://${MGR}/confluent-api/self/deploycfg > $deploycfg
else
chroot . usr/bin/curl -f -H "CONFLUENT_MGTIFACE: $MGTIFACE" -H "CONFLUENT_NODENAME: $NODENAME" -H "CONFLUENT_APIKEY: $(cat /root//custom-installation/confluent/confluent.apikey)" https://${MGR}/confluent-api/self/deploycfg > $deploycfg
fi
umask $oum
nic=$(grep ^MANAGER /custom-installation/confluent/confluent.info|grep fe80::|sed -e s/.*%//|head -n 1)
nic=$(ip link |grep ^$nic:|awk '{print $2}')
DEVICE=${nic%:}
ipv4m=$(grep ^ipv4_method $deploycfg|awk '{print$2}')
ipv4m=$(grep ^ipv4_method $netcfgfile|awk '{print$2}')
. /scripts/functions
if [ "$ipv4m" = "dhcp" ]; then
IP=dhcp
configure_networking
elif [ "$ipv4m" = "static" ]; then
v4addr=$(grep ^ipv4_address: $deploycfg)
v4addr=$(grep ^ipv4_address: $netcfgfile| sed -e 's!/.*!!')
v4addr=${v4addr#ipv4_address: }
v4gw=$(grep ^ipv4_gateway: $deploycfg)
v4gw=$(grep ^ipv4_gateway: $netcfgfile)
v4gw=${v4gw#ipv4_gateway: }
if [ "$v4gw" = "null" ]; then
v4gw=""
fi
v4nm=$(grep ipv4_netmask: $deploycfg)
v4nm=$(grep ipv4_netmask: $netcfgfile)
v4nm=${v4nm#ipv4_netmask: }
dnsdomain=$(grep ^dnsdomain: $deploycfg)
dnsdomain=${dnsdomain#dnsdomain: }
@@ -5,10 +5,70 @@ done
mkdir -p /custom-installation
cp -a /opt/confluent /custom-installation
touch /custom-installation/confluent/confluent.info
while ! grep NODENAME /custom-installation/confluent/confluent.info; do
/opt/confluent/bin/copernicus -t > /custom-installation/confluent/confluent.info
TRIES=5
while [ ! -e /dev/disk/by-label ] && [ $TRIES -gt 0 ]; do
sleep 2
TRIES=$((TRIES - 1))
done
MGR="[$(grep MANAGER: /custom-installation/confluent/confluent.info | head -n 1 | awk '{print $2}')]"
if [ -e /dev/disk/by-label/CNFLNT_IDNT ]; then
tmnt=/tmp/idntmnt
mkdir -p /tmp/identdata/
mkdir -p $tmnt
tcfg=/tmp/idnttmp
mount /dev/disk/by-label/CNFLNT_IDNT $tmnt
cp -a $tmnt/* /tmp/identdata/
cd $tmnt
deploysrvs=$(sed -n '/^deploy_servers:/,/^[^-]/p' cnflnt.yml |grep ^-|sed -e 's/^- //'|grep -v :)
sed -n '/^net_cfgs:/,/^[^- ]/{/^[^- ]/!p}' cnflnt.yml |sed -n '/^-/,/^-/{/^-/!p}'| sed -e 's/^[- ]*//'> $tcfg
autoconfigmethod=$(grep ^ipv4_method: $tcfg)
autoconfigmethod=${autoconfigmethod#ipv4_method: }
. /scripts/functions
if [ "$autoconfigmethod" = "static" ]; then
MYIP=$(grep ^ipv4_address: $tcfg | awk '{print $2}'|sed -e s'!/.*!!')
v4addr=$(grep ^ipv4_address: $tcfg|cut -d: -f 2|sed -e 's/ //')
MYGW=$(grep ^ipv4_gateway: $tcfg | awk '{print $2}')
if [ "$MYGW" = "null" ]; then
MYGW=""
fi
MYNM=$(grep ^ipv4_netmask: $tcfg | awk '{print $2}')
for NICGUESS in $(ip link|grep LOWER_UP|grep -v LOOPBACK|cut -d ' ' -f 2 | sed -e 's/:$//'); do
ip addr add dev $NICGUESS $v4addr
if [ ! -z "$MYGW" ]; then
ip route add default via $MYGW
fi
for dsrv in $deploysrvs; do
if openssl s_client -connect $dsrv:443 > /dev/null 2>&1; then
deploysrvs=$dsrv
NIC=$NICGUESS
break
fi
done
if [ -z "$NIC" ]; then
ip -4 a flush dev $NICGUESS
else
break
fi
done
ipconfig -d $MYIP::$MYGW:$MYNM::$NIC
echo $NIC > /tmp/autodetectnic
else
configure_networking
fi
MGR=$deploysrvs
NODENAME=$(grep ^nodename: /tmp/idntmnt/cnflnt.yml | awk '{print $2}')
echo "NODENAME: $NODENAME" >> /custom-installation/confluent/confluent.info
echo "MANAGER: $MGR" >> /custom-installation/confluent/confluent.info
echo "EXTMGRINFO: $MGR||1" >> /custom-installation/confluent/confluent.info
hmackeyfile=/tmp/cnflnthmackeytmp
echo -n $(grep ^apitoken: cnflnt.yml|awk '{print $2}') > $hmackeyfile
cd -
umount $tmnt
else
while ! grep NODENAME /custom-installation/confluent/confluent.info; do
/opt/confluent/bin/copernicus -t > /custom-installation/confluent/confluent.info
done
MGR="[$(grep MANAGER: /custom-installation/confluent/confluent.info | head -n 1 | awk '{print $2}')]"
fi
osprofile=$(sed -e 's/.*osprofile=//' -e 's/ .*//' /proc/cmdline)
cat /proc/cmdline > /custom-installation/confluent/cmdline.orig
if [ -f /custom-installation/autocons.info ]; then
@@ -1,5 +1,8 @@
#!/bin/bash
echo "Confluent first boot is running"
HOME=$(getent passwd $(whoami)|cut -d: -f 6)
export HOME
seems a potentially relevant thing to put i... by Jarrod Johnson
cp -a /etc/confluent/ssh/* /etc/ssh/
systemctl restart sshd
rootpw=$(grep ^rootpassword: /etc/confluent/confluent.deploycfg |awk '{print $2}')
@@ -1,10 +1,10 @@
#!/bin/bash
function test_mgr() {
whost=$1
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
if curl -s https://${whost}/confluent-api/ > /dev/null; then
if curl -gs https://${whost}/confluent-api/ > /dev/null; then
return 0
fi
return 1
@@ -63,10 +63,10 @@ fetch_remote() {
set_confluent_vars
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -f -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo $1 failed to download; return 1; fi
}
@@ -174,10 +174,10 @@ run_remote_python() {
cd $confluentscripttmpdir
mkdir -p $(dirname $1)
whost=$confluent_mgr
if [[ "$whost" == *:* ]]; then
if [[ "$whost" == *:* ]] && [[ "$whost" != *[* ]] ; then
whost="[$whost]"
fi
curl -f -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
curl -gf -sS $curlargs https://$whost/confluent-public/os/$confluent_profile/scripts/$1 > $1
if [ $? != 0 ]; then echo "'$*'" failed to download; return 1; fi
confluentpython $*
retcode=$?
@@ -74,8 +74,11 @@ if [ -e /sys/firmware/efi ]; then
fi
fi
cat /target/etc/confluent/tls/*.pem > /target/etc/confluent/ca.pem
cat /target/etc/confluent/tls/*.pem > /target/usr/local/share/ca-certificates/confluent.crt
cat /target/etc/confluent/tls/*.pem > /etc/confluent/ca.pem
chroot /target update-ca-certificates
chroot /target bash -c "source /etc/confluent/functions; run_remote_python syncfileclient"
chroot /target bash -c "source /etc/confluent/functions; run_remote_python confignet"
chroot /target bash -c "source /etc/confluent/functions; run_remote_parts post.d"
source /target/etc/confluent/functions
+1
View File
@@ -0,0 +1 @@
ubuntu20.04-diskless
@@ -11,32 +11,48 @@ MGR=$(grep ^MANAGER: /custom-installation/confluent/confluent.info|head -n 1| aw
MGTIFACE=$(grep $MGR /custom-installation/confluent/confluent.info | grep ^EXTMGRINFO: | head -n 1 | awk -F'|' '{print $2}')
oum=$(umask)
umask 077
chroot . custom-installation/confluent/bin/clortho $NODENAME $MGR > /root/custom-installation/confluent/confluent.apikey
MGR=[$MGR]
deploycfg=/root/custom-installation/confluent/confluent.deploycfg
netcfgfile=$deploycfg
if [ -e /tmp/cnflnthmackeytmp ]; then
netcfgfile=/tmp/idnttmp
hmackeyfile=/tmp/cnflnthmackeytmp
#echo -n $(grep ^apitoken: /tmp/identdata/cnflnt.yml|awk '{print $2}') > $hmackeyfile
passfile=/tmp/cnflnttmppassfile
passcrypt=/tmp/cnflntcryptfile
hmacfile=/tmp/cnflnthmacfile
chroot . ln -sf /custom-installation/confluent/bin/clortho custom-installation/confluent/bin/genpasshmac
cp $hmackeyfile tmp
chroot . custom-installation/confluent/bin/genpasshmac $passfile $passcrypt $hmacfile $hmackeyfile
chroot . curl -f -H "CONFLUENT_NODENAME: $NODENAME" -H "CONFLUENT_CRYPTHMAC: $(cat /root/$hmacfile)" -d @/tmp/cnflntcryptfile https://$MGR/confluent-api/self/registerapikey
cp /root/$passfile /root/custom-installation/confluent/confluent.apikey
DEVICE=$(cat /tmp/autodetectnic)
else
chroot . custom-installation/confluent/bin/clortho $NODENAME $MGR > /root/custom-installation/confluent/confluent.apikey
MGR=[$MGR]
nic=$(grep ^MANAGER /custom-installation/confluent/confluent.info|grep fe80::|sed -e s/.*%//|head -n 1)
nic=$(ip link |grep ^$nic:|awk '{print $2}')
DEVICE=${nic%:}
fi
if [ -z "$MGTIFACE" ]; then
chroot . usr/bin/curl -f -H "CONFLUENT_NODENAME: $NODENAME" -H "CONFLUENT_APIKEY: $(cat /root//custom-installation/confluent/confluent.apikey)" https://${MGR}/confluent-api/self/deploycfg > $deploycfg
else
chroot . usr/bin/curl -f -H "CONFLUENT_MGTIFACE: $MGTIFACE" -H "CONFLUENT_NODENAME: $NODENAME" -H "CONFLUENT_APIKEY: $(cat /root//custom-installation/confluent/confluent.apikey)" https://${MGR}/confluent-api/self/deploycfg > $deploycfg
fi
umask $oum
nic=$(grep ^MANAGER /custom-installation/confluent/confluent.info|grep fe80::|sed -e s/.*%//|head -n 1)
nic=$(ip link |grep ^$nic:|awk '{print $2}')
DEVICE=${nic%:}
ipv4m=$(grep ^ipv4_method $deploycfg|awk '{print$2}')
ipv4m=$(grep ^ipv4_method $netcfgfile|awk '{print$2}')
. /scripts/functions
if [ "$ipv4m" = "dhcp" ]; then
IP=dhcp
configure_networking
elif [ "$ipv4m" = "static" ]; then
v4addr=$(grep ^ipv4_address: $deploycfg)
v4addr=$(grep ^ipv4_address: $netcfgfile | sed -e 's!/.*!!')
v4addr=${v4addr#ipv4_address: }
v4gw=$(grep ^ipv4_gateway: $deploycfg)
v4gw=$(grep ^ipv4_gateway: $netcfgfile)
v4gw=${v4gw#ipv4_gateway: }
if [ "$v4gw" = "null" ]; then
v4gw=""
fi
v4nm=$(grep ipv4_netmask: $deploycfg)
v4nm=$(grep ipv4_netmask: $netcfgfile)
v4nm=${v4nm#ipv4_netmask: }
dnsdomain=$(grep ^dnsdomain: $deploycfg)
dnsdomain=${dnsdomain#dnsdomain: }
@@ -5,10 +5,70 @@ done
mkdir -p /custom-installation
cp -a /opt/confluent /custom-installation
touch /custom-installation/confluent/confluent.info
while ! grep NODENAME /custom-installation/confluent/confluent.info; do
/opt/confluent/bin/copernicus -t > /custom-installation/confluent/confluent.info
TRIES=5
while [ ! -e /dev/disk/by-label ] && [ $TRIES -gt 0 ]; do
sleep 2
TRIES=$((TRIES - 1))
done
MGR="[$(grep MANAGER: /custom-installation/confluent/confluent.info | head -n 1 | awk '{print $2}')]"
if [ -e /dev/disk/by-label/CNFLNT_IDNT ]; then
tmnt=/tmp/idntmnt
mkdir -p /tmp/identdata/
mkdir -p $tmnt
tcfg=/tmp/idnttmp
mount /dev/disk/by-label/CNFLNT_IDNT $tmnt
cp -a $tmnt/* /tmp/identdata/
cd $tmnt
deploysrvs=$(sed -n '/^deploy_servers:/,/^[^-]/p' cnflnt.yml |grep ^-|sed -e 's/^- //'|grep -v :)
sed -n '/^net_cfgs:/,/^[^- ]/{/^[^- ]/!p}' cnflnt.yml |sed -n '/^-/,/^-/{/^-/!p}'| sed -e 's/^[- ]*//'> $tcfg
autoconfigmethod=$(grep ^ipv4_method: $tcfg)
autoconfigmethod=${autoconfigmethod#ipv4_method: }
. /scripts/functions
if [ "$autoconfigmethod" = "static" ]; then
MYIP=$(grep ^ipv4_address: $tcfg | awk '{print $2}'|sed -e s'!/.*!!')
v4addr=$(grep ^ipv4_address: $tcfg|cut -d: -f 2|sed -e 's/ //')
MYGW=$(grep ^ipv4_gateway: $tcfg | awk '{print $2}')
if [ "$MYGW" = "null" ]; then
MYGW=""
fi
MYNM=$(grep ^ipv4_netmask: $tcfg | awk '{print $2}')
for NICGUESS in $(ip link|grep LOWER_UP|grep -v LOOPBACK|cut -d ' ' -f 2 | sed -e 's/:$//'); do
ip addr add dev $NICGUESS $v4addr
if [ ! -z "$MYGW" ]; then
ip route add default via $MYGW
fi
for dsrv in $deploysrvs; do
if openssl s_client -connect $dsrv:443 > /dev/null 2>&1; then
deploysrvs=$dsrv
NIC=$NICGUESS
break
fi
done
if [ -z "$NIC" ]; then
ip -4 a flush dev $NICGUESS
else
break
fi
done
ipconfig -d $MYIP::$MYGW:$MYNM::$NIC
echo $NIC > /tmp/autodetectnic
else
configure_networking
fi
MGR=$deploysrvs
NODENAME=$(grep ^nodename: /tmp/idntmnt/cnflnt.yml | awk '{print $2}')
echo "NODENAME: $NODENAME" >> /custom-installation/confluent/confluent.info
echo "MANAGER: $MGR" >> /custom-installation/confluent/confluent.info
echo "EXTMGRINFO: $MGR||1" >> /custom-installation/confluent/confluent.info
hmackeyfile=/tmp/cnflnthmackeytmp
echo -n $(grep ^apitoken: cnflnt.yml|awk '{print $2}') > $hmackeyfile
cd -
umount $tmnt
else
while ! grep NODENAME /custom-installation/confluent/confluent.info; do
/opt/confluent/bin/copernicus -t > /custom-installation/confluent/confluent.info
done
MGR="[$(grep MANAGER: /custom-installation/confluent/confluent.info | head -n 1 | awk '{print $2}')]"
fi
osprofile=$(sed -e 's/.*osprofile=//' -e 's/ .*//' /proc/cmdline)
cat /proc/cmdline > /custom-installation/confluent/cmdline.orig
if [ -f /custom-installation/autocons.info ]; then

Some files were not shown because too many files have changed in this diff Show More