Skip to content

Commit

Permalink
Add integrity information to must-gather
Browse files Browse the repository at this point in the history
  • Loading branch information
tnozicka committed Mar 19, 2024
1 parent 8b32358 commit 88c93a5
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 18 deletions.
7 changes: 7 additions & 0 deletions pkg/cmd/operator/mustgather.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package operator

import (
"context"
"encoding/hex"
"fmt"
"time"

Expand Down Expand Up @@ -320,5 +321,11 @@ func (o *MustGatherOptions) run(ctx context.Context) error {
}
}

integritySHA, err := collector.WriteIntegrityFile()
if err != nil {
errs = append(errs, fmt.Errorf("can't write integrity file: %w", err))
}
klog.InfoS("Witten integrity file", "SHA", hex.EncodeToString(integritySHA))

return utilerrors.NewAggregate(errs)
}
43 changes: 43 additions & 0 deletions pkg/cmd/operator/mustgather_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/google/go-cmp/cmp"
scyllav1 "github.com/scylladb/scylla-operator/pkg/api/scylla/v1"
scyllav1alpha1 "github.com/scylladb/scylla-operator/pkg/api/scylla/v1alpha1"
"github.com/scylladb/scylla-operator/pkg/gather/collect"
"github.com/scylladb/scylla-operator/pkg/gather/collect/testhelpers"
"github.com/scylladb/scylla-operator/pkg/genericclioptions"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -157,6 +158,25 @@ metadata:
name: scylla-operator
spec: {}
status: {}
`, "\n"),
},
{
Name: collect.IntegrityFileName,
Content: strings.TrimPrefix(`
checksum: f3d8c4e7e30f0170945cd374ca6a2e6dbfaa84a1534e5b3da4f5bbfab165369c9c89f982779cb2630dfc9392876edf4daf5906d285741dfcf3d6f65bf688db66
directories:
/cluster-scoped/namespaces:
checksum: bbaf277edfa96fc011b6ca9db1b76eae803d26ab6169f816e88d223e2808e0dadc1733e71a8c0288630c7ab0ec77d1be34b3d78daa62f2f2b90c0dfabc3b2331
fileCount: 1
/namespaces/my-namespace/scyllaclusters.scylla.scylladb.com:
checksum: 7ab5ffe5b82d7f78398b1a4f7081ac649c28eeef72bf89cdd70eaba7f266f2d109415e7186555a718b784239677c53ddb97be08a20303fa36580c8e73c73dfff
fileCount: 1
/namespaces/my-other-namespace/scyllaclusters.scylla.scylladb.com:
checksum: f06efc479e7c5363282891bfebf7906d388bb1f6e8aa7852510b8025ee00f89bf30d648402230f310ed1e91f7266ad7434a9e56f142cdb7c9eb25eb69b9340b7
fileCount: 1
/namespaces/scylla-operator/secrets:
checksum: e46f1567de5a4a6d647595ee5f5ca424f6c05e6c044b71f694735379577250629ed421fc9d71c8e048067a3b04980e126d832589ada664609ebd5a81597920e6
fileCount: 1
`, "\n"),
},
{
Expand Down Expand Up @@ -258,6 +278,19 @@ metadata:
name: scylla-operator
spec: {}
status: {}
`, "\n"),
},
{
Name: collect.IntegrityFileName,
Content: strings.TrimPrefix(`
checksum: 6ad59d9fa641a55f9f81b554d0ea73a19d3fa03c05e08aceb757076158aab691efae7c6ca040f44e142764d71fbe25b67265a33ddb10e32d91016ce69ba99605
directories:
/cluster-scoped/namespaces:
checksum: bbaf277edfa96fc011b6ca9db1b76eae803d26ab6169f816e88d223e2808e0dadc1733e71a8c0288630c7ab0ec77d1be34b3d78daa62f2f2b90c0dfabc3b2331
fileCount: 1
/namespaces/my-namespace/scyllaclusters.scylla.scylladb.com:
checksum: 7ab5ffe5b82d7f78398b1a4f7081ac649c28eeef72bf89cdd70eaba7f266f2d109415e7186555a718b784239677c53ddb97be08a20303fa36580c8e73c73dfff
fileCount: 1
`, "\n"),
},
{
Expand Down Expand Up @@ -300,6 +333,16 @@ status: {}
expectedDump: &testhelpers.GatherDump{
EmptyDirs: nil,
Files: []testhelpers.File{
{
Name: collect.IntegrityFileName,
Content: strings.TrimPrefix(`
checksum: 3198c682f6798c42c7b94228c7f3568f045abcb8ad191caa67fc568b5dd93afd48c2fb3da372c3ebe4cf5c51a7711ddcffe8a488b4da6e1702dd2622b59c8323
directories:
/namespaces/storageversions.internal.apiserver.k8s.io:
checksum: 3198c682f6798c42c7b94228c7f3568f045abcb8ad191caa67fc568b5dd93afd48c2fb3da372c3ebe4cf5c51a7711ddcffe8a488b4da6e1702dd2622b59c8323
fileCount: 1
`, "\n"),
},
{
Name: "namespaces/storageversions.internal.apiserver.k8s.io/my-non-standard-resource.yaml",
Content: strings.TrimPrefix(`
Expand Down
56 changes: 38 additions & 18 deletions pkg/gather/collect/collect.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package collect
import (
"bytes"
"context"
"crypto/sha512"
"fmt"
"io"
"os"
"path/filepath"
"strings"

"github.com/scylladb/scylla-operator/pkg/helpers"
"github.com/scylladb/scylla-operator/pkg/helpers/slices"
Expand All @@ -26,11 +28,13 @@ import (
"k8s.io/client-go/dynamic"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/klog/v2"
"sigs.k8s.io/yaml"
)

const (
namespacesDirName = "namespaces"
clusterScopedDirName = "cluster-scoped"
IntegrityFileName = "integrity.yaml"
)

type ResourceInfo struct {
Expand All @@ -45,23 +49,6 @@ func NewResourceInfoFromMapping(mapping *meta.RESTMapping) *ResourceInfo {
}
}

func writeObject(printer ResourcePrinterInterface, filePath string, resourceInfo *ResourceInfo, obj kubeinterfaces.ObjectInterface) error {
buf := bytes.NewBuffer(nil)
err := printer.PrintObj(resourceInfo, obj, buf)
if err != nil {
return fmt.Errorf("can't print object %q (%s): %w", naming.ObjRef(obj), resourceInfo.Resource, err)
}

err = os.WriteFile(filePath, buf.Bytes(), 0770)
if err != nil {
return fmt.Errorf("can't write file %q: %w", filePath, err)
}

klog.V(4).InfoS("Written resource", "Path", filePath)

return nil
}

func getResourceKey(obj *unstructured.Unstructured, resourceInfo *ResourceInfo) string {
var nsPrefix string
if resourceInfo.Scope.Name() == meta.RESTScopeNameNamespace {
Expand All @@ -82,6 +69,7 @@ type Collector struct {
logsLimitBytes int64

collectedResources sets.Set[string]
counters *Counters
}

func NewCollector(
Expand All @@ -104,6 +92,7 @@ func NewCollector(
keepGoing: keepGoing,
logsLimitBytes: logsLimitBytes,
collectedResources: sets.Set[string]{},
counters: NewCounters(),
}
}

Expand Down Expand Up @@ -134,10 +123,24 @@ func (c *Collector) writeObject(ctx context.Context, dirPath string, obj kubeint
var err error
for _, printer := range c.printers {
filePath := filepath.Join(dirPath, obj.GetName()+printer.GetSuffix())
err = writeObject(printer, filePath, resourceInfo, obj)
buf := bytes.NewBuffer(nil)

err = printer.PrintObj(resourceInfo, obj, buf)
if err != nil {
return fmt.Errorf("can't print object %q (%s): %w", naming.ObjRef(obj), resourceInfo.Resource, err)
}

err = os.WriteFile(filePath, buf.Bytes(), 0770)
if err != nil {
return fmt.Errorf("can't write file %q: %w", filePath, err)
}

err = c.counters.writeFile(strings.TrimPrefix(dirPath, c.baseDir), buf.Bytes())
if err != nil {
return fmt.Errorf("can't write object: %w", err)
}

klog.V(4).InfoS("Written resource", "Path", filePath)
}

return nil
Expand Down Expand Up @@ -504,3 +507,20 @@ func (c *Collector) CollectResources(ctx context.Context, resourceInfo *Resource

return apierrors.NewAggregate(errs)
}

func (c *Collector) WriteIntegrityFile() ([]byte, error) {
data, err := yaml.Marshal(c.counters)
if err != nil {
return nil, fmt.Errorf("can't marsah identity: %w", err)
}

integrityFilePath := filepath.Join(c.baseDir, IntegrityFileName)
err = os.WriteFile(integrityFilePath, data, 0770)
if err != nil {
return nil, fmt.Errorf("can't write file %q: %w", integrityFilePath, err)
}

h := sha512.New()
h.Write(data)
return h.Sum(nil), nil
}
68 changes: 68 additions & 0 deletions pkg/gather/collect/collect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ func TestCollector_CollectObject(t *testing.T) {
"namespaces/test/pods/my-pod",
},
Files: []testhelpers.File{
{
Name: IntegrityFileName,
Content: strings.TrimPrefix(`
checksum: d763fa8cc6665af15380368055bb31a5720ef80d7e49232a4527e450d3d8a5fa129cac17068863ce63374afb32494089462ad79e47898b48a3f24957334fd4e8
directories:
/namespaces/test/pods:
checksum: d763fa8cc6665af15380368055bb31a5720ef80d7e49232a4527e450d3d8a5fa129cac17068863ce63374afb32494089462ad79e47898b48a3f24957334fd4e8
fileCount: 1
`, "\n"),
},
{
Name: "namespaces/test/pods/my-pod.yaml",
Content: strings.TrimPrefix(`
Expand Down Expand Up @@ -125,6 +135,16 @@ status: {}
"namespaces/test/pods/my-pod",
},
Files: []testhelpers.File{
{
Name: IntegrityFileName,
Content: strings.TrimPrefix(`
checksum: d2503c86cb530b941dd9239ee48033d804b5e7d1e4861b0b116d205b38232c9564ed13634b96901f1e471777b419754962bbe559921a34b0bb0b54b8e11fe303
directories:
/namespaces/test/pods:
checksum: d2503c86cb530b941dd9239ee48033d804b5e7d1e4861b0b116d205b38232c9564ed13634b96901f1e471777b419754962bbe559921a34b0bb0b54b8e11fe303
fileCount: 1
`, "\n"),
},
{
Name: "namespaces/test/pods/my-pod.yaml",
Content: strings.TrimPrefix(`
Expand Down Expand Up @@ -215,6 +235,16 @@ status:
expectedDump: &testhelpers.GatherDump{
EmptyDirs: nil,
Files: []testhelpers.File{
{
Name: IntegrityFileName,
Content: strings.TrimPrefix(`
checksum: 25149bc2e1d1c698989b4f6c9d6a9d87bd51369bc9328b2923ab1cddda62ecc397f254634a184da550a3b39d114d7c19a69cfd7cb266576907656ba1e6535bd7
directories:
/namespaces/test/pods:
checksum: 25149bc2e1d1c698989b4f6c9d6a9d87bd51369bc9328b2923ab1cddda62ecc397f254634a184da550a3b39d114d7c19a69cfd7cb266576907656ba1e6535bd7
fileCount: 1
`, "\n"),
},
{
Name: "namespaces/test/pods/my-pod.yaml",
Content: strings.TrimPrefix(`
Expand Down Expand Up @@ -351,6 +381,16 @@ status:
expectedDump: &testhelpers.GatherDump{
EmptyDirs: nil,
Files: []testhelpers.File{
{
Name: IntegrityFileName,
Content: strings.TrimPrefix(`
checksum: 35795801b54e77cfbe1567452e2ab7053631a02696dcc7418e173c6db99fb4dc0fab98f444b6020be77da398e8b147a47b08c64a3bfb8e96912f4aa67c04e677
directories:
/namespaces/test/pods:
checksum: 35795801b54e77cfbe1567452e2ab7053631a02696dcc7418e173c6db99fb4dc0fab98f444b6020be77da398e8b147a47b08c64a3bfb8e96912f4aa67c04e677
fileCount: 1
`, "\n"),
},
{
Name: "namespaces/test/pods/my-pod.yaml",
Content: strings.TrimPrefix(`
Expand Down Expand Up @@ -468,6 +508,16 @@ metadata:
namespace: test
spec: {}
status: {}
`, "\n"),
},
{
Name: IntegrityFileName,
Content: strings.TrimPrefix(`
checksum: 3b11d89fb3b46dd29852f0efd5eefbced9d664f0d7b93aefa8532d62c856c6a6ba0cc7eb1f898d1c337d6827d77a4d325e6ae6c555f0bf0b0973819bf85a1c51
directories:
/cluster-scoped/namespaces:
checksum: 3b11d89fb3b46dd29852f0efd5eefbced9d664f0d7b93aefa8532d62c856c6a6ba0cc7eb1f898d1c337d6827d77a4d325e6ae6c555f0bf0b0973819bf85a1c51
fileCount: 1
`, "\n"),
},
},
Expand Down Expand Up @@ -507,6 +557,19 @@ metadata:
name: my-namespace
spec: {}
status: {}
`, "\n"),
},
{
Name: IntegrityFileName,
Content: strings.TrimPrefix(`
checksum: 7f340ac7a111169126248f69c955b347d6ff5422e0cc792031bd8398dc766137896fcc188aa3ccbc274a6128296572e971dde235fc050cbf1baaa1af3a6b397a
directories:
/cluster-scoped/namespaces:
checksum: 03cb220813bf01d43c5c8316e4a3b5a766770fa3437196ddaabc478269025570f33c93f6c54791af2b450e3b197af0df5ca8ec4c3285b427c743c40b771fc225
fileCount: 1
/namespaces/my-namespace/secrets:
checksum: 99a521ab8ba30d21687b0eca6ffa1f4a4a98c2ca05a016d5f215b9a8690820abbbfddf63be1e486392a236c2c91b2a19e0ec50644c97ecb6d4b39406ecaa2e48
fileCount: 1
`, "\n"),
},
{
Expand Down Expand Up @@ -600,6 +663,11 @@ metadata:
t.Fatal(err)
}

_, err = collector.WriteIntegrityFile()
if err != nil {
t.Fatal(err)
}

got, err := testhelpers.ReadGatherDump(tmpDir)
if err != nil {
t.Fatal(err)
Expand Down
69 changes: 69 additions & 0 deletions pkg/gather/collect/counter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package collect

import (
"crypto/sha512"
"encoding/hex"
"encoding/json"
"fmt"
"hash"
)

type hasher struct {
hash.Hash
}

func (h hasher) MarshalJSON() ([]byte, error) {
return json.Marshal(hex.EncodeToString(h.Sum(nil)))
}

type IntegrityCounter struct {
FileCount uint `json:"fileCount"`
Hasher hasher `json:"checksum"`
}

func (ic *IntegrityCounter) writeFile(data []byte) error {
if ic.FileCount == 0 {
ic.Hasher = hasher{sha512.New()}
}
ic.FileCount++

_, err := ic.Hasher.Write(data)
if err != nil {
return fmt.Errorf("can't write data to hasher: %w", err)
}

return nil
}

type Counters struct {
Dirs map[string]IntegrityCounter `json:"directories"`
Hasher hasher `json:"checksum"`
}

func NewCounters() *Counters {
return &Counters{
Dirs: map[string]IntegrityCounter{},
Hasher: hasher{sha512.New()},
}
}

func (c *Counters) writeFile(dirPath string, data []byte) error {
_, err := c.Hasher.Write(data)
if err != nil {
return fmt.Errorf("can't hash data: %w", err)
}

ic, found := c.Dirs[dirPath]
if !found {
ic = IntegrityCounter{}
}

err = ic.writeFile(data)
if err != nil {
return fmt.Errorf("can't write file to identity counter: %w", err)
}

c.Dirs[dirPath] = ic

return nil
}

0 comments on commit 88c93a5

Please sign in to comment.