blob: cd33003c3c20159e1d7ff492aaac3fdca0116740 [file] [edit]
// Copyright 2020 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"context"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/GoogleCloudPlatform/osconfig/util"
"github.com/google/go-cmp/cmp"
"cloud.google.com/go/osconfig/agentendpoint/apiv1/agentendpointpb"
)
func TestFileResourceValidate(t *testing.T) {
ctx := context.Background()
tmpDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
tmpFile := filepath.Join(tmpDir, "foo")
if err := ioutil.WriteFile(tmpFile, nil, 0644); err != nil {
t.Fatal(err)
}
var tests = []struct {
name string
frpb *agentendpointpb.OSPolicy_Resource_FileResource
wantMR ManagedFile
}{
{
"Absent",
&agentendpointpb.OSPolicy_Resource_FileResource{
Path: tmpFile,
State: agentendpointpb.OSPolicy_Resource_FileResource_ABSENT,
},
ManagedFile{
Path: tmpFile,
State: agentendpointpb.OSPolicy_Resource_FileResource_ABSENT,
},
},
{
"Present",
&agentendpointpb.OSPolicy_Resource_FileResource{
Path: tmpFile,
State: agentendpointpb.OSPolicy_Resource_FileResource_PRESENT,
},
ManagedFile{
Path: tmpFile,
State: agentendpointpb.OSPolicy_Resource_FileResource_PRESENT,
Permisions: defaultFilePerms,
},
},
{
"ContentsMatch",
&agentendpointpb.OSPolicy_Resource_FileResource{
Path: tmpFile,
Source: &agentendpointpb.OSPolicy_Resource_FileResource_File{
File: &agentendpointpb.OSPolicy_Resource_File{
Type: &agentendpointpb.OSPolicy_Resource_File_LocalPath{
LocalPath: tmpFile,
},
},
},
State: agentendpointpb.OSPolicy_Resource_FileResource_CONTENTS_MATCH,
},
ManagedFile{
Path: tmpFile,
source: tmpFile,
checksum: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
State: agentendpointpb.OSPolicy_Resource_FileResource_CONTENTS_MATCH,
Permisions: defaultFilePerms,
},
},
{
"Permissions",
&agentendpointpb.OSPolicy_Resource_FileResource{
Path: tmpFile,
State: agentendpointpb.OSPolicy_Resource_FileResource_PRESENT,
Permissions: "0777",
},
ManagedFile{
Path: tmpFile,
State: agentendpointpb.OSPolicy_Resource_FileResource_PRESENT,
Permisions: 0777,
},
},
{
"LocalPath",
&agentendpointpb.OSPolicy_Resource_FileResource{
Path: tmpFile,
Source: &agentendpointpb.OSPolicy_Resource_FileResource_File{
File: &agentendpointpb.OSPolicy_Resource_File{
Type: &agentendpointpb.OSPolicy_Resource_File_LocalPath{
LocalPath: tmpFile,
},
},
},
State: agentendpointpb.OSPolicy_Resource_FileResource_PRESENT,
},
ManagedFile{
Path: tmpFile,
State: agentendpointpb.OSPolicy_Resource_FileResource_PRESENT,
Permisions: defaultFilePerms,
checksum: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
source: tmpFile,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pr := &OSPolicyResource{
OSPolicy_Resource: &agentendpointpb.OSPolicy_Resource{
ResourceType: &agentendpointpb.OSPolicy_Resource_File_{
File: tt.frpb,
},
},
}
if err := pr.Validate(ctx); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if diff := cmp.Diff(pr.ManagedResources(), &ManagedResources{Files: []ManagedFile{tt.wantMR}}, cmp.AllowUnexported(ManagedFile{})); diff != "" {
t.Errorf("OSPolicyResource does not match expectation: (-got +want)\n%s", diff)
}
if diff := cmp.Diff(pr.resource.(*fileResource).managedFile, tt.wantMR, cmp.AllowUnexported(ManagedFile{})); diff != "" {
t.Errorf("fileResource does not match expectation: (-got +want)\n%s", diff)
}
})
}
}
func TestFileResourceCheckState(t *testing.T) {
ctx := context.Background()
tmpDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
tmpFile := filepath.Join(tmpDir, "foo")
if err := ioutil.WriteFile(tmpFile, []byte("foo"), 0644); err != nil {
t.Fatal(err)
}
tmpFile2 := filepath.Join(tmpDir, "bar")
if err := ioutil.WriteFile(tmpFile2, []byte("bar"), 0644); err != nil {
t.Fatal(err)
}
var tests = []struct {
name string
frpb *agentendpointpb.OSPolicy_Resource_FileResource
wantInDesiredState bool
}{
{
"AbsentAndAbsent",
&agentendpointpb.OSPolicy_Resource_FileResource{
Path: filepath.Join(tmpDir, "dne"),
State: agentendpointpb.OSPolicy_Resource_FileResource_ABSENT,
},
true,
},
{
"AbsentAndPresent",
&agentendpointpb.OSPolicy_Resource_FileResource{
Path: tmpFile,
State: agentendpointpb.OSPolicy_Resource_FileResource_ABSENT,
},
false,
},
{
"PresentAndAbsent",
&agentendpointpb.OSPolicy_Resource_FileResource{
Path: filepath.Join(tmpDir, "dne"),
Source: &agentendpointpb.OSPolicy_Resource_FileResource_File{
File: &agentendpointpb.OSPolicy_Resource_File{
Type: &agentendpointpb.OSPolicy_Resource_File_LocalPath{
LocalPath: tmpFile,
},
},
},
State: agentendpointpb.OSPolicy_Resource_FileResource_PRESENT,
},
false,
},
{
"PresentAndPresent",
&agentendpointpb.OSPolicy_Resource_FileResource{
Path: tmpFile,
State: agentendpointpb.OSPolicy_Resource_FileResource_PRESENT,
},
true,
},
{
"ContentsMatchLocalPath",
&agentendpointpb.OSPolicy_Resource_FileResource{
Path: tmpFile,
Source: &agentendpointpb.OSPolicy_Resource_FileResource_File{
File: &agentendpointpb.OSPolicy_Resource_File{
Type: &agentendpointpb.OSPolicy_Resource_File_LocalPath{
LocalPath: tmpFile,
},
},
},
State: agentendpointpb.OSPolicy_Resource_FileResource_CONTENTS_MATCH,
},
true,
},
{
"ContentsDontMatchLocalPath",
&agentendpointpb.OSPolicy_Resource_FileResource{
Path: tmpFile2,
Source: &agentendpointpb.OSPolicy_Resource_FileResource_File{
File: &agentendpointpb.OSPolicy_Resource_File{
Type: &agentendpointpb.OSPolicy_Resource_File_LocalPath{
LocalPath: tmpFile,
},
},
},
State: agentendpointpb.OSPolicy_Resource_FileResource_CONTENTS_MATCH,
},
false,
},
{
"ContentsDontMatchDNE",
&agentendpointpb.OSPolicy_Resource_FileResource{
Path: filepath.Join(tmpDir, "dne"),
Source: &agentendpointpb.OSPolicy_Resource_FileResource_File{
File: &agentendpointpb.OSPolicy_Resource_File{
Type: &agentendpointpb.OSPolicy_Resource_File_LocalPath{
LocalPath: tmpFile,
},
},
},
State: agentendpointpb.OSPolicy_Resource_FileResource_CONTENTS_MATCH,
},
false,
},
{
"ContentMatchFromContent",
&agentendpointpb.OSPolicy_Resource_FileResource{
Path: tmpFile,
Source: &agentendpointpb.OSPolicy_Resource_FileResource_Content{
Content: "foo",
},
State: agentendpointpb.OSPolicy_Resource_FileResource_CONTENTS_MATCH,
},
true,
},
{
"ContentsDontMatchFromContent",
&agentendpointpb.OSPolicy_Resource_FileResource{
Path: tmpFile,
Source: &agentendpointpb.OSPolicy_Resource_FileResource_Content{
Content: "bar",
},
State: agentendpointpb.OSPolicy_Resource_FileResource_CONTENTS_MATCH,
},
false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pr := &OSPolicyResource{
OSPolicy_Resource: &agentendpointpb.OSPolicy_Resource{
ResourceType: &agentendpointpb.OSPolicy_Resource_File_{
File: tt.frpb,
},
},
}
if err := pr.Validate(ctx); err != nil {
t.Fatalf("Unexpected Validate error: %v", err)
}
if err := pr.CheckState(ctx); err != nil {
t.Fatalf("Unexpected CheckState error: %v", err)
}
if tt.wantInDesiredState != pr.InDesiredState() {
t.Fatalf("Unexpected InDesiredState, want: %t, got: %t", tt.wantInDesiredState, pr.InDesiredState())
}
})
}
}
func TestFileResourceEnforceStateAbsent(t *testing.T) {
ctx := context.Background()
tmpDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
tmpFile := filepath.Join(tmpDir, "foo")
if err := ioutil.WriteFile(tmpFile, []byte("foo"), 0644); err != nil {
t.Fatal(err)
}
frpb := &agentendpointpb.OSPolicy_Resource_FileResource{
Path: tmpFile,
State: agentendpointpb.OSPolicy_Resource_FileResource_ABSENT,
}
pr := &OSPolicyResource{
OSPolicy_Resource: &agentendpointpb.OSPolicy_Resource{
ResourceType: &agentendpointpb.OSPolicy_Resource_File_{File: frpb},
},
}
if err := pr.Validate(ctx); err != nil {
t.Fatalf("Unexpected Validate error: %v", err)
}
if err := pr.EnforceState(ctx); err != nil {
t.Fatalf("Unexpected EnforceState error: %v", err)
}
if util.Exists(tmpFile) {
t.Error("tmpFile still exists after EnforceState")
}
}
func TestFileResourceEnforceStatePresent(t *testing.T) {
ctx := context.Background()
tmpDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
srcFile := filepath.Join(tmpDir, "foo")
if err := ioutil.WriteFile(srcFile, []byte("foo"), 0644); err != nil {
t.Fatal(err)
}
wantFile := filepath.Join(tmpDir, "bar")
frpb := &agentendpointpb.OSPolicy_Resource_FileResource{
Path: wantFile,
Source: &agentendpointpb.OSPolicy_Resource_FileResource_File{
File: &agentendpointpb.OSPolicy_Resource_File{
Type: &agentendpointpb.OSPolicy_Resource_File_LocalPath{
LocalPath: srcFile,
},
},
},
State: agentendpointpb.OSPolicy_Resource_FileResource_PRESENT,
}
pr := &OSPolicyResource{
OSPolicy_Resource: &agentendpointpb.OSPolicy_Resource{
ResourceType: &agentendpointpb.OSPolicy_Resource_File_{File: frpb},
},
}
if err := pr.Validate(ctx); err != nil {
t.Fatalf("Unexpected Validate error: %v", err)
}
if err := pr.EnforceState(ctx); err != nil {
t.Fatalf("Unexpected EnforceState error: %v", err)
}
match, err := contentsMatch(ctx, wantFile, pr.resource.(*fileResource).managedFile.checksum)
if err != nil {
t.Fatal(err)
}
if !match {
t.Fatal("Repo file contents do not match after enforcement")
}
}