| // 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") |
| } |
| } |