Skip to content

Commit

Permalink
pack: fix error with custom pre/post scripts
Browse files Browse the repository at this point in the history
Fixed: if a user provides pre or post install script to `tt pack rpm`,
it uses script file name instead of its content.
  • Loading branch information
psergee committed Feb 20, 2024
1 parent b3d0554 commit 0c4bf4f
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 22 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ empty, for example.
between local system and docker container. Install current `tt` version
in docker image if possible.
- `tt binaries list` invalid argument error if `tarantool` is not a symlink.
- if a user provides pre or post install script to `tt pack rpm`, it
uses file name as a script instead of its content.

## [2.1.2] - 2024-02-02

Expand Down
20 changes: 7 additions & 13 deletions cli/pack/deb_control_dir.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package pack

import (
_ "embed"
"fmt"
"os"
"path/filepath"
Expand Down Expand Up @@ -180,9 +181,9 @@ func getLexer() *stateful.Definition {
func initScript(destDirPath, scriptName string, mp map[string]interface{}) error {
var scriptTemplate string
if scriptName == PostInstScriptName {
scriptTemplate = PostInstScriptContent
scriptTemplate = postInstScriptContent
} else if scriptName == PreInstScriptName {
scriptTemplate = PreInstScriptContent
scriptTemplate = debPreInstScriptContent
}

text, err := util.GetTextTemplatedStr(&scriptTemplate, mp)
Expand All @@ -196,6 +197,9 @@ func initScript(destDirPath, scriptName string, mp map[string]interface{}) error
return nil
}

//go:embed templates/deb_preinst.sh
var debPreInstScriptContent string

const (
defaultMaintainer = "Tarantool developer"

Expand All @@ -207,15 +211,5 @@ Description: Tarantool environment: {{ .Name }}
Depends: {{ .Depends }}
`
PreInstScriptContent = `/bin/sh -c 'groupadd -r tarantool > /dev/null 2>&1 || :'
/bin/sh -c 'useradd -M -N -g tarantool -r -d /var/lib/tarantool -s /sbin/nologin \
-c "Tarantool Server" tarantool > /dev/null 2>&1 || :'
/bin/sh -c 'mkdir -p /etc/tarantool/conf.d/ --mode 755 2>&1 || :'
/bin/sh -c 'mkdir -p /var/lib/tarantool/ --mode 755 2>&1 || :'
/bin/sh -c 'chown tarantool:tarantool /var/lib/tarantool 2>&1 || :'
/bin/sh -c 'mkdir -p /var/run/tarantool/ --mode 755 2>&1 || :'
/bin/sh -c 'chown tarantool:tarantool /var/run/tarantool 2>&1 || :'
`

PostInstScriptContent = ``
postInstScriptContent = ``
)
36 changes: 29 additions & 7 deletions cli/pack/rpm_header.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package pack

import (
_ "embed"
"fmt"
"io/fs"
"os"
Expand Down Expand Up @@ -88,15 +89,36 @@ func addDependenciesRPM(rpmHeader *rpmTagSetType, deps PackDependencies) {
}...)
}

//go:embed templates/rpm_preinst.sh
var rpmPreInstScriptContent string

// addPreAndPostInstallScriptsRPM writes passed paths of pre-install
// and post-install scripts to the rpm header.
func addPreAndPostInstallScriptsRPM(rpmHeader *rpmTagSetType, preInst string, postInst string) {
func addPreAndPostInstallScriptsRPM(rpmHeader *rpmTagSetType,
preInst string, postInst string) error {
preInstScript := rpmPreInstScriptContent
if preInst != "" {
userPreInstBytes, err := os.ReadFile(preInst)
if err != nil {
return fmt.Errorf("error reading preinst file %q: %s", preInst, err)
}
preInstScript += "\n" + string(userPreInstBytes)
}

postInstScript := postInstScriptContent
if preInst != "" {
userPostInstBytes, err := os.ReadFile(postInst)
if err != nil {
return fmt.Errorf("error reading postinst file %q: %s", postInst, err)
}
postInstScript += "\n" + string(userPostInstBytes)
}

rpmHeader.addTags([]rpmTagType{
{ID: tagPrein, Type: rpmTypeString,
Value: strings.Join([]string{PreInstScriptContent, preInst}, "\n")},
{ID: tagPostin, Type: rpmTypeString,
Value: postInst},
{ID: tagPrein, Type: rpmTypeString, Value: preInstScript},
{ID: tagPostin, Type: rpmTypeString, Value: postInstScript},
}...)
return nil
}

// genRpmHeader generates rpm headers.
Expand Down Expand Up @@ -189,10 +211,10 @@ func genRpmHeader(relPaths []string, cpioPath, compresedCpioPath, packageFilesDi
}

addDependenciesRPM(&rpmHeader, deps)
addPreAndPostInstallScriptsRPM(&rpmHeader, packCtx.RpmDeb.PreInst,
err = addPreAndPostInstallScriptsRPM(&rpmHeader, packCtx.RpmDeb.PreInst,
packCtx.RpmDeb.PostInst)

return rpmHeader, nil
return rpmHeader, err
}

// getFilesInfo returns the meta information about all items inside the passed
Expand Down
12 changes: 12 additions & 0 deletions cli/pack/templates/deb_preinst.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/sh

set -e

SYSUSER=tarantool

if ! id "$SYSUSER" >/dev/null 2>&1; then
/usr/sbin/groupadd -r $SYSUSER >/dev/null 2>&1

/usr/sbin/useradd -M -N -g $SYSUSER -r -d /var/lib/tarantool -s /sbin/nologin \
-c "Tarantool Server" $SYSUSER >/dev/null 2>&1
fi
8 changes: 8 additions & 0 deletions cli/pack/templates/rpm_preinst.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
SYSUSER=tarantool

if ! id "$SYSUSER" >/dev/null 2>&1; then
/usr/sbin/groupadd -r $SYSUSER >/dev/null 2>&1 || :

/usr/sbin/useradd -M -N -g $SYSUSER -r -d /var/lib/tarantool -s /sbin/nologin \
-c "Tarantool Server" $SYSUSER >/dev/null 2>&1 || :
fi
64 changes: 62 additions & 2 deletions test/integration/pack/test_pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -1045,13 +1045,17 @@ def test_pack_deb(tt_cmd, tmpdir):
'&& cat /usr/lib/systemd/system/app1.service'
' /usr/lib/systemd/system/[email protected] '
' /usr/share/tarantool/bundle1/tt.yaml '
'&& dpkg -x {0} /tmp/unpack'
.format(package_file_name)])
'&& id tarantool '
' && dpkg -x {0} /tmp/unpack '
' && chown {1}:{2} /tmp/unpack -R'.
format(package_file_name, os.getuid(), os.getgid())
])
assert rc == 0

assert re.search(r'Preparing to unpack {0}'.format(package_file_name), output)
assert re.search(r'Unpacking bundle1 \(0\.1\.0\)', output)
assert re.search(r'Setting up bundle1 \(0\.1\.0\)', output)
assert re.search(r'uid=\d+\(tarantool\) gid=\d+\(tarantool\) groups=\d+\(tarantool\)', output)

installed_package_paths = ['app.lua', 'app2', 'instances.enabled', config_name]
systemd_units = ['app1.service', '[email protected]']
Expand Down Expand Up @@ -1118,12 +1122,15 @@ def test_pack_rpm(tt_cmd, tmpdir):
'&& cat /usr/lib/systemd/system/app1.service'
' /usr/lib/systemd/system/[email protected] '
' /usr/share/tarantool/bundle1/tt.yaml '
'&& id tarantool '
'&& rpm2cpio {0} > /tmp/unpack/pkg.cpio'
.format(package_file_name)])
assert rc == 0
installed_package_paths = ['app.lua', 'app2', 'instances.enabled', config_name]
systemd_units = ['app1.service', '[email protected]']

assert re.search(r'uid=\d+\(tarantool\) gid=\d+\(tarantool\) groups=\d+\(tarantool\)', output)

for path in installed_package_paths:
assert re.search(path, output)
for unit in systemd_units:
Expand Down Expand Up @@ -1326,3 +1333,56 @@ def test_pack_deb_use_docker(tt_cmd, tmpdir):
re.search(path, output)

assert rc == 0


@pytest.mark.slow
def test_pack_rpm_with_pre_and_post_inst(tt_cmd, tmpdir):
if shutil.which('docker') is None:
pytest.skip("docker is not installed in this system")

# check if docker daemon is up
rc, _ = run_command_and_get_output(['docker', 'ps'])
assert rc == 0

tmpdir = os.path.join(tmpdir, "bundle1")
shutil.copytree(os.path.join(os.path.dirname(__file__), "test_bundles", "bundle1"),
tmpdir, symlinks=True, ignore=None,
copy_function=shutil.copy2, ignore_dangling_symlinks=True,
dirs_exist_ok=True)

base_dir = tmpdir

with open(os.path.join(tmpdir, "preinst.sh"), "w") as pre_inst:
pre_inst.write("echo 'hello'")
with open(os.path.join(tmpdir, "postinst.sh"), "w") as post_inst:
post_inst.write("echo 'bye'")

cmd = [tt_cmd, "pack", "rpm", "--preinst", os.path.join(tmpdir, "preinst.sh"),
"--postinst", os.path.join(tmpdir, "postinst.sh")]

rc, output = run_command_and_get_output(
cmd,
cwd=base_dir, env=dict(os.environ, PWD=tmpdir))
assert rc == 0

package_file_name = "bundle1-0.1.0.0-1." + get_arch() + ".rpm"
package_file = os.path.join(base_dir, package_file_name)
assert os.path.isfile(package_file)

rc, output = run_command_and_get_output(['docker', 'run', '--rm', '-v',
'{0}:/usr/src/'.format(base_dir),
'-w', '/usr/src',
'jrei/systemd-fedora',
'/bin/bash', '-c',
'rpm -qp --scripts {0} '
.format(package_file_name)])
assert rc == 0

assert """preinstall scriptlet (using /bin/sh):
SYSUSER=tarantool
""" in output
assert "echo 'hello'" in output
assert """postinstall scriptlet (using /bin/sh):
echo 'bye'
""" in output

0 comments on commit 0c4bf4f

Please sign in to comment.