-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7117 from allenxu404/issue6567
Add hook status to backup/restore CR
- Loading branch information
Showing
19 changed files
with
1,173 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Add hooks status to backup/restore CR |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
/* | ||
Copyright 2020 the Velero contributors. | ||
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 hook | ||
|
||
import "sync" | ||
|
||
const ( | ||
HookSourceAnnotation = "annotation" | ||
HookSourceSpec = "spec" | ||
) | ||
|
||
// hookTrackerKey identifies a backup/restore hook | ||
type hookTrackerKey struct { | ||
// PodNamespace indicates the namespace of pod where hooks are executed. | ||
// For hooks specified in the backup/restore spec, this field is the namespace of an applicable pod. | ||
// For hooks specified in pod annotation, this field is the namespace of pod where hooks are annotated. | ||
podNamespace string | ||
// PodName indicates the pod where hooks are executed. | ||
// For hooks specified in the backup/restore spec, this field is an applicable pod name. | ||
// For hooks specified in pod annotation, this field is the pod where hooks are annotated. | ||
podName string | ||
// HookPhase is only for backup hooks, for restore hooks, this field is empty. | ||
hookPhase hookPhase | ||
// HookName is only for hooks specified in the backup/restore spec. | ||
// For hooks specified in pod annotation, this field is empty or "<from-annotation>". | ||
hookName string | ||
// HookSource indicates where hooks come from. | ||
hookSource string | ||
// Container indicates the container hooks use. | ||
// For hooks specified in the backup/restore spec, the container might be the same under different hookName. | ||
container string | ||
} | ||
|
||
// hookTrackerVal records the execution status of a specific hook. | ||
// hookTrackerVal is extensible to accommodate additional fields as needs develop. | ||
type hookTrackerVal struct { | ||
// HookFailed indicates if hook failed to execute. | ||
hookFailed bool | ||
// hookExecuted indicates if hook already execute. | ||
hookExecuted bool | ||
} | ||
|
||
// HookTracker tracks all hooks' execution status | ||
type HookTracker struct { | ||
lock *sync.RWMutex | ||
tracker map[hookTrackerKey]hookTrackerVal | ||
} | ||
|
||
// NewHookTracker creates a hookTracker. | ||
func NewHookTracker() *HookTracker { | ||
return &HookTracker{ | ||
lock: &sync.RWMutex{}, | ||
tracker: make(map[hookTrackerKey]hookTrackerVal), | ||
} | ||
} | ||
|
||
// Add adds a hook to the tracker | ||
func (ht *HookTracker) Add(podNamespace, podName, container, source, hookName string, hookPhase hookPhase) { | ||
ht.lock.Lock() | ||
defer ht.lock.Unlock() | ||
|
||
key := hookTrackerKey{ | ||
podNamespace: podNamespace, | ||
podName: podName, | ||
hookSource: source, | ||
container: container, | ||
hookPhase: hookPhase, | ||
hookName: hookName, | ||
} | ||
|
||
if _, ok := ht.tracker[key]; !ok { | ||
ht.tracker[key] = hookTrackerVal{ | ||
hookFailed: false, | ||
hookExecuted: false, | ||
} | ||
} | ||
} | ||
|
||
// Record records the hook's execution status | ||
func (ht *HookTracker) Record(podNamespace, podName, container, source, hookName string, hookPhase hookPhase, hookFailed bool) { | ||
ht.lock.Lock() | ||
defer ht.lock.Unlock() | ||
|
||
key := hookTrackerKey{ | ||
podNamespace: podNamespace, | ||
podName: podName, | ||
hookSource: source, | ||
container: container, | ||
hookPhase: hookPhase, | ||
hookName: hookName, | ||
} | ||
|
||
if _, ok := ht.tracker[key]; ok { | ||
ht.tracker[key] = hookTrackerVal{ | ||
hookFailed: hookFailed, | ||
hookExecuted: true, | ||
} | ||
} | ||
} | ||
|
||
// Stat calculates the number of attempted hooks and failed hooks | ||
func (ht *HookTracker) Stat() (hookAttemptedCnt int, hookFailed int) { | ||
ht.lock.RLock() | ||
defer ht.lock.RUnlock() | ||
|
||
for _, hookInfo := range ht.tracker { | ||
if hookInfo.hookExecuted { | ||
hookAttemptedCnt++ | ||
if hookInfo.hookFailed { | ||
hookFailed++ | ||
} | ||
} | ||
} | ||
return | ||
} | ||
|
||
// GetTracker gets the tracker inside HookTracker | ||
func (ht *HookTracker) GetTracker() map[hookTrackerKey]hookTrackerVal { | ||
ht.lock.RLock() | ||
defer ht.lock.RUnlock() | ||
|
||
return ht.tracker | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* | ||
Copyright 2020 the Velero contributors. | ||
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 hook | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestNewHookTracker(t *testing.T) { | ||
tracker := NewHookTracker() | ||
|
||
assert.NotNil(t, tracker) | ||
assert.Empty(t, tracker.tracker) | ||
} | ||
|
||
func TestHookTracker_Add(t *testing.T) { | ||
tracker := NewHookTracker() | ||
|
||
tracker.Add("ns1", "pod1", "container1", HookSourceAnnotation, "h1", PhasePre) | ||
|
||
key := hookTrackerKey{ | ||
podNamespace: "ns1", | ||
podName: "pod1", | ||
container: "container1", | ||
hookPhase: PhasePre, | ||
hookSource: HookSourceAnnotation, | ||
hookName: "h1", | ||
} | ||
|
||
_, ok := tracker.tracker[key] | ||
assert.True(t, ok) | ||
} | ||
|
||
func TestHookTracker_Record(t *testing.T) { | ||
tracker := NewHookTracker() | ||
tracker.Add("ns1", "pod1", "container1", HookSourceAnnotation, "h1", PhasePre) | ||
tracker.Record("ns1", "pod1", "container1", HookSourceAnnotation, "h1", PhasePre, true) | ||
|
||
key := hookTrackerKey{ | ||
podNamespace: "ns1", | ||
podName: "pod1", | ||
container: "container1", | ||
hookPhase: PhasePre, | ||
hookSource: HookSourceAnnotation, | ||
hookName: "h1", | ||
} | ||
|
||
info := tracker.tracker[key] | ||
assert.True(t, info.hookFailed) | ||
} | ||
|
||
func TestHookTracker_Stat(t *testing.T) { | ||
tracker := NewHookTracker() | ||
|
||
tracker.Add("ns1", "pod1", "container1", HookSourceAnnotation, "h1", PhasePre) | ||
tracker.Add("ns2", "pod2", "container1", HookSourceAnnotation, "h2", PhasePre) | ||
tracker.Record("ns1", "pod1", "container1", HookSourceAnnotation, "h1", PhasePre, true) | ||
|
||
attempted, failed := tracker.Stat() | ||
assert.Equal(t, 1, attempted) | ||
assert.Equal(t, 1, failed) | ||
} | ||
|
||
func TestHookTracker_Get(t *testing.T) { | ||
tracker := NewHookTracker() | ||
tracker.Add("ns1", "pod1", "container1", HookSourceAnnotation, "h1", PhasePre) | ||
|
||
tr := tracker.GetTracker() | ||
assert.NotNil(t, tr) | ||
|
||
t.Logf("tracker :%+v", tr) | ||
} |
Oops, something went wrong.