Skip to content
Snippets Groups Projects
Select Git revision
  • 1b3d20e6ff89e9a2d3559d20ce80d8a967cbfe5b
  • master default
  • registry-mirror
  • nginx-default-site
  • acmeserver2
  • clickhouse
  • improve-dns-toplevel-probes
  • tabacco-in-container
  • rsyslog-modern-json
  • improve-service-discovery
  • prometheus-external-healthchecks
  • env-vars-in-include-paths
  • dns-resolver
  • service-turndown
  • use_proxy_protocol
  • loki
  • docs_operating
  • net-overlay_firewall_containers
  • webdiff
19 results

ansible-buster.patch

Blame
  • repository_restic_test.go 5.04 KiB
    package tabacco
    
    import (
    	"bytes"
    	"context"
    	"io/ioutil"
    	"os"
    	"os/exec"
    	"path/filepath"
    	"testing"
    
    	"git.autistici.org/ai3/tools/tabacco/jobs"
    )
    
    // Create a temporary directory with two subdirs: 'data', for
    // the test backup data, and 'repo' to store the (remote)
    // repository. Populate 'data' with two tiny files.
    //
    // nolint
    func createTempDirWithData(t *testing.T) string {
    	tmpdir, err := ioutil.TempDir("", "")
    	if err != nil {
    		t.Fatal(err)
    	}
    	for _, d := range []string{"data", "repo", "restore"} {
    		os.Mkdir(filepath.Join(tmpdir, d), 0700)
    	}
    	ioutil.WriteFile(
    		filepath.Join(tmpdir, "data", "file1"),
    		[]byte("this is file number one."),
    		0600,
    	)
    	ioutil.WriteFile(
    		filepath.Join(tmpdir, "data", "file2"),
    		[]byte("this is file number two."),
    		0600,
    	)
    	return tmpdir
    }
    
    // nolint: gocyclo
    func runResticTest(t *testing.T, tmpdir string, source *SourceSpec, restorePattern string, checkFn func(testing.TB, string)) {
    	// Check that we can actually run restic.
    	resticVersion, err := getResticVersion("restic")
    	if err != nil {
    		t.Skip("can't find restic: ", err)
    	}
    	if resticVersion.LessThan(resticMinGoodVersion) {
    		t.Skip("restic version ", resticVersion,
    			" is older than the minimum supported version ",
    			resticMinGoodVersion)
    	}
    
    	// Temporary cache dir.
    	cacheDir, err := ioutil.TempDir("", "")
    	if err != nil {
    		t.Fatal(err)
    	}
    	defer os.RemoveAll(cacheDir)
    
    	store := &dummyMetadataStore{}
    
    	repoSpec := RepositorySpec{
    		Name: "main",
    		Type: "restic",
    		Params: map[string]interface{}{
    			"uri":       tmpdir + "/repo",
    			"password":  "testpass",
    			"cache_dir": cacheDir,
    		},
    	}
    	handlerSpecs := []*HandlerSpec{
    		// 'file' is predefined.
    		&HandlerSpec{
    			Name: "data",
    			Type: "pipe",
    			Params: map[string]interface{}{
    				"backup_command": "echo data",
    				// The restore command also verifies the data.
    				"restore_command": "read row ; test \"x$$row\" = xdata",
    			},
    		},
    	}
    	queueSpec := &jobs.QueueSpec{
    		Concurrency: 2,
    	}
    	sourceSpecs := []*SourceSpec{source}
    
    	// Run the backup.
    	configMgr, err := NewConfigManager(&Config{
    		Queue:        queueSpec,
    		Repository:   repoSpec,
    		HandlerSpecs: handlerSpecs,
    		SourceSpecs:  sourceSpecs,
    	})
    	if err != nil {
    		t.Fatal(err)
    	}
    	defer configMgr.Close()
    
    	m, err := NewManager(context.TODO(), configMgr, store)
    	if err != nil {
    		t.Fatal(err)
    	}
    	defer m.Close()
    
    	backup, err := m.Backup(context.TODO(), configMgr.current().SourceSpecs()[0])
    	if err != nil {
    		t.Fatal(err)
    	}
    	if backup.ID == "" || backup.Host == "" {
    		t.Fatalf("empty fields in backup: %+v", backup)
    	}
    
    	// Check the 'restic snapshots' output.
    	output, err := exec.Command("env", "RESTIC_REPOSITORY=", "RESTIC_PASSWORD_FILE=", "RESTIC_PASSWORD=testpass", "restic", "-r", tmpdir+"/repo", "snapshots", "--json").Output()
    	if err != nil {
    		t.Fatalf("'restic snapshots' failed: %v", err)
    	}
    	snaps, err := parseResticSnapshots(output)
    	if err != nil {
    		t.Fatalf("parsing restic snaphots output: %v, output:\n%s", err, string(output))
    	}
    	if len(snaps) != 1 {
    		t.Fatalf("wrong number of snapshots: %+v", snaps)
    	}
    	snap := snaps[0]
    	if len(snap.Tags) != 3 {
    		t.Fatalf("woops, bad number of tags: %+v", snap)
    	}
    
    	// Now try to restore.
    	err = m.Restore(
    		context.TODO(),
    		&FindRequest{Pattern: restorePattern},
    		tmpdir+"/restore",
    	)
    	if err != nil {
    		t.Fatal("Restore", err)
    	}
    
    	if checkFn != nil {
    		checkFn(t, tmpdir)
    	}
    }
    
    func checkRestoredData(t testing.TB, tmpdir string) {
    	data, err := ioutil.ReadFile(filepath.Join(tmpdir, "restore", tmpdir, "data", "file1"))
    	if err != nil {
    		t.Fatalf("data/file1 has not been restored: %v", err)
    	}
    	if !bytes.Equal(data, []byte("this is file number one.")) {
    		t.Fatalf("data/file1 has bad restored contents: %s", string(data))
    	}
    }
    
    func TestRestic(t *testing.T) {
    	tmpdir := createTempDirWithData(t)
    	defer os.RemoveAll(tmpdir)
    
    	runResticTest(
    		t, tmpdir,
    		&SourceSpec{
    			Name:     "source1",
    			Handler:  "file",
    			Schedule: "@random_every 1h",
    			Params: map[string]interface{}{
    				"path": filepath.Join(tmpdir, "data"),
    			},
    			Datasets: []*DatasetSpec{
    				&DatasetSpec{
    					Atoms: []Atom{
    						{
    							Name: "f1",
    							Path: "file1",
    						},
    						{
    							Name: "f2",
    							Path: "file2",
    						},
    					},
    				},
    			},
    		},
    		"source1/*",
    		checkRestoredData,
    	)
    }
    
    func TestRestic_Stream(t *testing.T) {
    	tmpdir := createTempDirWithData(t)
    	defer os.RemoveAll(tmpdir)
    
    	runResticTest(
    		t, tmpdir,
    		&SourceSpec{
    			Name:     "source1",
    			Handler:  "data",
    			Schedule: "@random_every 1h",
    			Datasets: []*DatasetSpec{
    				&DatasetSpec{
    					Atoms: []Atom{
    						{
    							Name: "f1",
    						},
    					},
    				},
    			},
    		},
    		"source1/*",
    		nil,
    	)
    }
    
    func TestRestic_Stream_Compress(t *testing.T) {
    	tmpdir := createTempDirWithData(t)
    	defer os.RemoveAll(tmpdir)
    
    	runResticTest(
    		t, tmpdir,
    		&SourceSpec{
    			Name:     "source1",
    			Handler:  "data",
    			Schedule: "@random_every 1h",
    			Datasets: []*DatasetSpec{
    				&DatasetSpec{
    					Atoms: []Atom{
    						{
    							Name: "f1",
    						},
    					},
    				},
    			},
    			Params: map[string]interface{}{
    				"compress": true,
    			},
    		},
    		"source1/*",
    		nil,
    	)
    }