-
-
Notifications
You must be signed in to change notification settings - Fork 779
Pants+Packaging: Add makeself_archive for each pack to facilitate installation
#6311
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There is some legacy bits in st2-packages.git that attempt to pull the packs group and system user from /etc/st2/st2.conf. But, that code is not in use. Effectively, the user/group names have been hard-coded. Rather than preserve an unused install feature, the pants+nfpm based system package build will use hard-coded group/user names.
| f"/opt/stackstorm/packs/{pack_name}", | ||
| # reproducibility flags: | ||
| "--tar-extra", # extra tar args: '--arg=value' (equals delimited) space separated | ||
| f"--owner=root --group={ST2_PACKS_GROUP} --mtime={MTIME} --exclude=LICENSE", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| f"--owner=root --group={ST2_PACKS_GROUP} --mtime={MTIME} --exclude=LICENSE", | |
| f"--owner=root --group={ST2_PACKS_GROUP} --mtime={MTIME}", |
Should the LICENSE file be installed with the pack like this? If we install it, it will end up as /opt/StackStorm/packs/<pack>/LICENSE even though the LICENSE file is not in the pack directory in our git repo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pack licence is that of st2, so there's no need to install a copy in each pack directory in my opinion.
Background
Pack install
There are several packs that get installed with st2 (Installing via the deb/rpm is the only official way to get these):
chatopscoredefaultlinuxpacksUnlike exchange packs, these 5 packs are not git repos, so if anyone makes a change (for shame 😉), there isn't a simple way to revert the pack without reinstalling the st2 rpm/deb.
There are 3 other packs in the st2 repo:
examplesexamplespack gets installed under/usr/share/doc/st2/examples. The official way to install that pack is to copy it manually: https://docs.stackstorm.com/start.html#start-deploy-exampleshello_st2hello_st2pack is only for a docs tutorial on creating packs, so there is no official way to install it: https://docs.stackstorm.com/reference/packs.html#creating-your-first-packdebugdebugpack is a much more recent pack added in Add a debug contrib pack #5155, but it is not mentioned in the docs and there is no official install method.Pantsbuild + nFPM
Once we start building rpm/deb packages with pants + nfpm, we will need to enumerate all of the files that go in the rpm/deb packages. Pants runs nfpm in a sandbox, and pants does not have a way to populate the sandbox with file owner, file group, file permissions (except the execute bit which is also the only thing git can persist), or file modification times. nFPM has a feature that allows it to include a
treeof files, but that pulls the file owner, file group, file permissions and file modification times from the tree of files, so pants does not expose that nFPM feature. Instead, each file--with all of its file attributes--must be explicitly defined in BUILD metadata.For most of the files in our rpm/deb file, that pants+nfpm limitation is a non-issue; we were already defining those explicitly in the deb control files and rpm spec files. The big exception to that is packs. Listing each file in a pack sounds very onerous and error prone. All of the pack files have uniform file attributes (except for the execute bit, but everything has a way to deal with that difference).
Solution: Pants + Makeself
So, I looked for a way to package an archive of each pack's contents, and then include that archive in the rpm/deb. During installation, the post-install (or similar) scriptlet would be responsible for unpacking those archives under
/opt/stackstorm/packs.Someone in the pants community slack pointed me towards a nifty tool that pants has an integration for:
makeself. This tool makes it relatively simple to build self-extracting archives with very few runtime deps. These are the relevant pants docs about it:Packaging the 8 in-repo st2 packs via pants
makeself_archivetargets has several benefits:So, this PR adds a
makeself_archivetarget in pants BUILD metadata for each of the packs undercontrib/. Since these all need to be built the same, I created thest2_pack_archivemacro inpants-plugins/macros.py(see the docs about macros).The first step in using
makeselfis enabling the pantsmakeselfbackend:st2/pants.toml
Lines 30 to 31 in 940fb13
Macro Name Note: All of our other macros are prefixed with
st2_and targets defined in actual plugins (not macros) do not have that prefix. So, this uses thest2_prefix as well.The simpleast usage of the
st2_pack_archivemacro is for thedefaultpack:st2/contrib/default/BUILD
Lines 7 to 11 in 940fb13
The
:metadatatarget is ourpack_metadatatarget (implemented bypants-plugins/pack_metadata).Markdown files in packs
So far,
pack_metadatadid not include markdown files--which should be distributed with the pack--so I added**/*.mdto the default sources list:st2/pants-plugins/pack_metadata/target_types.py
Line 129 in 940fb13
And registered markdown files as the new resource type
pack_dochere:st2/pants-plugins/pack_metadata/target_types.py
Lines 90 to 91 in 940fb13
st2_pack_archiveusageThe chatops pack has non-metadata files (python actions) and test files that need to be included in the installed pack. So, we register these as deps here:
st2/contrib/chatops/BUILD
Lines 7 to 13 in 940fb13
This, however caused a visibility error because tests have
__dependents_rules__that block anything outside of the tests directory from depending on the tests. So, I added an exception for the:filestarget (which is created in thest2_pack_archivemacro and is described further below) like this:st2/contrib/chatops/tests/BUILD
Lines 1 to 2 in 940fb13
In this,
build_file_dir()returns a pathlib.Path object that we can use to reference the parent directory. We have to use this instead of../because pants does not support relative parent paths in dependencies. So, the//anchors the address at the root of the repo, and thenbuild_file_dir().parentpicks the pack's directory (the parent of tests) without hardcoding the absolute path. This should make any future refactoring more seamless as fewer places need to be updated if a pack dir is moved/renamed.The
corepack also needs to include itsrequirements.txtfile (Which is owned by thepython_requirementstarget named:reqs), as well as a shell script in actions (./actionspulls in the python, and./actions/send_mail:send_mail_resourcespulls in the shell script).st2/contrib/core/BUILD
Lines 21 to 29 in 940fb13
Unlike the
corepack, thehello_st2andexamplespacks do not havepython_requirementstargets. And, we don't want pants to pull requirements from that file as having the same requirement in multiple requirements files (in this caserequirements-pants.txtand the packrequirements.txtfile) causes problems for pants dep inferrence. So, I had to remove these requirements files from the pants ignore list (inpants.toml) and add afilestarget (instead of apython_requirementstarget) to own that file:st2/contrib/hello_st2/BUILD
Lines 7 to 12 in 940fb13
st2/contrib/examples/BUILD
Lines 22 to 26 in 940fb13
The
examplespack has the most complex usage ofst2_pack_archivebecause, sadly, transitive deps do not get included, so I had to list a bunch of deps:st2/contrib/examples/BUILD
Lines 28 to 46 in 940fb13
The other packs are similar.
st2_pack_archiveimplementationst2_pack_archiveis a macro function:st2/pants-plugins/macros.py
Lines 120 to 124 in 940fb13
First we get the directory of the BUILD file and return without creating any targets if the pack is in
st2tests/. This is important because thecontrib/corepack is symlinked under st2tests, and we only want to create an archive for the pack once.st2/pants-plugins/macros.py
Lines 125 to 129 in 940fb13
There are many packs in
st2testswithpack_metadatatargets, but they do not need pack archives for distribution. That's why I keptpack_metadataseparate fromst2_pack_archive. It's a very good thing that pants macros do not have to create targets, allowing us to return early in this case.Next, the macro ensures that a dep on
:metadatais always present, even if we don't explicitly provide it in the BUILD file that usesst2_pack_archive. I did explicitly include:metadata, so this is a safety mechanism for future development where we might add a new pack.st2/pants-plugins/macros.py
Lines 132 to 134 in 940fb13
:filestargetI mentioned the
:filestarget above. One of the quirks ofmakeself_archivetargets is that they only includefilestargets. So anything that ispython_sources,shell_sources,resources, or other targets will be silently excluded from the makeself archive. So, I needed a way to treat all these targets--all of the targets listed independencies--asfilestargets. There are some experimental pants targets that allow for treating targets as if they werepython_sources(experimental_wrap_as_python_sources) orresources(experimental_wrap_as_resources). But there is noexperimental_wrap_as_filestarget, so I needed a different way to capture the dependencies as files. I usedshell_commandto do this:st2/pants-plugins/macros.py
Lines 136 to 143 in 940fb13
The command
trueserves as a "noop" of sorts. The key pieces of this areexecution_dependencieswhich causes all of the deps to go in this noop command's sandbox, thenoutput_directories=["."]says to capture all output files in the BUILD file's directory in the sandbox, androot_output_directory="."makes pants strip the BUILD file directory so that all of the files in the pack end up at the root of the makeself archive.Finally, we build the
makeself_archivewith a convenientlabelthat gets printed when the archive extracts itself:st2/pants-plugins/macros.py
Lines 147 to 149 in 940fb13
Next we include all of the pack files by putting
:filesin files:st2/pants-plugins/macros.py
Lines 150 to 153 in 940fb13
I also included the LICENSE file so that the makeself archive can prompt the user to accept the license before unpacking. I configured that makeself feature here with
--license:st2/pants-plugins/macros.py
Lines 154 to 157 in 940fb13
Then, we pre-configure the archive so it will extract itself under
/opt/stackstorm/packs:st2/pants-plugins/macros.py
Lines 158 to 159 in 940fb13
And we configure the pack file permissions/attributes using args that get passed through to tar. Note that st2-packages uses owner
rootand groupst2packsfor everything in/opt/stackstorm/packs(1, 2, 3 and 4), but this uses root as the group temporarily. a follow-up PR will handle adding thest2packsgroup. We also set all timestamps to the value ofMTIMEso that the build is repeatable - no matter when we build an archive from a given commit, it will always generate exactly the same archive byte-for-byte.st2/pants-plugins/macros.py
Lines 164 to 168 in 1a66cef
ST2_PACKS_GROUPS is defined here. There was some logic in st2-packages that attempted to pull the user/group from
st2.conf(here), but that code was not actually used anywhere (there's even a comment saying "NOT USED!"), so the group name is effectively hardcoded asst2packs(1, 2, 3). Plus, we're already hard-coding the group in the systemd files (here and here), so I went with hard-coding it here:st2/pants-plugins/macros.py
Lines 119 to 120 in 1a66cef
MTIME is defined here, using the same value used by pex (thus, this will be the timestamp of
/opt/stackstorm/st2once unpacked using the pex added in #6307):st2/pants-plugins/macros.py
Lines 115 to 117 in 940fb13
Using a
makeself_archiveThese examples use the
chatopspack, but could just as easily use any of the other 7 packs.To package the
chatopspack run:Or to be more precise, you could use the target name like this
Then, you can run the pack to install it (/opt/stackstorm/packs should already exist):
Or to test it with a temp directory:
This is how the post-install deb/rpm script will unpack the pack archive (packaging scriptlets run as root):
The license gets piped through the PAGER before allowing the user to accept the license, even if auto accept is on the command line, using
PAGER=catensures this does not pause the automated install.And, to populate
/usr/share/docs/st2/examplesusing the archive, the post-install script would do: