mirror of
https://github.com/mudler/luet.git
synced 2025-06-27 07:50:18 +00:00
Merge pull request #119 from mudler/config-protect
Integrate feature config-protect like Gentoo/Funtoo do
This commit is contained in:
commit
7b51e83902
@ -19,6 +19,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
config "github.com/mudler/luet/pkg/config"
|
config "github.com/mudler/luet/pkg/config"
|
||||||
|
installer "github.com/mudler/luet/pkg/installer"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@ -52,6 +53,23 @@ var configCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(config.LuetCfg.ConfigProtectConfDir) > 0 {
|
||||||
|
|
||||||
|
// Load config protect configs
|
||||||
|
installer.LoadConfigProtectConfs(config.LuetCfg)
|
||||||
|
|
||||||
|
fmt.Println("config_protect_confdir:")
|
||||||
|
for _, dir := range config.LuetCfg.ConfigProtectConfDir {
|
||||||
|
fmt.Println(" - ", dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(config.LuetCfg.GetConfigProtectConfFiles()) > 0 {
|
||||||
|
fmt.Println("protect_conf_files:")
|
||||||
|
for _, file := range config.LuetCfg.GetConfigProtectConfFiles() {
|
||||||
|
fmt.Println(" - ", file.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,6 +80,9 @@ var installCmd = &cobra.Command{
|
|||||||
|
|
||||||
Debug("Solver", LuetCfg.GetSolverOptions().CompactString())
|
Debug("Solver", LuetCfg.GetSolverOptions().CompactString())
|
||||||
|
|
||||||
|
// Load config protect configs
|
||||||
|
installer.LoadConfigProtectConfs(LuetCfg)
|
||||||
|
|
||||||
inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{
|
inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{
|
||||||
Concurrency: LuetCfg.GetGeneral().Concurrency,
|
Concurrency: LuetCfg.GetGeneral().Concurrency,
|
||||||
SolverOptions: *LuetCfg.GetSolverOptions(),
|
SolverOptions: *LuetCfg.GetSolverOptions(),
|
||||||
|
@ -73,7 +73,15 @@
|
|||||||
# - /etc/luet/repos.conf.d
|
# - /etc/luet/repos.conf.d
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# ---------------------------------------------
|
# ------------------------------------------------
|
||||||
|
# Config protect configuration files directories.
|
||||||
|
# -----------------------------------------------
|
||||||
|
# Define the list of directories where load
|
||||||
|
# configuration files with the list of config
|
||||||
|
# protect paths.
|
||||||
|
# config_protect_confdir:
|
||||||
|
# - /etc/luet/config.protect.d
|
||||||
|
#
|
||||||
# System repositories
|
# System repositories
|
||||||
# ---------------------------------------------
|
# ---------------------------------------------
|
||||||
# In alternative to define repositories files
|
# In alternative to define repositories files
|
||||||
|
2
go.mod
2
go.mod
@ -46,4 +46,4 @@ require (
|
|||||||
mvdan.cc/sh/v3 v3.0.0-beta1
|
mvdan.cc/sh/v3 v3.0.0-beta1
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/docker/docker => github.com/Luet-lab/moby v17.12.0-ce-rc1.0.20200418093736-b2b0766ef22c+incompatible
|
replace github.com/docker/docker => github.com/Luet-lab/moby v17.12.0-ce-rc1.0.20200605210607-749178b8f80d+incompatible
|
||||||
|
2
go.sum
2
go.sum
@ -10,6 +10,8 @@ github.com/Luet-lab/moby v17.12.0-ce-rc1.0.20200418091245-6e0951be974d+incompati
|
|||||||
github.com/Luet-lab/moby v17.12.0-ce-rc1.0.20200418091245-6e0951be974d+incompatible/go.mod h1:/XyFFC7lL96pE2kKmar2jd4LKxWzy1MmbiDHV0nK3bU=
|
github.com/Luet-lab/moby v17.12.0-ce-rc1.0.20200418091245-6e0951be974d+incompatible/go.mod h1:/XyFFC7lL96pE2kKmar2jd4LKxWzy1MmbiDHV0nK3bU=
|
||||||
github.com/Luet-lab/moby v17.12.0-ce-rc1.0.20200418093736-b2b0766ef22c+incompatible h1:0cMtxRtHURUYiWHyJ7FOwd+wH5kPNGjXlDf48ovuLlw=
|
github.com/Luet-lab/moby v17.12.0-ce-rc1.0.20200418093736-b2b0766ef22c+incompatible h1:0cMtxRtHURUYiWHyJ7FOwd+wH5kPNGjXlDf48ovuLlw=
|
||||||
github.com/Luet-lab/moby v17.12.0-ce-rc1.0.20200418093736-b2b0766ef22c+incompatible/go.mod h1:/XyFFC7lL96pE2kKmar2jd4LKxWzy1MmbiDHV0nK3bU=
|
github.com/Luet-lab/moby v17.12.0-ce-rc1.0.20200418093736-b2b0766ef22c+incompatible/go.mod h1:/XyFFC7lL96pE2kKmar2jd4LKxWzy1MmbiDHV0nK3bU=
|
||||||
|
github.com/Luet-lab/moby v17.12.0-ce-rc1.0.20200605210607-749178b8f80d+incompatible h1:YddBuPhhRLoz7uhSJ3Zm//e62jQeTW/qXEZrk5I4qsk=
|
||||||
|
github.com/Luet-lab/moby v17.12.0-ce-rc1.0.20200605210607-749178b8f80d+incompatible/go.mod h1:/XyFFC7lL96pE2kKmar2jd4LKxWzy1MmbiDHV0nK3bU=
|
||||||
github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q=
|
github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q=
|
||||||
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||||
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
|
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
|
||||||
|
@ -18,6 +18,8 @@ package compiler
|
|||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@ -34,6 +36,7 @@ import (
|
|||||||
. "github.com/mudler/luet/pkg/config"
|
. "github.com/mudler/luet/pkg/config"
|
||||||
"github.com/mudler/luet/pkg/helpers"
|
"github.com/mudler/luet/pkg/helpers"
|
||||||
. "github.com/mudler/luet/pkg/logger"
|
. "github.com/mudler/luet/pkg/logger"
|
||||||
|
pkg "github.com/mudler/luet/pkg/package"
|
||||||
"github.com/mudler/luet/pkg/solver"
|
"github.com/mudler/luet/pkg/solver"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
yaml "gopkg.in/yaml.v2"
|
yaml "gopkg.in/yaml.v2"
|
||||||
@ -277,8 +280,95 @@ func (a *PackageArtifact) Compress(src string, concurrency int) error {
|
|||||||
return errors.New("Compression type must be supplied")
|
return errors.New("Compression type must be supplied")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tarModifierWrapperFunc(dst, path string, header *tar.Header, content io.Reader) (*tar.Header, []byte, error) {
|
||||||
|
// If the destination path already exists I rename target file name with postfix.
|
||||||
|
var destPath string
|
||||||
|
|
||||||
|
// Read data. TODO: We need change archive callback to permit to return a Reader
|
||||||
|
buffer := bytes.Buffer{}
|
||||||
|
if content != nil {
|
||||||
|
if _, err := buffer.ReadFrom(content); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If file is not present on archive but is defined on mods
|
||||||
|
// I receive the callback. Prevent nil exception.
|
||||||
|
if header != nil {
|
||||||
|
switch header.Typeflag {
|
||||||
|
case tar.TypeReg:
|
||||||
|
destPath = filepath.Join(dst, path)
|
||||||
|
default:
|
||||||
|
// Nothing to do. I return original reader
|
||||||
|
return header, buffer.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if exists
|
||||||
|
if helpers.Exists(destPath) {
|
||||||
|
for i := 1; i < 1000; i++ {
|
||||||
|
name := filepath.Join(filepath.Join(filepath.Dir(path),
|
||||||
|
fmt.Sprintf("._cfg%04d_%s", i, filepath.Base(path))))
|
||||||
|
|
||||||
|
if helpers.Exists(name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
Info(fmt.Sprintf("Found protected file %s. Creating %s.", destPath,
|
||||||
|
filepath.Join(dst, name)))
|
||||||
|
return &tar.Header{
|
||||||
|
Mode: header.Mode,
|
||||||
|
Typeflag: header.Typeflag,
|
||||||
|
PAXRecords: header.PAXRecords,
|
||||||
|
Name: name,
|
||||||
|
}, buffer.Bytes(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return header, buffer.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *PackageArtifact) GetProtectFiles() []string {
|
||||||
|
ans := []string{}
|
||||||
|
|
||||||
|
if LuetCfg.GetConfigProtectConfFiles() != nil && len(LuetCfg.GetConfigProtectConfFiles()) > 0 {
|
||||||
|
|
||||||
|
for _, file := range a.Files {
|
||||||
|
for _, conf := range LuetCfg.GetConfigProtectConfFiles() {
|
||||||
|
for _, dir := range conf.Directories {
|
||||||
|
// Note file is without / at begin.
|
||||||
|
if strings.HasPrefix("/"+file, filepath.Clean(dir)) {
|
||||||
|
// docker archive modifier works with path without / at begin.
|
||||||
|
ans = append(ans, file)
|
||||||
|
goto nextFile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.CompileSpec.GetPackage().HasAnnotation(string(pkg.ConfigProtectAnnnotation)) {
|
||||||
|
dir, ok := a.CompileSpec.GetPackage().GetAnnotations()[string(pkg.ConfigProtectAnnnotation)]
|
||||||
|
if ok {
|
||||||
|
if strings.HasPrefix("/"+file, filepath.Clean(dir)) {
|
||||||
|
ans = append(ans, file)
|
||||||
|
goto nextFile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nextFile:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
|
||||||
// Unpack Untar and decompress (TODO) to the given path
|
// Unpack Untar and decompress (TODO) to the given path
|
||||||
func (a *PackageArtifact) Unpack(dst string, keepPerms bool) error {
|
func (a *PackageArtifact) Unpack(dst string, keepPerms bool) error {
|
||||||
|
|
||||||
|
// Create
|
||||||
|
protectedFiles := a.GetProtectFiles()
|
||||||
|
|
||||||
|
tarModifier := helpers.NewTarModifierWrapper(dst, tarModifierWrapperFunc)
|
||||||
|
|
||||||
switch a.CompressionType {
|
switch a.CompressionType {
|
||||||
case GZip:
|
case GZip:
|
||||||
// Create the uncompressed archive
|
// Create the uncompressed archive
|
||||||
@ -307,15 +397,16 @@ func (a *PackageArtifact) Unpack(dst string, keepPerms bool) error {
|
|||||||
return errors.Wrap(err, "Cannot copy to "+a.GetPath()+".uncompressed")
|
return errors.Wrap(err, "Cannot copy to "+a.GetPath()+".uncompressed")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = helpers.Untar(a.GetPath()+".uncompressed", dst,
|
err = helpers.UntarProtect(a.GetPath()+".uncompressed", dst,
|
||||||
LuetCfg.GetGeneral().SameOwner)
|
LuetCfg.GetGeneral().SameOwner, protectedFiles, tarModifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
// Defaults to tar only (covers when "none" is supplied)
|
// Defaults to tar only (covers when "none" is supplied)
|
||||||
default:
|
default:
|
||||||
return helpers.Untar(a.GetPath(), dst, LuetCfg.GetGeneral().SameOwner)
|
return helpers.UntarProtect(a.GetPath(), dst, LuetCfg.GetGeneral().SameOwner,
|
||||||
|
protectedFiles, tarModifier)
|
||||||
}
|
}
|
||||||
return errors.New("Compression type must be supplied")
|
return errors.New("Compression type must be supplied")
|
||||||
}
|
}
|
||||||
|
@ -201,8 +201,11 @@ type LuetConfig struct {
|
|||||||
Solver LuetSolverOptions `mapstructure:"solver"`
|
Solver LuetSolverOptions `mapstructure:"solver"`
|
||||||
|
|
||||||
RepositoriesConfDir []string `mapstructure:"repos_confdir"`
|
RepositoriesConfDir []string `mapstructure:"repos_confdir"`
|
||||||
|
ConfigProtectConfDir []string `mapstructure:"config_protect_confdir"`
|
||||||
CacheRepositories []LuetRepository `mapstructure:"repetitors"`
|
CacheRepositories []LuetRepository `mapstructure:"repetitors"`
|
||||||
SystemRepositories []LuetRepository `mapstructure:"repositories"`
|
SystemRepositories []LuetRepository `mapstructure:"repositories"`
|
||||||
|
|
||||||
|
ConfigProtectConfFiles []ConfigProtectConfFile
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLuetConfig(viper *v.Viper) *LuetConfig {
|
func NewLuetConfig(viper *v.Viper) *LuetConfig {
|
||||||
@ -211,7 +214,7 @@ func NewLuetConfig(viper *v.Viper) *LuetConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GenDefault(viper)
|
GenDefault(viper)
|
||||||
return &LuetConfig{Viper: viper}
|
return &LuetConfig{Viper: viper, ConfigProtectConfFiles: nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenDefault(viper *v.Viper) {
|
func GenDefault(viper *v.Viper) {
|
||||||
@ -244,6 +247,7 @@ func GenDefault(viper *v.Viper) {
|
|||||||
viper.SetDefault("system.pkgs_cache_path", "packages")
|
viper.SetDefault("system.pkgs_cache_path", "packages")
|
||||||
|
|
||||||
viper.SetDefault("repos_confdir", []string{"/etc/luet/repos.conf.d"})
|
viper.SetDefault("repos_confdir", []string{"/etc/luet/repos.conf.d"})
|
||||||
|
viper.SetDefault("config_protect_confdir", []string{"/etc/luet/config.protect.d"})
|
||||||
viper.SetDefault("cache_repositories", []string{})
|
viper.SetDefault("cache_repositories", []string{})
|
||||||
viper.SetDefault("system_repositories", []string{})
|
viper.SetDefault("system_repositories", []string{})
|
||||||
|
|
||||||
@ -273,6 +277,18 @@ func (c *LuetConfig) GetSolverOptions() *LuetSolverOptions {
|
|||||||
return &c.Solver
|
return &c.Solver
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *LuetConfig) GetConfigProtectConfFiles() []ConfigProtectConfFile {
|
||||||
|
return c.ConfigProtectConfFiles
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LuetConfig) AddConfigProtectConfFile(file *ConfigProtectConfFile) {
|
||||||
|
if c.ConfigProtectConfFiles == nil {
|
||||||
|
c.ConfigProtectConfFiles = []ConfigProtectConfFile{*file}
|
||||||
|
} else {
|
||||||
|
c.ConfigProtectConfFiles = append(c.ConfigProtectConfFiles, *file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *LuetConfig) GetSystemRepository(name string) (*LuetRepository, error) {
|
func (c *LuetConfig) GetSystemRepository(name string) (*LuetRepository, error) {
|
||||||
var ans *LuetRepository = nil
|
var ans *LuetRepository = nil
|
||||||
|
|
||||||
|
41
pkg/config/config_protect.go
Normal file
41
pkg/config/config_protect.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// Copyright © 2019-2020 Ettore Di Giacinto <mudler@gentoo.org>
|
||||||
|
// Daniele Rondina <geaaru@sabayonlinux.org>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along
|
||||||
|
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConfigProtectConfFile struct {
|
||||||
|
Filename string
|
||||||
|
|
||||||
|
Name string `mapstructure:"name" yaml:"name" json:"name"`
|
||||||
|
Directories []string `mapstructure:"dirs" yaml:"dirs" json:"dirs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConfigProtectConfFile(filename string) *ConfigProtectConfFile {
|
||||||
|
return &ConfigProtectConfFile{
|
||||||
|
Filename: filename,
|
||||||
|
Name: "",
|
||||||
|
Directories: []string{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConfigProtectConfFile) String() string {
|
||||||
|
return fmt.Sprintf("[%s] filename: %s, dirs: %s", c.Name, c.Filename,
|
||||||
|
c.Directories)
|
||||||
|
}
|
@ -17,6 +17,7 @@ package helpers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -49,6 +50,146 @@ func Tar(src, dest string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TarModifierWrapperFunc func(path, dst string, header *tar.Header, content io.Reader) (*tar.Header, []byte, error)
|
||||||
|
type TarModifierWrapper struct {
|
||||||
|
DestinationPath string
|
||||||
|
Modifier TarModifierWrapperFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTarModifierWrapper(dst string, modifier TarModifierWrapperFunc) *TarModifierWrapper {
|
||||||
|
return &TarModifierWrapper{
|
||||||
|
DestinationPath: dst,
|
||||||
|
Modifier: modifier,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *TarModifierWrapper) GetModifier() archive.TarModifierFunc {
|
||||||
|
return func(path string, header *tar.Header, content io.Reader) (*tar.Header, []byte, error) {
|
||||||
|
return m.Modifier(m.DestinationPath, path, header, content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func UntarProtect(src, dst string, sameOwner bool, protectedFiles []string, modifier *TarModifierWrapper) error {
|
||||||
|
var ans error
|
||||||
|
|
||||||
|
if len(protectedFiles) <= 0 {
|
||||||
|
return Untar(src, dst, sameOwner)
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST: we have files to protect. I create a ReplaceFileTarWrapper
|
||||||
|
in, err := os.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer in.Close()
|
||||||
|
|
||||||
|
// Create modifier map
|
||||||
|
mods := make(map[string]archive.TarModifierFunc)
|
||||||
|
for _, file := range protectedFiles {
|
||||||
|
mods[file] = modifier.GetModifier()
|
||||||
|
}
|
||||||
|
|
||||||
|
if sameOwner {
|
||||||
|
// PRE: i have root privileged.
|
||||||
|
|
||||||
|
replacerArchive := archive.ReplaceFileTarWrapper(in, mods)
|
||||||
|
|
||||||
|
opts := &archive.TarOptions{
|
||||||
|
// NOTE: NoLchown boolean is used for chmod of the symlink
|
||||||
|
// Probably it's needed set this always to true.
|
||||||
|
NoLchown: true,
|
||||||
|
ExcludePatterns: []string{"dev/"}, // prevent 'operation not permitted'
|
||||||
|
ContinueOnError: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
ans = archive.Untar(replacerArchive, dst, opts)
|
||||||
|
} else {
|
||||||
|
ans = unTarIgnoreOwner(dst, in, mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
|
||||||
|
func unTarIgnoreOwner(dest string, in io.ReadCloser, mods map[string]archive.TarModifierFunc) error {
|
||||||
|
tr := tar.NewReader(in)
|
||||||
|
for {
|
||||||
|
header, err := tr.Next()
|
||||||
|
|
||||||
|
var data []byte
|
||||||
|
var headerReplaced = false
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case err == io.EOF:
|
||||||
|
goto tarEof
|
||||||
|
case err != nil:
|
||||||
|
return err
|
||||||
|
case header == nil:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// the target location where the dir/file should be created
|
||||||
|
target := filepath.Join(dest, header.Name)
|
||||||
|
if mods != nil {
|
||||||
|
modifier, ok := mods[header.Name]
|
||||||
|
if ok {
|
||||||
|
header, data, err = modifier(header.Name, header, tr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override target path
|
||||||
|
target = filepath.Join(dest, header.Name)
|
||||||
|
headerReplaced = true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the file type
|
||||||
|
switch header.Typeflag {
|
||||||
|
|
||||||
|
// if its a dir and it doesn't exist create it
|
||||||
|
case tar.TypeDir:
|
||||||
|
if _, err := os.Stat(target); err != nil {
|
||||||
|
if err := os.MkdirAll(target, 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle creation of file
|
||||||
|
case tar.TypeReg:
|
||||||
|
|
||||||
|
f, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy over contents
|
||||||
|
if headerReplaced {
|
||||||
|
_, err = io.Copy(f, bytes.NewReader(data))
|
||||||
|
} else {
|
||||||
|
_, err = io.Copy(f, tr)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// manually close here after each file operation; defering would cause each
|
||||||
|
// file close to wait until all operations have completed.
|
||||||
|
f.Close()
|
||||||
|
|
||||||
|
case tar.TypeSymlink:
|
||||||
|
source := header.Linkname
|
||||||
|
err := os.Symlink(source, target)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tarEof:
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Untar just a wrapper around the docker functions
|
// Untar just a wrapper around the docker functions
|
||||||
func Untar(src, dest string, sameOwner bool) error {
|
func Untar(src, dest string, sameOwner bool) error {
|
||||||
var ans error
|
var ans error
|
||||||
@ -72,62 +213,7 @@ func Untar(src, dest string, sameOwner bool) error {
|
|||||||
|
|
||||||
ans = archive.Untar(in, dest, opts)
|
ans = archive.Untar(in, dest, opts)
|
||||||
} else {
|
} else {
|
||||||
|
ans = unTarIgnoreOwner(dest, in, nil)
|
||||||
// TODO: replace with https://github.com/mholt/archiver ?
|
|
||||||
var fileReader io.ReadCloser = in
|
|
||||||
|
|
||||||
tr := tar.NewReader(fileReader)
|
|
||||||
for {
|
|
||||||
header, err := tr.Next()
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case err == io.EOF:
|
|
||||||
goto tarEof
|
|
||||||
case err != nil:
|
|
||||||
return err
|
|
||||||
case header == nil:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// the target location where the dir/file should be created
|
|
||||||
target := filepath.Join(dest, header.Name)
|
|
||||||
|
|
||||||
// Check the file type
|
|
||||||
switch header.Typeflag {
|
|
||||||
|
|
||||||
// if its a dir and it doesn't exist create it
|
|
||||||
case tar.TypeDir:
|
|
||||||
if _, err := os.Stat(target); err != nil {
|
|
||||||
if err := os.MkdirAll(target, 0755); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle creation of file
|
|
||||||
case tar.TypeReg:
|
|
||||||
f, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy over contents
|
|
||||||
if _, err := io.Copy(f, tr); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// manually close here after each file operation; defering would cause each
|
|
||||||
// file close to wait until all operations have completed.
|
|
||||||
f.Close()
|
|
||||||
|
|
||||||
case tar.TypeSymlink:
|
|
||||||
source := header.Linkname
|
|
||||||
err := os.Symlink(source, target)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tarEof:
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ans
|
return ans
|
||||||
|
134
pkg/helpers/archive_test.go
Normal file
134
pkg/helpers/archive_test.go
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
// Copyright © 2019-2020 Ettore Di Giacinto <mudler@gentoo.org>
|
||||||
|
// Daniele Rondina <geaaru@sabayonlinux.org>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along
|
||||||
|
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package helpers_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/docker/docker/pkg/archive"
|
||||||
|
. "github.com/mudler/luet/pkg/helpers"
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Code from moby/moby pkg/archive/archive_test
|
||||||
|
func prepareUntarSourceDirectory(numberOfFiles int, targetPath string, makeLinks bool) (int, error) {
|
||||||
|
fileData := []byte("fooo")
|
||||||
|
for n := 0; n < numberOfFiles; n++ {
|
||||||
|
fileName := fmt.Sprintf("file-%d", n)
|
||||||
|
if err := ioutil.WriteFile(filepath.Join(targetPath, fileName), fileData, 0700); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if makeLinks {
|
||||||
|
if err := os.Link(filepath.Join(targetPath, fileName), filepath.Join(targetPath, fileName+"-link")); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalSize := numberOfFiles * len(fileData)
|
||||||
|
return totalSize, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func tarModifierWrapperFunc(dst, path string, header *tar.Header, content io.Reader) (*tar.Header, []byte, error) {
|
||||||
|
// If the destination path already exists I rename target file name with postfix.
|
||||||
|
var basePath string
|
||||||
|
|
||||||
|
// Read data. TODO: We need change archive callback to permit to return a Reader
|
||||||
|
buffer := bytes.Buffer{}
|
||||||
|
if content != nil {
|
||||||
|
if _, err := buffer.ReadFrom(content); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if header != nil {
|
||||||
|
|
||||||
|
switch header.Typeflag {
|
||||||
|
case tar.TypeReg:
|
||||||
|
basePath = filepath.Base(path)
|
||||||
|
default:
|
||||||
|
// Nothing to do. I return original reader
|
||||||
|
return header, buffer.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if basePath == "file-0" {
|
||||||
|
name := filepath.Join(filepath.Join(filepath.Dir(path), fmt.Sprintf("._cfg%04d_%s", 1, basePath)))
|
||||||
|
return &tar.Header{
|
||||||
|
Mode: header.Mode,
|
||||||
|
Typeflag: header.Typeflag,
|
||||||
|
PAXRecords: header.PAXRecords,
|
||||||
|
Name: name,
|
||||||
|
}, buffer.Bytes(), nil
|
||||||
|
} else if basePath == "file-1" {
|
||||||
|
return header, []byte("newcontent"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// else file not present
|
||||||
|
}
|
||||||
|
|
||||||
|
return header, buffer.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = Describe("Helpers Archive", func() {
|
||||||
|
Context("Untar Protect", func() {
|
||||||
|
|
||||||
|
It("Detect existing and not-existing files", func() {
|
||||||
|
|
||||||
|
archiveSourceDir, err := ioutil.TempDir("", "archive-source")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
defer os.RemoveAll(archiveSourceDir)
|
||||||
|
|
||||||
|
_, err = prepareUntarSourceDirectory(10, archiveSourceDir, false)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
targetDir, err := ioutil.TempDir("", "archive-target")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
// defer os.RemoveAll(targetDir)
|
||||||
|
|
||||||
|
sourceArchive, err := archive.TarWithOptions(archiveSourceDir, &archive.TarOptions{})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
defer sourceArchive.Close()
|
||||||
|
|
||||||
|
tarModifier := NewTarModifierWrapper(targetDir, tarModifierWrapperFunc)
|
||||||
|
mods := make(map[string]archive.TarModifierFunc)
|
||||||
|
mods["file-0"] = tarModifier.GetModifier()
|
||||||
|
mods["file-1"] = tarModifier.GetModifier()
|
||||||
|
mods["file-9999"] = tarModifier.GetModifier()
|
||||||
|
|
||||||
|
replacerArchive := archive.ReplaceFileTarWrapper(sourceArchive, mods)
|
||||||
|
//replacerArchive := archive.ReplaceFileTarWrapper(sourceArchive, mods)
|
||||||
|
opts := &archive.TarOptions{
|
||||||
|
// NOTE: NoLchown boolean is used for chmod of the symlink
|
||||||
|
// Probably it's needed set this always to true.
|
||||||
|
NoLchown: true,
|
||||||
|
ExcludePatterns: []string{"dev/"}, // prevent 'operation not permitted'
|
||||||
|
ContinueOnError: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = archive.Untar(replacerArchive, targetDir, opts)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(Exists(filepath.Join(targetDir, "._cfg0001_file-0"))).Should(Equal(true))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
86
pkg/installer/config_protect.go
Normal file
86
pkg/installer/config_protect.go
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
// Copyright © 2019-2020 Ettore Di Giacinto <mudler@gentoo.org>
|
||||||
|
// Daniele Rondina <geaaru@sabayonlinux.org>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along
|
||||||
|
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package installer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"path"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/ghodss/yaml"
|
||||||
|
|
||||||
|
. "github.com/mudler/luet/pkg/config"
|
||||||
|
. "github.com/mudler/luet/pkg/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func LoadConfigProtectConfs(c *LuetConfig) error {
|
||||||
|
var regexConfs = regexp.MustCompile(`.yml$`)
|
||||||
|
|
||||||
|
for _, cdir := range c.ConfigProtectConfDir {
|
||||||
|
Debug("Parsing Config Protect Directory", cdir, "...")
|
||||||
|
|
||||||
|
files, err := ioutil.ReadDir(cdir)
|
||||||
|
if err != nil {
|
||||||
|
Debug("Skip dir", cdir, ":", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
if file.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !regexConfs.MatchString(file.Name()) {
|
||||||
|
Debug("File", file.Name(), "skipped.")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := ioutil.ReadFile(path.Join(cdir, file.Name()))
|
||||||
|
if err != nil {
|
||||||
|
Warning("On read file", file.Name(), ":", err.Error())
|
||||||
|
Warning("File", file.Name(), "skipped.")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := LoadConfigProtectConFile(file.Name(), content)
|
||||||
|
if err != nil {
|
||||||
|
Warning("On parse file", file.Name(), ":", err.Error())
|
||||||
|
Warning("File", file.Name(), "skipped.")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Name == "" || len(r.Directories) == 0 {
|
||||||
|
Warning("Invalid config protect file", file.Name())
|
||||||
|
Warning("File", file.Name(), "skipped.")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
c.AddConfigProtectConfFile(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadConfigProtectConFile(filename string, data []byte) (*ConfigProtectConfFile, error) {
|
||||||
|
ans := NewConfigProtectConfFile(filename)
|
||||||
|
err := yaml.Unmarshal(data, &ans)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ans, nil
|
||||||
|
}
|
23
pkg/package/annotations.go
Normal file
23
pkg/package/annotations.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright © 2019-2020 Ettore Di Giacinto <mudler@gentoo.org>
|
||||||
|
// Daniele Rondina <geaaru@sabayonlinux.org>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along
|
||||||
|
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package pkg
|
||||||
|
|
||||||
|
type AnnotationKey string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ConfigProtectAnnnotation AnnotationKey = "config_protect"
|
||||||
|
)
|
9
tests/fixtures/config_protect/a/build.yaml
vendored
Normal file
9
tests/fixtures/config_protect/a/build.yaml
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
image: "alpine"
|
||||||
|
prelude:
|
||||||
|
- echo foo > /test
|
||||||
|
- echo bar > /test2
|
||||||
|
steps:
|
||||||
|
- echo c > /c
|
||||||
|
- echo c > /cd
|
||||||
|
- mkdir /etc/a
|
||||||
|
- echo config > /etc/a/conf
|
3
tests/fixtures/config_protect/a/definition.yaml
vendored
Normal file
3
tests/fixtures/config_protect/a/definition.yaml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
category: "test"
|
||||||
|
name: "a"
|
||||||
|
version: "1.0"
|
9
tests/fixtures/config_protect_annotation/a/build.yaml
vendored
Normal file
9
tests/fixtures/config_protect_annotation/a/build.yaml
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
image: "alpine"
|
||||||
|
prelude:
|
||||||
|
- echo foo > /test
|
||||||
|
- echo bar > /test2
|
||||||
|
steps:
|
||||||
|
- echo c > /c
|
||||||
|
- echo c > /cd
|
||||||
|
- mkdir /opt/etc
|
||||||
|
- echo config > /opt/etc/conf
|
5
tests/fixtures/config_protect_annotation/a/definition.yaml
vendored
Normal file
5
tests/fixtures/config_protect_annotation/a/definition.yaml
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
category: "test"
|
||||||
|
name: "a"
|
||||||
|
version: "1.0"
|
||||||
|
annotations:
|
||||||
|
config_protect: "/opt/etc"
|
106
tests/integration/12_config_protect.sh
Executable file
106
tests/integration/12_config_protect.sh
Executable file
@ -0,0 +1,106 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export LUET_NOLOCK=true
|
||||||
|
|
||||||
|
oneTimeSetUp() {
|
||||||
|
export tmpdir="$(mktemp -d)"
|
||||||
|
}
|
||||||
|
|
||||||
|
oneTimeTearDown() {
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
}
|
||||||
|
|
||||||
|
testBuild() {
|
||||||
|
mkdir $tmpdir/testbuild
|
||||||
|
luet build --tree "$ROOT_DIR/tests/fixtures/config_protect" --destination $tmpdir/testbuild --compression gzip test/a
|
||||||
|
buildst=$?
|
||||||
|
assertEquals 'builds successfully' "$buildst" "0"
|
||||||
|
assertTrue 'create package' "[ -e '$tmpdir/testbuild/a-test-1.0.package.tar.gz' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
testRepo() {
|
||||||
|
assertTrue 'no repository' "[ ! -e '$tmpdir/testbuild/repository.yaml' ]"
|
||||||
|
luet create-repo --tree "$ROOT_DIR/tests/fixtures/config_protect" \
|
||||||
|
--output $tmpdir/testbuild \
|
||||||
|
--packages $tmpdir/testbuild \
|
||||||
|
--name "test" \
|
||||||
|
--descr "Test Repo" \
|
||||||
|
--urls $tmpdir/testrootfs \
|
||||||
|
--type disk > /dev/null
|
||||||
|
|
||||||
|
createst=$?
|
||||||
|
assertEquals 'create repo successfully' "$createst" "0"
|
||||||
|
assertTrue 'create repository' "[ -e '$tmpdir/testbuild/repository.yaml' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
testConfig() {
|
||||||
|
mkdir $tmpdir/testrootfs
|
||||||
|
|
||||||
|
mkdir $tmpdir/config.protect.d
|
||||||
|
|
||||||
|
cat <<EOF > $tmpdir/config.protect.d/conf1.yml
|
||||||
|
name: "protect1"
|
||||||
|
dirs:
|
||||||
|
- /etc/
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat <<EOF > $tmpdir/luet.yaml
|
||||||
|
general:
|
||||||
|
debug: true
|
||||||
|
system:
|
||||||
|
rootfs: $tmpdir/testrootfs
|
||||||
|
database_path: "/"
|
||||||
|
database_engine: "boltdb"
|
||||||
|
config_protect_confdir:
|
||||||
|
- $tmpdir/config.protect.d
|
||||||
|
repositories:
|
||||||
|
- name: "main"
|
||||||
|
type: "disk"
|
||||||
|
enable: true
|
||||||
|
urls:
|
||||||
|
- "$tmpdir/testbuild"
|
||||||
|
EOF
|
||||||
|
luet config --config $tmpdir/luet.yaml
|
||||||
|
res=$?
|
||||||
|
assertEquals 'config test successfully' "$res" "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
testInstall() {
|
||||||
|
|
||||||
|
# Simulate previous installation
|
||||||
|
mkdir $tmpdir/testrootfs/etc/a -p
|
||||||
|
echo "fakeconf" > $tmpdir/testrootfs/etc/a/conf
|
||||||
|
|
||||||
|
luet install --config $tmpdir/luet.yaml test/a
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test successfully' "$installst" "0"
|
||||||
|
|
||||||
|
|
||||||
|
# Simulate config protect
|
||||||
|
assertTrue 'package A installed' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||||
|
assertTrue 'config protect created' "[ -e '$tmpdir/testrootfs/etc/a/._cfg0001_conf' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
testUnInstall() {
|
||||||
|
luet uninstall --full --config $tmpdir/luet.yaml test/a
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'uninstall test successfully' "$installst" "0"
|
||||||
|
assertTrue 'package uninstalled' "[ ! -e '$tmpdir/testrootfs/c' ]"
|
||||||
|
# TODO: we need remove it or not??
|
||||||
|
assertTrue 'config protect created' "[ -e '$tmpdir/testrootfs/etc/a/._cfg0001_conf' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
testCleanup() {
|
||||||
|
luet cleanup --config $tmpdir/luet.yaml
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test successfully' "$installst" "0"
|
||||||
|
assertTrue 'package installed' "[ ! -e '$tmpdir/testrootfs/packages/a-test-1.0.package.tar.gz' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load shUnit2.
|
||||||
|
. "$ROOT_DIR/tests/integration/shunit2"/shunit2
|
||||||
|
|
106
tests/integration/13_config_protect_annotation.sh
Executable file
106
tests/integration/13_config_protect_annotation.sh
Executable file
@ -0,0 +1,106 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export LUET_NOLOCK=true
|
||||||
|
|
||||||
|
oneTimeSetUp() {
|
||||||
|
export tmpdir="$(mktemp -d)"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
oneTimeTearDown() {
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
}
|
||||||
|
|
||||||
|
testBuild() {
|
||||||
|
mkdir $tmpdir/testbuild
|
||||||
|
luet build --tree "$ROOT_DIR/tests/fixtures/config_protect_annotation" --destination $tmpdir/testbuild --compression gzip test/a
|
||||||
|
buildst=$?
|
||||||
|
assertEquals 'builds successfully' "$buildst" "0"
|
||||||
|
assertTrue 'create package' "[ -e '$tmpdir/testbuild/a-test-1.0.package.tar.gz' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
testRepo() {
|
||||||
|
assertTrue 'no repository' "[ ! -e '$tmpdir/testbuild/repository.yaml' ]"
|
||||||
|
luet create-repo --tree "$ROOT_DIR/tests/fixtures/config_protect_annotation" \
|
||||||
|
--output $tmpdir/testbuild \
|
||||||
|
--packages $tmpdir/testbuild \
|
||||||
|
--name "test" \
|
||||||
|
--descr "Test Repo" \
|
||||||
|
--urls $tmpdir/testrootfs \
|
||||||
|
--type disk > /dev/null
|
||||||
|
|
||||||
|
createst=$?
|
||||||
|
assertEquals 'create repo successfully' "$createst" "0"
|
||||||
|
assertTrue 'create repository' "[ -e '$tmpdir/testbuild/repository.yaml' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
testConfig() {
|
||||||
|
mkdir $tmpdir/testrootfs
|
||||||
|
|
||||||
|
mkdir $tmpdir/config.protect.d
|
||||||
|
|
||||||
|
cat <<EOF > $tmpdir/config.protect.d/conf1.yml
|
||||||
|
name: "protect1"
|
||||||
|
dirs:
|
||||||
|
- /etc/
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat <<EOF > $tmpdir/luet.yaml
|
||||||
|
general:
|
||||||
|
debug: true
|
||||||
|
system:
|
||||||
|
rootfs: $tmpdir/testrootfs
|
||||||
|
database_path: "/"
|
||||||
|
database_engine: "boltdb"
|
||||||
|
config_protect_confdir:
|
||||||
|
- $tmpdir/config.protect.d
|
||||||
|
repositories:
|
||||||
|
- name: "main"
|
||||||
|
type: "disk"
|
||||||
|
enable: true
|
||||||
|
urls:
|
||||||
|
- "$tmpdir/testbuild"
|
||||||
|
EOF
|
||||||
|
luet config --config $tmpdir/luet.yaml
|
||||||
|
res=$?
|
||||||
|
assertEquals 'config test successfully' "$res" "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
testInstall() {
|
||||||
|
# Simulate previous installation
|
||||||
|
mkdir $tmpdir/testrootfs/opt/etc -p
|
||||||
|
echo "fakeconf" > $tmpdir/testrootfs/opt/etc/conf
|
||||||
|
|
||||||
|
luet install --config $tmpdir/luet.yaml test/a
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test successfully' "$installst" "0"
|
||||||
|
|
||||||
|
|
||||||
|
# Simulate config protect
|
||||||
|
assertTrue 'package A installed' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||||
|
assertTrue 'config protect created' "[ -e '$tmpdir/testrootfs/opt/etc/._cfg0001_conf' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
testUnInstall() {
|
||||||
|
luet uninstall --full --config $tmpdir/luet.yaml test/a
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'uninstall test successfully' "$installst" "0"
|
||||||
|
assertTrue 'package uninstalled' "[ ! -e '$tmpdir/testrootfs/c' ]"
|
||||||
|
# TODO: we need remove it or not??
|
||||||
|
assertTrue 'config protect created' "[ -e '$tmpdir/testrootfs/opt/etc/._cfg0001_conf' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
testCleanup() {
|
||||||
|
luet cleanup --config $tmpdir/luet.yaml
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test successfully' "$installst" "0"
|
||||||
|
assertTrue 'package installed' "[ ! -e '$tmpdir/testrootfs/packages/a-test-1.0.package.tar.gz' ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load shUnit2.
|
||||||
|
. "$ROOT_DIR/tests/integration/shunit2"/shunit2
|
||||||
|
|
2
vendor/github.com/docker/docker/pkg/archive/archive.go
generated
vendored
2
vendor/github.com/docker/docker/pkg/archive/archive.go
generated
vendored
@ -279,7 +279,9 @@ func ReplaceFileTarWrapper(inputTarStream io.ReadCloser, mods map[string]TarModi
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if header.Name == "" {
|
||||||
header.Name = name
|
header.Name = name
|
||||||
|
}
|
||||||
header.Size = int64(len(data))
|
header.Size = int64(len(data))
|
||||||
if err := tarWriter.WriteHeader(header); err != nil {
|
if err := tarWriter.WriteHeader(header); err != nil {
|
||||||
return err
|
return err
|
||||||
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -66,7 +66,7 @@ github.com/docker/distribution/manifest/schema1
|
|||||||
github.com/docker/distribution/manifest/schema2
|
github.com/docker/distribution/manifest/schema2
|
||||||
github.com/docker/distribution/reference
|
github.com/docker/distribution/reference
|
||||||
github.com/docker/distribution/registry/api/errcode
|
github.com/docker/distribution/registry/api/errcode
|
||||||
# github.com/docker/docker v17.12.0-ce-rc1.0.20200417035958-130b0bc6032c+incompatible => github.com/Luet-lab/moby v17.12.0-ce-rc1.0.20200418093736-b2b0766ef22c+incompatible
|
# github.com/docker/docker v17.12.0-ce-rc1.0.20200417035958-130b0bc6032c+incompatible => github.com/Luet-lab/moby v17.12.0-ce-rc1.0.20200605210607-749178b8f80d+incompatible
|
||||||
github.com/docker/docker/api/types/blkiodev
|
github.com/docker/docker/api/types/blkiodev
|
||||||
github.com/docker/docker/api/types/container
|
github.com/docker/docker/api/types/container
|
||||||
github.com/docker/docker/api/types/filters
|
github.com/docker/docker/api/types/filters
|
||||||
|
Loading…
Reference in New Issue
Block a user