From 133db854b2570f2caa9467e98ed3d2db57f11a14 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Tue, 5 Aug 2025 18:55:55 +0800 Subject: [PATCH 001/104] backup repo cache design Signed-off-by: Lyndon-Li --- changelogs/unreleased/9148-Lyndon-Li | 1 + design/backup-repo-cache-volume.md | 241 +++++++++++++++++++++++++++ 2 files changed, 242 insertions(+) create mode 100644 changelogs/unreleased/9148-Lyndon-Li create mode 100644 design/backup-repo-cache-volume.md diff --git a/changelogs/unreleased/9148-Lyndon-Li b/changelogs/unreleased/9148-Lyndon-Li new file mode 100644 index 000000000..5607e26d7 --- /dev/null +++ b/changelogs/unreleased/9148-Lyndon-Li @@ -0,0 +1 @@ +Fix issue #7725, add design for backup repo cache configuration \ No newline at end of file diff --git a/design/backup-repo-cache-volume.md b/design/backup-repo-cache-volume.md new file mode 100644 index 000000000..bff839853 --- /dev/null +++ b/design/backup-repo-cache-volume.md @@ -0,0 +1,241 @@ +# Backup Repository Cache Volume Design + +## Glossary & Abbreviation + +**Backup Storage**: The storage to store the backup data. Check [Unified Repository design][1] for details. +**Backup Repository**: Backup repository is layered between BR data movers and Backup Storage to provide BR related features that is introduced in [Unified Repository design][1]. +**Velero Generic Data Path (VGDP)**: VGDP is the collective of modules that is introduced in [Unified Repository design][1]. Velero uses these modules to finish data transfer for various purposes (i.e., PodVolume backup/restore, Volume Snapshot Data Movement). VGDP modules include uploaders and the backup repository. +**Data Mover Pods**: Intermediate pods which hold VGDP and complete the data transfer. See [VGDP Micro Service for Volume Snapshot Data Movement][2] and [VGDP Micro Service For fs-backup][3] for details. +**Repository Maintenance Pods**: Pods for [Repository Maintenance Jobs][4], which holds VGDP to run repository maintenance. + +## Background + +According to the [Unified Repository design][1] Velero uses selectable backup repositories for various backup/restore methods, i.e., fs-backup, volume snapshot data movement, etc. Some backup repositories may need to cache data on the client side for various repository operation, so as to accelerate the execution. +In the existing [Backup Repository Configuration][5], we allow users to configure the cache data size (`cacheLimitMB`). However, the cache data is still stored in the root file system of data mover pods/repository maintenance pods, so stored in the root file system of the node. This is not good enough, reasons: +- In many distributions, the node's system disk size is predefined, non configurable and limit, e.g., the system disk size may be 20G or less +- Velero supports concurrent data movements in each node. The cache in each of the concurrent data mover pods could quickly run out of the system disk and cause problems like pod eviction, failure of pod creation, degradation of Kubernetes QoS, etc. + +We need to allow users to prepare a dedicated location, e.g., a dedictated volume, for the cache. +Not all backup repositories or not all backup repository operations require cache, we need to define the details when and how the cache is used. + +## Goals + +- Create a mechanism for users to configure cache volumes for various pods running VGDP +- Design the workflow to assign the cache volume pod path to backup repositories +- Describe when and how the cache volume is used + +## Non-Goals + +- The solution is based on [Unified Repository design][1], [VGDP Micro Service for Volume Snapshot Data Movement][2] and [VGDP Micro Service For fs-backup][3], legacy data paths are not supported. E.g., when a pod volume restore (PVR) runs with legacy Restic path, if any data is cached, the cache still resides in the root file system. + +## Solution + +### Cache Data + +Varying on backup repositoires, cache data may include payload data or repository metadata, e.g., indexes to the payload data chunks. + +Payload data is highly related to the backup data, and normally take the majority of the repository data as well as the cache data. + +Repository metadata is related to the backup repository's chunking algorithm, data chunk mapping method, etc, and so the size is not proportional to the backup data size. +On the other hand for some backup repository, in extreme cases, the repository metadata may be significantly large. E.g., Kopia's indexes are per chunks, if there are huge number of small files in the repository, Kopia's index data may be in the same level of or even larger than the payload data. +However, in the cases that repository metadata data become the majority, other bottlenecks may emerge and concurrency of data movers may be significantly constrained, so the requirement to cache volumes may go away. + +Therefore, for now we only consider the cache volume requirement for payload data, and leave the consideration for metadata as a future enhancement. + +### Scenarios + +Backup repository cache varies on backup repositories and backup repository operation during VGDP runs. Below are the scenarios when VGDP runs: +- Data Upload for Backup: this is the process to upload/write the backup data into the backup repository, e.g., DataUpload or PodVolumeBackup. The pieces of data is almost directly written to the repository, sometimes with a small group staying shortly in the local place. That is to say, there should not be large scale data cached for this scenario, so we don't prepare dedicated cache for this scenario. +- Repository Maintenance: Repository maintenance most often visits the backup repository's metadata and sometimes it needs to visit the file system directories from the backed up data. On the other hand, it is not practical to run concurrent maintenance jobs in one node. So the cache data is neither large nor affect the root file system too much. Therefore, we don't need to prepare dedicated cache for this scenario. +- Data Download for Restore: this is the process to download/read the backup data from the backup repository during restore, e.g., DataDownload or PodVolumeRestore. For backup repositories for which data are stored in remote backup storages (e.g., Kopia repository stores data in remote object stores), large scale of data are cached locally to accerlerate the restore. Therefore, we need dedicate cache volumes for this scenario. +- Backup Deletion: During this scenario, backup repository is connected, metadata is enumerated to find the repository snapshot representing the backup data. That is to say, only metadata is cached if any. Therefore, dedicated cache volumes are not required in this scenario. + +The above analyses are based on the common behavior of backup repositories and they are not considering the case that backup repository metadata takes majority or siginficant proportion of the cache data. +As a conclusion of the analyses, we will create dedicated cache volumes for restore scenarios. +For other scenarios, we can add them regarded to the future changes/requirements. The mechanism to expose and connect the cache volumes should work for all scenarios. E.g., if we need to consider the backup repository metadata case, we may need cache volumes for backup and repository maintenance as well, then we can just reuse the same cache volume provision and connection mechanism to backup and repository maintenance scenarios. + +### Cache Data and Lifecycle + +If available, one cache volume is dedicately assigned to one data mover pod. That is, the cached data is destroyed when the data mover pod completes. Then the backup repository instance also closes. +Cache data are fully managed by the specific backup repository. So the backup repository may also have its own way to GC the cache data. +That is to say, cache data GC may be launched by the backup repository instance during the running of the data mover pod; then the left data are automatically destroyed when the data mover pod and the cache PVC are destroyed. So no specially logics are needed for cache data GC. + +### Data Size + +Cache volumes take storage space and cluster resources (PVC, PV), therefore, cache volumes should be created only when necessary and the volumes should be with reasonable size based on the cache data size: +- It is not a good bargain to have cache volumes for small backups, small backups will use resident cache location (the cache location in the root file system) +- The cache data size has a limit, the existing `cacheLimitMB` is used for this purpose. E.g., it could be set as 1024 for a 1TB backup, which means 1GB of data is cached and the old cache data exceeding this size will be cleared. Therefore, it is meaningless to set the cache volume size much larger than `cacheLimitMB` + +### Cache Volume Size + +The cache volume size is calculated from below factors (for Restore scenarios): +- **Limit**: The limit of the cache data, that is represented by `cacheLimitMB`, the default value is 5GB +- **backupSize**: The size of the backup as a reference to evaluate whether to create a cache volume. It doesn't mean the backup data really decides the cache data all the time, it is just a reference to evaluate the scale of the backup, small scale backups may need small cache data. Sometimes, backupSize is not applicable/available or is irrelevant to the size of cache data, in this case, Limit will be used directly. +- **ResidentThreshold**: The minimum backup size that a cache volume is created +- **InflationPercentage**: Considering the overhead of the file system and the possible delay of the cache cleanup, there should be an inflation for the final volume size vs. the logical size, otherwise, the cache volume may be overrun. This inflation percentage is hardcoded, e.g., 20% + +A formula is as below: +``` +cacheVolumeSize = (backupSize != 0 ? (backupSize > residentThreshold ? limit : 0) : limit) * inflationPercentage +``` +Finally, the `cacheVolumeSize` will be rounded up to GiB considering the UX friendliness, storage friendliness and management friendliness. + +### PVC/PV + +The PVC for a cache volume is created in Velero namespace and a storage class is required for the cache PVC. The PVC's accessMode is `ReadWriteOnce` and volumeMode is `FileSystem`, so the storage class provided should support this specification. Otherwise, if the storageclass doesn't support either of the specifications, the data mover pod may be hang in `Pending` state until a timeout setting with the data movement (e.g. `prepareTimeout`) and the data movement will finally fail. + +### Cache Volume Configurations + +Below configurations are introduced: +- **residentThresholdMB**: the minimum data size(in MB) to be processed (if available) that a cache volume is created +- **cacheStorageClass**: the name of the storage class to provision the cache PVC + +Not like `cacheLimitMB` which is set to and affect the backup repository, the above two configurations are actually data mover configurations of how to create cache volumes to data mover pods; and the two configurations don't need to be per backup repository. So we add them to the node-agent Configuration. + +### Sample + +Below are some examples of the node-agent configMap with the configurations: + +Sample-1: +```json +{ + "cacheVolume": { + "storageClass": "sc-1", + "residentThresholdMB": 1024 + } +} +``` + +Sample-2: +```json +{ + "cacheVolume": { + "storageClass": "sc-1", + } +} +``` + +Sample-3: +```json +{ + "cacheVolume": { + "residentThresholdMB": 1024 + } +} +``` + +**sample-1**: This is a valid configuration. Restores with backup data size larger than 1G will be assigned a cache volume using storage class `sc-1`. +**sample-2**: This is a valid configuration. Data mover pods are always assigned a cache volume using storage class `sc-1`. +**sample-3**: This is not a valid configuration because the storage class is absent. Velero gives up creating a cache volume. + +To create the configMap, users need to save something like the above sample to a json file and then run below command: +``` +kubectl create cm -n velero --from-file= +``` + +The cache volume configurations will be visited by node-agent server, so they also need to specify the `--node-agent-configmap` to the `velero node-agent` parameters. + +## Detailed Design + +### Backup and Restore + +The restore needs to know the backup size so as to calculate the cache volume size, some new fields are added to the DataUpload, DataDownload, PodVolumeBackup and PodVolumeRestore CRDs. + +`snapshotSize` field is added to DataUpload and PodVolumeBackup's `status`: +```yaml + status: + snapshotID: + description: SnapshotID is the identifier for the snapshot in the + backup repository. + type: string + snapshotSize: + description: SnapshotSize is the logical size of the snapshot. + format: int64 + type: integer +``` + +`snapshotSize` field is also added to DataDownload and PodVolumeRestore's `spec`: +```yaml + spec: + snapshotID: + description: SnapshotID is the ID of the Velero backup snapshot to + be restored from. + type: string + snapshotSize: + description: SnapshotSize is the logical size of the snapshot. + format: int64 + type: integer +``` + +`snapshotSize` represents the total size of the backup; during restore, the value is transferred from DataUpload/PodVolumeBackup to DataDownload/PodVolumeRestore. + +When restoring from backups created by previous versions, `snapshotSize` is not available, according to the above formula, `residentThresholdMB` is ignored, cache volume size is calculated directly from cache limit for the corresponding backup repository. + +### Exposer + +Cache volume configurations are retrieved by node-agent and passed through DataDownload/PodVolumeRestore to GenericRestore exposer/PodVolume exposer. +The exposers are responsible to calculate cache volume size, create cache PVCs and mount them to the restorePods. +If the calculated cache volume size is 0, or any of the critical parameters is missing (e.g., cache volume storage class), the exposers ignore the cache volume configuration and continue with creating restorePods without cache volumes, so no impact to the result of the restore. + +Exposers mount the cache volume to a predefined directory and pass the directory to the data mover pods through the `cache-volume-path` parameter. + +Below data structure is added to the exposers' expose parameters: + +```go +type GenericRestoreExposeParam struct { + // RestoreSize specifies the data size for the volume to be restored + RestoreSize int64 + + // CacheVolume specifies the info for cache volumes + CacheVolume *CacheVolumeInfo +} + +type PodVolumeExposeParam struct { + // RestoreSize specifies the data size for the volume to be restored + RestoreSize int64 + + // CacheVolume specifies the info for cache volumes + CacheVolume *repocache.CacheConfigs +} + +type CacheConfigs struct { + // StorageClass specifies the storage class for cache volumes + StorageClass string + + // Limit specifies the maximum size of the cache data + Limit int64 + + // ResidentThreshold specifies the minimum size of the cache data to create a cache volume + ResidentThreshold int64 +} +``` + +### Data Mover Pods + +Data mover pods retrieve the cache volume directory from `cache-volume-path` parameter and pass it to Unified Repository. +If the directory is empty, Unified Repository uses the resident location for data cache, that is, the root file system. + +### Kopia Repository + +Kopia repository supports cache directory configuration for both metadata and data. The existing `SetupConnectOptions` is modified to customize the `CacheDirectory`: + +```go +func SetupConnectOptions(ctx context.Context, repoOptions udmrepo.RepoOptions) repo.ConnectOptions { + ... + + return repo.ConnectOptions{ + CachingOptions: content.CachingOptions{ + CacheDirectory: cacheDir, + ... + }, + ... + } +} +``` + + +[1]: Implemented/unified-repo-and-kopia-integration/unified-repo-and-kopia-integration.md +[2]: Implemented/vgdp-micro-service/vgdp-micro-service.md +[3]: Implemented/vgdp-micro-service-for-fs-backup/vgdp-micro-service-for-fs-backup.md +[4]: Implemented/repo_maintenance_job_config.md +[5]: Implemented/backup-repo-config.md \ No newline at end of file From 571a816a61f4b3e50ca357db63cd9ab2cd84b1b1 Mon Sep 17 00:00:00 2001 From: Joseph Date: Wed, 2 Jul 2025 11:45:57 -0400 Subject: [PATCH 002/104] Add design doc Signed-off-by: Joseph --- design/wildcard-namespace-support-design.md | 146 ++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 design/wildcard-namespace-support-design.md diff --git a/design/wildcard-namespace-support-design.md b/design/wildcard-namespace-support-design.md new file mode 100644 index 000000000..b7b1b01ba --- /dev/null +++ b/design/wildcard-namespace-support-design.md @@ -0,0 +1,146 @@ +# Wildcard Namespace Support Design + +## Abstract +This proposal introduces wildcard pattern support for namespace inclusion and exclusion in Velero backups (e.g., `prod-*`, `*-staging`). +The implementation uses lazy evaluation within the existing `ShouldInclude()` method to resolve wildcards on-demand with request-scoped caching. +Based on [Issue #1874](https://github.com/vmware-tanzu/velero/issues/1874). + +## Background +- Currently, Velero users must explicitly list each namespace for backup operations +- In environments with many namespaces following naming conventions (e.g., `prod-app`, `prod-db`, `prod-cache`), this becomes: + - Cumbersome to maintain + - Error-prone to manage +- Users have requested wildcard support to enable patterns like `--include-namespaces "prod-*"` + +## Goals +- Enable wildcard pattern support for namespace includes and excludes in Velero backup specifications +- Maintain optimal performance with lazy evaluation and request-scoped caching +- Preserve original wildcard patterns in backup specifications for audit and readability purposes + +## Non Goals +- Support for complex regex patterns beyond basic glob-style wildcards (`*`) +- Persistent caching of namespace resolution across backup requests +- Real-time namespace discovery that changes during backup execution + +## High-Level Design + +**Core Approach:** We're making the existing concrete type (`*IncludesExcludes`) polymorphic so we can substitute our new lazy evaluation type (`*LazyNamespaceIncludesExcludes`) without changing any calling code. + +- Implementation at **backup request level** within the `ShouldInclude()` method +- Uses lazy evaluation with `LazyNamespaceIncludesExcludes` wrapper +- On-demand namespace resolution with thread-safe caching +- First call triggers Kubernetes API namespace enumeration and wildcard resolution +- Results cached for subsequent calls within the same backup request + +## Detailed Design + +### Polymorphic Interface Approach + +The key insight is that all existing backup code already calls the same 4 methods on namespace filtering: +- `ShouldInclude(namespace string) bool` - Core filtering logic +- `IncludesString() string` - Logging display +- `ExcludesString() string` - Logging display +- `IncludeEverything() bool` - Optimization checks + +By creating a `NamespaceIncludesExcludesInterface` with these methods, we can: +1. **Standard case**: Use existing `*IncludesExcludes` (no wildcards) +2. **Wildcard case**: Use new `*LazyNamespaceIncludesExcludes` (with K8s API enumeration) + +**No calling code changes needed** - the interface abstraction handles everything. + +**Cache Scope:** Single backup request only - automatic cleanup when request completes. + +### Implementation Strategy + +**Location:** `pkg/util/collections/includes_excludes.go` +- New interface defining the 4 required methods +- `LazyNamespaceIncludesExcludes` struct embedding `*IncludesExcludes` for fallback +- Lazy resolution with thread-safe caching using mutex +- Special case handling for lone `*` to preserve existing efficient behavior + +**Integration:** `pkg/backup/backup.go` +- Wildcard detection logic determines which implementation to return +- Lone `*` pattern → standard `IncludesExcludes` (preserve current behavior) +- Any other wildcards → lazy `LazyNamespaceIncludesExcludes` + +**Type Updates:** Change struct fields from concrete `*IncludesExcludes` to interface type +- `pkg/backup/request.go` - Request struct field type +- `pkg/backup/item_collector.go` - Function parameter types + +### Performance Characteristics +- **First `ShouldInclude()` call:** ~500ms (K8s API namespace enumeration + wildcard resolution) +- **Subsequent calls:** ~1ms (cached lookup with read lock) +- **Memory overhead:** Minimal (resolved namespace list stored once per backup request) +- **Concurrency:** Full concurrent read access to cached results + +## Alternatives Considered + +### CLI-Level Resolution +**Problem:** Resolving wildcards during `velero backup create` command + +**Why rejected:** +- **Lost User Intent:** Backup specs store resolved lists instead of original patterns +- **Audit Trail Issues:** Original wildcard intent not visible when examining backup specifications +- **CLI Complexity:** CLI requires cluster access and namespace enumeration capabilities + +### Server-Level (Controller) Resolution +**Problem:** Resolving wildcards in backup controller with persistent caching + +**Why rejected:** +- **Architectural Complexity:** Requires additional API schema changes for storing resolved namespace lists +- **Cache Management:** Need cache invalidation, storage, and lifecycle management +- **Limited Benefit:** Performance gain only applies to narrow controller reconciliation retry scenarios +- **State Management:** Introduces persistent state maintained across backup lifecycle + +### Request-Level (ShouldInclude) Resolution +**Chosen Approach:** Lazy evaluation within backup request processing + +**Benefits:** +- **Preserved Intent:** Original wildcard patterns remain in backup specifications +- **Optimal Performance:** First resolution (~500ms), subsequent calls (~1ms) with request-scoped caching +- **Clean Architecture:** No persistent state, no API schema changes, minimal code changes +- **Thread Safety:** Proper mutex usage for concurrent worker access +- **Scoped Lifetime:** Cache automatically cleaned up when backup request completes + +## Security Considerations +- Implementation requires Velero service account to have `list` permissions on namespace resources +- Aligns with existing Velero RBAC requirements +- No additional privileges or security surface area introduced + +## Addressing Implementation Concerns + +### Multiple Pattern Support +Multiple wildcards work naturally: `--include-namespaces "prod-*,staging-*,dev-*"` - each pattern evaluated independently during lazy resolution. + +### Mixed Literal and Wildcard Detection +Simple approach: strings containing `*` are wildcards, others use existing literal namespace logic. Zero breaking changes for existing validation. + +### Include/Exclude Conflict Detection +Runtime resolution simplifies conflicts - wildcards resolve to actual namespace lists first, then standard include/exclude precedence applies. + +### Backward Compatibility +Lazy evaluation triggers only when wildcards detected. Non-wildcard backups have zero overhead and identical behavior to current implementation. + +## Special Consideration: Existing `*` Behavior + +**Current Velero Behavior:** `--include-namespaces "*"` (the CLI default) means "include all namespaces" and uses special logic that doesn't enumerate namespaces - it simply bypasses namespace filtering entirely. + +**Potential Breaking Change:** Our wildcard implementation would treat `*` as a glob pattern, resolving it to a specific list of namespaces at backup start time, which changes the behavior from "include everything" to "include these specific namespaces." + +**Required Solution:** Special-case handling for the lone `*` pattern to preserve existing behavior by using original `IncludesExcludes` logic instead of wildcard resolution. + +This ensures that `--include-namespaces "*"` continues to work exactly as before, while enabling new wildcard patterns like `prod-*`, `*-staging`, etc. + +## Compatibility +- Full backward compatibility with existing backup specifications using literal namespace lists +- No changes required to CLI commands, existing backups, or restore operations + +## Implementation +The implementation consists of approximately 200 lines of new code across four files: +- `pkg/util/collections/includes_excludes.go`: Core lazy evaluation logic (~150 lines) +- `pkg/backup/backup.go`: Wildcard detection logic (~20 lines) +- `pkg/backup/request.go`: Interface type usage (~5 lines) +- `pkg/backup/item_collector.go`: Compatibility method calls (~25 lines) + +## Open Issues +None. \ No newline at end of file From 69e307918bdedd03e12838d018cea084b984f0f6 Mon Sep 17 00:00:00 2001 From: Joseph Date: Mon, 28 Jul 2025 08:42:26 -0400 Subject: [PATCH 003/104] Update design Signed-off-by: Joseph --- design/wildcard-namespace-support-design.md | 261 ++++++++++++++++++++ 1 file changed, 261 insertions(+) diff --git a/design/wildcard-namespace-support-design.md b/design/wildcard-namespace-support-design.md index b7b1b01ba..32245dc87 100644 --- a/design/wildcard-namespace-support-design.md +++ b/design/wildcard-namespace-support-design.md @@ -73,6 +73,267 @@ By creating a `NamespaceIncludesExcludesInterface` with these methods, we can: - **Memory overhead:** Minimal (resolved namespace list stored once per backup request) - **Concurrency:** Full concurrent read access to cached results +## Namespace Discovery Timing and Behavior + +### Snapshot Timing +**Wildcard patterns are resolved at backup start time** and remain fixed for the entire backup duration. This provides: +- **Consistent behavior**: All resources in a backup come from the same namespace set +- **Predictable results**: Backup contents don't change mid-execution +- **Performance**: No repeated namespace enumeration during backup processing + +### Runtime Namespace Changes +When namespaces are created or deleted during backup execution: + +**Newly Created Namespaces:** +- If `prod-new` is created after backup starts, it will **NOT** be included even if it matches `prod-*` +- The resolved namespace list is fixed at backup start time + +**Deleted Namespaces:** +- If a namespace matching the pattern is deleted during backup, the backup continues +- Resources already processed from that namespace remain in the backup +- Subsequent resource enumeration for that namespace may result in "not found" errors (handled gracefully) + - This should ideally fail so that the user can re-run it without a namespace being deleted while a backup is started which is rare. + +**User Expectations:** +This behavior should be explicitly documented with examples: +``` +# At backup start: namespaces [prod-app, prod-db] exist +velero backup create --include-namespaces "prod-*" + +# During backup: prod-cache namespace is created +# Result: prod-cache is NOT included in this backup +# Recommendation: Run another backup to capture newly created namespaces +``` + +## Pattern Complexity and Validation + +### Supported Patterns +**Basic Wildcard Support (`*` only):** +- `prefix-*` - Matches namespaces starting with "prefix-" +- `*-suffix` - Matches namespaces ending with "-suffix" +- `*-middle-*` - Matches namespaces containing "-middle-" +- `*` - Special case: matches all namespaces (preserves current behavior) + +### Unsupported Patterns +**Not supported in initial implementation:** +- `?` for single character matching (e.g., `prod-?-app`) +- Character classes (e.g., `prod-[abc]-app`) +- Regex patterns (e.g., `prod-\d+-app`) + +### Pattern Validation +**Creation-time validation:** +- Invalid patterns containing unsupported characters will be rejected at backup creation +- Validation occurs in CLI and API server admission controller +- Clear error messages guide users to supported patterns + +**Example validation errors:** +```bash +# Unsupported pattern +velero backup create --include-namespaces "prod-?-app" +# Error: Pattern 'prod-?-app' contains unsupported character '?'. Only '*' wildcards are supported. + +# Valid patterns +velero backup create --include-namespaces "prod-*,*-staging" +# Success: Patterns validated successfully +``` + +## Error Handling + +### Kubernetes API Failures +**Namespace enumeration failures:** +- If initial namespace list API call fails → backup fails with clear error message +- Transient failures are retried using standard Kubernetes client retry logic +- No fallback to cached/partial data to ensure consistent behavior + +**Error response example:** +``` +Error: Failed to enumerate namespaces for wildcard resolution: unable to connect to Kubernetes API +Backup creation aborted. Please verify cluster connectivity and try again. +``` + +### Zero Namespace Matches +**When wildcard patterns match no namespaces:** +- **Behavior**: Warning logged, backup proceeds with empty namespace set +- **User notification**: Warning in backup status and logs +- **Rationale**: Allows for valid scenarios (e.g., temporary namespace absence) + +**Warning example:** +``` +Warning: Wildcard pattern 'prod-*' matched 0 namespaces. Backup will include no namespaces from this pattern. +``` + +### Dry-Run Support +**Preview functionality:** +```bash +# New flag to preview wildcard resolution +velero backup create my-backup --include-namespaces "prod-*" --dry-run=wildcards + +# Output: +Wildcard pattern 'prod-*' would include namespaces: [prod-app, prod-db, prod-cache] +Wildcard pattern '*-staging' would include namespaces: [app-staging, db-staging] +Total namespaces: 5 +``` + +## Restore Operations + +### Wildcard Behavior During Restore +**Restore uses namespaces captured at backup time:** +- Wildcard patterns in backup specs are **not** re-evaluated during restore +- Restore operates on the concrete namespace list that was resolved during backup +- This ensures restore consistency even if cluster namespace state has changed + +**Implementation approach:** +1. **Backup metadata storage**: Store both original patterns and resolved namespace lists +2. **Restore processing**: Use resolved namespace lists, ignore original patterns +3. **Audit trail**: Both patterns and resolved lists visible in backup metadata + +**Example scenario:** +```yaml +# Original backup spec +includedNamespaces: ["prod-*"] + +# Stored in backup metadata +resolvedNamespaces: ["prod-app", "prod-db"] +originalPatterns: ["prod-*"] + +# During restore (even if prod-cache now exists) +# Only prod-app and prod-db are restored +``` + +### Disaster Recovery Scenarios +**Cross-cluster restore behavior:** +- Restore attempts to create resources in target namespaces +- If target namespaces don't exist, Velero creates them (existing behavior) +- Wildcard patterns are not re-evaluated against target cluster + +## Scheduled Backups + +### Namespace State Changes Between Runs +**Each scheduled backup run performs fresh wildcard resolution:** +- Pattern `prod-*` may include different namespaces in each backup run +- This allows scheduled backups to automatically capture newly created namespaces +- **Trade-off**: Backup contents may vary between runs vs. automatic inclusion of new resources + +**Storage implications:** +- Varying namespace sets between runs may affect deduplication efficiency +- Each backup stores its own resolved namespace list independently + +**Example behavior:** +``` +# Monday backup: prod-* matches [prod-app, prod-db] +# Tuesday: prod-cache namespace created +# Tuesday backup: prod-* matches [prod-app, prod-db, prod-cache] +``` + +**User expectations:** +- Document that scheduled backups automatically include newly matching namespaces +- Provide guidance on namespace naming conventions for predictable backup behavior + +## Testing Strategy + +### Unit Tests +**Pattern matching tests:** +```go +func TestWildcardPatterns(t *testing.T) { + tests := []struct { + pattern string + namespace string + expected bool + }{ + {"prod-*", "prod-app", true}, + {"prod-*", "staging-app", false}, + {"*-staging", "app-staging", true}, + {"*-test-*", "app-test-db", true}, + } + // ... test implementation +} +``` + +**Edge cases:** +- Empty pattern list +- Pattern with no matches +- Pattern matching single namespace +- Multiple overlapping patterns +- Special case lone `*` behavior + +### Integration Tests +**Kubernetes cluster scenarios:** +- Create namespaces, verify wildcard resolution +- Test namespace creation/deletion during backup +- Verify thread safety with concurrent backup operations +- Error scenarios (API failures, network issues) + +**Concurrency testing:** +- Multiple concurrent `ShouldInclude()` calls +- Thread safety verification +- Cache hit ratio measurement + +## Example Usage + +### CLI Usage +```bash +# Single wildcard pattern +velero backup create prod-backup --include-namespaces "prod-*" + +# Multiple patterns +velero backup create env-backup --include-namespaces "prod-*,staging-*,dev-*" + +# Mixed literal and wildcard +velero backup create mixed-backup --include-namespaces "prod-*,kube-system,monitoring" + +# Exclude patterns +velero backup create no-test --include-namespaces "*" --exclude-namespaces "*-test,*-temp" + +# Preview before creating +velero backup create my-backup --include-namespaces "prod-*" --dry-run=wildcards +``` + +### Backup Specification YAML +```yaml +apiVersion: velero.io/v1 +kind: Backup +metadata: + name: production-backup + namespace: velero +spec: + # Wildcard patterns in includedNamespaces + includedNamespaces: + - "prod-*" # All namespaces starting with "prod-" + - "production-*" # All namespaces starting with "production-" + - "critical-app" # Literal namespace (mixed with wildcards) + + # Wildcard patterns in excludedNamespaces + excludedNamespaces: + - "*-test" # Exclude any test namespaces + - "*-temp" # Exclude any temporary namespaces + + # Other backup configuration + storageLocation: default + volumeSnapshotLocations: + - default + includeClusterResources: false +``` + +### Stored Backup Metadata +```yaml +# What gets stored in backup metadata +apiVersion: velero.io/v1 +kind: Backup +metadata: + name: production-backup +status: + # Original user patterns preserved for audit + originalIncludePatterns: ["prod-*", "production-*", "critical-app"] + originalExcludePatterns: ["*-test", "*-temp"] + + # Resolved concrete namespace lists (used for restore) + resolvedIncludedNamespaces: ["prod-app", "prod-db", "production-web", "critical-app"] + resolvedExcludedNamespaces: ["prod-app-test", "staging-temp"] + + # Resolution timestamp + namespaceResolutionTime: "2024-01-15T10:30:00Z" +``` + ## Alternatives Considered ### CLI-Level Resolution From c0699c443bdcd9d0f859b01f826c108de0aab016 Mon Sep 17 00:00:00 2001 From: Joseph Date: Fri, 1 Aug 2025 13:25:44 -0400 Subject: [PATCH 004/104] New design doc Signed-off-by: Joseph --- design/wildcard-namespace-support-design.md | 424 +++----------------- 1 file changed, 48 insertions(+), 376 deletions(-) diff --git a/design/wildcard-namespace-support-design.md b/design/wildcard-namespace-support-design.md index 32245dc87..b5dfd3618 100644 --- a/design/wildcard-namespace-support-design.md +++ b/design/wildcard-namespace-support-design.md @@ -1,407 +1,79 @@ -# Wildcard Namespace Support Design + +# Wildcard namespace includes/excludes support for backups and restores ## Abstract -This proposal introduces wildcard pattern support for namespace inclusion and exclusion in Velero backups (e.g., `prod-*`, `*-staging`). -The implementation uses lazy evaluation within the existing `ShouldInclude()` method to resolve wildcards on-demand with request-scoped caching. -Based on [Issue #1874](https://github.com/vmware-tanzu/velero/issues/1874). +One to two sentences that describes the goal of this proposal and the problem being solved by the proposed change. +The reader should be able to tell by the title, and the opening paragraph, if this document is relevant to them. + +Velero currently does not have any support for wildcard characters in the namespace spec. +It fully expects the namespaces to be string literals. + +The only and notable exception is the "*" character by it's lonesome, which acts as an include all and ignore excludes option. +Internally Velero treats not specifying anything as the "*" case. + +This document details the approach to implementing wildcard namespaces, while keeping the "*" characters purpose intact for legacy purposes. ## Background -- Currently, Velero users must explicitly list each namespace for backup operations -- In environments with many namespaces following naming conventions (e.g., `prod-app`, `prod-db`, `prod-cache`), this becomes: - - Cumbersome to maintain - - Error-prone to manage -- Users have requested wildcard support to enable patterns like `--include-namespaces "prod-*"` +This was raised in Issue [#1874](https://github.com/vmware-tanzu/velero/issues/1874) + ## Goals -- Enable wildcard pattern support for namespace includes and excludes in Velero backup specifications -- Maintain optimal performance with lazy evaluation and request-scoped caching -- Preserve original wildcard patterns in backup specifications for audit and readability purposes +- A short list of things which will be accomplished by implementing this proposal. +- Two things is ok. +- Three is pushing it. +- More than three goals suggests that the proposal's scope is too large. + +- Add support for wildcard namespaces in --include-namespaces and --exclude-namespaces +- Ensure legacy "*" support is not affected ## Non Goals -- Support for complex regex patterns beyond basic glob-style wildcards (`*`) -- Persistent caching of namespace resolution across backup requests -- Real-time namespace discovery that changes during backup execution +- A short list of items which are: +- a. out of scope +- b. follow on items which are deliberately excluded from this proposal. + +- Completely rethinking the way "*" is treated and allowing it to work with wildcard excludes. + ## High-Level Design +One to two paragraphs that describe the high level changes that will be made to implement this proposal. -**Core Approach:** We're making the existing concrete type (`*IncludesExcludes`) polymorphic so we can substitute our new lazy evaluation type (`*LazyNamespaceIncludesExcludes`) without changing any calling code. +Points of interest are two funcs within the utility layer, in file `velero/pkg/backup/item_collector.go` +- [collectNamespaces](https://github.com/vmware-tanzu/velero/blob/1535afb45e33a3d3820088e4189800a21ba55293/pkg/backup/item_collector.go#L742) +- [getNamespacesToList](https://github.com/vmware-tanzu/velero/blob/1535afb45e33a3d3820088e4189800a21ba55293/pkg/backup/item_collector.go#L638) -- Implementation at **backup request level** within the `ShouldInclude()` method -- Uses lazy evaluation with `LazyNamespaceIncludesExcludes` wrapper -- On-demand namespace resolution with thread-safe caching -- First call triggers Kubernetes API namespace enumeration and wildcard resolution -- Results cached for subsequent calls within the same backup request +collectNamespaces gets all the active namespaces and matches it against the user spec for included namespaces (r.backupRequest.Backup.Spec.IncludedNamespaces) +This is an ideal point where wildcard expansion can take place. +The implementation would mean that just like "*", namespaces with wildcard symbols would also be passed through without an existence check. +The resolved namespaces are stored in new status fields on the backup. ## Detailed Design +A detailed design describing how the changes to the product should be made. -### Polymorphic Interface Approach +The names of types, fields, interfaces, and methods should be agreed on here, not debated in code review. +The same applies to changes in CRDs, YAML examples, and so on. -The key insight is that all existing backup code already calls the same 4 methods on namespace filtering: -- `ShouldInclude(namespace string) bool` - Core filtering logic -- `IncludesString() string` - Logging display -- `ExcludesString() string` - Logging display -- `IncludeEverything() bool` - Optimization checks +Ideally the changes should be made in sequence so that the work required to implement this design can be done incrementally, possibly in parallel. -By creating a `NamespaceIncludesExcludesInterface` with these methods, we can: -1. **Standard case**: Use existing `*IncludesExcludes` (no wildcards) -2. **Wildcard case**: Use new `*LazyNamespaceIncludesExcludes` (with K8s API enumeration) - -**No calling code changes needed** - the interface abstraction handles everything. - -**Cache Scope:** Single backup request only - automatic cleanup when request completes. - -### Implementation Strategy - -**Location:** `pkg/util/collections/includes_excludes.go` -- New interface defining the 4 required methods -- `LazyNamespaceIncludesExcludes` struct embedding `*IncludesExcludes` for fallback -- Lazy resolution with thread-safe caching using mutex -- Special case handling for lone `*` to preserve existing efficient behavior - -**Integration:** `pkg/backup/backup.go` -- Wildcard detection logic determines which implementation to return -- Lone `*` pattern → standard `IncludesExcludes` (preserve current behavior) -- Any other wildcards → lazy `LazyNamespaceIncludesExcludes` - -**Type Updates:** Change struct fields from concrete `*IncludesExcludes` to interface type -- `pkg/backup/request.go` - Request struct field type -- `pkg/backup/item_collector.go` - Function parameter types - -### Performance Characteristics -- **First `ShouldInclude()` call:** ~500ms (K8s API namespace enumeration + wildcard resolution) -- **Subsequent calls:** ~1ms (cached lookup with read lock) -- **Memory overhead:** Minimal (resolved namespace list stored once per backup request) -- **Concurrency:** Full concurrent read access to cached results - -## Namespace Discovery Timing and Behavior - -### Snapshot Timing -**Wildcard patterns are resolved at backup start time** and remain fixed for the entire backup duration. This provides: -- **Consistent behavior**: All resources in a backup come from the same namespace set -- **Predictable results**: Backup contents don't change mid-execution -- **Performance**: No repeated namespace enumeration during backup processing - -### Runtime Namespace Changes -When namespaces are created or deleted during backup execution: - -**Newly Created Namespaces:** -- If `prod-new` is created after backup starts, it will **NOT** be included even if it matches `prod-*` -- The resolved namespace list is fixed at backup start time - -**Deleted Namespaces:** -- If a namespace matching the pattern is deleted during backup, the backup continues -- Resources already processed from that namespace remain in the backup -- Subsequent resource enumeration for that namespace may result in "not found" errors (handled gracefully) - - This should ideally fail so that the user can re-run it without a namespace being deleted while a backup is started which is rare. - -**User Expectations:** -This behavior should be explicitly documented with examples: -``` -# At backup start: namespaces [prod-app, prod-db] exist -velero backup create --include-namespaces "prod-*" - -# During backup: prod-cache namespace is created -# Result: prod-cache is NOT included in this backup -# Recommendation: Run another backup to capture newly created namespaces +1. Add new status fields to the backup CRD to store expanded wildcard namespaces ``` -## Pattern Complexity and Validation - -### Supported Patterns -**Basic Wildcard Support (`*` only):** -- `prefix-*` - Matches namespaces starting with "prefix-" -- `*-suffix` - Matches namespaces ending with "-suffix" -- `*-middle-*` - Matches namespaces containing "-middle-" -- `*` - Special case: matches all namespaces (preserves current behavior) - -### Unsupported Patterns -**Not supported in initial implementation:** -- `?` for single character matching (e.g., `prod-?-app`) -- Character classes (e.g., `prod-[abc]-app`) -- Regex patterns (e.g., `prod-\d+-app`) - -### Pattern Validation -**Creation-time validation:** -- Invalid patterns containing unsupported characters will be rejected at backup creation -- Validation occurs in CLI and API server admission controller -- Clear error messages guide users to supported patterns - -**Example validation errors:** -```bash -# Unsupported pattern -velero backup create --include-namespaces "prod-?-app" -# Error: Pattern 'prod-?-app' contains unsupported character '?'. Only '*' wildcards are supported. - -# Valid patterns -velero backup create --include-namespaces "prod-*,*-staging" -# Success: Patterns validated successfully ``` +2. Create a util package for wildcard expansion -## Error Handling - -### Kubernetes API Failures -**Namespace enumeration failures:** -- If initial namespace list API call fails → backup fails with clear error message -- Transient failures are retried using standard Kubernetes client retry logic -- No fallback to cached/partial data to ensure consistent behavior - -**Error response example:** -``` -Error: Failed to enumerate namespaces for wildcard resolution: unable to connect to Kubernetes API -Backup creation aborted. Please verify cluster connectivity and try again. -``` - -### Zero Namespace Matches -**When wildcard patterns match no namespaces:** -- **Behavior**: Warning logged, backup proceeds with empty namespace set -- **User notification**: Warning in backup status and logs -- **Rationale**: Allows for valid scenarios (e.g., temporary namespace absence) - -**Warning example:** -``` -Warning: Wildcard pattern 'prod-*' matched 0 namespaces. Backup will include no namespaces from this pattern. -``` - -### Dry-Run Support -**Preview functionality:** -```bash -# New flag to preview wildcard resolution -velero backup create my-backup --include-namespaces "prod-*" --dry-run=wildcards - -# Output: -Wildcard pattern 'prod-*' would include namespaces: [prod-app, prod-db, prod-cache] -Wildcard pattern '*-staging' would include namespaces: [app-staging, db-staging] -Total namespaces: 5 -``` - -## Restore Operations - -### Wildcard Behavior During Restore -**Restore uses namespaces captured at backup time:** -- Wildcard patterns in backup specs are **not** re-evaluated during restore -- Restore operates on the concrete namespace list that was resolved during backup -- This ensures restore consistency even if cluster namespace state has changed - -**Implementation approach:** -1. **Backup metadata storage**: Store both original patterns and resolved namespace lists -2. **Restore processing**: Use resolved namespace lists, ignore original patterns -3. **Audit trail**: Both patterns and resolved lists visible in backup metadata - -**Example scenario:** -```yaml -# Original backup spec -includedNamespaces: ["prod-*"] - -# Stored in backup metadata -resolvedNamespaces: ["prod-app", "prod-db"] -originalPatterns: ["prod-*"] - -# During restore (even if prod-cache now exists) -# Only prod-app and prod-db are restored -``` - -### Disaster Recovery Scenarios -**Cross-cluster restore behavior:** -- Restore attempts to create resources in target namespaces -- If target namespaces don't exist, Velero creates them (existing behavior) -- Wildcard patterns are not re-evaluated against target cluster - -## Scheduled Backups - -### Namespace State Changes Between Runs -**Each scheduled backup run performs fresh wildcard resolution:** -- Pattern `prod-*` may include different namespaces in each backup run -- This allows scheduled backups to automatically capture newly created namespaces -- **Trade-off**: Backup contents may vary between runs vs. automatic inclusion of new resources - -**Storage implications:** -- Varying namespace sets between runs may affect deduplication efficiency -- Each backup stores its own resolved namespace list independently - -**Example behavior:** -``` -# Monday backup: prod-* matches [prod-app, prod-db] -# Tuesday: prod-cache namespace created -# Tuesday backup: prod-* matches [prod-app, prod-db, prod-cache] -``` - -**User expectations:** -- Document that scheduled backups automatically include newly matching namespaces -- Provide guidance on namespace naming conventions for predictable backup behavior - -## Testing Strategy - -### Unit Tests -**Pattern matching tests:** -```go -func TestWildcardPatterns(t *testing.T) { - tests := []struct { - pattern string - namespace string - expected bool - }{ - {"prod-*", "prod-app", true}, - {"prod-*", "staging-app", false}, - {"*-staging", "app-staging", true}, - {"*-test-*", "app-test-db", true}, - } - // ... test implementation -} -``` - -**Edge cases:** -- Empty pattern list -- Pattern with no matches -- Pattern matching single namespace -- Multiple overlapping patterns -- Special case lone `*` behavior - -### Integration Tests -**Kubernetes cluster scenarios:** -- Create namespaces, verify wildcard resolution -- Test namespace creation/deletion during backup -- Verify thread safety with concurrent backup operations -- Error scenarios (API failures, network issues) - -**Concurrency testing:** -- Multiple concurrent `ShouldInclude()` calls -- Thread safety verification -- Cache hit ratio measurement - -## Example Usage - -### CLI Usage -```bash -# Single wildcard pattern -velero backup create prod-backup --include-namespaces "prod-*" - -# Multiple patterns -velero backup create env-backup --include-namespaces "prod-*,staging-*,dev-*" - -# Mixed literal and wildcard -velero backup create mixed-backup --include-namespaces "prod-*,kube-system,monitoring" - -# Exclude patterns -velero backup create no-test --include-namespaces "*" --exclude-namespaces "*-test,*-temp" - -# Preview before creating -velero backup create my-backup --include-namespaces "prod-*" --dry-run=wildcards -``` - -### Backup Specification YAML -```yaml -apiVersion: velero.io/v1 -kind: Backup -metadata: - name: production-backup - namespace: velero -spec: - # Wildcard patterns in includedNamespaces - includedNamespaces: - - "prod-*" # All namespaces starting with "prod-" - - "production-*" # All namespaces starting with "production-" - - "critical-app" # Literal namespace (mixed with wildcards) - - # Wildcard patterns in excludedNamespaces - excludedNamespaces: - - "*-test" # Exclude any test namespaces - - "*-temp" # Exclude any temporary namespaces - - # Other backup configuration - storageLocation: default - volumeSnapshotLocations: - - default - includeClusterResources: false -``` - -### Stored Backup Metadata -```yaml -# What gets stored in backup metadata -apiVersion: velero.io/v1 -kind: Backup -metadata: - name: production-backup -status: - # Original user patterns preserved for audit - originalIncludePatterns: ["prod-*", "production-*", "critical-app"] - originalExcludePatterns: ["*-test", "*-temp"] - - # Resolved concrete namespace lists (used for restore) - resolvedIncludedNamespaces: ["prod-app", "prod-db", "production-web", "critical-app"] - resolvedExcludedNamespaces: ["prod-app-test", "staging-temp"] - - # Resolution timestamp - namespaceResolutionTime: "2024-01-15T10:30:00Z" -``` +3. If required, expand wildcards and replace the request's includes and excludes with expanded namespaces +4. Populate the expanded namespace status field with the namespaces. ## Alternatives Considered - -### CLI-Level Resolution -**Problem:** Resolving wildcards during `velero backup create` command - -**Why rejected:** -- **Lost User Intent:** Backup specs store resolved lists instead of original patterns -- **Audit Trail Issues:** Original wildcard intent not visible when examining backup specifications -- **CLI Complexity:** CLI requires cluster access and namespace enumeration capabilities - -### Server-Level (Controller) Resolution -**Problem:** Resolving wildcards in backup controller with persistent caching - -**Why rejected:** -- **Architectural Complexity:** Requires additional API schema changes for storing resolved namespace lists -- **Cache Management:** Need cache invalidation, storage, and lifecycle management -- **Limited Benefit:** Performance gain only applies to narrow controller reconciliation retry scenarios -- **State Management:** Introduces persistent state maintained across backup lifecycle - -### Request-Level (ShouldInclude) Resolution -**Chosen Approach:** Lazy evaluation within backup request processing - -**Benefits:** -- **Preserved Intent:** Original wildcard patterns remain in backup specifications -- **Optimal Performance:** First resolution (~500ms), subsequent calls (~1ms) with request-scoped caching -- **Clean Architecture:** No persistent state, no API schema changes, minimal code changes -- **Thread Safety:** Proper mutex usage for concurrent worker access -- **Scoped Lifetime:** Cache automatically cleaned up when backup request completes +If there are alternative high level or detailed designs that were not pursued they should be called out here with a brief explanation of why they were not pursued. ## Security Considerations -- Implementation requires Velero service account to have `list` permissions on namespace resources -- Aligns with existing Velero RBAC requirements -- No additional privileges or security surface area introduced - -## Addressing Implementation Concerns - -### Multiple Pattern Support -Multiple wildcards work naturally: `--include-namespaces "prod-*,staging-*,dev-*"` - each pattern evaluated independently during lazy resolution. - -### Mixed Literal and Wildcard Detection -Simple approach: strings containing `*` are wildcards, others use existing literal namespace logic. Zero breaking changes for existing validation. - -### Include/Exclude Conflict Detection -Runtime resolution simplifies conflicts - wildcards resolve to actual namespace lists first, then standard include/exclude precedence applies. - -### Backward Compatibility -Lazy evaluation triggers only when wildcards detected. Non-wildcard backups have zero overhead and identical behavior to current implementation. - -## Special Consideration: Existing `*` Behavior - -**Current Velero Behavior:** `--include-namespaces "*"` (the CLI default) means "include all namespaces" and uses special logic that doesn't enumerate namespaces - it simply bypasses namespace filtering entirely. - -**Potential Breaking Change:** Our wildcard implementation would treat `*` as a glob pattern, resolving it to a specific list of namespaces at backup start time, which changes the behavior from "include everything" to "include these specific namespaces." - -**Required Solution:** Special-case handling for the lone `*` pattern to preserve existing behavior by using original `IncludesExcludes` logic instead of wildcard resolution. - -This ensures that `--include-namespaces "*"` continues to work exactly as before, while enabling new wildcard patterns like `prod-*`, `*-staging`, etc. +If this proposal has an impact to the security of the product, its users, or data stored or transmitted via the product, they must be addressed here. ## Compatibility -- Full backward compatibility with existing backup specifications using literal namespace lists -- No changes required to CLI commands, existing backups, or restore operations +A discussion of any compatibility issues that need to be considered ## Implementation -The implementation consists of approximately 200 lines of new code across four files: -- `pkg/util/collections/includes_excludes.go`: Core lazy evaluation logic (~150 lines) -- `pkg/backup/backup.go`: Wildcard detection logic (~20 lines) -- `pkg/backup/request.go`: Interface type usage (~5 lines) -- `pkg/backup/item_collector.go`: Compatibility method calls (~25 lines) +A description of the implementation, timelines, and any resources that have agreed to contribute. ## Open Issues -None. \ No newline at end of file +A discussion of issues relating to this proposal for which the author does not know the solution. This section may be omitted if there are none. From 4c1457c3181eee14181362debfd5ba2d760a4d1c Mon Sep 17 00:00:00 2001 From: Joseph Date: Fri, 1 Aug 2025 13:51:44 -0400 Subject: [PATCH 005/104] Enhance wildcard namespace support in backup and restore design document - Updated the abstract to clarify the current limitations of namespace specifications in Velero. - Expanded the goals section to include specific objectives for implementing wildcard patterns in `--include-namespaces` and `--exclude-namespaces`. - Detailed the high-level design and implementation steps, including the addition of new status fields in the backup CRD and the creation of a utility package for wildcard expansion. - Addressed backward compatibility and known limitations regarding the use of wildcards alongside the existing "*" character. This update aims to provide a comprehensive overview of the proposed changes for improved namespace selection flexibility. Signed-off-by: Joseph --- design/wildcard-namespace-support-design.md | 171 +++++++++++++++----- 1 file changed, 128 insertions(+), 43 deletions(-) diff --git a/design/wildcard-namespace-support-design.md b/design/wildcard-namespace-support-design.md index b5dfd3618..fb3426719 100644 --- a/design/wildcard-namespace-support-design.md +++ b/design/wildcard-namespace-support-design.md @@ -1,79 +1,164 @@ -# Wildcard namespace includes/excludes support for backups and restores +# Wildcard Namespace Includes/Excludes Support for Backups and Restores ## Abstract -One to two sentences that describes the goal of this proposal and the problem being solved by the proposed change. -The reader should be able to tell by the title, and the opening paragraph, if this document is relevant to them. -Velero currently does not have any support for wildcard characters in the namespace spec. -It fully expects the namespaces to be string literals. +Velero currently does not support wildcard characters in namespace specifications, requiring all namespaces to be specified as string literals. The only exception is the standalone "*" character, which includes all namespaces and ignores excludes. -The only and notable exception is the "*" character by it's lonesome, which acts as an include all and ignore excludes option. -Internally Velero treats not specifying anything as the "*" case. - -This document details the approach to implementing wildcard namespaces, while keeping the "*" characters purpose intact for legacy purposes. +This document details the approach to implementing wildcard namespace support for `--include-namespaces` and `--exclude-namespaces` flags, while preserving the existing "*" behavior for backward compatibility. ## Background -This was raised in Issue [#1874](https://github.com/vmware-tanzu/velero/issues/1874) +This feature was requested in Issue [#1874](https://github.com/vmware-tanzu/velero/issues/1874) to provide more flexible namespace selection using wildcard patterns. ## Goals -- A short list of things which will be accomplished by implementing this proposal. -- Two things is ok. -- Three is pushing it. -- More than three goals suggests that the proposal's scope is too large. -- Add support for wildcard namespaces in --include-namespaces and --exclude-namespaces -- Ensure legacy "*" support is not affected +- Add support for wildcard patterns in `--include-namespaces` and `--exclude-namespaces` flags +- Ensure legacy "*" behavior remains unchanged for backward compatibility -## Non Goals -- A short list of items which are: -- a. out of scope -- b. follow on items which are deliberately excluded from this proposal. +## Non-Goals -- Completely rethinking the way "*" is treated and allowing it to work with wildcard excludes. +- Completely rethinking the way "*" is treated and allowing it to work with wildcard excludes +- Supporting complex regex patterns beyond basic glob patterns ## High-Level Design -One to two paragraphs that describe the high level changes that will be made to implement this proposal. -Points of interest are two funcs within the utility layer, in file `velero/pkg/backup/item_collector.go` -- [collectNamespaces](https://github.com/vmware-tanzu/velero/blob/1535afb45e33a3d3820088e4189800a21ba55293/pkg/backup/item_collector.go#L742) -- [getNamespacesToList](https://github.com/vmware-tanzu/velero/blob/1535afb45e33a3d3820088e4189800a21ba55293/pkg/backup/item_collector.go#L638) +The wildcard expansion implementation focuses on two key functions in `pkg/backup/item_collector.go`: -collectNamespaces gets all the active namespaces and matches it against the user spec for included namespaces (r.backupRequest.Backup.Spec.IncludedNamespaces) -This is an ideal point where wildcard expansion can take place. -The implementation would mean that just like "*", namespaces with wildcard symbols would also be passed through without an existence check. -The resolved namespaces are stored in new status fields on the backup. +- [`collectNamespaces`](https://github.com/vmware-tanzu/velero/blob/1535afb45e33a3d3820088e4189800a21ba55293/pkg/backup/item_collector.go#L742) - Retrieves all active namespaces and processes include/exclude filters +- [`getNamespacesToList`](https://github.com/vmware-tanzu/velero/blob/1535afb45e33a3d3820088e4189800a21ba55293/pkg/backup/item_collector.go#L638) - Resolves namespace includes/excludes to final list + +The `collectNamespaces` function is the ideal integration point because it: +- Already retrieves all active namespaces from the cluster +- Processes the user-specified namespace filters +- Can expand wildcard patterns against the complete namespace list +- Stores the resolved namespaces in new backup status fields for visibility + +This approach ensures wildcard namespaces are handled consistently with the existing "*" behavior, bypassing individual namespace existence checks. ## Detailed Design -A detailed design describing how the changes to the product should be made. -The names of types, fields, interfaces, and methods should be agreed on here, not debated in code review. -The same applies to changes in CRDs, YAML examples, and so on. +The implementation involves four main components that can be developed incrementally: -Ideally the changes should be made in sequence so that the work required to implement this design can be done incrementally, possibly in parallel. +### Add new status fields to the backup CRD to store expanded wildcard namespaces -1. Add new status fields to the backup CRD to store expanded wildcard namespaces +```go +// BackupStatus captures the current status of a Velero backup. +type BackupStatus struct { + // ... existing fields ... + + // ExpandedIncludedNamespaces records the expanded include wildcard namespaces + // +optional + // +nullable + ExpandedIncludedNamespaces []string `json:"expandedIncludedNamespaces,omitempty"` + + // ExpandedExcludedNamespaces records the expanded exclude wildcard namespaces + // +optional + // +nullable + ExpandedExcludedNamespaces []string `json:"expandedExcludedNamespaces,omitempty"` + + // ... other fields ... +} ``` -``` -2. Create a util package for wildcard expansion +**Implementation**: Added status fields `ExpandedIncludedNamespaces` and `ExpandedExcludedNamespaces` to `pkg/apis/velero/v1/backup_types.go` to track the resolved namespace lists after wildcard expansion. -3. If required, expand wildcards and replace the request's includes and excludes with expanded namespaces -4. Populate the expanded namespace status field with the namespaces. +### Create a util package for wildcard expansion + +**Implementation**: Created `pkg/util/wildcard/expand.go` package containing: + +- `ShouldExpandWildcards(includes, excludes []string) bool` - Determines if wildcard expansion is needed (excludes simple "*" case) +- `ExpandWildcards(activeNamespaces, includes, excludes []string) ([]string, []string, error)` - Main expansion function +- `containsWildcardPattern(pattern string) bool` - Detects wildcard patterns (`*`, `?`, `[abc]`, `{a,b,c}`) +- `validateWildcardPatterns(patterns []string) error` - Validates patterns and rejects unsupported regex symbols +- Uses `github.com/gobwas/glob` library for glob pattern matching + +**Supported patterns**: +- `*` (any characters) +- `?` (single character) +- `[abc]` (character classes) +- `{a,b,c}` (alternatives) + +**Unsupported**: Regex symbols `|()`, consecutive asterisks `**` + +### If required, expand wildcards and replace the request's includes and excludes with expanded namespaces + +**Implementation**: In `pkg/backup/item_collector.go`: + +```go +// collectNamespaces function (line 748-803) +if wildcard.ShouldExpandWildcards(namespaceSelector.GetIncludes(), namespaceSelector.GetExcludes()) { + if err := r.expandNamespaceWildcards(activeNamespacesList, namespaceSelector); err != nil { + return nil, errors.WithMessage(err, "failed to expand namespace wildcard patterns") + } +} +``` + +The expansion occurs when collecting namespaces, after retrieving all active namespaces from the cluster. The `expandNamespaceWildcards` method: +- Calls `wildcard.ExpandWildcards()` with active namespaces and original patterns +- Updates the namespace selector with expanded results using `SetIncludes()` and `SetExcludes()` +- Preserves backward compatibility by skipping expansion for simple "*" pattern + +**Performance Improvement**: As part of this implementation, active namespaces are stored in a hashset rather than being iterated for each resolved/literal namespace check. This eliminates a [nested loop anti-pattern](https://github.com/vmware-tanzu/velero/blob/1535afb45e33a3d3820088e4189800a21ba55293/pkg/backup/item_collector.go#L767) and improves performance. + +### Populate the expanded namespace status field with the namespaces + +**Implementation**: In `expandNamespaceWildcards` function (line 889-891): + +```go +// Record the expanded wildcard includes/excludes in the request status +r.backupRequest.Status.ExpandedIncludedNamespaces = expandedIncludes +r.backupRequest.Status.ExpandedExcludedNamespaces = expandedExcludes +``` + +The status fields are populated immediately after successful wildcard expansion, providing visibility into which namespaces were actually matched by the wildcard patterns. ## Alternatives Considered -If there are alternative high level or detailed designs that were not pursued they should be called out here with a brief explanation of why they were not pursued. + +Several implementation approaches were considered for the wildcard expansion logic: + +### 1. Wildcard expansion in `getNamespacesToList` + +This approach was ruled out because: +- The `collectNamespaces` function encounters wildcard patterns first in the processing flow +- `collectNamespaces` already has access to the complete list of active namespaces, eliminating the need for additional API calls +- Placing the logic in `getNamespacesToList` would require redundant namespace retrieval + +### 2. Client-side wildcard expansion + +Expanding wildcards on the CLI side was considered but rejected because: +- It would only work for command-line initiated backups +- Scheduled backups would not benefit from this approach +- The server-side approach provides consistent behavior across all backup initiation methods ## Security Considerations -If this proposal has an impact to the security of the product, its users, or data stored or transmitted via the product, they must be addressed here. + +This feature does not introduce any security vulnerabilities as it only affects namespace selection logic within the existing backup authorization framework. ## Compatibility -A discussion of any compatibility issues that need to be considered + +### Backward Compatibility + +The implementation maintains full backward compatibility with existing behavior: +- The standalone "*" character continues to work as before (include all namespaces, ignore excludes) +- Existing backup configurations remain unaffected + +### Known Limitations + +1. **Mixed "*" and wildcard usage**: When using the standalone "*" in includes, the legacy implementation takes precedence and wildcard expansion is skipped. This means you cannot combine "*" (all namespaces) in includes with wildcard patterns in excludes. + +2. **Selective exclusion limitation**: The current design does not support selective pattern-based exclusion when including all namespaces via "*". ## Implementation -A description of the implementation, timelines, and any resources that have agreed to contribute. + +The implementation follows the detailed design outlined above, with the following timeline: + +1. **Phase 1**: Add backup CRD status fields for expanded namespaces +2. **Phase 2**: Implement wildcard utility package with validation +3. **Phase 3**: Integrate expansion logic into backup item collection +4. **Phase 4**: Add status field population and logging ## Open Issues -A discussion of issues relating to this proposal for which the author does not know the solution. This section may be omitted if there are none. + +**Restore Integration**: Currently investigating how restore operations should handle wildcard-expanded backups. The proposed approach is to apply wildcard patterns against the expanded namespace list stored in the backup's status fields, ensuring consistency between backup and restore operations. \ No newline at end of file From 037db22afe7758cd2fdbac25cddd1c7ebec03567 Mon Sep 17 00:00:00 2001 From: Joseph Date: Fri, 1 Aug 2025 13:55:38 -0400 Subject: [PATCH 006/104] Refine wildcard namespace support design document - Clarified the use of the standalone `*` character in namespace specifications. - Ensured consistent formatting for `*` throughout the document. - Maintained focus on backward compatibility and limitations regarding wildcard usage. This update enhances the clarity and consistency of the design document for implementing wildcard namespace support in Velero. Signed-off-by: Joseph --- design/wildcard-namespace-support-design.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/design/wildcard-namespace-support-design.md b/design/wildcard-namespace-support-design.md index fb3426719..d6d529a02 100644 --- a/design/wildcard-namespace-support-design.md +++ b/design/wildcard-namespace-support-design.md @@ -3,9 +3,9 @@ ## Abstract -Velero currently does not support wildcard characters in namespace specifications, requiring all namespaces to be specified as string literals. The only exception is the standalone "*" character, which includes all namespaces and ignores excludes. +Velero currently does not support wildcard characters in namespace specifications, requiring all namespaces to be specified as string literals. The only exception is the standalone `*` character, which includes all namespaces and ignores excludes. -This document details the approach to implementing wildcard namespace support for `--include-namespaces` and `--exclude-namespaces` flags, while preserving the existing "*" behavior for backward compatibility. +This document details the approach to implementing wildcard namespace support for `--include-namespaces` and `--exclude-namespaces` flags, while preserving the existing `*` behavior for backward compatibility. ## Background @@ -14,11 +14,11 @@ This feature was requested in Issue [#1874](https://github.com/vmware-tanzu/vele ## Goals - Add support for wildcard patterns in `--include-namespaces` and `--exclude-namespaces` flags -- Ensure legacy "*" behavior remains unchanged for backward compatibility +- Ensure legacy `*` behavior remains unchanged for backward compatibility ## Non-Goals -- Completely rethinking the way "*" is treated and allowing it to work with wildcard excludes +- Completely rethinking the way `*` is treated and allowing it to work with wildcard excludes - Supporting complex regex patterns beyond basic glob patterns @@ -141,14 +141,14 @@ This feature does not introduce any security vulnerabilities as it only affects ### Backward Compatibility The implementation maintains full backward compatibility with existing behavior: -- The standalone "*" character continues to work as before (include all namespaces, ignore excludes) +- The standalone `*` character continues to work as before (include all namespaces, ignore excludes) - Existing backup configurations remain unaffected ### Known Limitations -1. **Mixed "*" and wildcard usage**: When using the standalone "*" in includes, the legacy implementation takes precedence and wildcard expansion is skipped. This means you cannot combine "*" (all namespaces) in includes with wildcard patterns in excludes. +1. **Mixed `*` and wildcard usage**: When using the standalone `*` in includes, the legacy implementation takes precedence and wildcard expansion is skipped. This means you cannot combine "*" (all namespaces) in includes with wildcard patterns in excludes. -2. **Selective exclusion limitation**: The current design does not support selective pattern-based exclusion when including all namespaces via "*". +2. **Selective exclusion limitation**: The current design does not support selective pattern-based exclusion when including all namespaces via `*`. ## Implementation From 571c9bd3ef1cc64fbee2f98467ee73731099ba94 Mon Sep 17 00:00:00 2001 From: Joseph Date: Sat, 2 Aug 2025 21:14:26 -0400 Subject: [PATCH 007/104] Enhance wildcard namespace support design document - Expanded the design to include detailed implementation steps for wildcard expansion in both backup and restore operations. - Added new status fields to the backup and restore CRDs to track expanded wildcard namespaces. - Clarified the approach to ensure backward compatibility with existing `*` behavior. - Addressed limitations and provided insights on restore operations handling wildcard-expanded backups. This update aims to provide a comprehensive and clear framework for implementing wildcard namespace support in Velero. Signed-off-by: Joseph --- design/wildcard-namespace-support-design.md | 100 ++++++++++++++++---- 1 file changed, 82 insertions(+), 18 deletions(-) diff --git a/design/wildcard-namespace-support-design.md b/design/wildcard-namespace-support-design.md index d6d529a02..c807ad347 100644 --- a/design/wildcard-namespace-support-design.md +++ b/design/wildcard-namespace-support-design.md @@ -3,9 +3,9 @@ ## Abstract -Velero currently does not support wildcard characters in namespace specifications, requiring all namespaces to be specified as string literals. The only exception is the standalone `*` character, which includes all namespaces and ignores excludes. +Velero currently does not support wildcard characters in namespace specifications, requiring all namespaces to be specified as string literals. The only exception is the standalone "*" character, which includes all namespaces and ignores excludes. -This document details the approach to implementing wildcard namespace support for `--include-namespaces` and `--exclude-namespaces` flags, while preserving the existing `*` behavior for backward compatibility. +This document details the approach to implementing wildcard namespace support for `--include-namespaces` and `--exclude-namespaces` flags, while preserving the existing "*" behavior for backward compatibility. ## Background @@ -13,17 +13,19 @@ This feature was requested in Issue [#1874](https://github.com/vmware-tanzu/vele ## Goals -- Add support for wildcard patterns in `--include-namespaces` and `--exclude-namespaces` flags -- Ensure legacy `*` behavior remains unchanged for backward compatibility +- Add support for wildcard patterns in `--include-namespaces` and `--exclude-namespaces` flags for both backup and restore +- Ensure legacy "*" behavior remains unchanged for backward compatibility ## Non-Goals -- Completely rethinking the way `*` is treated and allowing it to work with wildcard excludes +- Completely rethinking the way "*" is treated and allowing it to work with wildcard excludes - Supporting complex regex patterns beyond basic glob patterns ## High-Level Design +## Backup + The wildcard expansion implementation focuses on two key functions in `pkg/backup/item_collector.go`: - [`collectNamespaces`](https://github.com/vmware-tanzu/velero/blob/1535afb45e33a3d3820088e4189800a21ba55293/pkg/backup/item_collector.go#L742) - Retrieves all active namespaces and processes include/exclude filters @@ -37,32 +39,52 @@ The `collectNamespaces` function is the ideal integration point because it: This approach ensures wildcard namespaces are handled consistently with the existing "*" behavior, bypassing individual namespace existence checks. +## Restore + +The wildcard expansion implementation for restore operations focuses on the main execution flow in `pkg/restore/restore.go`: + +- [`execute`](https://github.com/vmware-tanzu/velero/blob/main/pkg/restore/restore.go#L430) - Main restore execution that parses backup contents and processes namespace filters +- [`extractNamespacesFromBackup`](https://github.com/vmware-tanzu/velero/blob/main/pkg/restore/restore.go#L2407) - Extracts available namespaces from backup tar contents + +The `execute` function is the ideal integration point because it: +- Already parses the backup tar file to understand available resources +- Processes the user-specified namespace filters for the restore operation +- Can expand wildcard patterns against namespaces that actually exist in the backup +- Stores the resolved namespaces in new restore status fields for visibility + +This approach ensures wildcard namespaces in restore operations are based on actual backup contents rather than original backup specifications, providing safety and consistency regardless of how the backup was created. + ## Detailed Design The implementation involves four main components that can be developed incrementally: -### Add new status fields to the backup CRD to store expanded wildcard namespaces +### Add new status fields to the backup and restore CRDs to store expanded wildcard namespaces ```go // BackupStatus captures the current status of a Velero backup. type BackupStatus struct { // ... existing fields ... - // ExpandedIncludedNamespaces records the expanded include wildcard namespaces + // IncludeWildcardMatches records the expanded include wildcard namespaces // +optional // +nullable - ExpandedIncludedNamespaces []string `json:"expandedIncludedNamespaces,omitempty"` + IncludeWildcardMatches []string `json:"includeWildcardMatches,omitempty"` - // ExpandedExcludedNamespaces records the expanded exclude wildcard namespaces + // ExcludeWildcardMatches records the expanded exclude wildcard namespaces // +optional // +nullable - ExpandedExcludedNamespaces []string `json:"expandedExcludedNamespaces,omitempty"` + ExcludeWildcardMatches []string `json:"excludeWildcardMatches,omitempty"` + + // WildcardResult records the final namespaces after applying wildcard include/exclude logic + // +optional + // +nullable + WildcardResult []string `json:"wildcardResult,omitempty"` // ... other fields ... } ``` -**Implementation**: Added status fields `ExpandedIncludedNamespaces` and `ExpandedExcludedNamespaces` to `pkg/apis/velero/v1/backup_types.go` to track the resolved namespace lists after wildcard expansion. +**Implementation**: Added status fields `IncludeWildcardMatches`, `ExcludeWildcardMatches`, and `WildcardResult` to `pkg/apis/velero/v1/backup_types.go` and `pkg/apis/velero/v1/restore_types.go` to track the resolved namespace lists after wildcard expansion. ### Create a util package for wildcard expansion @@ -84,6 +106,8 @@ type BackupStatus struct { ### If required, expand wildcards and replace the request's includes and excludes with expanded namespaces +### Backup: + **Implementation**: In `pkg/backup/item_collector.go`: ```go @@ -102,17 +126,55 @@ The expansion occurs when collecting namespaces, after retrieving all active nam **Performance Improvement**: As part of this implementation, active namespaces are stored in a hashset rather than being iterated for each resolved/literal namespace check. This eliminates a [nested loop anti-pattern](https://github.com/vmware-tanzu/velero/blob/1535afb45e33a3d3820088e4189800a21ba55293/pkg/backup/item_collector.go#L767) and improves performance. +### Restore + +**Implementation**: In `pkg/restore/restore.go`: + +```go +// Lines 478-509: Wildcard expansion in restore context +if wildcard.ShouldExpandWildcards(ctx.restore.Spec.IncludedNamespaces, ctx.restore.Spec.ExcludedNamespaces) { + availableNamespaces := extractNamespacesFromBackup(backupResources) + expandedIncludes, expandedExcludes, err := wildcard.ExpandWildcards( + availableNamespaces, + ctx.restore.Spec.IncludedNamespaces, + ctx.restore.Spec.ExcludedNamespaces, + ) + // Update restore context with expanded patterns + ctx.namespaceIncludesExcludes = collections.NewIncludesExcludes(). + Includes(expandedIncludes...). + Excludes(expandedExcludes...) +} +``` + +The restore expansion occurs after parsing the backup tar contents, using `extractNamespacesFromBackup` to determine which namespaces are actually available for restoration. This ensures wildcard patterns are applied against materialized backup contents rather than original backup specifications. + + + ### Populate the expanded namespace status field with the namespaces +#### Backup Status Fields + **Implementation**: In `expandNamespaceWildcards` function (line 889-891): ```go // Record the expanded wildcard includes/excludes in the request status -r.backupRequest.Status.ExpandedIncludedNamespaces = expandedIncludes -r.backupRequest.Status.ExpandedExcludedNamespaces = expandedExcludes +r.backupRequest.Status.IncludeWildcardMatches = expandedIncludes +r.backupRequest.Status.ExcludeWildcardMatches = expandedExcludes +r.backupRequest.Status.WildcardResult = wildcardResult ``` -The status fields are populated immediately after successful wildcard expansion, providing visibility into which namespaces were actually matched by the wildcard patterns. +#### Restore Status Fields + +**Implementation**: In `pkg/restore/restore.go` (lines 499-502): + +```go +// Record the expanded wildcard includes/excludes in the restore status +ctx.restore.Status.IncludeWildcardMatches = expandedIncludes +ctx.restore.Status.ExcludeWildcardMatches = expandedExcludes +ctx.restore.Status.WildcardResult = wildcardResult +``` + +The status fields are populated immediately after successful wildcard expansion, providing visibility into which namespaces were actually matched by the wildcard patterns and the final list of namespaces that will be processed. ## Alternatives Considered @@ -141,14 +203,14 @@ This feature does not introduce any security vulnerabilities as it only affects ### Backward Compatibility The implementation maintains full backward compatibility with existing behavior: -- The standalone `*` character continues to work as before (include all namespaces, ignore excludes) +- The standalone "*" character continues to work as before (include all namespaces, ignore excludes) - Existing backup configurations remain unaffected ### Known Limitations -1. **Mixed `*` and wildcard usage**: When using the standalone `*` in includes, the legacy implementation takes precedence and wildcard expansion is skipped. This means you cannot combine "*" (all namespaces) in includes with wildcard patterns in excludes. +1. **Mixed "*" and wildcard usage**: When using the standalone "*" in includes, the legacy implementation takes precedence and wildcard expansion is skipped. This means you cannot combine "*" (all namespaces) in includes with wildcard patterns in excludes. -2. **Selective exclusion limitation**: The current design does not support selective pattern-based exclusion when including all namespaces via `*`. +2. **Selective exclusion limitation**: The current design does not support selective pattern-based exclusion when including all namespaces via "*". ## Implementation @@ -161,4 +223,6 @@ The implementation follows the detailed design outlined above, with the followin ## Open Issues -**Restore Integration**: Currently investigating how restore operations should handle wildcard-expanded backups. The proposed approach is to apply wildcard patterns against the expanded namespace list stored in the backup's status fields, ensuring consistency between backup and restore operations. \ No newline at end of file +**Restore Integration**: Restore operations are completely decoupled from backup wildcard specifications and work safely with wildcard-created backups. The restore process reads the actual tar file contents to determine available namespaces, not the original backup spec. Since the tar file contains real, materialized namespaces (e.g., `test01`, `test02`) rather than wildcard patterns (e.g., `test*`), restore operations work with concrete namespace names. + +When wildcard patterns are specified in restore operations, they are expanded against the namespaces that actually exist in the backup tar file. This ensures that restore wildcard expansion is based on what was actually backed up, not what was originally intended to be backed up. From eb8b3828161b7073132a414680e6a107c8c87a03 Mon Sep 17 00:00:00 2001 From: Joseph Date: Sun, 3 Aug 2025 09:21:33 -0400 Subject: [PATCH 008/104] Update design Signed-off-by: Joseph --- design/wildcard-namespace-support-design.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/design/wildcard-namespace-support-design.md b/design/wildcard-namespace-support-design.md index c807ad347..3d475d3a5 100644 --- a/design/wildcard-namespace-support-design.md +++ b/design/wildcard-namespace-support-design.md @@ -226,3 +226,6 @@ The implementation follows the detailed design outlined above, with the followin **Restore Integration**: Restore operations are completely decoupled from backup wildcard specifications and work safely with wildcard-created backups. The restore process reads the actual tar file contents to determine available namespaces, not the original backup spec. Since the tar file contains real, materialized namespaces (e.g., `test01`, `test02`) rather than wildcard patterns (e.g., `test*`), restore operations work with concrete namespace names. When wildcard patterns are specified in restore operations, they are expanded against the namespaces that actually exist in the backup tar file. This ensures that restore wildcard expansion is based on what was actually backed up, not what was originally intended to be backed up. + +**Crucially, restore does not treat `*` as a catch all case**. +This means that if `*` is mentioned in restore, wildcard expansion is skipped owing to how it's treated in backup. From 56df64b625e6debbc724baeff98fda794fb0653c Mon Sep 17 00:00:00 2001 From: Joseph Date: Tue, 5 Aug 2025 11:15:09 -0400 Subject: [PATCH 009/104] Status fields are part of a struct Signed-off-by: Joseph --- design/wildcard-namespace-support-design.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/design/wildcard-namespace-support-design.md b/design/wildcard-namespace-support-design.md index 3d475d3a5..13d0fdcb3 100644 --- a/design/wildcard-namespace-support-design.md +++ b/design/wildcard-namespace-support-design.md @@ -158,9 +158,11 @@ The restore expansion occurs after parsing the backup tar contents, using `extra ```go // Record the expanded wildcard includes/excludes in the request status -r.backupRequest.Status.IncludeWildcardMatches = expandedIncludes -r.backupRequest.Status.ExcludeWildcardMatches = expandedExcludes -r.backupRequest.Status.WildcardResult = wildcardResult +r.backupRequest.Status.WildcardNamespaces = &velerov1api.WildcardNamespaceStatus{ + IncludeWildcardMatches: expandedIncludes, + ExcludeWildcardMatches: expandedExcludes, + WildcardResult: wildcardResult, +} ``` #### Restore Status Fields @@ -169,9 +171,11 @@ r.backupRequest.Status.WildcardResult = wildcardResult ```go // Record the expanded wildcard includes/excludes in the restore status -ctx.restore.Status.IncludeWildcardMatches = expandedIncludes -ctx.restore.Status.ExcludeWildcardMatches = expandedExcludes -ctx.restore.Status.WildcardResult = wildcardResult +ctx.restore.Status.WildcardNamespaces = &velerov1api.WildcardNamespaceStatus{ + IncludeWildcardMatches: expandedIncludes, + ExcludeWildcardMatches: expandedExcludes, + WildcardResult: wildcardResult, +} ``` The status fields are populated immediately after successful wildcard expansion, providing visibility into which namespaces were actually matched by the wildcard patterns and the final list of namespaces that will be processed. From 528392ac5bcef96a651b510e591e5fbcd2ba6066 Mon Sep 17 00:00:00 2001 From: Joseph Date: Tue, 5 Aug 2025 12:59:28 -0400 Subject: [PATCH 010/104] Added struct change Signed-off-by: Joseph --- design/wildcard-namespace-support-design.md | 64 +++++++++++++++++---- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/design/wildcard-namespace-support-design.md b/design/wildcard-namespace-support-design.md index 13d0fdcb3..d95390812 100644 --- a/design/wildcard-namespace-support-design.md +++ b/design/wildcard-namespace-support-design.md @@ -60,31 +60,75 @@ The implementation involves four main components that can be developed increment ### Add new status fields to the backup and restore CRDs to store expanded wildcard namespaces +#### Backup + ```go -// BackupStatus captures the current status of a Velero backup. -type BackupStatus struct { - // ... existing fields ... - - // IncludeWildcardMatches records the expanded include wildcard namespaces +// WildcardNamespaceStatus contains information about wildcard namespace matching results +type WildcardNamespaceStatus struct { + // IncludeWildcardMatches records the namespaces that matched include wildcard patterns // +optional // +nullable IncludeWildcardMatches []string `json:"includeWildcardMatches,omitempty"` - // ExcludeWildcardMatches records the expanded exclude wildcard namespaces + // ExcludeWildcardMatches records the namespaces that matched exclude wildcard patterns // +optional // +nullable ExcludeWildcardMatches []string `json:"excludeWildcardMatches,omitempty"` // WildcardResult records the final namespaces after applying wildcard include/exclude logic - // +optional - // +nullable - WildcardResult []string `json:"wildcardResult,omitempty"` + // +optional + // +nullable + WildcardResult []string `json:"wildcardResult,omitempty"` +} + +// BackupStatus captures the current status of a Velero backup. +type BackupStatus struct { + // ... existing fields ... + + // WildcardNamespaces contains information about wildcard namespace processing + // +optional + // +nullable + WildcardNamespaces *WildcardNamespaceStatus `json:"wildcardNamespaces,omitempty"` // ... other fields ... } ``` -**Implementation**: Added status fields `IncludeWildcardMatches`, `ExcludeWildcardMatches`, and `WildcardResult` to `pkg/apis/velero/v1/backup_types.go` and `pkg/apis/velero/v1/restore_types.go` to track the resolved namespace lists after wildcard expansion. +#### Restore + +```go +// WildcardNamespaceStatus contains information about wildcard namespace matching results +type WildcardNamespaceStatus struct { + // IncludeWildcardMatches records the namespaces that matched include wildcard patterns + // +optional + // +nullable + IncludeWildcardMatches []string `json:"includeWildcardMatches,omitempty"` + + // ExcludeWildcardMatches records the namespaces that matched exclude wildcard patterns + // +optional + // +nullable + ExcludeWildcardMatches []string `json:"excludeWildcardMatches,omitempty"` + + // WildcardResult records the final namespaces after applying wildcard include/exclude logic + // +optional + // +nullable + WildcardResult []string `json:"wildcardResult,omitempty"` +} + +// RestoreStatus captures the current status of a Velero restore. +type RestoreStatus struct { + // ... existing fields ... + + // WildcardNamespaces contains information about wildcard namespace processing + // +optional + // +nullable + WildcardNamespaces *WildcardNamespaceStatus `json:"wildcardNamespaces,omitempty"` + + // ... other fields ... +} +``` + +**Implementation**: Added a structured `WildcardNamespaceStatus` type and `WildcardNamespaces` field to `pkg/apis/velero/v1/backup_types.go` and `pkg/apis/velero/v1/restore_types.go` to track the resolved namespace lists after wildcard expansion in a well-organized manner. ### Create a util package for wildcard expansion From 0f43f999db9feb41df6e9b82c7ae0e0cfa70719f Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Wed, 20 Aug 2025 23:13:36 +0800 Subject: [PATCH 011/104] Update the E2E upgrade test's from versions. Signed-off-by: Xun Jiang --- test/Makefile | 2 +- test/util/velero/velero_utils.go | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/Makefile b/test/Makefile index 65e462240..4eb6103e5 100644 --- a/test/Makefile +++ b/test/Makefile @@ -74,7 +74,7 @@ HAS_VSPHERE_PLUGIN ?= false RESTORE_HELPER_IMAGE ?= #Released version only -UPGRADE_FROM_VELERO_VERSION ?= v1.14.1,v1.15.2 +UPGRADE_FROM_VELERO_VERSION ?= v1.15.2,v1.16.2 # UPGRADE_FROM_VELERO_CLI can has the same format(a list divided by comma) with UPGRADE_FROM_VELERO_VERSION # Upgrade tests will be executed sequently according to the list by UPGRADE_FROM_VELERO_VERSION diff --git a/test/util/velero/velero_utils.go b/test/util/velero/velero_utils.go index 1d17e4ace..5985dd509 100644 --- a/test/util/velero/velero_utils.go +++ b/test/util/velero/velero_utils.go @@ -87,13 +87,13 @@ var ImagesMatrix = map[string]map[string][]string{ "velero-restore-helper": {"velero/velero-restore-helper:v1.15.2"}, }, "v1.16": { - "aws": {"velero/velero-plugin-for-aws:v1.12.0"}, - "azure": {"velero/velero-plugin-for-microsoft-azure:v1.12.0"}, + "aws": {"velero/velero-plugin-for-aws:v1.12.2"}, + "azure": {"velero/velero-plugin-for-microsoft-azure:v1.12.2"}, "vsphere": {"vsphereveleroplugin/velero-plugin-for-vsphere:v1.5.2"}, - "gcp": {"velero/velero-plugin-for-gcp:v1.12.0"}, - "datamover": {"velero/velero-plugin-for-aws:v1.12.0"}, - "velero": {"velero/velero:v1.15.0"}, - "velero-restore-helper": {"velero/velero:v1.16.0"}, + "gcp": {"velero/velero-plugin-for-gcp:v1.12.2"}, + "datamover": {"velero/velero-plugin-for-aws:v1.12.2"}, + "velero": {"velero/velero:v1.16.2"}, + "velero-restore-helper": {"velero/velero:v1.16.2"}, }, "main": { "aws": {"velero/velero-plugin-for-aws:main"}, From 2178d36d14f7795bc833f87c910609995331a86f Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Mon, 18 Aug 2025 10:45:23 +0800 Subject: [PATCH 012/104] Change the CreateFileToPod function's OS parameter as the E2E pass-in value. Fix GetResourceWithLabel's bug: labels were not applied. Add workOS for deployment and pod creationg. Add OS label for select node. Enlarge the context timeout to 10 minutes. 5 min is not enough for Windows. Enlarge the Kibishii test context to 15 minutes for Windows. Signed-off-by: Xun Jiang --- .../resource_policies_test.go | 33 ++++- test/e2e/backup/backup.go | 2 +- test/e2e/basic/backup-volume-info/base.go | 24 ++-- test/e2e/basic/pvc-selected-node-changing.go | 29 +++- test/e2e/basic/storage-class-changing.go | 19 ++- .../parallel_files_download.go | 24 +++- .../parallel_files_upload.go | 25 +++- test/e2e/pv-backup/pv-backup-filter.go | 38 +++-- test/e2e/resource-filtering/base.go | 19 ++- test/e2e/resource-filtering/exclude_label.go | 21 ++- test/e2e/resource-filtering/label_selector.go | 16 ++- .../resourcemodifiers/resource_modifiers.go | 20 ++- .../e2e/resourcepolicies/resource_policies.go | 34 +++-- test/e2e/schedule/in_progress.go | 12 +- test/e2e/schedule/ordered_resources.go | 20 ++- test/util/common/common.go | 3 + test/util/k8s/common.go | 20 +-- test/util/k8s/deployment.go | 121 ++++++++++++---- test/util/k8s/namespace.go | 8 +- test/util/k8s/node.go | 9 +- test/util/k8s/pod.go | 135 ++++++++++++++---- test/util/kibishii/kibishii_utils.go | 27 ++-- 22 files changed, 530 insertions(+), 129 deletions(-) diff --git a/internal/resourcepolicies/resource_policies_test.go b/internal/resourcepolicies/resource_policies_test.go index 9f3d0922a..b0d5f1fbd 100644 --- a/internal/resourcepolicies/resource_policies_test.go +++ b/internal/resourcepolicies/resource_policies_test.go @@ -227,9 +227,10 @@ func TestGetResourceMatchedAction(t *testing.T) { }, } testCases := []struct { - name string - volume *structuredVolume - expectedAction *Action + name string + volume *structuredVolume + expectedAction *Action + resourcePolicies *ResourcePolicies }{ { name: "match policy", @@ -299,12 +300,36 @@ func TestGetResourceMatchedAction(t *testing.T) { }, expectedAction: nil, }, + { + name: "nil condition always match the action", + volume: &structuredVolume{ + capacity: *resource.NewQuantity(5<<30, resource.BinarySI), + storageClass: "some-class", + pvcLabels: map[string]string{ + "environment": "staging", + }, + }, + resourcePolicies: &ResourcePolicies{ + Version: "v1", + VolumePolicies: []VolumePolicy{ + { + Action: Action{Type: "skip"}, + Conditions: map[string]any{}, + }, + }, + }, + expectedAction: &Action{Type: "skip"}, + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { policies := &Policies{} - err := policies.BuildPolicy(resPolicies) + currentResourcePolicy := resPolicies + if tc.resourcePolicies != nil { + currentResourcePolicy = tc.resourcePolicies + } + err := policies.BuildPolicy(currentResourcePolicy) if err != nil { t.Errorf("Failed to build policy with error %v", err) } diff --git a/test/e2e/backup/backup.go b/test/e2e/backup/backup.go index 48ebd0500..43a6f4f23 100644 --- a/test/e2e/backup/backup.go +++ b/test/e2e/backup/backup.go @@ -109,7 +109,7 @@ func BackupRestoreTest(backupRestoreTestConfig BackupRestoreTestConfig) { DeleteStorageClass(context.Background(), *veleroCfg.ClientToInstallVelero, KibishiiStorageClassName) }) if InstallVelero { - ctx, ctxCancel := context.WithTimeout(context.Background(), time.Minute*5) + ctx, ctxCancel := context.WithTimeout(context.Background(), time.Minute*10) defer ctxCancel() err = VeleroUninstall(ctx, veleroCfg) Expect(err).To(Succeed()) diff --git a/test/e2e/basic/backup-volume-info/base.go b/test/e2e/basic/backup-volume-info/base.go index 04c962fe4..2cd574b5c 100644 --- a/test/e2e/basic/backup-volume-info/base.go +++ b/test/e2e/basic/backup-volume-info/base.go @@ -29,6 +29,7 @@ import ( . "github.com/vmware-tanzu/velero/test" . "github.com/vmware-tanzu/velero/test/e2e/test" + "github.com/vmware-tanzu/velero/test/util/common" . "github.com/vmware-tanzu/velero/test/util/common" . "github.com/vmware-tanzu/velero/test/util/k8s" ) @@ -77,11 +78,6 @@ func (v *BackupVolumeInfo) Init() error { } func (v *BackupVolumeInfo) Start() error { - if v.VeleroCfg.CloudProvider == Vsphere && (!strings.Contains(v.CaseBaseName, "fs-upload") && !strings.Contains(v.CaseBaseName, "skipped")) { - fmt.Printf("Skip snapshot case %s for vsphere environment.\n", v.CaseBaseName) - Skip("Skip snapshot case due to vsphere environment doesn't cover the CSI test, and it doesn't have a Velero native snapshot plugin.") - } - if strings.Contains(v.VeleroCfg.Features, FeatureCSI) { if strings.Contains(v.CaseBaseName, "native-snapshot") { fmt.Printf("Skip native snapshot case %s when the CSI feature is enabled.\n", v.CaseBaseName) @@ -100,6 +96,12 @@ func (v *BackupVolumeInfo) CreateResources() error { labels := map[string]string{ "volume-info": "true", } + + if v.VeleroCfg.WorkerOS == common.WorkerOSWindows { + labels["pod-security.kubernetes.io/enforce"] = "privileged" + labels["pod-security.kubernetes.io/enforce-version"] = "latest" + } + for nsNum := 0; nsNum < v.NamespacesTotal; nsNum++ { fmt.Printf("Creating namespaces ...\n") createNSName := v.CaseBaseName @@ -121,7 +123,14 @@ func (v *BackupVolumeInfo) CreateResources() error { volumeName := fmt.Sprintf("volume-info-pv-%d", i) vols = append(vols, CreateVolumes(pvc.Name, []string{volumeName})...) } - deployment := NewDeployment(v.CaseBaseName, createNSName, 1, labels, v.VeleroCfg.ImageRegistryProxy).WithVolume(vols).Result() + deployment := NewDeployment( + v.CaseBaseName, + createNSName, + 1, + labels, + v.VeleroCfg.ImageRegistryProxy, + v.VeleroCfg.WorkerOS, + ).WithVolume(vols).Result() deployment, err := CreateDeployment(v.Client.ClientGo, createNSName, deployment) if err != nil { return errors.Wrap(err, fmt.Sprintf("failed to delete the namespace %q", createNSName)) @@ -139,14 +148,13 @@ func (v *BackupVolumeInfo) CreateResources() error { // So populate data only to some of pods, leave other pods empty to verify empty PV datamover if i%2 == 0 { Expect(CreateFileToPod( - v.Ctx, createNSName, pod.Name, DefaultContainerName, vols[i].Name, fmt.Sprintf("file-%s", pod.Name), CreateFileContent(createNSName, pod.Name, vols[i].Name), - WorkerOSLinux, + v.VeleroCfg.WorkerOS, )).To(Succeed()) } } diff --git a/test/e2e/basic/pvc-selected-node-changing.go b/test/e2e/basic/pvc-selected-node-changing.go index c1008e9b1..fc2b64a38 100644 --- a/test/e2e/basic/pvc-selected-node-changing.go +++ b/test/e2e/basic/pvc-selected-node-changing.go @@ -10,6 +10,7 @@ import ( velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" . "github.com/vmware-tanzu/velero/test" . "github.com/vmware-tanzu/velero/test/e2e/test" + "github.com/vmware-tanzu/velero/test/util/common" . "github.com/vmware-tanzu/velero/test/util/k8s" . "github.com/vmware-tanzu/velero/test/util/velero" ) @@ -64,19 +65,36 @@ func (p *PVCSelectedNodeChanging) Init() error { func (p *PVCSelectedNodeChanging) CreateResources() error { By(fmt.Sprintf("Create namespace %s", p.namespace), func() { - Expect(CreateNamespace(p.Ctx, p.Client, p.namespace)).To(Succeed(), + labels := make(map[string]string) + if p.VeleroCfg.WorkerOS == common.WorkerOSWindows { + labels = map[string]string{ + "pod-security.kubernetes.io/enforce": "privileged", + "pod-security.kubernetes.io/enforce-version": "latest", + } + } + Expect(CreateNamespaceWithLabel(p.Ctx, p.Client, p.namespace, labels)).To(Succeed(), fmt.Sprintf("Failed to create namespace %s", p.namespace)) }) By(fmt.Sprintf("Create pod %s in namespace %s", p.podName, p.namespace), func() { - nodeNameList, err := GetWorkerNodes(p.Ctx) + nodeNameList, err := GetWorkerNodes(p.Ctx, p.VeleroCfg.WorkerOS) Expect(err).To(Succeed()) for _, nodeName := range nodeNameList { p.oldNodeName = nodeName fmt.Printf("Create PVC on node %s\n", p.oldNodeName) pvcAnn := map[string]string{p.ann: nodeName} - _, err := CreatePod(p.Client, p.namespace, p.podName, StorageClassName, p.pvcName, []string{p.volume}, - pvcAnn, nil, p.VeleroCfg.ImageRegistryProxy) + _, err := CreatePod( + p.Client, + p.namespace, + p.podName, + StorageClassName, + p.pvcName, + []string{p.volume}, + pvcAnn, + nil, + p.VeleroCfg.ImageRegistryProxy, + p.VeleroCfg.WorkerOS, + ) Expect(err).To(Succeed()) err = WaitForPods(p.Ctx, p.Client, p.namespace, []string{p.podName}) Expect(err).To(Succeed()) @@ -85,8 +103,9 @@ func (p *PVCSelectedNodeChanging) CreateResources() error { }) By("Prepare ConfigMap data", func() { - nodeNameList, err := GetWorkerNodes(p.Ctx) + nodeNameList, err := GetWorkerNodes(p.Ctx, p.VeleroCfg.WorkerOS) Expect(err).To(Succeed()) + // Expect Windows node or Linux node number are no less than 2. Expect(len(nodeNameList)).To(BeNumerically(">=", 2)) for _, nodeName := range nodeNameList { if nodeName != p.oldNodeName { diff --git a/test/e2e/basic/storage-class-changing.go b/test/e2e/basic/storage-class-changing.go index 77f6c3b7c..08481d4ad 100644 --- a/test/e2e/basic/storage-class-changing.go +++ b/test/e2e/basic/storage-class-changing.go @@ -10,6 +10,7 @@ import ( velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" . "github.com/vmware-tanzu/velero/test" . "github.com/vmware-tanzu/velero/test/e2e/test" + "github.com/vmware-tanzu/velero/test/util/common" . "github.com/vmware-tanzu/velero/test/util/k8s" . "github.com/vmware-tanzu/velero/test/util/velero" ) @@ -73,7 +74,14 @@ func (s *StorageClasssChanging) CreateResources() error { } By(fmt.Sprintf("Create namespace %s", s.namespace), func() { - Expect(CreateNamespace(s.Ctx, s.Client, s.namespace)).To(Succeed(), + nsLabels := make(map[string]string) + if s.VeleroCfg.WorkerOS == common.WorkerOSWindows { + nsLabels = map[string]string{ + "pod-security.kubernetes.io/enforce": "privileged", + "pod-security.kubernetes.io/enforce-version": "latest", + } + } + Expect(CreateNamespaceWithLabel(s.Ctx, s.Client, s.namespace, nsLabels)).To(Succeed(), fmt.Sprintf("Failed to create namespace %s", s.namespace)) }) @@ -82,7 +90,14 @@ func (s *StorageClasssChanging) CreateResources() error { Expect(err).To(Succeed()) vols := CreateVolumes(pvc.Name, []string{s.volume}) - deployment := NewDeployment(s.CaseBaseName, s.namespace, 1, label, s.VeleroCfg.ImageRegistryProxy).WithVolume(vols).Result() + deployment := NewDeployment( + s.CaseBaseName, + s.namespace, + 1, + label, + s.VeleroCfg.ImageRegistryProxy, + s.VeleroCfg.WorkerOS, + ).WithVolume(vols).Result() deployment, err = CreateDeployment(s.Client.ClientGo, s.namespace, deployment) Expect(err).To(Succeed()) s.deploymentName = deployment.Name diff --git a/test/e2e/parallelfilesdownload/parallel_files_download.go b/test/e2e/parallelfilesdownload/parallel_files_download.go index b11a9061d..bc4d61323 100644 --- a/test/e2e/parallelfilesdownload/parallel_files_download.go +++ b/test/e2e/parallelfilesdownload/parallel_files_download.go @@ -24,6 +24,7 @@ import ( . "github.com/vmware-tanzu/velero/test" . "github.com/vmware-tanzu/velero/test/e2e/test" + "github.com/vmware-tanzu/velero/test/util/common" . "github.com/vmware-tanzu/velero/test/util/k8s" ) @@ -90,13 +91,30 @@ func (p *ParallelFilesDownload) Init() error { func (p *ParallelFilesDownload) CreateResources() error { By(fmt.Sprintf("Create namespace %s", p.namespace), func() { - Expect(CreateNamespace(p.Ctx, p.Client, p.namespace)).To(Succeed(), + labels := make(map[string]string) + if p.VeleroCfg.WorkerOS == common.WorkerOSWindows { + labels = map[string]string{ + "pod-security.kubernetes.io/enforce": "privileged", + "pod-security.kubernetes.io/enforce-version": "latest", + } + } + Expect(CreateNamespaceWithLabel(p.Ctx, p.Client, p.namespace, labels)).To(Succeed(), fmt.Sprintf("Failed to create namespace %s", p.namespace)) }) By(fmt.Sprintf("Create pod %s in namespace %s", p.pod, p.namespace), func() { - _, err := CreatePod(p.Client, p.namespace, p.pod, StorageClassName, p.pvc, []string{p.volume}, - nil, nil, p.VeleroCfg.ImageRegistryProxy) + _, err := CreatePod( + p.Client, + p.namespace, + p.pod, + StorageClassName, + p.pvc, + []string{p.volume}, + nil, + nil, + p.VeleroCfg.ImageRegistryProxy, + p.VeleroCfg.WorkerOS, + ) Expect(err).To(Succeed()) err = WaitForPods(p.Ctx, p.Client, p.namespace, []string{p.pod}) Expect(err).To(Succeed()) diff --git a/test/e2e/parallelfilesupload/parallel_files_upload.go b/test/e2e/parallelfilesupload/parallel_files_upload.go index 2721752bd..b11e3382b 100644 --- a/test/e2e/parallelfilesupload/parallel_files_upload.go +++ b/test/e2e/parallelfilesupload/parallel_files_upload.go @@ -24,6 +24,7 @@ import ( . "github.com/vmware-tanzu/velero/test" . "github.com/vmware-tanzu/velero/test/e2e/test" + "github.com/vmware-tanzu/velero/test/util/common" . "github.com/vmware-tanzu/velero/test/util/k8s" ) @@ -81,13 +82,31 @@ func (p *ParallelFilesUpload) Init() error { func (p *ParallelFilesUpload) CreateResources() error { By(fmt.Sprintf("Create namespace %s", p.namespace), func() { - Expect(CreateNamespace(p.Ctx, p.Client, p.namespace)).To(Succeed(), + labels := make(map[string]string) + if p.VeleroCfg.WorkerOS == common.WorkerOSWindows { + labels = map[string]string{ + "pod-security.kubernetes.io/enforce": "privileged", + "pod-security.kubernetes.io/enforce-version": "latest", + } + } + + Expect(CreateNamespaceWithLabel(p.Ctx, p.Client, p.namespace, labels)).To(Succeed(), fmt.Sprintf("Failed to create namespace %s", p.namespace)) }) By(fmt.Sprintf("Create pod %s in namespace %s", p.pod, p.namespace), func() { - _, err := CreatePod(p.Client, p.namespace, p.pod, StorageClassName, p.pvc, - []string{p.volume}, nil, nil, p.VeleroCfg.ImageRegistryProxy) + _, err := CreatePod( + p.Client, + p.namespace, + p.pod, + StorageClassName, + p.pvc, + []string{p.volume}, + nil, + nil, + p.VeleroCfg.ImageRegistryProxy, + p.VeleroCfg.WorkerOS, + ) Expect(err).To(Succeed()) err = WaitForPods(p.Ctx, p.Client, p.namespace, []string{p.pod}) Expect(err).To(Succeed()) diff --git a/test/e2e/pv-backup/pv-backup-filter.go b/test/e2e/pv-backup/pv-backup-filter.go index f9b52b788..5a6730551 100644 --- a/test/e2e/pv-backup/pv-backup-filter.go +++ b/test/e2e/pv-backup/pv-backup-filter.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "strings" + "unicode" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -11,6 +12,7 @@ import ( . "github.com/vmware-tanzu/velero/test" . "github.com/vmware-tanzu/velero/test/e2e/test" + "github.com/vmware-tanzu/velero/test/util/common" . "github.com/vmware-tanzu/velero/test/util/common" . "github.com/vmware-tanzu/velero/test/util/k8s" ) @@ -65,7 +67,14 @@ func (p *PVBackupFiltering) Init() error { func (p *PVBackupFiltering) CreateResources() error { for _, ns := range *p.NSIncluded { By(fmt.Sprintf("Create namespaces %s for workload\n", ns), func() { - Expect(CreateNamespace(p.Ctx, p.Client, ns)).To(Succeed(), fmt.Sprintf("Failed to create namespace %s", ns)) + labels := make(map[string]string) + if p.VeleroCfg.WorkerOS == common.WorkerOSWindows { + labels = map[string]string{ + "pod-security.kubernetes.io/enforce": "privileged", + "pod-security.kubernetes.io/enforce-version": "latest", + } + } + Expect(CreateNamespaceWithLabel(p.Ctx, p.Client, ns, labels)).To(Succeed(), fmt.Sprintf("Failed to create namespace %s", ns)) }) var pods []string By(fmt.Sprintf("Deploy a few pods with several PVs in namespace %s", ns), func() { @@ -87,8 +96,18 @@ func (p *PVBackupFiltering) CreateResources() error { podName := fmt.Sprintf("pod-%d", i) pods = append(pods, podName) By(fmt.Sprintf("Create pod %s in namespace %s", podName, ns), func() { - pod, err := CreatePod(p.Client, ns, podName, StorageClassName, "", - volumes, nil, nil, p.VeleroCfg.ImageRegistryProxy) + pod, err := CreatePod( + p.Client, + ns, + podName, + StorageClassName, + "", + volumes, + nil, + nil, + p.VeleroCfg.ImageRegistryProxy, + p.VeleroCfg.WorkerOS, + ) Expect(err).To(Succeed()) ann := map[string]string{ p.annotation: volumesToAnnotation, @@ -116,7 +135,6 @@ func (p *PVBackupFiltering) CreateResources() error { for i, pod := range p.podsList[index] { for j := range p.volumesList[i] { Expect(CreateFileToPod( - p.Ctx, ns, pod, pod, @@ -207,16 +225,20 @@ func fileExist( volume string, workerOS string, ) error { - c, _, err := ReadFileFromPodVolume(ctx, namespace, podName, podName, volume, FILE_NAME, workerOS) + c, _, err := ReadFileFromPodVolume(namespace, podName, podName, volume, FILE_NAME, workerOS) if err != nil { + fmt.Printf("Fail to read file %s from volume %s of pod %s in %s: %s", + FILE_NAME, volume, podName, namespace, err.Error(), + ) return errors.Wrap(err, fmt.Sprintf("Fail to read file %s from volume %s of pod %s in %s ", FILE_NAME, volume, podName, namespace)) } - c = strings.Replace(c, "\n", "", -1) - origin_content := strings.Replace(CreateFileContent(namespace, podName, volume), "\n", "", -1) + c = strings.TrimRightFunc(c, unicode.IsSpace) + origin_content := strings.TrimRightFunc(CreateFileContent(namespace, podName, volume), unicode.IsSpace) if c == origin_content { return nil } else { + fmt.Printf("Content not match: \n origin: %s\n result: %s\n", origin_content, c) return errors.New(fmt.Sprintf("UNEXPECTED: File %s does not exist in volume %s of pod %s in namespace %s.", FILE_NAME, volume, podName, namespace)) } @@ -228,7 +250,7 @@ func fileNotExist( volume string, workerOS string, ) error { - _, _, err := ReadFileFromPodVolume(ctx, namespace, podName, podName, volume, FILE_NAME, workerOS) + _, _, err := ReadFileFromPodVolume(namespace, podName, podName, volume, FILE_NAME, workerOS) if err != nil { return nil } else { diff --git a/test/e2e/resource-filtering/base.go b/test/e2e/resource-filtering/base.go index 19e8ba056..f4070d9e7 100644 --- a/test/e2e/resource-filtering/base.go +++ b/test/e2e/resource-filtering/base.go @@ -24,6 +24,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" . "github.com/vmware-tanzu/velero/test/e2e/test" + "github.com/vmware-tanzu/velero/test/util/common" . "github.com/vmware-tanzu/velero/test/util/k8s" ) @@ -63,12 +64,26 @@ func (f *FilteringCase) CreateResources() error { for nsNum := 0; nsNum < f.NamespacesTotal; nsNum++ { namespace := fmt.Sprintf("%s-%00000d", f.CaseBaseName, nsNum) fmt.Printf("Creating resources in namespace ...%s\n", namespace) - if err := CreateNamespace(f.Ctx, f.Client, namespace); err != nil { + nsLabels := make(map[string]string) + if f.VeleroCfg.WorkerOS == common.WorkerOSWindows { + nsLabels = map[string]string{ + "pod-security.kubernetes.io/enforce": "privileged", + "pod-security.kubernetes.io/enforce-version": "latest", + } + } + if err := CreateNamespaceWithLabel(f.Ctx, f.Client, namespace, nsLabels); err != nil { return errors.Wrapf(err, "Failed to create namespace %s", namespace) } //Create deployment fmt.Printf("Creating deployment in namespaces ...%s\n", namespace) - deployment := NewDeployment(f.CaseBaseName, namespace, f.replica, f.labels, f.VeleroCfg.ImageRegistryProxy).Result() + deployment := NewDeployment( + f.CaseBaseName, + namespace, + f.replica, + f.labels, + f.VeleroCfg.ImageRegistryProxy, + f.VeleroCfg.WorkerOS, + ).Result() deployment, err := CreateDeployment(f.Client.ClientGo, namespace, deployment) if err != nil { return errors.Wrap(err, fmt.Sprintf("failed to delete the namespace %q", namespace)) diff --git a/test/e2e/resource-filtering/exclude_label.go b/test/e2e/resource-filtering/exclude_label.go index b2b2986af..695d7d8ed 100644 --- a/test/e2e/resource-filtering/exclude_label.go +++ b/test/e2e/resource-filtering/exclude_label.go @@ -26,6 +26,7 @@ import ( velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" . "github.com/vmware-tanzu/velero/test/e2e/test" + "github.com/vmware-tanzu/velero/test/util/common" . "github.com/vmware-tanzu/velero/test/util/k8s" ) @@ -83,12 +84,28 @@ func (e *ExcludeFromBackup) CreateResources() error { velerov1api.ExcludeFromBackupLabel: "false", } fmt.Printf("Creating resources in namespace ...%s\n", namespace) - if err := CreateNamespace(e.Ctx, e.Client, namespace); err != nil { + + nsLabels := make(map[string]string) + if e.VeleroCfg.WorkerOS == common.WorkerOSWindows { + nsLabels = map[string]string{ + "pod-security.kubernetes.io/enforce": "privileged", + "pod-security.kubernetes.io/enforce-version": "latest", + } + } + + if err := CreateNamespaceWithLabel(e.Ctx, e.Client, namespace, nsLabels); err != nil { return errors.Wrapf(err, "Failed to create namespace %s", namespace) } //Create deployment: to be included fmt.Printf("Creating deployment in namespaces ...%s\n", namespace) - deployment := NewDeployment(e.CaseBaseName, namespace, e.replica, label2, e.VeleroCfg.ImageRegistryProxy).Result() + deployment := NewDeployment( + e.CaseBaseName, + namespace, + e.replica, + label2, + e.VeleroCfg.ImageRegistryProxy, + e.VeleroCfg.WorkerOS, + ).Result() deployment, err := CreateDeployment(e.Client.ClientGo, namespace, deployment) if err != nil { return errors.Wrap(err, fmt.Sprintf("failed to delete the namespace %q", namespace)) diff --git a/test/e2e/resource-filtering/label_selector.go b/test/e2e/resource-filtering/label_selector.go index 2d745a0fc..9ecc66a0c 100644 --- a/test/e2e/resource-filtering/label_selector.go +++ b/test/e2e/resource-filtering/label_selector.go @@ -25,6 +25,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" . "github.com/vmware-tanzu/velero/test/e2e/test" + "github.com/vmware-tanzu/velero/test/util/common" . "github.com/vmware-tanzu/velero/test/util/k8s" ) @@ -82,13 +83,26 @@ func (l *LabelSelector) CreateResources() error { "resourcefiltering": "false", } } + + if l.VeleroCfg.WorkerOS == common.WorkerOSWindows { + labels["pod-security.kubernetes.io/enforce"] = "privileged" + labels["pod-security.kubernetes.io/enforce-version"] = "latest" + } + if err := CreateNamespaceWithLabel(l.Ctx, l.Client, namespace, labels); err != nil { return errors.Wrapf(err, "Failed to create namespace %s", namespace) } //Create deployment fmt.Printf("Creating deployment in namespaces ...%s\n", namespace) - deployment := NewDeployment(l.CaseBaseName, namespace, l.replica, labels, l.VeleroCfg.ImageRegistryProxy).Result() + deployment := NewDeployment( + l.CaseBaseName, + namespace, + l.replica, + labels, + l.VeleroCfg.ImageRegistryProxy, + l.VeleroCfg.WorkerOS, + ).Result() deployment, err := CreateDeployment(l.Client.ClientGo, namespace, deployment) if err != nil { return errors.Wrap(err, fmt.Sprintf("failed to delete the namespace %q", namespace)) diff --git a/test/e2e/resourcemodifiers/resource_modifiers.go b/test/e2e/resourcemodifiers/resource_modifiers.go index 2f048698a..06cbd91f1 100644 --- a/test/e2e/resourcemodifiers/resource_modifiers.go +++ b/test/e2e/resourcemodifiers/resource_modifiers.go @@ -25,6 +25,7 @@ import ( "github.com/pkg/errors" . "github.com/vmware-tanzu/velero/test/e2e/test" + "github.com/vmware-tanzu/velero/test/util/common" . "github.com/vmware-tanzu/velero/test/util/k8s" ) @@ -105,8 +106,16 @@ func (r *ResourceModifiersCase) CreateResources() error { for nsNum := 0; nsNum < r.NamespacesTotal; nsNum++ { namespace := fmt.Sprintf("%s-%00000d", r.CaseBaseName, nsNum) + nsLabels := make(map[string]string) + if r.VeleroCfg.WorkerOS == common.WorkerOSWindows { + nsLabels = map[string]string{ + "pod-security.kubernetes.io/enforce": "privileged", + "pod-security.kubernetes.io/enforce-version": "latest", + } + } + By(fmt.Sprintf("Create namespaces %s for workload\n", namespace), func() { - Expect(CreateNamespace(r.Ctx, r.Client, namespace)).To(Succeed(), fmt.Sprintf("Failed to create namespace %s", namespace)) + Expect(CreateNamespaceWithLabel(r.Ctx, r.Client, namespace, nsLabels)).To(Succeed(), fmt.Sprintf("Failed to create namespace %s", namespace)) }) By(fmt.Sprintf("Creating deployment in namespaces ...%s\n", namespace), func() { @@ -145,7 +154,14 @@ func (r *ResourceModifiersCase) Clean() error { } func (r *ResourceModifiersCase) createDeployment(namespace string) error { - deployment := NewDeployment(r.CaseBaseName, namespace, 1, map[string]string{"app": "test"}, r.VeleroCfg.ImageRegistryProxy).Result() + deployment := NewDeployment( + r.CaseBaseName, + namespace, + 1, + map[string]string{"app": "test"}, + r.VeleroCfg.ImageRegistryProxy, + r.VeleroCfg.WorkerOS, + ).Result() deployment, err := CreateDeployment(r.Client.ClientGo, namespace, deployment) if err != nil { return errors.Wrap(err, fmt.Sprintf("failed to create deloyment %s the namespace %q", deployment.Name, namespace)) diff --git a/test/e2e/resourcepolicies/resource_policies.go b/test/e2e/resourcepolicies/resource_policies.go index ef5e5afe8..f3254eb04 100644 --- a/test/e2e/resourcepolicies/resource_policies.go +++ b/test/e2e/resourcepolicies/resource_policies.go @@ -19,6 +19,7 @@ package resourcepolicies import ( "fmt" "strings" + "unicode" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -111,8 +112,17 @@ func (r *ResourcePoliciesCase) CreateResources() error { for nsNum := 0; nsNum < r.NamespacesTotal; nsNum++ { namespace := fmt.Sprintf("%s-%00000d", r.CaseBaseName, nsNum) + + nsLabels := make(map[string]string) + if r.VeleroCfg.WorkerOS == common.WorkerOSWindows { + nsLabels = map[string]string{ + "pod-security.kubernetes.io/enforce": "privileged", + "pod-security.kubernetes.io/enforce-version": "latest", + } + } + By(fmt.Sprintf("Create namespaces %s for workload\n", namespace), func() { - Expect(CreateNamespace(r.Ctx, r.Client, namespace)).To(Succeed(), fmt.Sprintf("Failed to create namespace %s", namespace)) + Expect(CreateNamespaceWithLabel(r.Ctx, r.Client, namespace, nsLabels)).To(Succeed(), fmt.Sprintf("Failed to create namespace %s", namespace)) }) volName := fmt.Sprintf("vol-%s-%00000d", r.CaseBaseName, nsNum) @@ -153,7 +163,6 @@ func (r *ResourcePoliciesCase) Verify() error { continue } content, _, err := ReadFileFromPodVolume( - r.Ctx, ns, pod.Name, "container-busybox", @@ -167,11 +176,12 @@ func (r *ResourcePoliciesCase) Verify() error { Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("Fail to read file %s from volume %s of pod %s in namespace %s", FileName, vol.Name, pod.Name, ns)) - content = strings.Replace(content, "\n", "", -1) - originContent := strings.Replace(fmt.Sprintf("ns-%s pod-%s volume-%s", ns, pod.Name, vol.Name), "\n", "", -1) + content = strings.TrimRightFunc(content, unicode.IsSpace) + originContent := fmt.Sprintf("ns-%s pod-%s volume-%s", ns, pod.Name, vol.Name) - Expect(content).To(Equal(originContent), fmt.Sprintf("File %s does not exist in volume %s of pod %s in namespace %s", - FileName, vol.Name, pod.Name, ns)) + Expect(content).To(Equal(originContent), + fmt.Sprintf("Content not match.\n origin: %s\n result: %s\n", originContent, content), + ) } } } @@ -218,7 +228,14 @@ func (r *ResourcePoliciesCase) createPVC(index int, namespace string, volList [] } func (r *ResourcePoliciesCase) createDeploymentWithVolume(namespace string, volList []*corev1api.Volume) error { - deployment := NewDeployment(r.CaseBaseName, namespace, 1, map[string]string{"resource-policies": "resource-policies"}, r.VeleroCfg.ImageRegistryProxy).WithVolume(volList).Result() + deployment := NewDeployment( + r.CaseBaseName, + namespace, + 1, + map[string]string{"resource-policies": "resource-policies"}, + r.VeleroCfg.ImageRegistryProxy, + r.VeleroCfg.WorkerOS, + ).WithVolume(volList).Result() deployment, err := CreateDeployment(r.Client.ClientGo, namespace, deployment) if err != nil { return errors.Wrap(err, fmt.Sprintf("failed to create deloyment %s the namespace %q", deployment.Name, namespace)) @@ -241,14 +258,13 @@ func (r *ResourcePoliciesCase) writeDataIntoPods(namespace, volName string) erro continue } err := CreateFileToPod( - r.Ctx, namespace, pod.Name, "container-busybox", vol.Name, FileName, fmt.Sprintf("ns-%s pod-%s volume-%s", namespace, pod.Name, vol.Name), - common.WorkerOSLinux, + r.VeleroCfg.WorkerOS, ) if err != nil { return errors.Wrap(err, fmt.Sprintf("failed to create file into pod %s in namespace: %q", pod.Name, namespace)) diff --git a/test/e2e/schedule/in_progress.go b/test/e2e/schedule/in_progress.go index 65b024fb2..060740c3f 100644 --- a/test/e2e/schedule/in_progress.go +++ b/test/e2e/schedule/in_progress.go @@ -14,6 +14,7 @@ import ( velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" "github.com/vmware-tanzu/velero/test" framework "github.com/vmware-tanzu/velero/test/e2e/test" + "github.com/vmware-tanzu/velero/test/util/common" k8sutil "github.com/vmware-tanzu/velero/test/util/k8s" veleroutil "github.com/vmware-tanzu/velero/test/util/velero" ) @@ -64,11 +65,19 @@ func (s *InProgressCase) Init() error { func (s *InProgressCase) CreateResources() error { By(fmt.Sprintf("Create namespace %s", s.namespace), func() { + labels := make(map[string]string) + if s.VeleroCfg.WorkerOS == common.WorkerOSWindows { + labels = map[string]string{ + "pod-security.kubernetes.io/enforce": "privileged", + "pod-security.kubernetes.io/enforce-version": "latest", + } + } Expect( - k8sutil.CreateNamespace( + k8sutil.CreateNamespaceWithLabel( s.Ctx, s.Client, s.namespace, + labels, ), ).To(Succeed(), fmt.Sprintf("Failed to create namespace %s", s.namespace)) @@ -85,6 +94,7 @@ func (s *InProgressCase) CreateResources() error { nil, s.podAnn, s.VeleroCfg.ImageRegistryProxy, + s.VeleroCfg.WorkerOS, ) Expect(err).To(Succeed()) diff --git a/test/e2e/schedule/ordered_resources.go b/test/e2e/schedule/ordered_resources.go index c562ea9d2..df0d8b972 100644 --- a/test/e2e/schedule/ordered_resources.go +++ b/test/e2e/schedule/ordered_resources.go @@ -32,6 +32,7 @@ import ( velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" framework "github.com/vmware-tanzu/velero/test/e2e/test" + "github.com/vmware-tanzu/velero/test/util/common" k8sutil "github.com/vmware-tanzu/velero/test/util/k8s" veleroutil "github.com/vmware-tanzu/velero/test/util/velero" ) @@ -92,14 +93,29 @@ func (o *OrderedResources) CreateResources() error { "orderedresources": "true", } fmt.Printf("Creating resources in %s namespace ...\n", o.Namespace) - if err := k8sutil.CreateNamespace(o.Ctx, o.Client, o.Namespace); err != nil { + + nsLabels := make(map[string]string) + if o.VeleroCfg.WorkerOS == common.WorkerOSWindows { + nsLabels = map[string]string{ + "pod-security.kubernetes.io/enforce": "privileged", + "pod-security.kubernetes.io/enforce-version": "latest", + } + } + if err := k8sutil.CreateNamespaceWithLabel(o.Ctx, o.Client, o.Namespace, nsLabels); err != nil { return errors.Wrapf(err, "failed to create namespace %s", o.Namespace) } //Create deployment deploymentName := fmt.Sprintf("deploy-%s", o.CaseBaseName) fmt.Printf("Creating deployment %s in %s namespaces ...\n", deploymentName, o.Namespace) - deployment := k8sutil.NewDeployment(deploymentName, o.Namespace, 1, label, o.VeleroCfg.ImageRegistryProxy).Result() + deployment := k8sutil.NewDeployment( + deploymentName, + o.Namespace, + 1, + label, + o.VeleroCfg.ImageRegistryProxy, + o.VeleroCfg.WorkerOS, + ).Result() _, err := k8sutil.CreateDeployment(o.Client.ClientGo, o.Namespace, deployment) if err != nil { return errors.Wrap(err, fmt.Sprintf("failed to create namespace %q with err %v", o.Namespace, err)) diff --git a/test/util/common/common.go b/test/util/common/common.go index 853c0bfc9..b49c61e50 100644 --- a/test/util/common/common.go +++ b/test/util/common/common.go @@ -72,10 +72,13 @@ func GetListByCmdPipes(ctx context.Context, cmdLines []*OsCommandLine) ([]string func GetResourceWithLabel(ctx context.Context, namespace, resourceName string, labels map[string]string) ([]string, error) { labelStr := "" + parts := make([]string, 0, len(labels)) for key, value := range labels { strings.Join([]string{labelStr, key + "=" + value}, ",") + parts = append(parts, key+"="+value) } + labelStr = strings.Join(parts, ",") cmds := []*OsCommandLine{} cmd := &OsCommandLine{ diff --git a/test/util/k8s/common.go b/test/util/k8s/common.go index c60450c33..3e0c553ce 100644 --- a/test/util/k8s/common.go +++ b/test/util/k8s/common.go @@ -323,7 +323,6 @@ func WriteRandomDataToFileInPod(ctx context.Context, namespace, podName, contain } func CreateFileToPod( - ctx context.Context, namespace string, podName string, containerName string, @@ -345,8 +344,9 @@ func CreateFileToPod( arg := []string{"exec", "-n", namespace, "-c", containerName, podName, "--", shell, shellParameter, fmt.Sprintf("echo ns-%s pod-%s volume-%s > %s", namespace, podName, volume, filePath)} - cmd := exec.CommandContext(ctx, "kubectl", arg...) + cmd := exec.CommandContext(context.Background(), "kubectl", arg...) fmt.Printf("Kubectl exec cmd =%v\n", cmd) + return cmd.Run() } @@ -359,9 +359,9 @@ func FileExistInPV( filename string, workerOS string, ) (bool, error) { - stdout, stderr, err := ReadFileFromPodVolume(ctx, namespace, podName, containerName, volume, filename, workerOS) + stdout, stderr, err := ReadFileFromPodVolume(namespace, podName, containerName, volume, filename, workerOS) - output := fmt.Sprintf("%s:%s", stdout, stderr) + output := fmt.Sprintf("%s:%s:%s", stdout, stderr, err) if workerOS == common.WorkerOSWindows { if strings.Contains(output, "The system cannot find the file specified") { @@ -380,8 +380,8 @@ func FileExistInPV( filename, volume, podName, namespace)) } } + func ReadFileFromPodVolume( - ctx context.Context, namespace string, podName string, containerName string, @@ -391,16 +391,20 @@ func ReadFileFromPodVolume( ) (string, string, error) { arg := []string{"exec", "-n", namespace, "-c", containerName, podName, "--", "cat", fmt.Sprintf("/%s/%s", volume, filename)} + if workerOS == common.WorkerOSWindows { arg = []string{"exec", "-n", namespace, "-c", containerName, podName, - "--", "cmd", "/c", fmt.Sprintf("type C:\\%s\\%s", volume, filename)} + "--", "cmd", "/c", "type", fmt.Sprintf("C:\\%s\\%s", volume, filename)} } - cmd := exec.CommandContext(ctx, "kubectl", arg...) - fmt.Printf("Kubectl exec cmd =%v\n", cmd) + cmd := exec.CommandContext(context.Background(), "kubectl", arg...) + fmt.Printf("kubectl exec cmd =%v\n", cmd) + stdout, stderr, err := veleroexec.RunCommand(cmd) fmt.Printf("stdout: %s\n", stdout) fmt.Printf("stderr: %s\n", stderr) + fmt.Printf("err: %v\n", err) + return stdout, stderr, err } diff --git a/test/util/k8s/deployment.go b/test/util/k8s/deployment.go index fdc334033..9c570aee1 100644 --- a/test/util/k8s/deployment.go +++ b/test/util/k8s/deployment.go @@ -29,6 +29,7 @@ import ( clientset "k8s.io/client-go/kubernetes" "github.com/vmware-tanzu/velero/pkg/util/boolptr" + common "github.com/vmware-tanzu/velero/test/util/common" ) const ( @@ -37,7 +38,8 @@ const ( PollInterval = 2 * time.Second PollTimeout = 15 * time.Minute DefaultContainerName = "container-busybox" - TestImage = "busybox:1.37.0" + LinuxTestImage = "busybox:1.37.0" + WindowTestImage = "mcr.microsoft.com/windows/nanoserver:ltsc2022" ) // DeploymentBuilder builds Deployment objects. @@ -50,30 +52,100 @@ func (d *DeploymentBuilder) Result() *appsv1api.Deployment { } // newDeployment returns a RollingUpdate Deployment with a fake container image -func NewDeployment(name, ns string, replicas int32, labels map[string]string, imageRegistryProxy string) *DeploymentBuilder { - imageAddress := TestImage - if imageRegistryProxy != "" { - imageAddress = path.Join(imageRegistryProxy, TestImage) +func NewDeployment( + name, ns string, + replicas int32, + labels map[string]string, + imageRegistryProxy string, + workerOS string, +) *DeploymentBuilder { + // Default to Linux environment + imageAddress := LinuxTestImage + command := []string{"sleep", "infinity"} + args := make([]string, 0) + var affinity corev1api.Affinity + var tolerations []corev1api.Toleration + + if workerOS == common.WorkerOSLinux && imageRegistryProxy != "" { + imageAddress = path.Join(imageRegistryProxy, LinuxTestImage) + } + + containerSecurityContext := &corev1api.SecurityContext{ + AllowPrivilegeEscalation: boolptr.False(), + Capabilities: &corev1api.Capabilities{ + Drop: []corev1api.Capability{"ALL"}, + }, + RunAsNonRoot: boolptr.True(), + RunAsUser: func(i int64) *int64 { return &i }(65534), + RunAsGroup: func(i int64) *int64 { return &i }(65534), + SeccompProfile: &corev1api.SeccompProfile{ + Type: corev1api.SeccompProfileTypeRuntimeDefault, + }, + } + + podSecurityContext := &corev1api.PodSecurityContext{ + FSGroup: func(i int64) *int64 { return &i }(65534), + FSGroupChangePolicy: func(policy corev1api.PodFSGroupChangePolicy) *corev1api.PodFSGroupChangePolicy { return &policy }(corev1api.FSGroupChangeAlways), + } + + // Settings for Windows + if workerOS == common.WorkerOSWindows { + imageAddress = WindowTestImage + command = []string{"cmd"} + args = []string{"/c", "ping -t localhost > NUL"} + + affinity = corev1api.Affinity{ + NodeAffinity: &corev1api.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1api.NodeSelector{ + NodeSelectorTerms: []corev1api.NodeSelectorTerm{ + { + MatchExpressions: []corev1api.NodeSelectorRequirement{ + { + Key: "kubernetes.io/os", + Values: []string{common.WorkerOSWindows}, + Operator: corev1api.NodeSelectorOpIn, + }, + }, + }, + }, + }, + }, + } + + tolerations = []corev1api.Toleration{ + { + Effect: corev1api.TaintEffectNoSchedule, + Key: "os", + Value: common.WorkerOSWindows, + }, + { + Effect: corev1api.TaintEffectNoExecute, + Key: "os", + Value: common.WorkerOSWindows, + }, + } + + whetherToRunAsRoot := false + containerSecurityContext = &corev1api.SecurityContext{ + RunAsNonRoot: &whetherToRunAsRoot, + } + + containerUserName := "ContainerAdministrator" + podSecurityContext = &corev1api.PodSecurityContext{ + WindowsOptions: &corev1api.WindowsSecurityContextOptions{ + RunAsUserName: &containerUserName, + }, + } } containers := []corev1api.Container{ { Name: DefaultContainerName, Image: imageAddress, - Command: []string{"sleep", "1000000"}, + Command: command, + Args: args, // Make pod obeys the restricted pod security standards. - SecurityContext: &corev1api.SecurityContext{ - AllowPrivilegeEscalation: boolptr.False(), - Capabilities: &corev1api.Capabilities{ - Drop: []corev1api.Capability{"ALL"}, - }, - RunAsNonRoot: boolptr.True(), - RunAsUser: func(i int64) *int64 { return &i }(65534), - RunAsGroup: func(i int64) *int64 { return &i }(65534), - SeccompProfile: &corev1api.SeccompProfile{ - Type: corev1api.SeccompProfileTypeRuntimeDefault, - }, - }, + SecurityContext: containerSecurityContext, }, } @@ -100,11 +172,10 @@ func NewDeployment(name, ns string, replicas int32, labels map[string]string, im Labels: labels, }, Spec: corev1api.PodSpec{ - SecurityContext: &corev1api.PodSecurityContext{ - FSGroup: func(i int64) *int64 { return &i }(65534), - FSGroupChangePolicy: func(policy corev1api.PodFSGroupChangePolicy) *corev1api.PodFSGroupChangePolicy { return &policy }(corev1api.FSGroupChangeAlways), - }, - Containers: containers, + SecurityContext: podSecurityContext, + Containers: containers, + Affinity: &affinity, + Tolerations: tolerations, }, }, }, @@ -127,10 +198,6 @@ func (d *DeploymentBuilder) WithVolume(volumes []*corev1api.Volume) *DeploymentB return d } -func CreateDeploy(c clientset.Interface, ns string, deployment *appsv1api.Deployment) error { - _, err := c.AppsV1().Deployments(ns).Create(context.TODO(), deployment, metav1.CreateOptions{}) - return err -} func CreateDeployment(c clientset.Interface, ns string, deployment *appsv1api.Deployment) (*appsv1api.Deployment, error) { return c.AppsV1().Deployments(ns).Create(context.TODO(), deployment, metav1.CreateOptions{}) } diff --git a/test/util/k8s/namespace.go b/test/util/k8s/namespace.go index b2a5cae0e..b46075fee 100644 --- a/test/util/k8s/namespace.go +++ b/test/util/k8s/namespace.go @@ -53,8 +53,12 @@ func CreateNamespaceWithLabel(ctx context.Context, client TestClient, namespace ns := builder.ForNamespace(namespace).Result() ns.Labels = label // Add label to avoid PSA check. - ns.Labels["pod-security.kubernetes.io/enforce"] = "baseline" - ns.Labels["pod-security.kubernetes.io/enforce-version"] = "latest" + if _, ok := ns.Labels["pod-security.kubernetes.io/enforce"]; !ok { + ns.Labels["pod-security.kubernetes.io/enforce"] = "baseline" + } + if _, ok := ns.Labels["pod-security.kubernetes.io/enforce-version"]; !ok { + ns.Labels["pod-security.kubernetes.io/enforce-version"] = "latest" + } _, err := client.ClientGo.CoreV1().Namespaces().Create(ctx, ns, metav1.CreateOptions{}) if apierrors.IsAlreadyExists(err) { return nil diff --git a/test/util/k8s/node.go b/test/util/k8s/node.go index e1e44b17b..5fd1dafc6 100644 --- a/test/util/k8s/node.go +++ b/test/util/k8s/node.go @@ -11,8 +11,13 @@ import ( common "github.com/vmware-tanzu/velero/test/util/common" ) -func GetWorkerNodes(ctx context.Context) ([]string, error) { - getCMD := exec.CommandContext(ctx, "kubectl", "get", "node", "-o", "json") +func GetWorkerNodes(ctx context.Context, workerOS string) ([]string, error) { + getCMD := exec.CommandContext( + ctx, + "kubectl", "get", "node", "-l", + fmt.Sprintf("kubernetes.io/os=%s", workerOS), + "-o", "json", + ) fmt.Printf("kubectl get node cmd =%v\n", getCMD) jsonBuf, err := common.CMDExecWithOutput(getCMD) diff --git a/test/util/k8s/pod.go b/test/util/k8s/pod.go index 06fa807e0..9906e08b5 100644 --- a/test/util/k8s/pod.go +++ b/test/util/k8s/pod.go @@ -18,14 +18,17 @@ package k8s import ( "context" + "encoding/json" "fmt" "path" "github.com/pkg/errors" corev1api "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" "github.com/vmware-tanzu/velero/pkg/util/boolptr" + common "github.com/vmware-tanzu/velero/test/util/common" ) func CreatePod( @@ -34,14 +37,88 @@ func CreatePod( volumeNameList []string, pvcAnn, ann map[string]string, imageRegistryProxy string, + workerOS string, ) (*corev1api.Pod, error) { if pvcName != "" && len(volumeNameList) != 1 { return nil, errors.New("Volume name list should contain only 1 since PVC name is not empty") } - imageAddress := TestImage - if imageRegistryProxy != "" { - imageAddress = path.Join(imageRegistryProxy, TestImage) + // Default to Linux environment + imageAddress := LinuxTestImage + command := []string{"sleep", "infinity"} + args := make([]string, 0) + var affinity corev1api.Affinity + var tolerations []corev1api.Toleration + + if workerOS == common.WorkerOSLinux && imageRegistryProxy != "" { + imageAddress = path.Join(imageRegistryProxy, LinuxTestImage) + } + + containerSecurityContext := &corev1api.SecurityContext{ + AllowPrivilegeEscalation: boolptr.False(), + Capabilities: &corev1api.Capabilities{ + Drop: []corev1api.Capability{"ALL"}, + }, + RunAsNonRoot: boolptr.True(), + RunAsUser: func(i int64) *int64 { return &i }(65534), + RunAsGroup: func(i int64) *int64 { return &i }(65534), + SeccompProfile: &corev1api.SeccompProfile{ + Type: corev1api.SeccompProfileTypeRuntimeDefault, + }, + } + + podSecurityContext := &corev1api.PodSecurityContext{ + FSGroup: func(i int64) *int64 { return &i }(65534), + FSGroupChangePolicy: func(policy corev1api.PodFSGroupChangePolicy) *corev1api.PodFSGroupChangePolicy { return &policy }(corev1api.FSGroupChangeAlways), + } + + // Settings for Windows + if workerOS == common.WorkerOSWindows { + imageAddress = WindowTestImage + command = []string{"cmd"} + args = []string{"/c", "ping -t localhost > NUL"} + affinity = corev1api.Affinity{ + NodeAffinity: &corev1api.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1api.NodeSelector{ + NodeSelectorTerms: []corev1api.NodeSelectorTerm{ + { + MatchExpressions: []corev1api.NodeSelectorRequirement{ + { + Key: "kubernetes.io/os", + Values: []string{common.WorkerOSWindows}, + Operator: corev1api.NodeSelectorOpIn, + }, + }, + }, + }, + }, + }, + } + + tolerations = []corev1api.Toleration{ + { + Effect: corev1api.TaintEffectNoSchedule, + Key: "os", + Value: common.WorkerOSWindows, + }, + { + Effect: corev1api.TaintEffectNoExecute, + Key: "os", + Value: common.WorkerOSWindows, + }, + } + + whetherToRunAsRoot := false + containerSecurityContext = &corev1api.SecurityContext{ + RunAsNonRoot: &whetherToRunAsRoot, + } + + containerUserName := "ContainerAdministrator" + podSecurityContext = &corev1api.PodSecurityContext{ + WindowsOptions: &corev1api.WindowsSecurityContextOptions{ + RunAsUserName: &containerUserName, + }, + } } volumes := []corev1api.Volume{} @@ -82,32 +159,20 @@ func CreatePod( Annotations: ann, }, Spec: corev1api.PodSpec{ - SecurityContext: &corev1api.PodSecurityContext{ - FSGroup: func(i int64) *int64 { return &i }(65534), - FSGroupChangePolicy: func(policy corev1api.PodFSGroupChangePolicy) *corev1api.PodFSGroupChangePolicy { return &policy }(corev1api.FSGroupChangeAlways), - }, + SecurityContext: podSecurityContext, Containers: []corev1api.Container{ { - Name: name, - Image: imageAddress, - Command: []string{"sleep", "3600"}, - VolumeMounts: vmList, - // Make pod obeys the restricted pod security standards. - SecurityContext: &corev1api.SecurityContext{ - AllowPrivilegeEscalation: boolptr.False(), - Capabilities: &corev1api.Capabilities{ - Drop: []corev1api.Capability{"ALL"}, - }, - RunAsNonRoot: boolptr.True(), - RunAsUser: func(i int64) *int64 { return &i }(65534), - RunAsGroup: func(i int64) *int64 { return &i }(65534), - SeccompProfile: &corev1api.SeccompProfile{ - Type: corev1api.SeccompProfileTypeRuntimeDefault, - }, - }, + Name: name, + Image: imageAddress, + Command: command, + Args: args, + VolumeMounts: vmList, + SecurityContext: containerSecurityContext, }, }, - Volumes: volumes, + Volumes: volumes, + Affinity: &affinity, + Tolerations: tolerations, }, } @@ -134,7 +199,25 @@ func AddAnnotationToPod(ctx context.Context, client TestClient, namespace, podNa newPod.Annotations = newAnn fmt.Println(newPod.Annotations) - return client.ClientGo.CoreV1().Pods(namespace).Update(ctx, newPod, metav1.UpdateOptions{}) + // Strategic merge patch to add/update label + patch := map[string]any{ + "metadata": map[string]any{ + "annotations": newAnn, + }, + } + patchBytes, err := json.Marshal(patch) + if err != nil { + fmt.Println("fail to marshal patch for pod: ", err.Error()) + return nil, err + } + + return client.ClientGo.CoreV1().Pods(namespace).Patch( + ctx, + newPod.Name, + types.StrategicMergePatchType, + patchBytes, + metav1.PatchOptions{}, + ) } func ListPods(ctx context.Context, client TestClient, namespace string) (*corev1api.PodList, error) { diff --git a/test/util/kibishii/kibishii_utils.go b/test/util/kibishii/kibishii_utils.go index f55b4226c..81be36cff 100644 --- a/test/util/kibishii/kibishii_utils.go +++ b/test/util/kibishii/kibishii_utils.go @@ -83,7 +83,7 @@ func RunKibishiiTests( ) error { pvCount := len(KibishiiPVCNameList) client := *veleroCfg.ClientToInstallVelero - timeOutContext, ctxCancel := context.WithTimeout(context.Background(), time.Minute*5) + timeOutContext, ctxCancel := context.WithTimeout(context.Background(), time.Minute*15) defer ctxCancel() veleroCLI := veleroCfg.VeleroCLI providerName := veleroCfg.CloudProvider @@ -208,11 +208,10 @@ func RunKibishiiTests( fmt.Printf("Re-populate volume %s\n", time.Now().Format("2006-01-02 15:04:05")) for _, pod := range KibishiiPodNameList { // To ensure Kibishii verification result is accurate - ClearKibishiiData(timeOutContext, kibishiiNamespace, pod, "kibishii", "data") + ClearKibishiiData(kibishiiNamespace, pod, "kibishii", "data", veleroCfg.WorkerOS) CreateFileContent := fileBaseContent + pod err := CreateFileToPod( - timeOutContext, kibishiiNamespace, pod, "kibishii", @@ -789,6 +788,13 @@ func KibishiiVerifyAfterRestore( if err := waitForKibishiiPods(oneHourTimeout, client, kibishiiNamespace); err != nil { return errors.Wrapf(err, "Failed to wait for ready status of kibishii pods in %s", kibishiiNamespace) } + + // TODO - check that namespace exists + fmt.Printf("running kibishii verify\n") + if err := verifyData(oneHourTimeout, kibishiiNamespace, kibishiiData); err != nil { + return errors.Wrap(err, "Failed to verify data generated by kibishii") + } + if incrementalFileName != "" { for _, pod := range KibishiiPodNameList { exist, err := FileExistInPV(oneHourTimeout, kibishiiNamespace, pod, "kibishii", "data", incrementalFileName, workerOS) @@ -801,19 +807,18 @@ func KibishiiVerifyAfterRestore( } } } - - // TODO - check that namespace exists - fmt.Printf("running kibishii verify\n") - if err := verifyData(oneHourTimeout, kibishiiNamespace, kibishiiData); err != nil { - return errors.Wrap(err, "Failed to verify data generated by kibishii") - } return nil } -func ClearKibishiiData(ctx context.Context, namespace, podName, containerName, dir string) error { +func ClearKibishiiData(namespace, podName, containerName, dir, workerOS string) error { arg := []string{"exec", "-n", namespace, "-c", containerName, podName, "--", "/bin/sh", "-c", "rm -rf /" + dir + "/*"} - cmd := exec.CommandContext(ctx, "kubectl", arg...) + + if workerOS == common.WorkerOSWindows { + arg = []string{"exec", "-n", namespace, "-c", containerName, podName, + "--", "cmd", "/c", fmt.Sprintf("del /Q C:\\%s\\*", dir)} + } + cmd := exec.CommandContext(context.Background(), "kubectl", arg...) fmt.Printf("Kubectl exec cmd =%v\n", cmd) return cmd.Run() } From c62a486765d2cab7b7339af8173f3acbb4a46161 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 22 Aug 2025 15:01:32 +0800 Subject: [PATCH 013/104] Add ConfigMap parameters validation for install CLI and server start. Signed-off-by: Xun Jiang --- changelogs/unreleased/9200-blackpiglet | 1 + pkg/cmd/cli/install/install.go | 30 ++++++- pkg/cmd/cli/nodeagent/server.go | 26 +++--- pkg/cmd/cli/nodeagent/server_test.go | 67 +++++++-------- pkg/cmd/server/server.go | 19 ++++- pkg/cmd/server/server_test.go | 24 +++++- pkg/controller/data_download_controller.go | 5 +- .../data_download_controller_test.go | 7 +- pkg/controller/data_upload_controller.go | 5 +- pkg/controller/data_upload_controller_test.go | 5 +- pkg/exposer/csi_snapshot.go | 3 +- pkg/exposer/csi_snapshot_test.go | 12 +-- pkg/exposer/generic_restore.go | 3 +- pkg/nodeagent/node_agent.go | 66 +-------------- pkg/nodeagent/node_agent_test.go | 15 ++-- pkg/repository/maintenance/maintenance.go | 37 +++----- .../maintenance/maintenance_test.go | 30 +++---- pkg/types/node_agent.go | 84 +++++++++++++++++++ pkg/types/repo_maintenance.go | 34 ++++++++ pkg/util/kube/utils.go | 27 ++++++ pkg/util/kube/utils_test.go | 53 +++++++++++- 21 files changed, 370 insertions(+), 183 deletions(-) create mode 100644 changelogs/unreleased/9200-blackpiglet create mode 100644 pkg/types/node_agent.go create mode 100644 pkg/types/repo_maintenance.go diff --git a/changelogs/unreleased/9200-blackpiglet b/changelogs/unreleased/9200-blackpiglet new file mode 100644 index 000000000..4c13079d9 --- /dev/null +++ b/changelogs/unreleased/9200-blackpiglet @@ -0,0 +1 @@ +Add ConfigMap parameters validation for install CLI and server start. diff --git a/pkg/cmd/cli/install/install.go b/pkg/cmd/cli/install/install.go index 7079ec79b..c7a7dfe7a 100644 --- a/pkg/cmd/cli/install/install.go +++ b/pkg/cmd/cli/install/install.go @@ -23,8 +23,6 @@ import ( "strings" "time" - "github.com/vmware-tanzu/velero/pkg/uploader" - "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -37,6 +35,8 @@ import ( "github.com/vmware-tanzu/velero/pkg/cmd/util/flag" "github.com/vmware-tanzu/velero/pkg/cmd/util/output" "github.com/vmware-tanzu/velero/pkg/install" + velerotypes "github.com/vmware-tanzu/velero/pkg/types" + "github.com/vmware-tanzu/velero/pkg/uploader" kubeutil "github.com/vmware-tanzu/velero/pkg/util/kube" ) @@ -540,5 +540,31 @@ func (o *Options) Validate(c *cobra.Command, args []string, f client.Factory) er return errors.New("--pod-volume-operation-timeout must be non-negative") } + crClient, err := f.KubebuilderClient() + if err != nil { + return fmt.Errorf("fail to create go-client %w", err) + } + + // If either Linux or Windows node-agent is installed, and the node-agent-configmap + // is specified, need to validate the ConfigMap. + if (o.UseNodeAgent || o.UseNodeAgentWindows) && len(o.NodeAgentConfigMap) > 0 { + if err := kubeutil.VerifyJSONConfigs(c.Context(), o.Namespace, crClient, o.NodeAgentConfigMap, &velerotypes.NodeAgentConfigs{}); err != nil { + return fmt.Errorf("--node-agent-configmap specified ConfigMap %s is invalid", o.NodeAgentConfigMap) + } + } + + if len(o.RepoMaintenanceJobConfigMap) > 0 { + if err := kubeutil.VerifyJSONConfigs(c.Context(), o.Namespace, crClient, o.RepoMaintenanceJobConfigMap, &velerotypes.JobConfigs{}); err != nil { + return fmt.Errorf("--repo-maintenance-job-configmap specified ConfigMap %s is invalid", o.RepoMaintenanceJobConfigMap) + } + } + + if len(o.BackupRepoConfigMap) > 0 { + config := make(map[string]any) + if err := kubeutil.VerifyJSONConfigs(c.Context(), o.Namespace, crClient, o.BackupRepoConfigMap, &config); err != nil { + return fmt.Errorf("--backup-repository-configmap specified ConfigMap %s is invalid", o.BackupRepoConfigMap) + } + } + return nil } diff --git a/pkg/cmd/cli/nodeagent/server.go b/pkg/cmd/cli/nodeagent/server.go index 0ff5b2f1c..873e03beb 100644 --- a/pkg/cmd/cli/nodeagent/server.go +++ b/pkg/cmd/cli/nodeagent/server.go @@ -26,6 +26,7 @@ import ( "time" "github.com/bombsimon/logrusr/v3" + snapshotv1client "github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/sirupsen/logrus" @@ -39,6 +40,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/kubernetes" + cacheutil "k8s.io/client-go/tools/cache" "k8s.io/klog/v2" "k8s.io/utils/clock" ctrl "sigs.k8s.io/controller-runtime" @@ -46,8 +48,6 @@ import ( ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" - snapshotv1client "github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned" - velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" velerov2alpha1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1" "github.com/vmware-tanzu/velero/pkg/buildinfo" @@ -60,11 +60,10 @@ import ( "github.com/vmware-tanzu/velero/pkg/exposer" "github.com/vmware-tanzu/velero/pkg/metrics" "github.com/vmware-tanzu/velero/pkg/nodeagent" + velerotypes "github.com/vmware-tanzu/velero/pkg/types" "github.com/vmware-tanzu/velero/pkg/util/filesystem" "github.com/vmware-tanzu/velero/pkg/util/kube" "github.com/vmware-tanzu/velero/pkg/util/logging" - - cacheutil "k8s.io/client-go/tools/cache" ) var ( @@ -140,7 +139,7 @@ type nodeAgentServer struct { kubeClient kubernetes.Interface csiSnapshotClient *snapshotv1client.Clientset dataPathMgr *datapath.Manager - dataPathConfigs *nodeagent.Configs + dataPathConfigs *velerotypes.NodeAgentConfigs vgdpCounter *exposer.VgdpCounter } @@ -252,7 +251,9 @@ func newNodeAgentServer(logger logrus.FieldLogger, factory client.Factory, confi return nil, err } - s.getDataPathConfigs() + if err := s.getDataPathConfigs(); err != nil { + return nil, err + } s.dataPathMgr = datapath.NewManager(s.getDataPathConcurrentNum(defaultDataPathConcurrentNum)) return s, nil @@ -301,7 +302,7 @@ func (s *nodeAgentServer) run() { s.logger.Infof("Using customized loadAffinity %v", loadAffinity) } - var backupPVCConfig map[string]nodeagent.BackupPVC + var backupPVCConfig map[string]velerotypes.BackupPVC if s.dataPathConfigs != nil && s.dataPathConfigs.BackupPVCConfig != nil { backupPVCConfig = s.dataPathConfigs.BackupPVCConfig s.logger.Infof("Using customized backupPVC config %v", backupPVCConfig) @@ -361,7 +362,7 @@ func (s *nodeAgentServer) run() { s.logger.WithError(err).Fatal("Unable to create the data upload controller") } - var restorePVCConfig nodeagent.RestorePVC + var restorePVCConfig velerotypes.RestorePVC if s.dataPathConfigs != nil && s.dataPathConfigs.RestorePVCConfig != nil { restorePVCConfig = *s.dataPathConfigs.RestorePVCConfig s.logger.Infof("Using customized restorePVC config %v", restorePVCConfig) @@ -546,19 +547,20 @@ func (s *nodeAgentServer) markLegacyPVRsFailed(client ctrlclient.Client) { var getConfigsFunc = nodeagent.GetConfigs -func (s *nodeAgentServer) getDataPathConfigs() { +func (s *nodeAgentServer) getDataPathConfigs() error { if s.config.nodeAgentConfig == "" { s.logger.Info("No node-agent configMap is specified") - return + return nil } configs, err := getConfigsFunc(s.ctx, s.namespace, s.kubeClient, s.config.nodeAgentConfig) if err != nil { - s.logger.WithError(err).Warnf("Failed to get node agent configs from configMap %s, ignore it", s.config.nodeAgentConfig) - return + s.logger.WithError(err).Errorf("Failed to get node agent configs from configMap %s, ignore it", s.config.nodeAgentConfig) + return err } s.dataPathConfigs = configs + return nil } func (s *nodeAgentServer) getDataPathConcurrentNum(defaultNum int) int { diff --git a/pkg/cmd/cli/nodeagent/server_test.go b/pkg/cmd/cli/nodeagent/server_test.go index 1ecd3ea0d..cb1750e6b 100644 --- a/pkg/cmd/cli/nodeagent/server_test.go +++ b/pkg/cmd/cli/nodeagent/server_test.go @@ -33,6 +33,7 @@ import ( "github.com/vmware-tanzu/velero/pkg/builder" "github.com/vmware-tanzu/velero/pkg/nodeagent" testutil "github.com/vmware-tanzu/velero/pkg/test" + velerotypes "github.com/vmware-tanzu/velero/pkg/types" ) func Test_validatePodVolumesHostPath(t *testing.T) { @@ -130,17 +131,17 @@ func Test_validatePodVolumesHostPath(t *testing.T) { } func Test_getDataPathConfigs(t *testing.T) { - configs := &nodeagent.Configs{ - LoadConcurrency: &nodeagent.LoadConcurrency{ + configs := &velerotypes.NodeAgentConfigs{ + LoadConcurrency: &velerotypes.LoadConcurrency{ GlobalConfig: -1, }, } tests := []struct { name string - getFunc func(context.Context, string, kubernetes.Interface, string) (*nodeagent.Configs, error) + getFunc func(context.Context, string, kubernetes.Interface, string) (*velerotypes.NodeAgentConfigs, error) configMapName string - expectConfigs *nodeagent.Configs + expectConfigs *velerotypes.NodeAgentConfigs expectLog string }{ { @@ -150,7 +151,7 @@ func Test_getDataPathConfigs(t *testing.T) { { name: "failed to get configs", configMapName: "node-agent-config", - getFunc: func(context.Context, string, kubernetes.Interface, string) (*nodeagent.Configs, error) { + getFunc: func(context.Context, string, kubernetes.Interface, string) (*velerotypes.NodeAgentConfigs, error) { return nil, errors.New("fake-get-error") }, expectLog: "Failed to get node agent configs from configMap node-agent-config, ignore it", @@ -158,7 +159,7 @@ func Test_getDataPathConfigs(t *testing.T) { { name: "configs cm not found", configMapName: "node-agent-config", - getFunc: func(context.Context, string, kubernetes.Interface, string) (*nodeagent.Configs, error) { + getFunc: func(context.Context, string, kubernetes.Interface, string) (*velerotypes.NodeAgentConfigs, error) { return nil, errors.New("fake-not-found-error") }, expectLog: "Failed to get node agent configs from configMap node-agent-config, ignore it", @@ -167,7 +168,7 @@ func Test_getDataPathConfigs(t *testing.T) { { name: "succeed", configMapName: "node-agent-config", - getFunc: func(context.Context, string, kubernetes.Interface, string) (*nodeagent.Configs, error) { + getFunc: func(context.Context, string, kubernetes.Interface, string) (*velerotypes.NodeAgentConfigs, error) { return configs, nil }, expectConfigs: configs, @@ -226,7 +227,7 @@ func Test_getDataPathConcurrentNum(t *testing.T) { tests := []struct { name string - configs nodeagent.Configs + configs velerotypes.NodeAgentConfigs setKubeClient bool kubeClientObj []runtime.Object expectNum int @@ -239,8 +240,8 @@ func Test_getDataPathConcurrentNum(t *testing.T) { }, { name: "global number is invalid", - configs: nodeagent.Configs{ - LoadConcurrency: &nodeagent.LoadConcurrency{ + configs: velerotypes.NodeAgentConfigs{ + LoadConcurrency: &velerotypes.LoadConcurrency{ GlobalConfig: -1, }, }, @@ -249,8 +250,8 @@ func Test_getDataPathConcurrentNum(t *testing.T) { }, { name: "global number is valid", - configs: nodeagent.Configs{ - LoadConcurrency: &nodeagent.LoadConcurrency{ + configs: velerotypes.NodeAgentConfigs{ + LoadConcurrency: &velerotypes.LoadConcurrency{ GlobalConfig: globalNum, }, }, @@ -258,10 +259,10 @@ func Test_getDataPathConcurrentNum(t *testing.T) { }, { name: "node is not found", - configs: nodeagent.Configs{ - LoadConcurrency: &nodeagent.LoadConcurrency{ + configs: velerotypes.NodeAgentConfigs{ + LoadConcurrency: &velerotypes.LoadConcurrency{ GlobalConfig: globalNum, - PerNodeConfig: []nodeagent.RuledConfigs{ + PerNodeConfig: []velerotypes.RuledConfigs{ { Number: 100, }, @@ -274,10 +275,10 @@ func Test_getDataPathConcurrentNum(t *testing.T) { }, { name: "failed to get selector", - configs: nodeagent.Configs{ - LoadConcurrency: &nodeagent.LoadConcurrency{ + configs: velerotypes.NodeAgentConfigs{ + LoadConcurrency: &velerotypes.LoadConcurrency{ GlobalConfig: globalNum, - PerNodeConfig: []nodeagent.RuledConfigs{ + PerNodeConfig: []velerotypes.RuledConfigs{ { NodeSelector: invalidLabelSelector, Number: 100, @@ -292,10 +293,10 @@ func Test_getDataPathConcurrentNum(t *testing.T) { }, { name: "rule number is invalid", - configs: nodeagent.Configs{ - LoadConcurrency: &nodeagent.LoadConcurrency{ + configs: velerotypes.NodeAgentConfigs{ + LoadConcurrency: &velerotypes.LoadConcurrency{ GlobalConfig: globalNum, - PerNodeConfig: []nodeagent.RuledConfigs{ + PerNodeConfig: []velerotypes.RuledConfigs{ { NodeSelector: validLabelSelector1, Number: -1, @@ -310,10 +311,10 @@ func Test_getDataPathConcurrentNum(t *testing.T) { }, { name: "label doesn't match", - configs: nodeagent.Configs{ - LoadConcurrency: &nodeagent.LoadConcurrency{ + configs: velerotypes.NodeAgentConfigs{ + LoadConcurrency: &velerotypes.LoadConcurrency{ GlobalConfig: globalNum, - PerNodeConfig: []nodeagent.RuledConfigs{ + PerNodeConfig: []velerotypes.RuledConfigs{ { NodeSelector: validLabelSelector1, Number: -1, @@ -328,10 +329,10 @@ func Test_getDataPathConcurrentNum(t *testing.T) { }, { name: "match one rule", - configs: nodeagent.Configs{ - LoadConcurrency: &nodeagent.LoadConcurrency{ + configs: velerotypes.NodeAgentConfigs{ + LoadConcurrency: &velerotypes.LoadConcurrency{ GlobalConfig: globalNum, - PerNodeConfig: []nodeagent.RuledConfigs{ + PerNodeConfig: []velerotypes.RuledConfigs{ { NodeSelector: validLabelSelector1, Number: 66, @@ -346,10 +347,10 @@ func Test_getDataPathConcurrentNum(t *testing.T) { }, { name: "match multiple rules", - configs: nodeagent.Configs{ - LoadConcurrency: &nodeagent.LoadConcurrency{ + configs: velerotypes.NodeAgentConfigs{ + LoadConcurrency: &velerotypes.LoadConcurrency{ GlobalConfig: globalNum, - PerNodeConfig: []nodeagent.RuledConfigs{ + PerNodeConfig: []velerotypes.RuledConfigs{ { NodeSelector: validLabelSelector1, Number: 66, @@ -368,10 +369,10 @@ func Test_getDataPathConcurrentNum(t *testing.T) { }, { name: "match multiple rules 2", - configs: nodeagent.Configs{ - LoadConcurrency: &nodeagent.LoadConcurrency{ + configs: velerotypes.NodeAgentConfigs{ + LoadConcurrency: &velerotypes.LoadConcurrency{ GlobalConfig: globalNum, - PerNodeConfig: []nodeagent.RuledConfigs{ + PerNodeConfig: []velerotypes.RuledConfigs{ { NodeSelector: validLabelSelector1, Number: 36, diff --git a/pkg/cmd/server/server.go b/pkg/cmd/server/server.go index e7ade6d31..15c4afd95 100644 --- a/pkg/cmd/server/server.go +++ b/pkg/cmd/server/server.go @@ -26,9 +26,8 @@ import ( "strings" "time" - volumegroupsnapshotv1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumegroupsnapshot/v1beta1" - logrusr "github.com/bombsimon/logrusr/v3" + volumegroupsnapshotv1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumegroupsnapshot/v1beta1" snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -83,6 +82,7 @@ import ( repokey "github.com/vmware-tanzu/velero/pkg/repository/keys" repomanager "github.com/vmware-tanzu/velero/pkg/repository/manager" "github.com/vmware-tanzu/velero/pkg/restore" + velerotypes "github.com/vmware-tanzu/velero/pkg/types" "github.com/vmware-tanzu/velero/pkg/uploader" "github.com/vmware-tanzu/velero/pkg/util/filesystem" "github.com/vmware-tanzu/velero/pkg/util/kube" @@ -209,6 +209,21 @@ func newServer(f client.Factory, config *config.Config, logger *logrus.Logger) ( // Therefore, we must explicitly call it on the error paths in this function. ctx, cancelFunc := context.WithCancel(context.Background()) + if len(config.BackupRepoConfig) > 0 { + repoConfig := make(map[string]any) + if err := kube.VerifyJSONConfigs(ctx, f.Namespace(), crClient, config.BackupRepoConfig, &repoConfig); err != nil { + cancelFunc() + return nil, err + } + } + + if len(config.RepoMaintenanceJobConfig) > 0 { + if err := kube.VerifyJSONConfigs(ctx, f.Namespace(), crClient, config.RepoMaintenanceJobConfig, &velerotypes.JobConfigs{}); err != nil { + cancelFunc() + return nil, err + } + } + clientConfig, err := f.ClientConfig() if err != nil { cancelFunc() diff --git a/pkg/cmd/server/server_test.go b/pkg/cmd/server/server_test.go index ebf0b478b..1ea9d0022 100644 --- a/pkg/cmd/server/server_test.go +++ b/pkg/cmd/server/server_test.go @@ -33,6 +33,7 @@ import ( velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" velerov2alpha1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1" + "github.com/vmware-tanzu/velero/pkg/builder" "github.com/vmware-tanzu/velero/pkg/client/mocks" "github.com/vmware-tanzu/velero/pkg/cmd/server/config" "github.com/vmware-tanzu/velero/pkg/constant" @@ -242,7 +243,28 @@ func Test_newServer(t *testing.T) { ClientBurst: 1, ClientPageSize: 100, }, logger) - assert.Error(t, err) + require.Error(t, err) + + invalidCM := builder.ForConfigMap("velero", "invalid").Data("invalid", "{\"a\": \"b}").Result() + crClient := velerotest.NewFakeControllerRuntimeClient(t, invalidCM) + + factory.On("KubeClient").Return(crClient, nil). + On("Client").Return(nil, nil). + On("DynamicClient").Return(nil, errors.New("error")) + _, err = newServer(factory, &config.Config{ + UploaderType: uploader.KopiaType, + BackupRepoConfig: "invalid", + }, logger) + require.Error(t, err) + + factory.On("KubeClient").Return(crClient, nil). + On("Client").Return(nil, nil). + On("DynamicClient").Return(nil, errors.New("error")) + _, err = newServer(factory, &config.Config{ + UploaderType: uploader.KopiaType, + RepoMaintenanceJobConfig: "invalid", + }, logger) + require.Error(t, err) } func Test_namespaceExists(t *testing.T) { diff --git a/pkg/controller/data_download_controller.go b/pkg/controller/data_download_controller.go index a8a2fc633..23328d387 100644 --- a/pkg/controller/data_download_controller.go +++ b/pkg/controller/data_download_controller.go @@ -49,6 +49,7 @@ import ( "github.com/vmware-tanzu/velero/pkg/exposer" "github.com/vmware-tanzu/velero/pkg/metrics" "github.com/vmware-tanzu/velero/pkg/nodeagent" + velerotypes "github.com/vmware-tanzu/velero/pkg/types" "github.com/vmware-tanzu/velero/pkg/uploader" "github.com/vmware-tanzu/velero/pkg/util" "github.com/vmware-tanzu/velero/pkg/util/kube" @@ -66,7 +67,7 @@ type DataDownloadReconciler struct { dataPathMgr *datapath.Manager vgdpCounter *exposer.VgdpCounter loadAffinity []*kube.LoadAffinity - restorePVCConfig nodeagent.RestorePVC + restorePVCConfig velerotypes.RestorePVC podResources corev1api.ResourceRequirements preparingTimeout time.Duration metrics *metrics.ServerMetrics @@ -81,7 +82,7 @@ func NewDataDownloadReconciler( dataPathMgr *datapath.Manager, counter *exposer.VgdpCounter, loadAffinity []*kube.LoadAffinity, - restorePVCConfig nodeagent.RestorePVC, + restorePVCConfig velerotypes.RestorePVC, podResources corev1api.ResourceRequirements, nodeName string, preparingTimeout time.Duration, diff --git a/pkg/controller/data_download_controller_test.go b/pkg/controller/data_download_controller_test.go index 048a1027c..d260056e6 100644 --- a/pkg/controller/data_download_controller_test.go +++ b/pkg/controller/data_download_controller_test.go @@ -46,13 +46,12 @@ import ( "github.com/vmware-tanzu/velero/pkg/datapath" datapathmockes "github.com/vmware-tanzu/velero/pkg/datapath/mocks" "github.com/vmware-tanzu/velero/pkg/exposer" + exposermockes "github.com/vmware-tanzu/velero/pkg/exposer/mocks" "github.com/vmware-tanzu/velero/pkg/metrics" - "github.com/vmware-tanzu/velero/pkg/nodeagent" velerotest "github.com/vmware-tanzu/velero/pkg/test" + velerotypes "github.com/vmware-tanzu/velero/pkg/types" "github.com/vmware-tanzu/velero/pkg/uploader" "github.com/vmware-tanzu/velero/pkg/util/kube" - - exposermockes "github.com/vmware-tanzu/velero/pkg/exposer/mocks" ) const dataDownloadName string = "datadownload-1" @@ -130,7 +129,7 @@ func initDataDownloadReconcilerWithError(t *testing.T, objects []any, needError dataPathMgr := datapath.NewManager(1) - return NewDataDownloadReconciler(&fakeClient, nil, fakeKubeClient, dataPathMgr, nil, nil, nodeagent.RestorePVC{}, corev1api.ResourceRequirements{}, "test-node", time.Minute*5, velerotest.NewLogger(), metrics.NewServerMetrics(), ""), nil + return NewDataDownloadReconciler(&fakeClient, nil, fakeKubeClient, dataPathMgr, nil, nil, velerotypes.RestorePVC{}, corev1api.ResourceRequirements{}, "test-node", time.Minute*5, velerotest.NewLogger(), metrics.NewServerMetrics(), ""), nil } func TestDataDownloadReconcile(t *testing.T) { diff --git a/pkg/controller/data_upload_controller.go b/pkg/controller/data_upload_controller.go index 502385c14..d0467a843 100644 --- a/pkg/controller/data_upload_controller.go +++ b/pkg/controller/data_upload_controller.go @@ -50,6 +50,7 @@ import ( "github.com/vmware-tanzu/velero/pkg/exposer" "github.com/vmware-tanzu/velero/pkg/metrics" "github.com/vmware-tanzu/velero/pkg/nodeagent" + velerotypes "github.com/vmware-tanzu/velero/pkg/types" "github.com/vmware-tanzu/velero/pkg/uploader" "github.com/vmware-tanzu/velero/pkg/util" "github.com/vmware-tanzu/velero/pkg/util/kube" @@ -76,7 +77,7 @@ type DataUploadReconciler struct { dataPathMgr *datapath.Manager vgdpCounter *exposer.VgdpCounter loadAffinity []*kube.LoadAffinity - backupPVCConfig map[string]nodeagent.BackupPVC + backupPVCConfig map[string]velerotypes.BackupPVC podResources corev1api.ResourceRequirements preparingTimeout time.Duration metrics *metrics.ServerMetrics @@ -92,7 +93,7 @@ func NewDataUploadReconciler( dataPathMgr *datapath.Manager, counter *exposer.VgdpCounter, loadAffinity []*kube.LoadAffinity, - backupPVCConfig map[string]nodeagent.BackupPVC, + backupPVCConfig map[string]velerotypes.BackupPVC, podResources corev1api.ResourceRequirements, clock clocks.WithTickerAndDelayedExecution, nodeName string, diff --git a/pkg/controller/data_upload_controller_test.go b/pkg/controller/data_upload_controller_test.go index 157ccd8d6..037726325 100644 --- a/pkg/controller/data_upload_controller_test.go +++ b/pkg/controller/data_upload_controller_test.go @@ -22,8 +22,6 @@ import ( "testing" "time" - "github.com/vmware-tanzu/velero/pkg/nodeagent" - snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1" snapshotFake "github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/fake" "github.com/pkg/errors" @@ -56,6 +54,7 @@ import ( "github.com/vmware-tanzu/velero/pkg/exposer" "github.com/vmware-tanzu/velero/pkg/metrics" velerotest "github.com/vmware-tanzu/velero/pkg/test" + velerotypes "github.com/vmware-tanzu/velero/pkg/types" "github.com/vmware-tanzu/velero/pkg/uploader" "github.com/vmware-tanzu/velero/pkg/util/boolptr" "github.com/vmware-tanzu/velero/pkg/util/kube" @@ -242,7 +241,7 @@ func initDataUploaderReconcilerWithError(needError ...error) (*DataUploadReconci dataPathMgr, nil, nil, - map[string]nodeagent.BackupPVC{}, + map[string]velerotypes.BackupPVC{}, corev1api.ResourceRequirements{}, testclocks.NewFakeClock(now), "test-node", diff --git a/pkg/exposer/csi_snapshot.go b/pkg/exposer/csi_snapshot.go index e404d5dcf..a886c60c3 100644 --- a/pkg/exposer/csi_snapshot.go +++ b/pkg/exposer/csi_snapshot.go @@ -34,6 +34,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/vmware-tanzu/velero/pkg/nodeagent" + velerotypes "github.com/vmware-tanzu/velero/pkg/types" "github.com/vmware-tanzu/velero/pkg/util/boolptr" "github.com/vmware-tanzu/velero/pkg/util/csi" "github.com/vmware-tanzu/velero/pkg/util/kube" @@ -75,7 +76,7 @@ type CSISnapshotExposeParam struct { Affinity []*kube.LoadAffinity // BackupPVCConfig is the config for backupPVC (intermediate PVC) of snapshot data movement - BackupPVCConfig map[string]nodeagent.BackupPVC + BackupPVCConfig map[string]velerotypes.BackupPVC // Resources defines the resource requirements of the hosting pod Resources corev1api.ResourceRequirements diff --git a/pkg/exposer/csi_snapshot_test.go b/pkg/exposer/csi_snapshot_test.go index d57d7699b..5dd745065 100644 --- a/pkg/exposer/csi_snapshot_test.go +++ b/pkg/exposer/csi_snapshot_test.go @@ -37,8 +37,8 @@ import ( clientFake "sigs.k8s.io/controller-runtime/pkg/client/fake" velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" - "github.com/vmware-tanzu/velero/pkg/nodeagent" velerotest "github.com/vmware-tanzu/velero/pkg/test" + velerotypes "github.com/vmware-tanzu/velero/pkg/types" "github.com/vmware-tanzu/velero/pkg/util/boolptr" "github.com/vmware-tanzu/velero/pkg/util/kube" ) @@ -423,7 +423,7 @@ func TestExpose(t *testing.T) { AccessMode: AccessModeFileSystem, OperationTimeout: time.Millisecond, ExposeTimeout: time.Millisecond, - BackupPVCConfig: map[string]nodeagent.BackupPVC{ + BackupPVCConfig: map[string]velerotypes.BackupPVC{ "fake-sc": { StorageClass: "fake-sc-read-only", ReadOnly: true, @@ -449,7 +449,7 @@ func TestExpose(t *testing.T) { AccessMode: AccessModeFileSystem, OperationTimeout: time.Millisecond, ExposeTimeout: time.Millisecond, - BackupPVCConfig: map[string]nodeagent.BackupPVC{ + BackupPVCConfig: map[string]velerotypes.BackupPVC{ "fake-sc": { StorageClass: "fake-sc-read-only", ReadOnly: true, @@ -476,7 +476,7 @@ func TestExpose(t *testing.T) { AccessMode: AccessModeFileSystem, OperationTimeout: time.Millisecond, ExposeTimeout: time.Millisecond, - BackupPVCConfig: map[string]nodeagent.BackupPVC{ + BackupPVCConfig: map[string]velerotypes.BackupPVC{ "fake-sc": { StorageClass: "fake-sc-read-only", }, @@ -551,7 +551,7 @@ func TestExpose(t *testing.T) { AccessMode: AccessModeFileSystem, OperationTimeout: time.Millisecond, ExposeTimeout: time.Millisecond, - BackupPVCConfig: map[string]nodeagent.BackupPVC{ + BackupPVCConfig: map[string]velerotypes.BackupPVC{ "fake-sc": { StorageClass: "fake-sc-read-only", }, @@ -607,7 +607,7 @@ func TestExpose(t *testing.T) { AccessMode: AccessModeFileSystem, OperationTimeout: time.Millisecond, ExposeTimeout: time.Millisecond, - BackupPVCConfig: map[string]nodeagent.BackupPVC{ + BackupPVCConfig: map[string]velerotypes.BackupPVC{ "fake-sc": { StorageClass: "fake-sc-read-only", }, diff --git a/pkg/exposer/generic_restore.go b/pkg/exposer/generic_restore.go index c8ac7fcce..26019d5d4 100644 --- a/pkg/exposer/generic_restore.go +++ b/pkg/exposer/generic_restore.go @@ -31,6 +31,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/vmware-tanzu/velero/pkg/nodeagent" + velerotypes "github.com/vmware-tanzu/velero/pkg/types" "github.com/vmware-tanzu/velero/pkg/util/boolptr" "github.com/vmware-tanzu/velero/pkg/util/kube" ) @@ -65,7 +66,7 @@ type GenericRestoreExposeParam struct { NodeOS string // RestorePVCConfig is the config for restorePVC (intermediate PVC) of generic restore - RestorePVCConfig nodeagent.RestorePVC + RestorePVCConfig velerotypes.RestorePVC // LoadAffinity specifies the node affinity of the backup pod LoadAffinity []*kube.LoadAffinity diff --git a/pkg/nodeagent/node_agent.go b/pkg/nodeagent/node_agent.go index d83a9eba3..7268b589a 100644 --- a/pkg/nodeagent/node_agent.go +++ b/pkg/nodeagent/node_agent.go @@ -29,6 +29,7 @@ import ( "k8s.io/client-go/kubernetes" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + velerotypes "github.com/vmware-tanzu/velero/pkg/types" "github.com/vmware-tanzu/velero/pkg/util/kube" ) @@ -56,67 +57,6 @@ var ( ErrNodeAgentTolerationNotFound = errors.New("node-agent toleration not found") ) -type LoadConcurrency struct { - // GlobalConfig specifies the concurrency number to all nodes for which per-node config is not specified - GlobalConfig int `json:"globalConfig,omitempty"` - - // PerNodeConfig specifies the concurrency number to nodes matched by rules - PerNodeConfig []RuledConfigs `json:"perNodeConfig,omitempty"` - - // PrepareQueueLength specifies the max number of loads that are under expose - PrepareQueueLength int `json:"prepareQueueLength,omitempty"` -} - -type LoadAffinity struct { - // NodeSelector specifies the label selector to match nodes - NodeSelector metav1.LabelSelector `json:"nodeSelector"` -} - -type RuledConfigs struct { - // NodeSelector specifies the label selector to match nodes - NodeSelector metav1.LabelSelector `json:"nodeSelector"` - - // Number specifies the number value associated to the matched nodes - Number int `json:"number"` -} - -type BackupPVC struct { - // StorageClass is the name of storage class to be used by the backupPVC - StorageClass string `json:"storageClass,omitempty"` - - // ReadOnly sets the backupPVC's access mode as read only - ReadOnly bool `json:"readOnly,omitempty"` - - // SPCNoRelabeling sets Spec.SecurityContext.SELinux.Type to "spc_t" for the pod mounting the backupPVC - // ignored if ReadOnly is false - SPCNoRelabeling bool `json:"spcNoRelabeling,omitempty"` -} - -type RestorePVC struct { - // IgnoreDelayBinding indicates to ignore delay binding the restorePVC when it is in WaitForFirstConsumer mode - IgnoreDelayBinding bool `json:"ignoreDelayBinding,omitempty"` -} - -type Configs struct { - // LoadConcurrency is the config for data path load concurrency per node. - LoadConcurrency *LoadConcurrency `json:"loadConcurrency,omitempty"` - - // LoadAffinity is the config for data path load affinity. - LoadAffinity []*kube.LoadAffinity `json:"loadAffinity,omitempty"` - - // BackupPVCConfig is the config for backupPVC (intermediate PVC) of snapshot data movement - BackupPVCConfig map[string]BackupPVC `json:"backupPVC,omitempty"` - - // RestoreVCConfig is the config for restorePVC (intermediate PVC) of generic restore - RestorePVCConfig *RestorePVC `json:"restorePVC,omitempty"` - - // PodResources is the resource config for various types of pods launched by node-agent, i.e., data mover pods. - PodResources *kube.PodResources `json:"podResources,omitempty"` - - // PriorityClassName is the priority class name for data mover pods created by the node agent - PriorityClassName string `json:"priorityClassName,omitempty"` -} - func IsRunningOnLinux(ctx context.Context, kubeClient kubernetes.Interface, namespace string) error { return isRunning(ctx, kubeClient, namespace, daemonSet) } @@ -193,7 +133,7 @@ func GetPodSpec(ctx context.Context, kubeClient kubernetes.Interface, namespace return &ds.Spec.Template.Spec, nil } -func GetConfigs(ctx context.Context, namespace string, kubeClient kubernetes.Interface, configName string) (*Configs, error) { +func GetConfigs(ctx context.Context, namespace string, kubeClient kubernetes.Interface, configName string) (*velerotypes.NodeAgentConfigs, error) { cm, err := kubeClient.CoreV1().ConfigMaps(namespace).Get(ctx, configName, metav1.GetOptions{}) if err != nil { return nil, errors.Wrapf(err, "error to get node agent configs %s", configName) @@ -208,7 +148,7 @@ func GetConfigs(ctx context.Context, namespace string, kubeClient kubernetes.Int jsonString = v } - configs := &Configs{} + configs := &velerotypes.NodeAgentConfigs{} err = json.Unmarshal([]byte(jsonString), configs) if err != nil { return nil, errors.Wrapf(err, "error to unmarshall configs from %s", configName) diff --git a/pkg/nodeagent/node_agent_test.go b/pkg/nodeagent/node_agent_test.go index aaf851d6e..bdc1085b4 100644 --- a/pkg/nodeagent/node_agent_test.go +++ b/pkg/nodeagent/node_agent_test.go @@ -31,6 +31,7 @@ import ( clientFake "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/vmware-tanzu/velero/pkg/builder" + velerotypes "github.com/vmware-tanzu/velero/pkg/types" "github.com/vmware-tanzu/velero/pkg/util/kube" ) @@ -254,7 +255,7 @@ func TestGetConfigs(t *testing.T) { kubeClientObj []runtime.Object namespace string kubeReactors []reactor - expectResult *Configs + expectResult *velerotypes.NodeAgentConfigs expectErr string }{ { @@ -293,7 +294,7 @@ func TestGetConfigs(t *testing.T) { kubeClientObj: []runtime.Object{ cmWithoutCocurrentData, }, - expectResult: &Configs{}, + expectResult: &velerotypes.NodeAgentConfigs{}, }, { name: "success", @@ -301,8 +302,8 @@ func TestGetConfigs(t *testing.T) { kubeClientObj: []runtime.Object{ cmWithValidData, }, - expectResult: &Configs{ - LoadConcurrency: &LoadConcurrency{ + expectResult: &velerotypes.NodeAgentConfigs{ + LoadConcurrency: &velerotypes.LoadConcurrency{ GlobalConfig: 5, }, }, @@ -313,7 +314,7 @@ func TestGetConfigs(t *testing.T) { kubeClientObj: []runtime.Object{ cmWithPriorityClass, }, - expectResult: &Configs{ + expectResult: &velerotypes.NodeAgentConfigs{ PriorityClassName: "high-priority", }, }, @@ -323,9 +324,9 @@ func TestGetConfigs(t *testing.T) { kubeClientObj: []runtime.Object{ cmWithPriorityClassAndOther, }, - expectResult: &Configs{ + expectResult: &velerotypes.NodeAgentConfigs{ PriorityClassName: "low-priority", - LoadConcurrency: &LoadConcurrency{ + LoadConcurrency: &velerotypes.LoadConcurrency{ GlobalConfig: 3, }, }, diff --git a/pkg/repository/maintenance/maintenance.go b/pkg/repository/maintenance/maintenance.go index 9bc61c058..16a94535f 100644 --- a/pkg/repository/maintenance/maintenance.go +++ b/pkg/repository/maintenance/maintenance.go @@ -27,6 +27,7 @@ import ( "github.com/pkg/errors" "github.com/sirupsen/logrus" + appsv1api "k8s.io/api/apps/v1" batchv1api "k8s.io/api/batch/v1" corev1api "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -36,14 +37,11 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + velerotypes "github.com/vmware-tanzu/velero/pkg/types" "github.com/vmware-tanzu/velero/pkg/util" "github.com/vmware-tanzu/velero/pkg/util/kube" - - appsv1api "k8s.io/api/apps/v1" - - veleroutil "github.com/vmware-tanzu/velero/pkg/util/velero" - "github.com/vmware-tanzu/velero/pkg/util/logging" + veleroutil "github.com/vmware-tanzu/velero/pkg/util/velero" ) const ( @@ -58,21 +56,6 @@ const ( DefaultMaintenanceJobMemLimit = "0" ) -type JobConfigs struct { - // LoadAffinities is the config for repository maintenance job load affinity. - LoadAffinities []*kube.LoadAffinity `json:"loadAffinity,omitempty"` - - // PodResources is the config for the CPU and memory resources setting. - PodResources *kube.PodResources `json:"podResources,omitempty"` - - // KeepLatestMaintenanceJobs is the number of latest maintenance jobs to keep for the repository. - KeepLatestMaintenanceJobs *int `json:"keepLatestMaintenanceJobs,omitempty"` - - // PriorityClassName is the priority class name for the maintenance job pod - // Note: This is only read from the global configuration, not per-repository - PriorityClassName string `json:"priorityClassName,omitempty"` -} - func GenerateJobName(repo string) string { millisecond := time.Now().UTC().UnixMilli() // millisecond @@ -215,7 +198,7 @@ func getJobConfig( veleroNamespace string, repoMaintenanceJobConfig string, repo *velerov1api.BackupRepository, -) (*JobConfigs, error) { +) (*velerotypes.JobConfigs, error) { var cm corev1api.ConfigMap if err := client.Get( ctx, @@ -248,10 +231,10 @@ func getJobConfig( repoJobConfigKey := repo.Spec.VolumeNamespace + "-" + repo.Spec.BackupStorageLocation + "-" + repo.Spec.RepositoryType - var result *JobConfigs + var result *velerotypes.JobConfigs if _, ok := cm.Data[repoJobConfigKey]; ok { logger.Debugf("Find the repo maintenance config %s for repo %s", repoJobConfigKey, repo.Name) - result = new(JobConfigs) + result = new(velerotypes.JobConfigs) if err := json.Unmarshal([]byte(cm.Data[repoJobConfigKey]), result); err != nil { return nil, errors.Wrapf( err, @@ -265,10 +248,10 @@ func getJobConfig( logger.Debugf("Find the global repo maintenance config for repo %s", repo.Name) if result == nil { - result = new(JobConfigs) + result = new(velerotypes.JobConfigs) } - globalResult := new(JobConfigs) + globalResult := new(velerotypes.JobConfigs) if err := json.Unmarshal([]byte(cm.Data[GlobalKeyForRepoMaintenanceJobCM]), globalResult); err != nil { return nil, errors.Wrapf( @@ -466,7 +449,7 @@ func StartNewJob( return maintenanceJob.Name, nil } -func getPriorityClassName(ctx context.Context, cli client.Client, config *JobConfigs, logger logrus.FieldLogger) string { +func getPriorityClassName(ctx context.Context, cli client.Client, config *velerotypes.JobConfigs, logger logrus.FieldLogger) string { // Use the priority class name from the global job configuration if available // Note: Priority class is only read from global config, not per-repository if config != nil && config.PriorityClassName != "" { @@ -491,7 +474,7 @@ func buildJob( ctx context.Context, repo *velerov1api.BackupRepository, bslName string, - config *JobConfigs, + config *velerotypes.JobConfigs, logLevel logrus.Level, logFormat *logging.FormatFlag, logger logrus.FieldLogger, diff --git a/pkg/repository/maintenance/maintenance_test.go b/pkg/repository/maintenance/maintenance_test.go index f0a8568be..3dd12e5fa 100644 --- a/pkg/repository/maintenance/maintenance_test.go +++ b/pkg/repository/maintenance/maintenance_test.go @@ -27,6 +27,7 @@ import ( "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + appsv1api "k8s.io/api/apps/v1" batchv1api "k8s.io/api/batch/v1" corev1api "k8s.io/api/core/v1" schedulingv1 "k8s.io/api/scheduling/v1" @@ -41,11 +42,10 @@ import ( "github.com/vmware-tanzu/velero/pkg/builder" "github.com/vmware-tanzu/velero/pkg/repository/provider" velerotest "github.com/vmware-tanzu/velero/pkg/test" + velerotypes "github.com/vmware-tanzu/velero/pkg/types" "github.com/vmware-tanzu/velero/pkg/util/boolptr" "github.com/vmware-tanzu/velero/pkg/util/kube" "github.com/vmware-tanzu/velero/pkg/util/logging" - - appsv1api "k8s.io/api/apps/v1" ) func TestGenerateJobName1(t *testing.T) { @@ -408,7 +408,7 @@ func TestGetJobConfig(t *testing.T) { testCases := []struct { name string repoJobConfig *corev1api.ConfigMap - expectedConfig *JobConfigs + expectedConfig *velerotypes.JobConfigs expectedError error }{ { @@ -441,7 +441,7 @@ func TestGetJobConfig(t *testing.T) { "test-default-kopia": "{\"podResources\":{\"cpuRequest\":\"100m\",\"cpuLimit\":\"200m\",\"memoryRequest\":\"100Mi\",\"memoryLimit\":\"200Mi\"},\"loadAffinity\":[{\"nodeSelector\":{\"matchExpressions\":[{\"key\":\"cloud.google.com/machine-family\",\"operator\":\"In\",\"values\":[\"e2\"]}]}}]}", }, }, - expectedConfig: &JobConfigs{ + expectedConfig: &velerotypes.JobConfigs{ PodResources: &kube.PodResources{ CPURequest: "100m", CPULimit: "200m", @@ -475,7 +475,7 @@ func TestGetJobConfig(t *testing.T) { GlobalKeyForRepoMaintenanceJobCM: "{\"podResources\":{\"cpuRequest\":\"50m\",\"cpuLimit\":\"100m\",\"memoryRequest\":\"50Mi\",\"memoryLimit\":\"100Mi\"},\"loadAffinity\":[{\"nodeSelector\":{\"matchExpressions\":[{\"key\":\"cloud.google.com/machine-family\",\"operator\":\"In\",\"values\":[\"n2\"]}]}}]}", }, }, - expectedConfig: &JobConfigs{ + expectedConfig: &velerotypes.JobConfigs{ PodResources: &kube.PodResources{ CPURequest: "50m", CPULimit: "100m", @@ -510,7 +510,7 @@ func TestGetJobConfig(t *testing.T) { "test-default-kopia": "{\"podResources\":{\"cpuRequest\":\"100m\",\"cpuLimit\":\"200m\",\"memoryRequest\":\"100Mi\",\"memoryLimit\":\"200Mi\"},\"loadAffinity\":[{\"nodeSelector\":{\"matchExpressions\":[{\"key\":\"cloud.google.com/machine-family\",\"operator\":\"In\",\"values\":[\"e2\"]}]}}]}", }, }, - expectedConfig: &JobConfigs{ + expectedConfig: &velerotypes.JobConfigs{ KeepLatestMaintenanceJobs: &keepLatestMaintenanceJobs, PodResources: &kube.PodResources{ CPURequest: "100m", @@ -930,7 +930,7 @@ func TestBuildJob(t *testing.T) { testCases := []struct { name string - m *JobConfigs + m *velerotypes.JobConfigs deploy *appsv1api.Deployment logLevel logrus.Level logFormat *logging.FormatFlag @@ -946,7 +946,7 @@ func TestBuildJob(t *testing.T) { }{ { name: "Valid maintenance job without third party labels", - m: &JobConfigs{ + m: &velerotypes.JobConfigs{ PodResources: &kube.PodResources{ CPURequest: "100m", MemoryRequest: "128Mi", @@ -998,7 +998,7 @@ func TestBuildJob(t *testing.T) { }, { name: "Valid maintenance job with third party labels", - m: &JobConfigs{ + m: &velerotypes.JobConfigs{ PodResources: &kube.PodResources{ CPURequest: "100m", MemoryRequest: "128Mi", @@ -1047,7 +1047,7 @@ func TestBuildJob(t *testing.T) { }, { name: "Error getting Velero server deployment", - m: &JobConfigs{ + m: &velerotypes.JobConfigs{ PodResources: &kube.PodResources{ CPURequest: "100m", MemoryRequest: "128Mi", @@ -1307,7 +1307,7 @@ func mockBackupRepo() *velerov1api.BackupRepository { func TestGetPriorityClassName(t *testing.T) { testCases := []struct { name string - config *JobConfigs + config *velerotypes.JobConfigs priorityClassExists bool expectedValue string expectedLogContains string @@ -1315,7 +1315,7 @@ func TestGetPriorityClassName(t *testing.T) { }{ { name: "empty priority class name should return empty string", - config: &JobConfigs{PriorityClassName: ""}, + config: &velerotypes.JobConfigs{PriorityClassName: ""}, expectedValue: "", expectedLogContains: "", }, @@ -1327,7 +1327,7 @@ func TestGetPriorityClassName(t *testing.T) { }, { name: "existing priority class should log info and return name", - config: &JobConfigs{PriorityClassName: "high-priority"}, + config: &velerotypes.JobConfigs{PriorityClassName: "high-priority"}, priorityClassExists: true, expectedValue: "high-priority", expectedLogContains: "Validated priority class \\\"high-priority\\\" exists in cluster", @@ -1335,7 +1335,7 @@ func TestGetPriorityClassName(t *testing.T) { }, { name: "non-existing priority class should log warning and still return name", - config: &JobConfigs{PriorityClassName: "missing-priority"}, + config: &velerotypes.JobConfigs{PriorityClassName: "missing-priority"}, priorityClassExists: false, expectedValue: "missing-priority", expectedLogContains: "Priority class \\\"missing-priority\\\" not found in cluster", @@ -1465,7 +1465,7 @@ func TestBuildJobWithPriorityClassName(t *testing.T) { require.NoError(t, err) // Create minimal job configs and resources - jobConfig := &JobConfigs{ + jobConfig := &velerotypes.JobConfigs{ PriorityClassName: tc.priorityClassName, } logLevel := logrus.InfoLevel diff --git a/pkg/types/node_agent.go b/pkg/types/node_agent.go new file mode 100644 index 000000000..d0696dc95 --- /dev/null +++ b/pkg/types/node_agent.go @@ -0,0 +1,84 @@ +/* +Copyright 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 types + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/vmware-tanzu/velero/pkg/util/kube" +) + +type LoadConcurrency struct { + // GlobalConfig specifies the concurrency number to all nodes for which per-node config is not specified + GlobalConfig int `json:"globalConfig,omitempty"` + + // PerNodeConfig specifies the concurrency number to nodes matched by rules + PerNodeConfig []RuledConfigs `json:"perNodeConfig,omitempty"` + + // PrepareQueueLength specifies the max number of loads that are under expose + PrepareQueueLength int `json:"prepareQueueLength,omitempty"` +} + +type LoadAffinity struct { + // NodeSelector specifies the label selector to match nodes + NodeSelector metav1.LabelSelector `json:"nodeSelector"` +} + +type RuledConfigs struct { + // NodeSelector specifies the label selector to match nodes + NodeSelector metav1.LabelSelector `json:"nodeSelector"` + + // Number specifies the number value associated to the matched nodes + Number int `json:"number"` +} + +type BackupPVC struct { + // StorageClass is the name of storage class to be used by the backupPVC + StorageClass string `json:"storageClass,omitempty"` + + // ReadOnly sets the backupPVC's access mode as read only + ReadOnly bool `json:"readOnly,omitempty"` + + // SPCNoRelabeling sets Spec.SecurityContext.SELinux.Type to "spc_t" for the pod mounting the backupPVC + // ignored if ReadOnly is false + SPCNoRelabeling bool `json:"spcNoRelabeling,omitempty"` +} + +type RestorePVC struct { + // IgnoreDelayBinding indicates to ignore delay binding the restorePVC when it is in WaitForFirstConsumer mode + IgnoreDelayBinding bool `json:"ignoreDelayBinding,omitempty"` +} + +type NodeAgentConfigs struct { + // LoadConcurrency is the config for data path load concurrency per node. + LoadConcurrency *LoadConcurrency `json:"loadConcurrency,omitempty"` + + // LoadAffinity is the config for data path load affinity. + LoadAffinity []*kube.LoadAffinity `json:"loadAffinity,omitempty"` + + // BackupPVCConfig is the config for backupPVC (intermediate PVC) of snapshot data movement + BackupPVCConfig map[string]BackupPVC `json:"backupPVC,omitempty"` + + // RestoreVCConfig is the config for restorePVC (intermediate PVC) of generic restore + RestorePVCConfig *RestorePVC `json:"restorePVC,omitempty"` + + // PodResources is the resource config for various types of pods launched by node-agent, i.e., data mover pods. + PodResources *kube.PodResources `json:"podResources,omitempty"` + + // PriorityClassName is the priority class name for data mover pods created by the node agent + PriorityClassName string `json:"priorityClassName,omitempty"` +} diff --git a/pkg/types/repo_maintenance.go b/pkg/types/repo_maintenance.go new file mode 100644 index 000000000..40454b248 --- /dev/null +++ b/pkg/types/repo_maintenance.go @@ -0,0 +1,34 @@ +/* +Copyright 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 types + +import "github.com/vmware-tanzu/velero/pkg/util/kube" + +type JobConfigs struct { + // LoadAffinities is the config for repository maintenance job load affinity. + LoadAffinities []*kube.LoadAffinity `json:"loadAffinity,omitempty"` + + // PodResources is the config for the CPU and memory resources setting. + PodResources *kube.PodResources `json:"podResources,omitempty"` + + // KeepLatestMaintenanceJobs is the number of latest maintenance jobs to keep for the repository. + KeepLatestMaintenanceJobs *int `json:"keepLatestMaintenanceJobs,omitempty"` + + // PriorityClassName is the priority class name for the maintenance job pod + // Note: This is only read from the global configuration, not per-repository + PriorityClassName string `json:"priorityClassName,omitempty"` +} diff --git a/pkg/util/kube/utils.go b/pkg/util/kube/utils.go index 1720f614f..002070376 100644 --- a/pkg/util/kube/utils.go +++ b/pkg/util/kube/utils.go @@ -18,6 +18,7 @@ package kube import ( "context" + "encoding/json" "fmt" "strings" "time" @@ -34,6 +35,7 @@ import ( "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/kubernetes" corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" "github.com/vmware-tanzu/velero/pkg/label" @@ -357,3 +359,28 @@ func HasBackupLabel(o *metav1.ObjectMeta, backupName string) bool { } return o.Labels[velerov1api.BackupNameLabel] == label.GetValidName(backupName) } + +func VerifyJSONConfigs(ctx context.Context, namespace string, crClient client.Client, configName string, configType any) error { + cm := new(corev1api.ConfigMap) + err := crClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: configName}, cm) + if err != nil { + return errors.Wrapf(err, "fail to find ConfigMap %s", configName) + } + + if cm.Data == nil { + return errors.Errorf("data is not available in ConfigMap %s", configName) + } + + jsonString := "" + for _, v := range cm.Data { + jsonString = v + } + + configs := configType + err = json.Unmarshal([]byte(jsonString), configs) + if err != nil { + return errors.Wrapf(err, "error to unmarshall data from ConfigMap %s", configName) + } + + return nil +} diff --git a/pkg/util/kube/utils_test.go b/pkg/util/kube/utils_test.go index ec2251744..df23903a0 100644 --- a/pkg/util/kube/utils_test.go +++ b/pkg/util/kube/utils_test.go @@ -33,12 +33,11 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/kubernetes/fake" "github.com/vmware-tanzu/velero/pkg/builder" velerotest "github.com/vmware-tanzu/velero/pkg/test" "github.com/vmware-tanzu/velero/pkg/uploader" - - "k8s.io/client-go/kubernetes/fake" ) func TestNamespaceAndName(t *testing.T) { @@ -681,3 +680,53 @@ func TestHasBackupLabel(t *testing.T) { assert.Equal(t, tc.expected, actual) } } + +func TestVerifyJsonConfigs(t *testing.T) { + testCases := []struct { + name string + configMapName string + configMap *corev1api.ConfigMap + configType any + expectedErr string + }{ + { + name: "ConfigMap not exist", + configMapName: "non-exist", + expectedErr: "fail to find ConfigMap non-exist: configmaps \"non-exist\" not found", + }, + { + name: "ConfigMap doesn't have data", + configMapName: "no-data", + expectedErr: "data is not available in ConfigMap no-data", + configMap: builder.ForConfigMap("velero", "no-data").Result(), + }, + { + name: "ConfigMap data is invalid", + configMapName: "invalid", + expectedErr: "error to unmarshall data from ConfigMap invalid: unexpected end of JSON input", + configMap: builder.ForConfigMap("velero", "invalid").Data("global", "{\"podResources\": {\"cpuRequest\": \"100m\", \"cpuLimit\": \"200m\", \"memoryRequest\": \"100Mi\", \"memoryLimit\": \"200Mi\"}, \"keepLatestMaintenanceJobs\": 1}", "other", "{\"podResources\": {\"cpuRequest\": \"100m\", \"cpuLimit\": \"200m\", \"memoryRequest\": \"100Mi\", \"memoryLimit\": \"200Mi\"}, \"keepLatestMaintenanceJobs: 1}").Result(), + }, + { + name: "Normal case", + configMapName: "normal", + configMap: builder.ForConfigMap("velero", "normal").Data("global", "{\"podResources\": {\"cpuRequest\": \"100m\", \"cpuLimit\": \"200m\", \"memoryRequest\": \"100Mi\", \"memoryLimit\": \"200Mi\"}, \"keepLatestMaintenanceJobs\": 1}", "other", "{\"podResources\": {\"cpuRequest\": \"100m\", \"cpuLimit\": \"200m\", \"memoryRequest\": \"100Mi\", \"memoryLimit\": \"200Mi\"}, \"keepLatestMaintenanceJobs\": 1}").Result(), + configType: make(map[string]any), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + objects := make([]runtime.Object, 0) + if tc.configMap != nil { + objects = append(objects, tc.configMap) + } + fakeClient := velerotest.NewFakeControllerRuntimeClient(t, objects...) + err := VerifyJSONConfigs(t.Context(), "velero", fakeClient, tc.configMapName, tc.configMap) + if len(tc.expectedErr) > 0 { + require.EqualError(t, err, tc.expectedErr) + } else { + require.NoError(t, err) + } + }) + } +} From b0c182cbf06515d031a9be94a8ea24cf78c0224d Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Wed, 27 Aug 2025 13:48:45 +0800 Subject: [PATCH 014/104] Add document change for 9196. Signed-off-by: Xun Jiang --- .../docs/main/customize-installation.md | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/site/content/docs/main/customize-installation.md b/site/content/docs/main/customize-installation.md index a7cf965a6..2ac23e5cd 100644 --- a/site/content/docs/main/customize-installation.md +++ b/site/content/docs/main/customize-installation.md @@ -474,6 +474,37 @@ If you get an error like `complete:13: command not found: compdef`, then add the compinit ``` +## Advanced configuration through external ConfigMaps + +Velero supports to configure its some advanced behaviors by external ConfigMaps. +Velero itself isn't responsible for creating and maintaining these ConfigMaps, instead the users should do that. + +By far, `velero install` supports the following parameters to specify the external ConfigMap names: +* --backup-repository-configmap: [backup repository configuration document][15] +* --node-agent-configmap: [node-agent concurrency configuration document][16], and there are some other documents specify other parts of node-agent-config. +* --repo-maintenance-job-configmap: [repository maintenance configuration document][17] + +From v1.17, Velero adds verification for the ConfigMaps in CLI and server side, which means `velero install` CLI will fail and velero server and node-agent pod will exit if the specified ConfigMaps don't exist or are invalid. + +The change's aim is validating the ConfigMaps and fail early instead of finding the ConfigMaps are not valid during running data mover pod or repository maintenance job. + +However, there means the user cannot just running `velero install` CLI then get a working environment, when the external ConfigMaps are involved. + +The new workflow is: +* Create the needed namespace: `kubectl create ns velero` +* Add PSA labels to the namespace: `kubectl label ns velero pod-security.velero.io/enforce=privileged` +* Create the needed ConfigMaps. +* Run the `velero install` CLI: + ``` bash + velero install \ + --provider aws \ + ...... + --backup-repository-configmap=... \ + --node-agent-configmap=... \ + --repo-maintenance-job-configmap=... + ``` + + [1]: https://github.com/vmware-tanzu/velero/releases/latest [2]: namespace.md [3]: file-system-backup.md @@ -487,3 +518,6 @@ If you get an error like `complete:13: command not found: compdef`, then add the [12]: csi-snapshot-data-movement.md [13]: performance-guidance.md [14]: repository-maintenance.md +[15]: backup-repository-configuration.md +[16]: node-agent-concurrency.md +[17]: repository-maintenance.md From c6d611aa7f5e875eab00a9f97a0c11d0c29d13c6 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Wed, 27 Aug 2025 14:03:26 +0800 Subject: [PATCH 015/104] update 1.17 readme and implemented design Signed-off-by: Lyndon-Li --- README.md | 1 + design/{ => Implemented}/clean_artifacts_in_csi_flow.md | 0 design/{ => Implemented}/node-agent-load-soothing.md | 0 design/{ => Implemented}/vgdp-affinity-enhancement.md | 0 design/{ => Implemented}/volume-group-snapshot.md | 0 5 files changed, 1 insertion(+) rename design/{ => Implemented}/clean_artifacts_in_csi_flow.md (100%) rename design/{ => Implemented}/node-agent-load-soothing.md (100%) rename design/{ => Implemented}/vgdp-affinity-enhancement.md (100%) rename design/{ => Implemented}/volume-group-snapshot.md (100%) diff --git a/README.md b/README.md index 942962733..0d5318873 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ The following is a list of the supported Kubernetes versions for each Velero ver | Velero version | Expected Kubernetes version compatibility | Tested on Kubernetes version | |----------------|-------------------------------------------|-------------------------------------| +| 1.17 | 1.18-latest | 1.31.7, 1.32.3, and 1.33.1 | | 1.16 | 1.18-latest | 1.31.4, 1.32.3, and 1.33.0 | | 1.15 | 1.18-latest | 1.28.8, 1.29.8, 1.30.4 and 1.31.1 | | 1.14 | 1.18-latest | 1.27.9, 1.28.9, and 1.29.4 | diff --git a/design/clean_artifacts_in_csi_flow.md b/design/Implemented/clean_artifacts_in_csi_flow.md similarity index 100% rename from design/clean_artifacts_in_csi_flow.md rename to design/Implemented/clean_artifacts_in_csi_flow.md diff --git a/design/node-agent-load-soothing.md b/design/Implemented/node-agent-load-soothing.md similarity index 100% rename from design/node-agent-load-soothing.md rename to design/Implemented/node-agent-load-soothing.md diff --git a/design/vgdp-affinity-enhancement.md b/design/Implemented/vgdp-affinity-enhancement.md similarity index 100% rename from design/vgdp-affinity-enhancement.md rename to design/Implemented/vgdp-affinity-enhancement.md diff --git a/design/volume-group-snapshot.md b/design/Implemented/volume-group-snapshot.md similarity index 100% rename from design/volume-group-snapshot.md rename to design/Implemented/volume-group-snapshot.md From 38f7d9c8ba2e671c587bd784c1fc995ef71b3a02 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Wed, 27 Aug 2025 14:40:49 +0800 Subject: [PATCH 016/104] move implemented design for 1.17 Signed-off-by: Lyndon-Li --- .../include-exclude-in-resource-policy.md | 0 design/Implemented/node-agent-load-soothing.md | 8 ++++---- .../vgdp-micro-service-for-fs-backup.md | 8 ++++---- .../vgdp-micro-service-for-fs-backup/vgdp-ms-1.png | Bin .../vgdp-micro-service-for-fs-backup/vgdp-ms-2.png | Bin 5 files changed, 8 insertions(+), 8 deletions(-) rename design/{ => Implemented}/include-exclude-in-resource-policy.md (100%) rename design/{ => Implemented}/vgdp-micro-service-for-fs-backup/vgdp-micro-service-for-fs-backup.md (99%) rename design/{ => Implemented}/vgdp-micro-service-for-fs-backup/vgdp-ms-1.png (100%) rename design/{ => Implemented}/vgdp-micro-service-for-fs-backup/vgdp-ms-2.png (100%) diff --git a/design/include-exclude-in-resource-policy.md b/design/Implemented/include-exclude-in-resource-policy.md similarity index 100% rename from design/include-exclude-in-resource-policy.md rename to design/Implemented/include-exclude-in-resource-policy.md diff --git a/design/Implemented/node-agent-load-soothing.md b/design/Implemented/node-agent-load-soothing.md index 008baace9..6b39c4e0d 100644 --- a/design/Implemented/node-agent-load-soothing.md +++ b/design/Implemented/node-agent-load-soothing.md @@ -114,8 +114,8 @@ In either case, because step 2~3 is short in time, it is less likely to reach th -[1]: Implemented/unified-repo-and-kopia-integration/unified-repo-and-kopia-integration.md -[2]: Implemented/node-agent-concurrency.md -[3]: Implemented/volume-snapshot-data-movement/volume-snapshot-data-movement.md -[4]: Implemented/vgdp-micro-service/vgdp-micro-service.md +[1]: unified-repo-and-kopia-integration/unified-repo-and-kopia-integration.md +[2]: node-agent-concurrency.md +[3]: volume-snapshot-data-movement/volume-snapshot-data-movement.md +[4]: vgdp-micro-service/vgdp-micro-service.md [5]: vgdp-micro-service-for-fs-backup/vgdp-micro-service-for-fs-backup.md \ No newline at end of file diff --git a/design/vgdp-micro-service-for-fs-backup/vgdp-micro-service-for-fs-backup.md b/design/Implemented/vgdp-micro-service-for-fs-backup/vgdp-micro-service-for-fs-backup.md similarity index 99% rename from design/vgdp-micro-service-for-fs-backup/vgdp-micro-service-for-fs-backup.md rename to design/Implemented/vgdp-micro-service-for-fs-backup/vgdp-micro-service-for-fs-backup.md index a6061461f..0766bc9d4 100644 --- a/design/vgdp-micro-service-for-fs-backup/vgdp-micro-service-for-fs-backup.md +++ b/design/Implemented/vgdp-micro-service-for-fs-backup/vgdp-micro-service-for-fs-backup.md @@ -650,10 +650,10 @@ CLI is not changed. -[1]: ../Implemented/unified-repo-and-kopia-integration/unified-repo-and-kopia-integration.md -[2]: ../Implemented/volume-snapshot-data-movement/volume-snapshot-data-movement.md -[3]: ../Implemented/vgdp-micro-service/vgdp-micro-service.md -[4]: ../Implemented/node-agent-concurrency.md +[1]: ../unified-repo-and-kopia-integration/unified-repo-and-kopia-integration.md +[2]: ../volume-snapshot-data-movement/volume-snapshot-data-movement.md +[3]: ../vgdp-micro-service/vgdp-micro-service.md +[4]: ../node-agent-concurrency.md [5]: https://github.com/vmware-tanzu/velero/issues/8955 [6]: https://github.com/vmware-tanzu/velero/issues/8956 [7]: https://github.com/vmware-tanzu/velero/issues/8289 diff --git a/design/vgdp-micro-service-for-fs-backup/vgdp-ms-1.png b/design/Implemented/vgdp-micro-service-for-fs-backup/vgdp-ms-1.png similarity index 100% rename from design/vgdp-micro-service-for-fs-backup/vgdp-ms-1.png rename to design/Implemented/vgdp-micro-service-for-fs-backup/vgdp-ms-1.png diff --git a/design/vgdp-micro-service-for-fs-backup/vgdp-ms-2.png b/design/Implemented/vgdp-micro-service-for-fs-backup/vgdp-ms-2.png similarity index 100% rename from design/vgdp-micro-service-for-fs-backup/vgdp-ms-2.png rename to design/Implemented/vgdp-micro-service-for-fs-backup/vgdp-ms-2.png From e581de1fe1f591d5285634808a912e5a547dbfaf Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Wed, 27 Aug 2025 15:24:34 +0800 Subject: [PATCH 017/104] add 1.17 chagnelog Signed-off-by: Lyndon-Li --- changelogs/CHANGELOG-1.17.md | 139 ++++++++++++++++++ .../unreleased/7505-pandurangkhandeparker | 1 - changelogs/unreleased/8557-kaovilai | 1 - changelogs/unreleased/8719-hu-keyu | 1 - .../unreleased/8778-shubham-pampattiwar | 1 - changelogs/unreleased/8845-flx5 | 2 - changelogs/unreleased/8875-hu-keyu | 1 - changelogs/unreleased/8880-kaovilai | 7 - changelogs/unreleased/8883-kaovilai | 1 - changelogs/unreleased/8890-blackpiglet | 1 - changelogs/unreleased/8891-Lyndon-Li | 1 - changelogs/unreleased/8902-sseago | 1 - changelogs/unreleased/8919-sseago | 1 - changelogs/unreleased/8924-blackpiglet | 1 - .../unreleased/8938-shubham-pampattiwar | 1 - changelogs/unreleased/8943-farodin91 | 1 - .../unreleased/8944-shubham-pampattiwar | 1 - changelogs/unreleased/8946-blackpiglet | 1 - changelogs/unreleased/8949-blackpiglet | 1 - changelogs/unreleased/8952-Lyndon-Li | 1 - changelogs/unreleased/8969-flx5 | 1 - changelogs/unreleased/8975-ywk253100 | 1 - changelogs/unreleased/8976-blackpiglet | 1 - changelogs/unreleased/8979-Lyndon-Li | 1 - changelogs/unreleased/8982-vishal-chdhry | 1 - changelogs/unreleased/8985-Lyndon-Li | 1 - changelogs/unreleased/8987-kaovilai | 1 - changelogs/unreleased/8990-blackpiglet | 1 - changelogs/unreleased/8998-Lyndon-Li | 1 - changelogs/unreleased/9005-Lyndon-Li | 1 - changelogs/unreleased/9014-Lyndon-Li | 1 - changelogs/unreleased/9015-Lyndon-Li | 1 - .../unreleased/9019-shubham-pampattiwar | 1 - changelogs/unreleased/9021-Lyndon-Li | 1 - changelogs/unreleased/9022-Lyndon-Li | 1 - changelogs/unreleased/9024-amastbau | 1 - changelogs/unreleased/9026-Lyndon-Li | 1 - changelogs/unreleased/9027-Lyndon-Li | 1 - changelogs/unreleased/9030-Lyndon-Li | 1 - changelogs/unreleased/9031-Lyndon-Li | 1 - changelogs/unreleased/9040-blackpiglet | 1 - changelogs/unreleased/9041-priyansh17 | 1 - changelogs/unreleased/9046-blackpiglet | 1 - changelogs/unreleased/9048-sseago | 1 - .../unreleased/9056-shubham-pampattiwar | 1 - changelogs/unreleased/9059-reasonerjt | 1 - changelogs/unreleased/9064-Lyndon-Li | 1 - changelogs/unreleased/9067-Lyndon-Li | 1 - changelogs/unreleased/9068-Lyndon-Li | 1 - changelogs/unreleased/9069-Lyndon-Li | 1 - changelogs/unreleased/9072-Lyndon-Li | 1 - changelogs/unreleased/9074-longxiucai | 1 - changelogs/unreleased/9076-Lyndon-Li | 1 - changelogs/unreleased/9092-blackpiglet | 1 - changelogs/unreleased/9096-blackpiglet | 1 - changelogs/unreleased/9098-Lyndon-Li | 1 - changelogs/unreleased/9100-Lyndon-Li | 1 - .../unreleased/9105-shubham-pampattiwar | 1 - changelogs/unreleased/9111-ywk253100 | 1 - changelogs/unreleased/9112-Lyndon-Li | 1 - changelogs/unreleased/9113-Lyndon-Li | 1 - changelogs/unreleased/9117-Lyndon-Li | 1 - changelogs/unreleased/9118-Lyndon-Li | 1 - .../unreleased/9123-shubham-pampattiwar | 1 - changelogs/unreleased/9124-blackpiglet | 1 - changelogs/unreleased/9130-blackpiglet | 1 - .../unreleased/9135-shubham-pampattiwar | 1 - changelogs/unreleased/9145-reasonerjt | 1 - changelogs/unreleased/9147-blackpiglet | 1 - changelogs/unreleased/9165-Lyndon-Li | 1 - changelogs/unreleased/9168-priyansh17 | 1 - changelogs/unreleased/9175-kaovilai | 1 - changelogs/unreleased/9200-blackpiglet | 1 - 73 files changed, 139 insertions(+), 79 deletions(-) create mode 100644 changelogs/CHANGELOG-1.17.md delete mode 100644 changelogs/unreleased/7505-pandurangkhandeparker delete mode 100644 changelogs/unreleased/8557-kaovilai delete mode 100644 changelogs/unreleased/8719-hu-keyu delete mode 100644 changelogs/unreleased/8778-shubham-pampattiwar delete mode 100644 changelogs/unreleased/8845-flx5 delete mode 100644 changelogs/unreleased/8875-hu-keyu delete mode 100644 changelogs/unreleased/8880-kaovilai delete mode 100644 changelogs/unreleased/8883-kaovilai delete mode 100644 changelogs/unreleased/8890-blackpiglet delete mode 100644 changelogs/unreleased/8891-Lyndon-Li delete mode 100644 changelogs/unreleased/8902-sseago delete mode 100644 changelogs/unreleased/8919-sseago delete mode 100644 changelogs/unreleased/8924-blackpiglet delete mode 100644 changelogs/unreleased/8938-shubham-pampattiwar delete mode 100644 changelogs/unreleased/8943-farodin91 delete mode 100644 changelogs/unreleased/8944-shubham-pampattiwar delete mode 100644 changelogs/unreleased/8946-blackpiglet delete mode 100644 changelogs/unreleased/8949-blackpiglet delete mode 100644 changelogs/unreleased/8952-Lyndon-Li delete mode 100644 changelogs/unreleased/8969-flx5 delete mode 100644 changelogs/unreleased/8975-ywk253100 delete mode 100644 changelogs/unreleased/8976-blackpiglet delete mode 100644 changelogs/unreleased/8979-Lyndon-Li delete mode 100644 changelogs/unreleased/8982-vishal-chdhry delete mode 100644 changelogs/unreleased/8985-Lyndon-Li delete mode 100644 changelogs/unreleased/8987-kaovilai delete mode 100644 changelogs/unreleased/8990-blackpiglet delete mode 100644 changelogs/unreleased/8998-Lyndon-Li delete mode 100644 changelogs/unreleased/9005-Lyndon-Li delete mode 100644 changelogs/unreleased/9014-Lyndon-Li delete mode 100644 changelogs/unreleased/9015-Lyndon-Li delete mode 100644 changelogs/unreleased/9019-shubham-pampattiwar delete mode 100644 changelogs/unreleased/9021-Lyndon-Li delete mode 100644 changelogs/unreleased/9022-Lyndon-Li delete mode 100644 changelogs/unreleased/9024-amastbau delete mode 100644 changelogs/unreleased/9026-Lyndon-Li delete mode 100644 changelogs/unreleased/9027-Lyndon-Li delete mode 100644 changelogs/unreleased/9030-Lyndon-Li delete mode 100644 changelogs/unreleased/9031-Lyndon-Li delete mode 100644 changelogs/unreleased/9040-blackpiglet delete mode 100644 changelogs/unreleased/9041-priyansh17 delete mode 100644 changelogs/unreleased/9046-blackpiglet delete mode 100644 changelogs/unreleased/9048-sseago delete mode 100644 changelogs/unreleased/9056-shubham-pampattiwar delete mode 100644 changelogs/unreleased/9059-reasonerjt delete mode 100644 changelogs/unreleased/9064-Lyndon-Li delete mode 100644 changelogs/unreleased/9067-Lyndon-Li delete mode 100644 changelogs/unreleased/9068-Lyndon-Li delete mode 100644 changelogs/unreleased/9069-Lyndon-Li delete mode 100644 changelogs/unreleased/9072-Lyndon-Li delete mode 100644 changelogs/unreleased/9074-longxiucai delete mode 100644 changelogs/unreleased/9076-Lyndon-Li delete mode 100644 changelogs/unreleased/9092-blackpiglet delete mode 100644 changelogs/unreleased/9096-blackpiglet delete mode 100644 changelogs/unreleased/9098-Lyndon-Li delete mode 100644 changelogs/unreleased/9100-Lyndon-Li delete mode 100644 changelogs/unreleased/9105-shubham-pampattiwar delete mode 100644 changelogs/unreleased/9111-ywk253100 delete mode 100644 changelogs/unreleased/9112-Lyndon-Li delete mode 100644 changelogs/unreleased/9113-Lyndon-Li delete mode 100644 changelogs/unreleased/9117-Lyndon-Li delete mode 100644 changelogs/unreleased/9118-Lyndon-Li delete mode 100644 changelogs/unreleased/9123-shubham-pampattiwar delete mode 100644 changelogs/unreleased/9124-blackpiglet delete mode 100644 changelogs/unreleased/9130-blackpiglet delete mode 100644 changelogs/unreleased/9135-shubham-pampattiwar delete mode 100644 changelogs/unreleased/9145-reasonerjt delete mode 100644 changelogs/unreleased/9147-blackpiglet delete mode 100644 changelogs/unreleased/9165-Lyndon-Li delete mode 100644 changelogs/unreleased/9168-priyansh17 delete mode 100644 changelogs/unreleased/9175-kaovilai delete mode 100644 changelogs/unreleased/9200-blackpiglet diff --git a/changelogs/CHANGELOG-1.17.md b/changelogs/CHANGELOG-1.17.md new file mode 100644 index 000000000..aaeecf20d --- /dev/null +++ b/changelogs/CHANGELOG-1.17.md @@ -0,0 +1,139 @@ +## v1.17 + +### Download +https://github.com/vmware-tanzu/velero/releases/tag/v1.17.0 + +### Container Image +`velero/velero:v1.17.0` + +### Documentation +https://velero.io/docs/v1.17/ + +### Upgrading +https://velero.io/docs/v1.17/upgrade-to-1.17/ + +### Highlights +#### Modernized fs-backup +In v1.17, Velero fs-backup is modernized to the micro-service architecture, which brings below benefits: +- Many features that were absent to fs-backup are now available, i.e., load concurrency control, cancel, resume on restart, etc. +- fs-backup is more robust, the running backup/restore could survive from node-agent restart; and the resource allocation is in a more granular manner, the failure of one backup/restore won't impact others. +- The resource usage of node-agent is steady, especially, the node-agent pods won't request huge memory and hold it for a long time. + +Check design https://github.com/vmware-tanzu/velero/blob/main/design/vgdp-micro-service-for-fs-backup/vgdp-micro-service-for-fs-backup.md for more details. + +#### fs-backup support Windows cluster +In v1.17, Velero fs-backup supports to backup/restore Windows workloads. By leveraging the new micro-service architecture for fs-backup, data mover pods could run in Windows nodes and backup/restore Windows volumes. Together with CSI snapshot data movement for Windows which is delivered in 1.16, Velero now supports Windows workload backup/restore in full scenarios. +Check design https://github.com/vmware-tanzu/velero/blob/main/design/vgdp-micro-service-for-fs-backup/vgdp-micro-service-for-fs-backup.md for more details. + +#### Volume group snapshot support +In v1.17, Velero supports volume group snapshots which is a beta feature in Kubernetes upstream (https://kubernetes.io/blog/2024/12/18/kubernetes-1-32-volume-group-snapshot-beta/), for both CSI snapshot backup and CSI snapshot data movement. This allows a snapshot to be taken from multiple volumes at the same point-in-time to achieve write order consistency, which is helpful to achieve better data consistency when multiple volumes being backed up are correlated. +Check the document https://velero.io/docs/main/volume-group-snapshots/ for more details. + +#### Priority class support +In v1.17, Kubernete priority class (https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#priorityclass) is supported for all modules across Velero. Specifically, users are allowed to configure priority class to Velero server, node-agent, data mover pods, backup repository maintenance jobs separately. +Check design https://github.com/vmware-tanzu/velero/blob/main/design/Implemented/priority-class-name-support_design.md for more details. + +#### Scalability and Resiliency improvements of data movers +##### Reduce excessive number of data mover pods in Pending state +In v1.17, Velero allows users to set a `PrepareQueueLength` in the node-agent configuration, data mover pods and volumes out of this number won't be created until data path quota is available, so that excessive number cluster resources won't be taken unnecessarily, which is particularly helpful for large scale environments. This improvement applies to all kinds of data movements, including fs-backup and CSI snapshot data movement. +Check design https://github.com/vmware-tanzu/velero/blob/main/design/node-agent-load-soothing.md for more details. + +##### Enhancement on node-agent restart handling for data movements +In v1.17, data movements in all phases could survive from node-agent restart and resume themselves; when a data movement gets orphaned in special cases, e.g., cluster node absent, it could also be canceled appropriately after the restart. This improvement applies to all kinds of data movements, including fs-backup and CSI snapshot data movement. +Check issue https://github.com/vmware-tanzu/velero/issues/8534 for more details. + +##### CSI snapshot data movement restore node-selection and node-selection by storage class +In v1.17, CSI snapshot data movement restore acquires the same node-selection capability as backup, that is, users could specify which nodes can/cannot run data mover pods for both backup and restore now. And users are also allowed to configure the node-selection per storage class, which is particularly helpful to the environments where a storage class are not usable by all cluster nodes. +Check issue https://github.com/vmware-tanzu/velero/issues/8186 and https://github.com/vmware-tanzu/velero/issues/8223 for more details. + +### Runtime and dependencies +Golang runtime: 1.24.6 +kopia: 0.21.1 + +### Limitations/Known issues + +### Breaking changes +#### Deprecation of Restic +According to [Velero deprecation policy][https://github.com/vmware-tanzu/velero/blob/main/GOVERNANCE.md#deprecation-policy], backup of fs-backup under Restic path is removed in v1.17, so `--uploader-type=restic` is not a valid installation configuration anymore. This means you cannot create a backup under Restic path, but you can still restore from the previous backups under Restic path until v1.19. + +#### Repository maintenance job configurations are removed from Velero server parameter +Since the repository maintenance job configurations are moved to repository maintenance job configMap, in v1.17 below Velero sever parameters are removed: +- --keep-latest-maintenance-jobs +- --maintenance-job-cpu-request +- --maintenance-job-mem-request +- --maintenance-job-cpu-limit +- --maintenance-job-mem-limit + +### All Changes + * Add ConfigMap parameters validation for install CLI and server start. (#9200, @blackpiglet) + * Add priorityclasses to high priority restore list (#9175, @kaovilai) + * Introduced context-based logger for backend implementations (Azure, GCS, S3, and Filesystem) (#9168, @priyansh17) + * Fix issue #9140, add os=windows:NoSchedule toleration for Windows pods (#9165, @Lyndon-Li) + * Remove the repository maintenance job parameters from velero server. (#9147, @blackpiglet) + * Add include/exclude policy to resources policy (#9145, @reasonerjt) + * Add ConfigMap support for keepLatestMaintenanceJobs with CLI parameter fallback (#9135, @shubham-pampattiwar) + * Fix the dd and du's node affinity issue. (#9130, @blackpiglet) + * Remove the WaitUntilVSCHandleIsReady from vs BIA. (#9124, @blackpiglet) + * Add comprehensive Volume Group Snapshots documentation with workflow diagrams and examples (#9123, @shubham-pampattiwar) + * Fix issue #9065, add doc for node-agent prepare queue length (#9118, @Lyndon-Li) + * Fix issue #9095, update restore doc for PVC selected-node (#9117, @Lyndon-Li) + * Update CSI Snapshot Data Movement doc for issue #8534, #8185 (#9113, @Lyndon-Li) + * Fix issue #8986, refactor fs-backup doc after VGDP Micro Service for fs-backup (#9112, @Lyndon-Li) + * Return error if timeout when checking server version (#9111, @ywk253100) + * Update "Default Volumes to Fs Backup" to "File System Backup (Default)" (#9105, @shubham-pampattiwar) + * Fix issue #9077, don't block backup deletion on list VS error (#9100, @Lyndon-Li) + * Bump up Kopia to v0.21.1 (#9098, @Lyndon-Li) + * Add imagePullSecrets inheritance for VGDP pod and maintenance job. (#9096, @blackpiglet) + * Avoid checking the VS and VSC status in the backup finalizing phase. (#9092, @blackpiglet) + * Fix issue #9053, Always remove selected-node annotation during PVC restore when no node mapping exists. Breaking change: Previously, the annotation was preserved if the node existed. (#9076, @Lyndon-Li) + * Enable parameterized kubelet mount path during node-agent installation (#9074, @longxiucai) + * Fix issue #8857, support third party tolerations for data mover pods (#9072, @Lyndon-Li) + * Fix issue #8813, remove restic from the valid uploader type (#9069, @Lyndon-Li) + * Fix issue #8185, allow users to disable pod volume host path mount for node-agent (#9068, @Lyndon-Li) + * Fix #8344, add the design for a mechanism to soothe creation of data mover pods for DataUpload, DataDownload, PodVolumeBackup and PodVolumeRestore (#9067, @Lyndon-Li) + * Fix #8344, add a mechanism to soothe creation of data mover pods for DataUpload, DataDownload, PodVolumeBackup and PodVolumeRestore (#9064, @Lyndon-Li) + * Add Gauge metric for BSL availability (#9059, @reasonerjt) + * Fix missing defaultVolumesToFsBackup flag output in Velero describe backup cmd (#9056, @shubham-pampattiwar) + * Allow for proper tracking of multiple hooks per container (#9048, @sseago) + * Make the backup repository controller doesn't invalidate the BSL on restart (#9046, @blackpiglet) + * Removed username/password credential handling from newConfigCredential as azidentity.UsernamePasswordCredentialOptions is reported as deprecated. (#9041, @priyansh17) + * Remove dependency with VolumeSnapshotClass in DataUpload. (#9040, @blackpiglet) + * Fix issue #8961, cancel PVB/PVR on Velero server restart (#9031, @Lyndon-Li) + * Fix issue #8962, resume PVB/PVR during node-agent restarts (#9030, @Lyndon-Li) + * Bump kopia v0.20.1 (#9027, @Lyndon-Li) + * Fix issue #8965, support PVB/PVR's cancel state in the backup/restore (#9026, @Lyndon-Li) + * Fix Issue 8816 When specifying LabelSelector on restore, related items such as PVC and VolumeSnapshot are not included (#9024, @amastbau) + * Fix issue #8963, add legacy PVR controller for Restic path (#9022, @Lyndon-Li) + * Fix issue #8964, add Windows support for VGDP MS for fs-backup (#9021, @Lyndon-Li) + * Accommodate VGS workflows in PVC CSI plugin (#9019, @shubham-pampattiwar) + * Fix issue #8958, add VGDP MS PVB controller (#9015, @Lyndon-Li) + * Fix issue #8959, add VGDP MS PVR controller (#9014, @Lyndon-Li) + * Fix issue #8988, add data path for VGDP ms PVR (#9005, @Lyndon-Li) + * Fix issue #8988, add data path for VGDP ms pvb (#8998, @Lyndon-Li) + * Skip VS and VSC not created by backup. (#8990, @blackpiglet) + * Make ResticIdentifier optional for kopia BackupRepositories (#8987, @kaovilai) + * Fix issue #8960, implement PodVolume exposer for PVB/PVR (#8985, @Lyndon-Li) + * fix: update mc command in minio-deployment example (#8982, @vishal-chdhry) + * Fix issue #8957, add design for VGDP MS for fs-backup (#8979, @Lyndon-Li) + * Add BSL status check for backup/restore operations. (#8976, @blackpiglet) + * Mark BackupRepository not ready when BSL changed (#8975, @ywk253100) + * Add support for [distributed snapshotting](https://github.com/kubernetes-csi/external-snapshotter/tree/4cedb3f45790ac593ebfa3324c490abedf739477?tab=readme-ov-file#distributed-snapshotting) (#8969, @flx5) + * Fix issue #8534, refactor dm controllers to tolerate cancel request in more cases, e.g., node restart, node drain (#8952, @Lyndon-Li) + * The backup and restore VGDP affinity enhancement implementation. (#8949, @blackpiglet) + * Remove CSI VS and VSC metadata from backup. (#8946, @blackpiglet) + * Extend PVCAction itemblock plugin to support grouping PVCs under VGS label key (#8944, @shubham-pampattiwar) + * Copy security context from origin pod (#8943, @farodin91) + * Add support for configuring VGS label key (#8938, @shubham-pampattiwar) + * Add VolumeSnapshotContent into the RIA and the mustHave resource list. (#8924, @blackpiglet) + * Mounted cloud credentials should not be world-readable (#8919, @sseago) + * Warn for not found error in patching managed fields (#8902, @sseago) + * Fix issue 8878, relief node os deduction error checks (#8891, @Lyndon-Li) + * Skip namespace in terminating state in backup resource collection. (#8890, @blackpiglet) + * Implement PriorityClass Support (#8883, @kaovilai) + * Fix Velero adding restore-wait init container when not needed. (#8880, @kaovilai) + * Pass the logger in kopia related operations. (#8875, @hu-keyu) + * Inherit the dnsPolicy and dnsConfig from the node agent pod. This is done so that the kopia task uses the same configuration. (#8845, @flx5) + * Add design for VolumeGroupSnapshot support (#8778, @shubham-pampattiwar) + * Inherit k8s default volumeSnapshotClass. (#8719, @hu-keyu) + * CLI automatically discovers and uses cacert from BSL for download requests (#8557, @kaovilai) + * This PR aims to add s390x support to Velero binary. (#7505, @pandurangkhandeparker) \ No newline at end of file diff --git a/changelogs/unreleased/7505-pandurangkhandeparker b/changelogs/unreleased/7505-pandurangkhandeparker deleted file mode 100644 index a5eacb4a6..000000000 --- a/changelogs/unreleased/7505-pandurangkhandeparker +++ /dev/null @@ -1 +0,0 @@ -This PR aims to add s390x support to Velero binary. diff --git a/changelogs/unreleased/8557-kaovilai b/changelogs/unreleased/8557-kaovilai deleted file mode 100644 index 7abdbe9bd..000000000 --- a/changelogs/unreleased/8557-kaovilai +++ /dev/null @@ -1 +0,0 @@ -CLI automatically discovers and uses cacert from BSL for download requests diff --git a/changelogs/unreleased/8719-hu-keyu b/changelogs/unreleased/8719-hu-keyu deleted file mode 100644 index eb6925ff2..000000000 --- a/changelogs/unreleased/8719-hu-keyu +++ /dev/null @@ -1 +0,0 @@ -Inherit k8s default volumeSnapshotClass. \ No newline at end of file diff --git a/changelogs/unreleased/8778-shubham-pampattiwar b/changelogs/unreleased/8778-shubham-pampattiwar deleted file mode 100644 index 569f43ecf..000000000 --- a/changelogs/unreleased/8778-shubham-pampattiwar +++ /dev/null @@ -1 +0,0 @@ -Add design for VolumeGroupSnapshot support \ No newline at end of file diff --git a/changelogs/unreleased/8845-flx5 b/changelogs/unreleased/8845-flx5 deleted file mode 100644 index 742d40a40..000000000 --- a/changelogs/unreleased/8845-flx5 +++ /dev/null @@ -1,2 +0,0 @@ -Inherit the dnsPolicy and dnsConfig from the node agent pod. -This is done so that the kopia task uses the same configuration. \ No newline at end of file diff --git a/changelogs/unreleased/8875-hu-keyu b/changelogs/unreleased/8875-hu-keyu deleted file mode 100644 index f1a292cb5..000000000 --- a/changelogs/unreleased/8875-hu-keyu +++ /dev/null @@ -1 +0,0 @@ -Pass the logger in kopia related operations. \ No newline at end of file diff --git a/changelogs/unreleased/8880-kaovilai b/changelogs/unreleased/8880-kaovilai deleted file mode 100644 index f5bcfa189..000000000 --- a/changelogs/unreleased/8880-kaovilai +++ /dev/null @@ -1,7 +0,0 @@ -Fix Velero adding restore-wait init container when not needed - -When restoring pods with volumes that were backed up using native datamover or CSI, -Velero was unnecessarily adding the restore-wait init container. This container is -only needed for file system restores. Now Velero checks if any volumes actually need -file system restores and removes the init container if it's not needed, rather than -just skipping its addition. diff --git a/changelogs/unreleased/8883-kaovilai b/changelogs/unreleased/8883-kaovilai deleted file mode 100644 index 63be04bf1..000000000 --- a/changelogs/unreleased/8883-kaovilai +++ /dev/null @@ -1 +0,0 @@ -Implement PriorityClass Support diff --git a/changelogs/unreleased/8890-blackpiglet b/changelogs/unreleased/8890-blackpiglet deleted file mode 100644 index e670b9635..000000000 --- a/changelogs/unreleased/8890-blackpiglet +++ /dev/null @@ -1 +0,0 @@ -Skip namespace in terminating state in backup resource collection. diff --git a/changelogs/unreleased/8891-Lyndon-Li b/changelogs/unreleased/8891-Lyndon-Li deleted file mode 100644 index c6ae6a433..000000000 --- a/changelogs/unreleased/8891-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue 8878, relief node os deduction error checks \ No newline at end of file diff --git a/changelogs/unreleased/8902-sseago b/changelogs/unreleased/8902-sseago deleted file mode 100644 index d05aa5c9c..000000000 --- a/changelogs/unreleased/8902-sseago +++ /dev/null @@ -1 +0,0 @@ -Warn for not found error in patching managed fields diff --git a/changelogs/unreleased/8919-sseago b/changelogs/unreleased/8919-sseago deleted file mode 100644 index 143c86850..000000000 --- a/changelogs/unreleased/8919-sseago +++ /dev/null @@ -1 +0,0 @@ -Mounted cloud credentials should not be world-readable diff --git a/changelogs/unreleased/8924-blackpiglet b/changelogs/unreleased/8924-blackpiglet deleted file mode 100644 index bb60675e3..000000000 --- a/changelogs/unreleased/8924-blackpiglet +++ /dev/null @@ -1 +0,0 @@ -Add VolumeSnapshotContent into the RIA and the mustHave resource list. diff --git a/changelogs/unreleased/8938-shubham-pampattiwar b/changelogs/unreleased/8938-shubham-pampattiwar deleted file mode 100644 index 1cc30b732..000000000 --- a/changelogs/unreleased/8938-shubham-pampattiwar +++ /dev/null @@ -1 +0,0 @@ -Add support for configuring VGS label key \ No newline at end of file diff --git a/changelogs/unreleased/8943-farodin91 b/changelogs/unreleased/8943-farodin91 deleted file mode 100644 index c77c1b887..000000000 --- a/changelogs/unreleased/8943-farodin91 +++ /dev/null @@ -1 +0,0 @@ -Copy security context from origin pod \ No newline at end of file diff --git a/changelogs/unreleased/8944-shubham-pampattiwar b/changelogs/unreleased/8944-shubham-pampattiwar deleted file mode 100644 index f59ba9844..000000000 --- a/changelogs/unreleased/8944-shubham-pampattiwar +++ /dev/null @@ -1 +0,0 @@ -Extend PVCAction itemblock plugin to support grouping PVCs under VGS label key \ No newline at end of file diff --git a/changelogs/unreleased/8946-blackpiglet b/changelogs/unreleased/8946-blackpiglet deleted file mode 100644 index a83ab9290..000000000 --- a/changelogs/unreleased/8946-blackpiglet +++ /dev/null @@ -1 +0,0 @@ -Remove CSI VS and VSC metadata from backup. diff --git a/changelogs/unreleased/8949-blackpiglet b/changelogs/unreleased/8949-blackpiglet deleted file mode 100644 index a434ee160..000000000 --- a/changelogs/unreleased/8949-blackpiglet +++ /dev/null @@ -1 +0,0 @@ -The backup and restore VGDP affinity enhancement implementation. diff --git a/changelogs/unreleased/8952-Lyndon-Li b/changelogs/unreleased/8952-Lyndon-Li deleted file mode 100644 index c360537b9..000000000 --- a/changelogs/unreleased/8952-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #8534, refactor dm controllers to tolerate cancel request in more cases, e.g., node restart, node drain \ No newline at end of file diff --git a/changelogs/unreleased/8969-flx5 b/changelogs/unreleased/8969-flx5 deleted file mode 100644 index 683f437a4..000000000 --- a/changelogs/unreleased/8969-flx5 +++ /dev/null @@ -1 +0,0 @@ -Add support for [distributed snapshotting](https://github.com/kubernetes-csi/external-snapshotter/tree/4cedb3f45790ac593ebfa3324c490abedf739477?tab=readme-ov-file#distributed-snapshotting) \ No newline at end of file diff --git a/changelogs/unreleased/8975-ywk253100 b/changelogs/unreleased/8975-ywk253100 deleted file mode 100644 index bd21417b7..000000000 --- a/changelogs/unreleased/8975-ywk253100 +++ /dev/null @@ -1 +0,0 @@ -Mark BackupRepository not ready when BSL changed \ No newline at end of file diff --git a/changelogs/unreleased/8976-blackpiglet b/changelogs/unreleased/8976-blackpiglet deleted file mode 100644 index c5aab6a51..000000000 --- a/changelogs/unreleased/8976-blackpiglet +++ /dev/null @@ -1 +0,0 @@ -Add BSL status check for backup/restore operations. diff --git a/changelogs/unreleased/8979-Lyndon-Li b/changelogs/unreleased/8979-Lyndon-Li deleted file mode 100644 index 7c26509e2..000000000 --- a/changelogs/unreleased/8979-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #8957, add design for VGDP MS for fs-backup \ No newline at end of file diff --git a/changelogs/unreleased/8982-vishal-chdhry b/changelogs/unreleased/8982-vishal-chdhry deleted file mode 100644 index 1d032f5b8..000000000 --- a/changelogs/unreleased/8982-vishal-chdhry +++ /dev/null @@ -1 +0,0 @@ -fix: update mc command in minio-deployment example diff --git a/changelogs/unreleased/8985-Lyndon-Li b/changelogs/unreleased/8985-Lyndon-Li deleted file mode 100644 index 7bb89251c..000000000 --- a/changelogs/unreleased/8985-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #8960, implement PodVolume exposer for PVB/PVR \ No newline at end of file diff --git a/changelogs/unreleased/8987-kaovilai b/changelogs/unreleased/8987-kaovilai deleted file mode 100644 index 26771dc16..000000000 --- a/changelogs/unreleased/8987-kaovilai +++ /dev/null @@ -1 +0,0 @@ -Make ResticIdentifier optional for kopia BackupRepositories diff --git a/changelogs/unreleased/8990-blackpiglet b/changelogs/unreleased/8990-blackpiglet deleted file mode 100644 index ec805dc58..000000000 --- a/changelogs/unreleased/8990-blackpiglet +++ /dev/null @@ -1 +0,0 @@ -Skip VS and VSC not created by backup. diff --git a/changelogs/unreleased/8998-Lyndon-Li b/changelogs/unreleased/8998-Lyndon-Li deleted file mode 100644 index a2385b5ad..000000000 --- a/changelogs/unreleased/8998-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #8988, add data path for VGDP ms pvb \ No newline at end of file diff --git a/changelogs/unreleased/9005-Lyndon-Li b/changelogs/unreleased/9005-Lyndon-Li deleted file mode 100644 index 8a40d62cb..000000000 --- a/changelogs/unreleased/9005-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #8988, add data path for VGDP ms PVR \ No newline at end of file diff --git a/changelogs/unreleased/9014-Lyndon-Li b/changelogs/unreleased/9014-Lyndon-Li deleted file mode 100644 index b36740f9d..000000000 --- a/changelogs/unreleased/9014-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #8959, add VGDP MS PVR controller \ No newline at end of file diff --git a/changelogs/unreleased/9015-Lyndon-Li b/changelogs/unreleased/9015-Lyndon-Li deleted file mode 100644 index 51021f8c0..000000000 --- a/changelogs/unreleased/9015-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #8958, add VGDP MS PVB controller \ No newline at end of file diff --git a/changelogs/unreleased/9019-shubham-pampattiwar b/changelogs/unreleased/9019-shubham-pampattiwar deleted file mode 100644 index ba487740c..000000000 --- a/changelogs/unreleased/9019-shubham-pampattiwar +++ /dev/null @@ -1 +0,0 @@ -Accommodate VGS workflows in PVC CSI plugin \ No newline at end of file diff --git a/changelogs/unreleased/9021-Lyndon-Li b/changelogs/unreleased/9021-Lyndon-Li deleted file mode 100644 index ea433c6bc..000000000 --- a/changelogs/unreleased/9021-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #8964, add Windows support for VGDP MS for fs-backup \ No newline at end of file diff --git a/changelogs/unreleased/9022-Lyndon-Li b/changelogs/unreleased/9022-Lyndon-Li deleted file mode 100644 index b23fa43d4..000000000 --- a/changelogs/unreleased/9022-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #8963, add legacy PVR controller for Restic path \ No newline at end of file diff --git a/changelogs/unreleased/9024-amastbau b/changelogs/unreleased/9024-amastbau deleted file mode 100644 index 1122267b9..000000000 --- a/changelogs/unreleased/9024-amastbau +++ /dev/null @@ -1 +0,0 @@ -Fix Issue 8816 When specifying LabelSelector on restore, related items such as PVC and VolumeSnapshot are not included diff --git a/changelogs/unreleased/9026-Lyndon-Li b/changelogs/unreleased/9026-Lyndon-Li deleted file mode 100644 index 96300961b..000000000 --- a/changelogs/unreleased/9026-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #8965, support PVB/PVR's cancel state in the backup/restore \ No newline at end of file diff --git a/changelogs/unreleased/9027-Lyndon-Li b/changelogs/unreleased/9027-Lyndon-Li deleted file mode 100644 index c7e607bea..000000000 --- a/changelogs/unreleased/9027-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Bump kopia v0.20.1 \ No newline at end of file diff --git a/changelogs/unreleased/9030-Lyndon-Li b/changelogs/unreleased/9030-Lyndon-Li deleted file mode 100644 index c423b4840..000000000 --- a/changelogs/unreleased/9030-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #8962, resume PVB/PVR during node-agent restarts \ No newline at end of file diff --git a/changelogs/unreleased/9031-Lyndon-Li b/changelogs/unreleased/9031-Lyndon-Li deleted file mode 100644 index 1d612dc0f..000000000 --- a/changelogs/unreleased/9031-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #8961, cancel PVB/PVR on Velero server restart \ No newline at end of file diff --git a/changelogs/unreleased/9040-blackpiglet b/changelogs/unreleased/9040-blackpiglet deleted file mode 100644 index 9475e8efa..000000000 --- a/changelogs/unreleased/9040-blackpiglet +++ /dev/null @@ -1 +0,0 @@ -Remove dependency with VolumeSnapshotClass in DataUpload. diff --git a/changelogs/unreleased/9041-priyansh17 b/changelogs/unreleased/9041-priyansh17 deleted file mode 100644 index ab2b25ab1..000000000 --- a/changelogs/unreleased/9041-priyansh17 +++ /dev/null @@ -1 +0,0 @@ -Removed username/password credential handling from newConfigCredential as azidentity.UsernamePasswordCredentialOptions is reported as deprecated. diff --git a/changelogs/unreleased/9046-blackpiglet b/changelogs/unreleased/9046-blackpiglet deleted file mode 100644 index 27d39541c..000000000 --- a/changelogs/unreleased/9046-blackpiglet +++ /dev/null @@ -1 +0,0 @@ -Make the backup repository controller doesn't invalidate the BSL on restart \ No newline at end of file diff --git a/changelogs/unreleased/9048-sseago b/changelogs/unreleased/9048-sseago deleted file mode 100644 index a78a6e1a9..000000000 --- a/changelogs/unreleased/9048-sseago +++ /dev/null @@ -1 +0,0 @@ -Allow for proper tracking of multiple hooks per container diff --git a/changelogs/unreleased/9056-shubham-pampattiwar b/changelogs/unreleased/9056-shubham-pampattiwar deleted file mode 100644 index 4f4908da6..000000000 --- a/changelogs/unreleased/9056-shubham-pampattiwar +++ /dev/null @@ -1 +0,0 @@ -Fix missing defaultVolumesToFsBackup flag output in Velero describe backup cmd \ No newline at end of file diff --git a/changelogs/unreleased/9059-reasonerjt b/changelogs/unreleased/9059-reasonerjt deleted file mode 100644 index abdc483aa..000000000 --- a/changelogs/unreleased/9059-reasonerjt +++ /dev/null @@ -1 +0,0 @@ -Add Gauge metric for BSL availability \ No newline at end of file diff --git a/changelogs/unreleased/9064-Lyndon-Li b/changelogs/unreleased/9064-Lyndon-Li deleted file mode 100644 index 34392dd82..000000000 --- a/changelogs/unreleased/9064-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix #8344, add a mechanism to soothe creation of data mover pods for DataUpload, DataDownload, PodVolumeBackup and PodVolumeRestore \ No newline at end of file diff --git a/changelogs/unreleased/9067-Lyndon-Li b/changelogs/unreleased/9067-Lyndon-Li deleted file mode 100644 index 7f3c38edb..000000000 --- a/changelogs/unreleased/9067-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix #8344, add the design for a mechanism to soothe creation of data mover pods for DataUpload, DataDownload, PodVolumeBackup and PodVolumeRestore \ No newline at end of file diff --git a/changelogs/unreleased/9068-Lyndon-Li b/changelogs/unreleased/9068-Lyndon-Li deleted file mode 100644 index 7eca57dfd..000000000 --- a/changelogs/unreleased/9068-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #8185, allow users to disable pod volume host path mount for node-agent \ No newline at end of file diff --git a/changelogs/unreleased/9069-Lyndon-Li b/changelogs/unreleased/9069-Lyndon-Li deleted file mode 100644 index a97bb3fba..000000000 --- a/changelogs/unreleased/9069-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #8813, remove restic from the valid uploader type \ No newline at end of file diff --git a/changelogs/unreleased/9072-Lyndon-Li b/changelogs/unreleased/9072-Lyndon-Li deleted file mode 100644 index c7ad770a4..000000000 --- a/changelogs/unreleased/9072-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #8857, support third party tolerations for data mover pods \ No newline at end of file diff --git a/changelogs/unreleased/9074-longxiucai b/changelogs/unreleased/9074-longxiucai deleted file mode 100644 index 068771621..000000000 --- a/changelogs/unreleased/9074-longxiucai +++ /dev/null @@ -1 +0,0 @@ -Enable parameterized kubelet mount path during node-agent installation diff --git a/changelogs/unreleased/9076-Lyndon-Li b/changelogs/unreleased/9076-Lyndon-Li deleted file mode 100644 index 03ba8e2b5..000000000 --- a/changelogs/unreleased/9076-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #9053, Always remove selected-node annotation during PVC restore when no node mapping exists. Breaking change: Previously, the annotation was preserved if the node existed. \ No newline at end of file diff --git a/changelogs/unreleased/9092-blackpiglet b/changelogs/unreleased/9092-blackpiglet deleted file mode 100644 index 6aa795ec1..000000000 --- a/changelogs/unreleased/9092-blackpiglet +++ /dev/null @@ -1 +0,0 @@ -Avoid checking the VS and VSC status in the backup finalizing phase. diff --git a/changelogs/unreleased/9096-blackpiglet b/changelogs/unreleased/9096-blackpiglet deleted file mode 100644 index 87a714b55..000000000 --- a/changelogs/unreleased/9096-blackpiglet +++ /dev/null @@ -1 +0,0 @@ -Add imagePullSecrets inheritance for VGDP pod and maintenance job. diff --git a/changelogs/unreleased/9098-Lyndon-Li b/changelogs/unreleased/9098-Lyndon-Li deleted file mode 100644 index 4f7d1dcc9..000000000 --- a/changelogs/unreleased/9098-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Bump up Kopia to v0.21.1 \ No newline at end of file diff --git a/changelogs/unreleased/9100-Lyndon-Li b/changelogs/unreleased/9100-Lyndon-Li deleted file mode 100644 index 80baa45a7..000000000 --- a/changelogs/unreleased/9100-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #9077, don't block backup deletion on list VS error \ No newline at end of file diff --git a/changelogs/unreleased/9105-shubham-pampattiwar b/changelogs/unreleased/9105-shubham-pampattiwar deleted file mode 100644 index 157fe7c6a..000000000 --- a/changelogs/unreleased/9105-shubham-pampattiwar +++ /dev/null @@ -1 +0,0 @@ -Update "Default Volumes to Fs Backup" to "File System Backup (Default)" diff --git a/changelogs/unreleased/9111-ywk253100 b/changelogs/unreleased/9111-ywk253100 deleted file mode 100644 index 1b5408f0b..000000000 --- a/changelogs/unreleased/9111-ywk253100 +++ /dev/null @@ -1 +0,0 @@ -Return error if timeout when checking server version \ No newline at end of file diff --git a/changelogs/unreleased/9112-Lyndon-Li b/changelogs/unreleased/9112-Lyndon-Li deleted file mode 100644 index 6e9e3b38d..000000000 --- a/changelogs/unreleased/9112-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #8986, refactor fs-backup doc after VGDP Micro Service for fs-backup \ No newline at end of file diff --git a/changelogs/unreleased/9113-Lyndon-Li b/changelogs/unreleased/9113-Lyndon-Li deleted file mode 100644 index c000cfeb9..000000000 --- a/changelogs/unreleased/9113-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Update CSI Snapshot Data Movement doc for issue #8534, #8185 \ No newline at end of file diff --git a/changelogs/unreleased/9117-Lyndon-Li b/changelogs/unreleased/9117-Lyndon-Li deleted file mode 100644 index 76fb30e06..000000000 --- a/changelogs/unreleased/9117-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #9095, update restore doc for PVC selected-node \ No newline at end of file diff --git a/changelogs/unreleased/9118-Lyndon-Li b/changelogs/unreleased/9118-Lyndon-Li deleted file mode 100644 index 8ae0e460f..000000000 --- a/changelogs/unreleased/9118-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #9065, add doc for node-agent prepare queue length \ No newline at end of file diff --git a/changelogs/unreleased/9123-shubham-pampattiwar b/changelogs/unreleased/9123-shubham-pampattiwar deleted file mode 100644 index f3be904d2..000000000 --- a/changelogs/unreleased/9123-shubham-pampattiwar +++ /dev/null @@ -1 +0,0 @@ -Add comprehensive Volume Group Snapshots documentation with workflow diagrams and examples \ No newline at end of file diff --git a/changelogs/unreleased/9124-blackpiglet b/changelogs/unreleased/9124-blackpiglet deleted file mode 100644 index 6f067caa3..000000000 --- a/changelogs/unreleased/9124-blackpiglet +++ /dev/null @@ -1 +0,0 @@ -Remove the WaitUntilVSCHandleIsReady from vs BIA. diff --git a/changelogs/unreleased/9130-blackpiglet b/changelogs/unreleased/9130-blackpiglet deleted file mode 100644 index 44bf261a9..000000000 --- a/changelogs/unreleased/9130-blackpiglet +++ /dev/null @@ -1 +0,0 @@ -Fix the dd and du's node affinity issue. diff --git a/changelogs/unreleased/9135-shubham-pampattiwar b/changelogs/unreleased/9135-shubham-pampattiwar deleted file mode 100644 index a489082a8..000000000 --- a/changelogs/unreleased/9135-shubham-pampattiwar +++ /dev/null @@ -1 +0,0 @@ -Add ConfigMap support for keepLatestMaintenanceJobs with CLI parameter fallback \ No newline at end of file diff --git a/changelogs/unreleased/9145-reasonerjt b/changelogs/unreleased/9145-reasonerjt deleted file mode 100644 index 0cf694adf..000000000 --- a/changelogs/unreleased/9145-reasonerjt +++ /dev/null @@ -1 +0,0 @@ -Add include/exclude policy to resources policy \ No newline at end of file diff --git a/changelogs/unreleased/9147-blackpiglet b/changelogs/unreleased/9147-blackpiglet deleted file mode 100644 index dadb7d558..000000000 --- a/changelogs/unreleased/9147-blackpiglet +++ /dev/null @@ -1 +0,0 @@ -Remove the repository maintenance job parameters from velero server. diff --git a/changelogs/unreleased/9165-Lyndon-Li b/changelogs/unreleased/9165-Lyndon-Li deleted file mode 100644 index e7a371263..000000000 --- a/changelogs/unreleased/9165-Lyndon-Li +++ /dev/null @@ -1 +0,0 @@ -Fix issue #9140, add os=windows:NoSchedule toleration for Windows pods \ No newline at end of file diff --git a/changelogs/unreleased/9168-priyansh17 b/changelogs/unreleased/9168-priyansh17 deleted file mode 100644 index 66b97075a..000000000 --- a/changelogs/unreleased/9168-priyansh17 +++ /dev/null @@ -1 +0,0 @@ -Introduced context-based logger for backend implementations (Azure, GCS, S3, and Filesystem) \ No newline at end of file diff --git a/changelogs/unreleased/9175-kaovilai b/changelogs/unreleased/9175-kaovilai deleted file mode 100644 index f38607034..000000000 --- a/changelogs/unreleased/9175-kaovilai +++ /dev/null @@ -1 +0,0 @@ -Add priorityclasses to high priority restore list diff --git a/changelogs/unreleased/9200-blackpiglet b/changelogs/unreleased/9200-blackpiglet deleted file mode 100644 index 4c13079d9..000000000 --- a/changelogs/unreleased/9200-blackpiglet +++ /dev/null @@ -1 +0,0 @@ -Add ConfigMap parameters validation for install CLI and server start. From 382827761af7f5c3ac8884098a546640a2113a8a Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Wed, 27 Aug 2025 15:53:16 +0800 Subject: [PATCH 018/104] add doc for 1.17 Signed-off-by: Lyndon-Li --- site/config.yaml | 3 +- site/content/docs/v1.17/_index.md | 58 ++ site/content/docs/v1.17/api-types/README.md | 21 + site/content/docs/v1.17/api-types/_index.md | 19 + site/content/docs/v1.17/api-types/backup.md | 211 +++++ .../v1.17/api-types/backupstoragelocation.md | 75 ++ site/content/docs/v1.17/api-types/restore.md | 219 +++++ site/content/docs/v1.17/api-types/schedule.md | 216 +++++ .../v1.17/api-types/volumesnapshotlocation.md | 46 ++ site/content/docs/v1.17/backup-hooks.md | 126 +++ site/content/docs/v1.17/backup-reference.md | 167 ++++ .../v1.17/backup-repository-configuration.md | 63 ++ .../docs/v1.17/backup-restore-windows.md | 79 ++ site/content/docs/v1.17/basic-install.md | 73 ++ site/content/docs/v1.17/build-from-source.md | 198 +++++ site/content/docs/v1.17/code-standards.md | 171 ++++ .../docs/v1.17/contributions/ibm-config.md | 102 +++ .../15ccaacf00640a04ae29ceed4c86195b.png | Bin 0 -> 132711 bytes .../1d53b0115644d43657c2a5ece805c9b4.png | Bin 0 -> 74478 bytes .../69194157ccd5e377d1e7d914fd8c0336.png | Bin 0 -> 32817 bytes .../9015313121ed7987558c88081b052574.png | Bin 0 -> 417063 bytes .../ceaca9ce6bc92bdce987c63d2fe71561.png | Bin 0 -> 292269 bytes .../e8c2ab4e5e31d1370c62fad25059a8a8.png | Bin 0 -> 65320 bytes .../e932223585c0b19891cc085ad7f438e1.png | Bin 0 -> 284090 bytes .../eb2bbabae48b188748f5278bedf177f1.png | Bin 0 -> 126032 bytes .../effe8a0a7ce3aa8e422db00bfdddc375.png | Bin 0 -> 85131 bytes .../f0fff5228527edc72d6e71a50d5dc966.png | Bin 0 -> 49558 bytes .../content/docs/v1.17/contributions/minio.md | 301 +++++++ .../docs/v1.17/contributions/oracle-config.md | 248 ++++++ .../v1.17/contributions/tencent-config.md | 168 ++++ .../docs/v1.17/csi-snapshot-data-movement.md | 414 ++++++++++ site/content/docs/v1.17/csi.md | 136 ++++ site/content/docs/v1.17/custom-plugins.md | 121 +++ .../docs/v1.17/customize-installation.md | 523 ++++++++++++ .../data-movement-backup-pvc-configuration.md | 71 ++ .../v1.17/data-movement-node-selection.md | 260 ++++++ ...ata-movement-pod-resource-configuration.md | 129 +++ ...data-movement-restore-pvc-configuration.md | 30 + site/content/docs/v1.17/debugging-install.md | 74 ++ site/content/docs/v1.17/debugging-restores.md | 105 +++ site/content/docs/v1.17/development.md | 49 ++ site/content/docs/v1.17/disaster-case.md | 44 + .../enable-api-group-versions-feature.md | 115 +++ site/content/docs/v1.17/examples.md | 70 ++ site/content/docs/v1.17/file-system-backup.md | 769 ++++++++++++++++++ site/content/docs/v1.17/how-velero-works.md | 117 +++ site/content/docs/v1.17/image-tagging.md | 24 + site/content/docs/v1.17/img/README.md | 1 + .../content/docs/v1.17/img/backup-process.png | Bin 0 -> 33630 bytes .../docs/v1.17/img/gv_priority1-caseA.png | Bin 0 -> 57254 bytes .../docs/v1.17/img/gv_priority1-caseB.png | Bin 0 -> 87058 bytes .../docs/v1.17/img/gv_priority2-caseC.png | Bin 0 -> 42106 bytes .../docs/v1.17/img/gv_priority3-caseD.png | Bin 0 -> 69760 bytes site/content/docs/v1.17/img/velero.png | Bin 0 -> 45564 bytes site/content/docs/v1.17/locations.md | 316 +++++++ site/content/docs/v1.17/maintainers.md | 37 + site/content/docs/v1.17/manual-testing.md | 98 +++ site/content/docs/v1.17/migration-case.md | 108 +++ site/content/docs/v1.17/namespace.md | 22 + .../docs/v1.17/node-agent-concurrency.md | 81 ++ .../v1.17/node-agent-prepare-queue-length.md | 48 ++ site/content/docs/v1.17/on-premises.md | 95 +++ site/content/docs/v1.17/output-file-format.md | 224 +++++ site/content/docs/v1.17/overview-plugins.md | 29 + .../docs/v1.17/performance-guidance.md | 163 ++++ .../docs/v1.17/plugin-release-instructions.md | 30 + site/content/docs/v1.17/proxy.md | 64 ++ site/content/docs/v1.17/rbac.md | 95 +++ .../docs/v1.17/release-instructions.md | 179 ++++ site/content/docs/v1.17/release-schedule.md | 15 + .../docs/v1.17/repository-maintenance.md | 213 +++++ site/content/docs/v1.17/resource-filtering.md | 572 +++++++++++++ site/content/docs/v1.17/restore-hooks.md | 300 +++++++ site/content/docs/v1.17/restore-reference.md | 403 +++++++++ .../docs/v1.17/restore-resource-modifiers.md | 187 +++++ site/content/docs/v1.17/run-locally.md | 53 ++ .../docs/v1.17/self-signed-certificates.md | 84 ++ site/content/docs/v1.17/start-contributing.md | 34 + site/content/docs/v1.17/style-guide.md | 345 ++++++++ site/content/docs/v1.17/support-process.md | 43 + .../content/docs/v1.17/supported-providers.md | 70 ++ site/content/docs/v1.17/tilt.md | 209 +++++ site/content/docs/v1.17/troubleshooting.md | 252 ++++++ site/content/docs/v1.17/uninstalling.md | 10 + site/content/docs/v1.17/upgrade-to-1.17.md | 96 +++ site/content/docs/v1.17/velero-install.md | 58 ++ .../docs/v1.17/volume-group-snapshots.md | 379 +++++++++ site/content/docs/v1.17/website-guidelines.md | 45 + site/data/docs/toc-mapping.yml | 1 + site/data/docs/v1-17-toc.yml | 123 +++ 90 files changed, 10696 insertions(+), 1 deletion(-) create mode 100644 site/content/docs/v1.17/_index.md create mode 100644 site/content/docs/v1.17/api-types/README.md create mode 100644 site/content/docs/v1.17/api-types/_index.md create mode 100644 site/content/docs/v1.17/api-types/backup.md create mode 100644 site/content/docs/v1.17/api-types/backupstoragelocation.md create mode 100644 site/content/docs/v1.17/api-types/restore.md create mode 100644 site/content/docs/v1.17/api-types/schedule.md create mode 100644 site/content/docs/v1.17/api-types/volumesnapshotlocation.md create mode 100644 site/content/docs/v1.17/backup-hooks.md create mode 100644 site/content/docs/v1.17/backup-reference.md create mode 100644 site/content/docs/v1.17/backup-repository-configuration.md create mode 100644 site/content/docs/v1.17/backup-restore-windows.md create mode 100644 site/content/docs/v1.17/basic-install.md create mode 100644 site/content/docs/v1.17/build-from-source.md create mode 100644 site/content/docs/v1.17/code-standards.md create mode 100644 site/content/docs/v1.17/contributions/ibm-config.md create mode 100644 site/content/docs/v1.17/contributions/img-for-tencent/15ccaacf00640a04ae29ceed4c86195b.png create mode 100644 site/content/docs/v1.17/contributions/img-for-tencent/1d53b0115644d43657c2a5ece805c9b4.png create mode 100644 site/content/docs/v1.17/contributions/img-for-tencent/69194157ccd5e377d1e7d914fd8c0336.png create mode 100644 site/content/docs/v1.17/contributions/img-for-tencent/9015313121ed7987558c88081b052574.png create mode 100644 site/content/docs/v1.17/contributions/img-for-tencent/ceaca9ce6bc92bdce987c63d2fe71561.png create mode 100644 site/content/docs/v1.17/contributions/img-for-tencent/e8c2ab4e5e31d1370c62fad25059a8a8.png create mode 100644 site/content/docs/v1.17/contributions/img-for-tencent/e932223585c0b19891cc085ad7f438e1.png create mode 100644 site/content/docs/v1.17/contributions/img-for-tencent/eb2bbabae48b188748f5278bedf177f1.png create mode 100644 site/content/docs/v1.17/contributions/img-for-tencent/effe8a0a7ce3aa8e422db00bfdddc375.png create mode 100644 site/content/docs/v1.17/contributions/img-for-tencent/f0fff5228527edc72d6e71a50d5dc966.png create mode 100644 site/content/docs/v1.17/contributions/minio.md create mode 100644 site/content/docs/v1.17/contributions/oracle-config.md create mode 100644 site/content/docs/v1.17/contributions/tencent-config.md create mode 100644 site/content/docs/v1.17/csi-snapshot-data-movement.md create mode 100644 site/content/docs/v1.17/csi.md create mode 100644 site/content/docs/v1.17/custom-plugins.md create mode 100644 site/content/docs/v1.17/customize-installation.md create mode 100644 site/content/docs/v1.17/data-movement-backup-pvc-configuration.md create mode 100644 site/content/docs/v1.17/data-movement-node-selection.md create mode 100644 site/content/docs/v1.17/data-movement-pod-resource-configuration.md create mode 100644 site/content/docs/v1.17/data-movement-restore-pvc-configuration.md create mode 100644 site/content/docs/v1.17/debugging-install.md create mode 100644 site/content/docs/v1.17/debugging-restores.md create mode 100644 site/content/docs/v1.17/development.md create mode 100644 site/content/docs/v1.17/disaster-case.md create mode 100644 site/content/docs/v1.17/enable-api-group-versions-feature.md create mode 100644 site/content/docs/v1.17/examples.md create mode 100644 site/content/docs/v1.17/file-system-backup.md create mode 100644 site/content/docs/v1.17/how-velero-works.md create mode 100644 site/content/docs/v1.17/image-tagging.md create mode 100644 site/content/docs/v1.17/img/README.md create mode 100644 site/content/docs/v1.17/img/backup-process.png create mode 100644 site/content/docs/v1.17/img/gv_priority1-caseA.png create mode 100644 site/content/docs/v1.17/img/gv_priority1-caseB.png create mode 100644 site/content/docs/v1.17/img/gv_priority2-caseC.png create mode 100644 site/content/docs/v1.17/img/gv_priority3-caseD.png create mode 100644 site/content/docs/v1.17/img/velero.png create mode 100644 site/content/docs/v1.17/locations.md create mode 100644 site/content/docs/v1.17/maintainers.md create mode 100644 site/content/docs/v1.17/manual-testing.md create mode 100644 site/content/docs/v1.17/migration-case.md create mode 100644 site/content/docs/v1.17/namespace.md create mode 100644 site/content/docs/v1.17/node-agent-concurrency.md create mode 100644 site/content/docs/v1.17/node-agent-prepare-queue-length.md create mode 100644 site/content/docs/v1.17/on-premises.md create mode 100644 site/content/docs/v1.17/output-file-format.md create mode 100644 site/content/docs/v1.17/overview-plugins.md create mode 100644 site/content/docs/v1.17/performance-guidance.md create mode 100644 site/content/docs/v1.17/plugin-release-instructions.md create mode 100644 site/content/docs/v1.17/proxy.md create mode 100644 site/content/docs/v1.17/rbac.md create mode 100644 site/content/docs/v1.17/release-instructions.md create mode 100644 site/content/docs/v1.17/release-schedule.md create mode 100644 site/content/docs/v1.17/repository-maintenance.md create mode 100644 site/content/docs/v1.17/resource-filtering.md create mode 100644 site/content/docs/v1.17/restore-hooks.md create mode 100644 site/content/docs/v1.17/restore-reference.md create mode 100644 site/content/docs/v1.17/restore-resource-modifiers.md create mode 100644 site/content/docs/v1.17/run-locally.md create mode 100644 site/content/docs/v1.17/self-signed-certificates.md create mode 100644 site/content/docs/v1.17/start-contributing.md create mode 100644 site/content/docs/v1.17/style-guide.md create mode 100644 site/content/docs/v1.17/support-process.md create mode 100644 site/content/docs/v1.17/supported-providers.md create mode 100644 site/content/docs/v1.17/tilt.md create mode 100644 site/content/docs/v1.17/troubleshooting.md create mode 100644 site/content/docs/v1.17/uninstalling.md create mode 100644 site/content/docs/v1.17/upgrade-to-1.17.md create mode 100644 site/content/docs/v1.17/velero-install.md create mode 100644 site/content/docs/v1.17/volume-group-snapshots.md create mode 100644 site/content/docs/v1.17/website-guidelines.md create mode 100644 site/data/docs/v1-17-toc.yml diff --git a/site/config.yaml b/site/config.yaml index ba2e55b0d..c7f25f9ad 100644 --- a/site/config.yaml +++ b/site/config.yaml @@ -12,9 +12,10 @@ params: hero: backgroundColor: med-blue versioning: true - latest: v1.16 + latest: v1.17 versions: - main + - v1.17 - v1.16 - v1.15 - v1.14 diff --git a/site/content/docs/v1.17/_index.md b/site/content/docs/v1.17/_index.md new file mode 100644 index 000000000..971fbdcce --- /dev/null +++ b/site/content/docs/v1.17/_index.md @@ -0,0 +1,58 @@ +--- +toc: "false" +cascade: + version: v1.17 + toc: "true" +--- +![100] + +[![Build Status][1]][2] + +## Overview + +Velero (formerly Heptio Ark) gives you tools to back up and restore your Kubernetes cluster resources and persistent volumes. You can run Velero with a cloud provider or on-premises. Velero lets you: + +* Take backups of your cluster and restore in case of loss. +* Migrate cluster resources to other clusters. +* Replicate your production cluster to development and testing clusters. + +Velero consists of: + +* A server that runs on your cluster +* A command-line client that runs locally + +## Documentation + +This site is our documentation home with installation instructions, plus information about customizing Velero for your needs, architecture, extending Velero, contributing to Velero and more. + +Please use the version selector at the top of the site to ensure you are using the appropriate documentation for your version of Velero. + +## Troubleshooting + +If you encounter issues, review the [troubleshooting docs][30], [file an issue][4], or talk to us on the [#velero-users channel][25] on the Kubernetes Slack server. + +## Contributing + +If you are ready to jump in and test, add code, or help with documentation, follow the instructions on our [Start contributing](https://velero.io/docs/v1.17.0/start-contributing/) documentation for guidance on how to setup Velero for development. + +## Changelog + +See [the list of releases][6] to find out about feature changes. + +[1]: https://github.com/vmware-tanzu/velero/workflows/Main%20CI/badge.svg +[2]: https://github.com/vmware-tanzu/velero/actions?query=workflow%3A"Main+CI" + +[4]: https://github.com/vmware-tanzu/velero/issues +[6]: https://github.com/vmware-tanzu/velero/releases + +[9]: https://kubernetes.io/docs/setup/ +[10]: https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-with-homebrew-on-macos +[11]: https://kubernetes.io/docs/tasks/tools/install-kubectl/#tabset-1 +[12]: https://github.com/kubernetes/kubernetes/blob/main/cluster/addons/dns/README.md +[14]: https://github.com/kubernetes/kubernetes +[24]: https://groups.google.com/forum/#!forum/projectvelero +[25]: https://kubernetes.slack.com/messages/velero-users + +[30]: troubleshooting.md + +[100]: img/velero.png diff --git a/site/content/docs/v1.17/api-types/README.md b/site/content/docs/v1.17/api-types/README.md new file mode 100644 index 000000000..54c23544d --- /dev/null +++ b/site/content/docs/v1.17/api-types/README.md @@ -0,0 +1,21 @@ +--- +title: "Table of Contents" +layout: docs +--- + +## API types + +Here we list the API types that have some functionality that you can only configure via json/yaml vs the `velero` cli +(hooks) + +* [Backup][1] +* [Restore][2] +* [Schedule][3] +* [BackupStorageLocation][4] +* [VolumeSnapshotLocation][5] + +[1]: backup.md +[2]: restore.md +[3]: schedule.md +[4]: backupstoragelocation.md +[5]: volumesnapshotlocation.md diff --git a/site/content/docs/v1.17/api-types/_index.md b/site/content/docs/v1.17/api-types/_index.md new file mode 100644 index 000000000..e60832500 --- /dev/null +++ b/site/content/docs/v1.17/api-types/_index.md @@ -0,0 +1,19 @@ +--- +layout: docs +title: API types +--- + +Here's a list the API types that have some functionality that you can only configure via json/yaml vs the `velero` cli +(hooks) + +* [Backup][1] +* [Restore][2] +* [Schedule][3] +* [BackupStorageLocation][4] +* [VolumeSnapshotLocation][5] + +[1]: backup.md +[2]: restore.md +[3]: schedule.md +[4]: backupstoragelocation.md +[5]: volumesnapshotlocation.md diff --git a/site/content/docs/v1.17/api-types/backup.md b/site/content/docs/v1.17/api-types/backup.md new file mode 100644 index 000000000..1768f0934 --- /dev/null +++ b/site/content/docs/v1.17/api-types/backup.md @@ -0,0 +1,211 @@ +--- +title: "Backup API Type" +layout: docs +--- + +## Use + +Use the `Backup` API type to request the Velero server to perform a backup. Once created, the +Velero Server immediately starts the backup process. + +## API GroupVersion + +Backup belongs to the API group version `velero.io/v1`. + +## Definition + +Here is a sample `Backup` object with each of the fields documented: + +```yaml +# Standard Kubernetes API Version declaration. Required. +apiVersion: velero.io/v1 +# Standard Kubernetes Kind declaration. Required. +kind: Backup +# Standard Kubernetes metadata. Required. +metadata: + # Backup name. May be any valid Kubernetes object name. Required. + name: a + # Backup namespace. Must be the namespace of the Velero server. Required. + namespace: velero +# Parameters about the backup. Required. +spec: + # CSISnapshotTimeout specifies the time used to wait for + # CSI VolumeSnapshot status turns to ReadyToUse during creation, before + # returning error as timeout. The default value is 10 minute. + csiSnapshotTimeout: 10m + # ItemOperationTimeout specifies the time used to wait for + # asynchronous BackupItemAction operations + # The default value is 4 hour. + itemOperationTimeout: 4h + # resourcePolicy specifies the referenced resource policies that backup should follow + # optional + resourcePolicy: + kind: configmap + name: resource-policy-configmap + # Array of namespaces to include in the backup. If unspecified, all namespaces are included. + # Optional. + includedNamespaces: + - '*' + # Array of namespaces to exclude from the backup. Optional. + excludedNamespaces: + - some-namespace + # Array of resources to include in the backup. Resources may be shortcuts (for example 'po' for 'pods') + # or fully-qualified. If unspecified, all resources are included. Optional. + includedResources: + - '*' + # Array of resources to exclude from the backup. Resources may be shortcuts (for example 'po' for 'pods') + # or fully-qualified. Optional. + excludedResources: + - storageclasses.storage.k8s.io + # Order of the resources to be collected during the backup process. It's a map with key being the plural resource + # name, and the value being a list of object names separated by comma. Each resource name has format "namespace/objectname". + # For cluster resources, simply use "objectname". Optional + orderedResources: + pods: mysql/mysql-cluster-replica-0,mysql/mysql-cluster-replica-1,mysql/mysql-cluster-source-0 + persistentvolumes: pvc-87ae0832-18fd-4f40-a2a4-5ed4242680c4,pvc-63be1bb0-90f5-4629-a7db-b8ce61ee29b3 + # Whether to include cluster-scoped resources. Valid values are true, false, and + # null/unset. If true, all cluster-scoped resources are included (subject to included/excluded + # resources and the label selector). If false, no cluster-scoped resources are included. If unset, + # all cluster-scoped resources are included if and only if all namespaces are included and there are + # no excluded namespaces. Otherwise, if there is at least one namespace specified in either + # includedNamespaces or excludedNamespaces, then the only cluster-scoped resources that are backed + # up are those associated with namespace-scoped resources included in the backup. For example, if a + # PersistentVolumeClaim is included in the backup, its associated PersistentVolume (which is + # cluster-scoped) would also be backed up. + includeClusterResources: null + # Array of cluster-scoped resources to exclude from the backup. Resources may be shortcuts + # (for example 'sc' for 'storageclasses'), or fully-qualified. If unspecified, + # no additional cluster-scoped resources are excluded. Optional. + # Cannot work with include-resources, exclude-resources and include-cluster-resources. + excludedClusterScopedResources: {} + # Array of cluster-scoped resources to include from the backup. Resources may be shortcuts + # (for example 'sc' for 'storageclasses'), or fully-qualified. If unspecified, + # no additional cluster-scoped resources are included. Optional. + # Cannot work with include-resources, exclude-resources and include-cluster-resources. + includedClusterScopedResources: {} + # Array of namespace-scoped resources to exclude from the backup. Resources may be shortcuts + # (for example 'cm' for 'configmaps'), or fully-qualified. If unspecified, + # no namespace-scoped resources are excluded. Optional. + # Cannot work with include-resources, exclude-resources and include-cluster-resources. + excludedNamespaceScopedResources: {} + # Array of namespace-scoped resources to include from the backup. Resources may be shortcuts + # (for example 'cm' for 'configmaps'), or fully-qualified. If unspecified, + # all namespace-scoped resources are included. Optional. + # Cannot work with include-resources, exclude-resources and include-cluster-resources. + includedNamespaceScopedResources: {} + # Individual objects must match this label selector to be included in the backup. Optional. + labelSelector: + matchLabels: + app: velero + component: server + # Individual object when matched with any of the label selector specified in the set are to be included in the backup. Optional. + # orLabelSelectors as well as labelSelector cannot co-exist, only one of them can be specified in the backup request + orLabelSelectors: + - matchLabels: + app: velero + - matchLabels: + app: data-protection + # Whether or not to snapshot volumes. Valid values are true, false, and null/unset. If unset, Velero performs snapshots as long as + # a persistent volume provider is configured for Velero. + snapshotVolumes: null + # Where to store the tarball and logs. + storageLocation: aws-primary + # The list of locations in which to store volume snapshots created for this backup. + volumeSnapshotLocations: + - aws-primary + - gcp-primary + # The amount of time before this backup is eligible for garbage collection. If not specified, + # a default value of 30 days will be used. The default can be configured on the velero server + # by passing the flag --default-backup-ttl. + ttl: 24h0m0s + # whether pod volume file system backup should be used for all volumes by default. + defaultVolumesToFsBackup: true + # Whether snapshot data should be moved. If set, data movement is launched after the snapshot is created. + snapshotMoveData: true + # The data mover to be used by the backup. If the value is "" or "velero", the built-in data mover will be used. + datamover: velero + # UploaderConfig specifies the configuration for the uploader + uploaderConfig: + # ParallelFilesUpload is the number of files parallel uploads to perform when using the uploader. + parallelFilesUpload: 10 + # Actions to perform at different times during a backup. The only hook supported is + # executing a command in a container in a pod using the pod exec API. Optional. + hooks: + # Array of hooks that are applicable to specific resources. Optional. + resources: + - + # Name of the hook. Will be displayed in backup log. + name: my-hook + # Array of namespaces to which this hook applies. If unspecified, the hook applies to all + # namespaces. Optional. + includedNamespaces: + - '*' + # Array of namespaces to which this hook does not apply. Optional. + excludedNamespaces: + - some-namespace + # Array of resources to which this hook applies. The only resource supported at this time is + # pods. + includedResources: + - pods + # Array of resources to which this hook does not apply. Optional. + excludedResources: [] + # This hook only applies to objects matching this label selector. Optional. + labelSelector: + matchLabels: + app: velero + component: server + # An array of hooks to run before executing custom actions. Only "exec" hooks are supported. + pre: + - + # The type of hook. This must be "exec". + exec: + # The name of the container where the command will be executed. If unspecified, the + # first container in the pod will be used. Optional. + container: my-container + # The command to execute, specified as an array. Required. + command: + - /bin/uname + - -a + # How to handle an error executing the command. Valid values are Fail and Continue. + # Defaults to Fail. Optional. + onError: Fail + # How long to wait for the command to finish executing. Defaults to 30 seconds. Optional. + timeout: 10s + # An array of hooks to run after all custom actions and additional items have been + # processed. Only "exec" hooks are supported. + post: + # Same content as pre above. +# Status about the Backup. Users should not set any data here. +status: + # The version of this Backup. The only version supported is 1. + version: 1 + # The date and time when the Backup is eligible for garbage collection. + expiration: null + # The current phase. + # Valid values are New, FailedValidation, InProgress, WaitingForPluginOperations, + # WaitingForPluginOperationsPartiallyFailed, FinalizingafterPluginOperations, + # FinalizingPartiallyFailed, Completed, PartiallyFailed, Failed. + phase: "" + # An array of any validation errors encountered. + validationErrors: null + # Date/time when the backup started being processed. + startTimestamp: 2019-04-29T15:58:43Z + # Date/time when the backup finished being processed. + completionTimestamp: 2019-04-29T15:58:56Z + # Number of volume snapshots that Velero tried to create for this backup. + volumeSnapshotsAttempted: 2 + # Number of volume snapshots that Velero successfully created for this backup. + volumeSnapshotsCompleted: 1 + # Number of attempted BackupItemAction operations for this backup. + backupItemOperationsAttempted: 2 + # Number of BackupItemAction operations that Velero successfully completed for this backup. + backupItemOperationsCompleted: 1 + # Number of BackupItemAction operations that ended in failure for this backup. + backupItemOperationsFailed: 0 + # Number of warnings that were logged by the backup. + warnings: 2 + # Number of errors that were logged by the backup. + errors: 0 + # An error that caused the entire backup to fail. + failureReason: "" +``` diff --git a/site/content/docs/v1.17/api-types/backupstoragelocation.md b/site/content/docs/v1.17/api-types/backupstoragelocation.md new file mode 100644 index 000000000..974d120b3 --- /dev/null +++ b/site/content/docs/v1.17/api-types/backupstoragelocation.md @@ -0,0 +1,75 @@ +--- +title: "Velero Backup Storage Locations" +layout: docs +--- + +## Backup Storage Location + +Velero can store backups in a number of locations. These are represented in the cluster via the `BackupStorageLocation` CRD. + +Velero must have at least one `BackupStorageLocation`. By default, this is expected to be named `default`, however the name can be changed by specifying `--default-backup-storage-location` on `velero server`. Backups that do not explicitly specify a storage location will be saved to this `BackupStorageLocation`. + +A sample YAML `BackupStorageLocation` looks like the following: + +```yaml +apiVersion: velero.io/v1 +kind: BackupStorageLocation +metadata: + name: default + namespace: velero +spec: + backupSyncPeriod: 2m0s + provider: aws + objectStorage: + bucket: myBucket + credential: + name: secret-name + key: key-in-secret + config: + region: us-west-2 + profile: "default" +``` + +### Example with self-signed certificate + +When using object storage with self-signed certificates, you can specify the CA certificate: + +```yaml +apiVersion: velero.io/v1 +kind: BackupStorageLocation +metadata: + name: default + namespace: velero +spec: + provider: aws + objectStorage: + bucket: velero-backups + # Base64 encoded CA certificate + caCert: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR1VENDQXFHZ0F3SUJBZ0lVTWRiWkNaYnBhcE9lYThDR0NMQnhhY3dVa213d0RRWUpLb1pJaHZjTkFRRUwKQlFBd2JERUxNQWtHQTFVRUJoTUNWVk14RXpBUkJnTlZCQWdNQ2tOaGJHbG1iM0p1YVdFeEZqQVVCZ05WQkFjTQpEVk5oYmlCR2NtRnVZMmx6WTI4eEdEQVdCZ05WQkFvTUQwVjRZVzF3YkdVZ1EyOXRjR0Z1ZVRFV01CUUdBMVVFCkF3d05aWGhoYlhCc1pTNXNiMk5oYkRBZUZ3MHlNekEzTVRBeE9UVXlNVGhhRncweU5EQTNNRGt4T1RVeU1UaGEKTUd3eEN6QUpCZ05WQkFZVEFsVlRNUk13RVFZRFZRUUNEQXBEWEJ4cG1iM0p1YVdFeEZqQVVCZ05WQkFjTURWTmgKYmlCR2NtRnVZMmx6WTI4eEdEQVdCZ05WQkFvTUQwVjRZVzF3YkdVZ1EyOXRjR0Z1ZVRFV01CUUdBMVVFQXd3TgpaWGhoYlhCc1pTNXNiMk5oYkRDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBS1dqCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + config: + region: us-east-1 + s3Url: https://minio.example.com +``` + +### Parameter Reference + +The configurable parameters are as follows: + +#### Main config parameters + +{{< table caption="Main config parameters" >}} +| Key | Type | Default | Meaning | +| --- | --- | --- | --- | +| `provider` | String | Required Field | The name for whichever object storage provider will be used to store the backups. See [your object storage provider's plugin documentation](../supported-providers) for the appropriate value to use. | +| `objectStorage` | ObjectStorageLocation | Required Field | Specification of the object storage for the given provider. | +| `objectStorage/bucket` | String | Required Field | The storage bucket where backups are to be uploaded. | +| `objectStorage/prefix` | String | Optional Field | The directory inside a storage bucket where backups are to be uploaded. | +| `objectStorage/caCert` | String | Optional Field | A base64 encoded CA bundle to be used when verifying TLS connections | +| `config` | map[string]string | None (Optional) | Provider-specific configuration keys/values to be passed to the object store plugin. See [your object storage provider's plugin documentation](../supported-providers) for details. | +| `accessMode` | String | `ReadWrite` | How Velero can access the backup storage location. Valid values are `ReadWrite`, `ReadOnly`. | +| `backupSyncPeriod` | metav1.Duration | Optional Field | How frequently Velero should synchronize backups in object storage. Default is Velero's server backup sync period. Set this to `0s` to disable sync. | +| `validationFrequency` | metav1.Duration | Optional Field | How frequently Velero should validate the object storage . Default is Velero's server validation frequency. Set this to `0s` to disable validation. Default 1 minute. | +| `credential` | [corev1.SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#secretkeyselector-v1-core) | Optional Field | The credential information to be used with this location. | +| `credential/name` | String | Optional Field | The name of the secret within the Velero namespace which contains the credential information. | +| `credential/key` | String | Optional Field | The key to use within the secret. | +{{< /table >}} diff --git a/site/content/docs/v1.17/api-types/restore.md b/site/content/docs/v1.17/api-types/restore.md new file mode 100644 index 000000000..ec3e19511 --- /dev/null +++ b/site/content/docs/v1.17/api-types/restore.md @@ -0,0 +1,219 @@ +--- +title: "Restore API Type" +layout: docs +--- + +## Use + +The `Restore` API type is used as a request for the Velero server to perform a Restore. Once created, the +Velero Server immediately starts the Restore process. + +## API GroupVersion + +Restore belongs to the API group version `velero.io/v1`. + +## Definition + +Here is a sample `Restore` object with each of the fields documented: + +```yaml +# Standard Kubernetes API Version declaration. Required. +apiVersion: velero.io/v1 +# Standard Kubernetes Kind declaration. Required. +kind: Restore +# Standard Kubernetes metadata. Required. +metadata: + # Restore name. May be any valid Kubernetes object name. Required. + name: a-very-special-backup-0000111122223333 + # Restore namespace. Must be the namespace of the Velero server. Required. + namespace: velero +# Parameters about the restore. Required. +spec: + # The unique name of the Velero backup to restore from. + backupName: a-very-special-backup + # The unique name of the Velero schedule + # to restore from. If specified, and BackupName is empty, Velero will + # restore from the most recent successful backup created from this schedule. + scheduleName: my-scheduled-backup-name + # ItemOperationTimeout specifies the time used to wait for + # asynchronous BackupItemAction operations + # The default value is 4 hour. + itemOperationTimeout: 4h + # UploaderConfig specifies the configuration for the restore. + uploaderConfig: + # WriteSparseFiles is a flag to indicate whether write files sparsely or not + writeSparseFiles: true + # ParallelFilesDownload is the concurrency number setting for restore + parallelFilesDownload: 10 + # Array of namespaces to include in the restore. If unspecified, all namespaces are included. + # Optional. + includedNamespaces: + - '*' + # Array of namespaces to exclude from the restore. Optional. + excludedNamespaces: + - some-namespace + # Array of resources to include in the restore. Resources may be shortcuts (for example 'po' for 'pods') + # or fully-qualified. If unspecified, all resources are included. Optional. + includedResources: + - '*' + # Array of resources to exclude from the restore. Resources may be shortcuts (for example 'po' for 'pods') + # or fully-qualified. Optional. + excludedResources: + - storageclasses.storage.k8s.io + + # restoreStatus selects resources to restore not only the specification, but + # the status of the manifest. This is specially useful for CRDs that maintain + # external references. By default, it excludes all resources. + restoreStatus: + # Array of resources to include in the restore status. Just like above, + # resources may be shortcuts (for example 'po' for 'pods') or fully-qualified. + # If unspecified, no resources are included. Optional. + includedResources: + - workflows + # Array of resources to exclude from the restore status. Resources may be + # shortcuts (for example 'po' for 'pods') or fully-qualified. + # If unspecified, all resources are excluded. Optional. + excludedResources: [] + + # Whether or not to include cluster-scoped resources. Valid values are true, false, and + # null/unset. If true, all cluster-scoped resources are included (subject to included/excluded + # resources and the label selector). If false, no cluster-scoped resources are included. If unset, + # all cluster-scoped resources are included if and only if all namespaces are included and there are + # no excluded namespaces. Otherwise, if there is at least one namespace specified in either + # includedNamespaces or excludedNamespaces, then the only cluster-scoped resources that are backed + # up are those associated with namespace-scoped resources included in the restore. For example, if a + # PersistentVolumeClaim is included in the restore, its associated PersistentVolume (which is + # cluster-scoped) would also be backed up. + includeClusterResources: null + # Individual objects must match this label selector to be included in the restore. Optional. + labelSelector: + matchLabels: + app: velero + component: server + # Individual object when matched with any of the label selector specified in the set are to be included in the restore. Optional. + # orLabelSelectors as well as labelSelector cannot co-exist, only one of them can be specified in the restore request + orLabelSelectors: + - matchLabels: + app: velero + - matchLabels: + app: data-protection + # namespaceMapping is a map of source namespace names to + # target namespace names to restore into. Any source namespaces not + # included in the map will be restored into namespaces of the same name. + namespaceMapping: + namespace-backup-from: namespace-to-restore-to + # restorePVs specifies whether to restore all included PVs + # from snapshot. Optional + restorePVs: true + # preserveNodePorts specifies whether to restore old nodePorts from backup, + # so that the exposed port numbers on the node will remain the same after restore. Optional + preserveNodePorts: true + # existingResourcePolicy specifies the restore behaviour + # for the Kubernetes resource to be restored. Optional + existingResourcePolicy: none + # ResourceModifier specifies the reference to JSON resource patches + # that should be applied to resources before restoration. Optional + resourceModifier: + kind: ConfigMap + name: resource-modifier-configmap + # Actions to perform during or post restore. The only hooks currently supported are + # adding an init container to a pod before it can be restored and executing a command in a + # restored pod's container. Optional. + hooks: + # Array of hooks that are applicable to specific resources. Optional. + resources: + # Name is the name of this hook. + - name: restore-hook-1 + # Array of namespaces to which this hook applies. If unspecified, the hook applies to all + # namespaces. Optional. + includedNamespaces: + - ns1 + # Array of namespaces to which this hook does not apply. Optional. + excludedNamespaces: + - ns3 + # Array of resources to which this hook applies. If unspecified, the hook applies to all resources in the backup. Optional. + # The only resource supported at this time is pods. + includedResources: + - pods + # Array of resources to which this hook does not apply. Optional. + excludedResources: [] + # This hook only applies to objects matching this label selector. Optional. + labelSelector: + matchLabels: + app: velero + component: server + # An array of hooks to run during or after restores. Currently only "init" and "exec" hooks + # are supported. + postHooks: + # The type of the hook. This must be "init" or "exec". + - init: + # An array of container specs to be added as init containers to pods to which this hook applies to. + initContainers: + - name: restore-hook-init1 + image: alpine:latest + # Mounting volumes from the podSpec to which this hooks applies to. + volumeMounts: + - mountPath: /restores/pvc1-vm + # Volume name from the podSpec + name: pvc1-vm + command: + - /bin/ash + - -c + - echo -n "FOOBARBAZ" >> /restores/pvc1-vm/foobarbaz + - name: restore-hook-init2 + image: alpine:latest + # Mounting volumes from the podSpec to which this hooks applies to. + volumeMounts: + - mountPath: /restores/pvc2-vm + # Volume name from the podSpec + name: pvc2-vm + command: + - /bin/ash + - -c + - echo -n "DEADFEED" >> /restores/pvc2-vm/deadfeed + - exec: + # The container name where the hook will be executed. Defaults to the first container. + # Optional. + container: foo + # The command that will be executed in the container. Required. + command: + - /bin/bash + - -c + - "psql < /backup/backup.sql" + # How long to wait for a container to become ready. This should be long enough for the + # container to start plus any preceding hooks in the same container to complete. The wait + # timeout begins when the container is restored and may require time for the image to pull + # and volumes to mount. If not set the restore will wait indefinitely. Optional. + waitTimeout: 5m + # How long to wait once execution begins. Defaults to 30 seconds. Optional. + execTimeout: 1m + # How to handle execution failures. Valid values are `Fail` and `Continue`. Defaults to + # `Continue`. With `Continue` mode, execution failures are logged only. With `Fail` mode, + # no more restore hooks will be executed in any container in any pod and the status of the + # Restore will be `PartiallyFailed`. Optional. + onError: Continue +# RestoreStatus captures the current status of a Velero restore. Users should not set any data here. +status: + # The current phase. + # Valid values are New, FailedValidation, InProgress, WaitingForPluginOperations, + # WaitingForPluginOperationsPartiallyFailed, Completed, PartiallyFailed, Failed. + phase: "" + # An array of any validation errors encountered. + validationErrors: null + # Number of attempted RestoreItemAction operations for this restore. + restoreItemOperationsAttempted: 2 + # Number of RestoreItemAction operations that Velero successfully completed for this restore. + restoreItemOperationsCompleted: 1 + # Number of RestoreItemAction operations that ended in failure for this restore. + restoreItemOperationsFailed: 0 + # Number of warnings that were logged by the restore. + warnings: 2 + # Errors is a count of all error messages that were generated + # during execution of the restore. The actual errors are stored in object + # storage. + errors: 0 + # FailureReason is an error that caused the entire restore + # to fail. + failureReason: + +``` diff --git a/site/content/docs/v1.17/api-types/schedule.md b/site/content/docs/v1.17/api-types/schedule.md new file mode 100644 index 000000000..c89fe60d7 --- /dev/null +++ b/site/content/docs/v1.17/api-types/schedule.md @@ -0,0 +1,216 @@ +--- +title: "Schedule API Type" +layout: docs +--- + +## Use + +The `Schedule` API type is used as a repeatable request for the Velero server to perform a backup for a given cron notation. Once created, the +Velero Server will start the backup process. It will then wait for the next valid point of the given cron expression and execute the backup +process on a repeating basis. + +### Schedule Control Fields + +The Schedule API provides several fields to control backup execution behavior: + +- **paused**: When set to `true`, the schedule is paused and no new backups will be created. When set back to `false`, the schedule is unpaused and will resume creating backups according to the cron schedule. + +- **skipImmediately**: Controls whether to skip an immediate backup when a schedule is created or unpaused. By default (when `false`), if a backup is due immediately upon creation or unpausing, it will be executed right away. When set to `true`, the controller will: + 1. Skip the immediate backup + 2. Record the current time in the `lastSkipped` status field + 3. Automatically reset `skipImmediately` back to `false` (one-time use) + 4. Schedule the next backup based on the cron expression, using `lastSkipped` as the reference time + +- **lastSkipped**: A status field (not directly settable) that records when a backup was last skipped due to `skipImmediately` being `true`. The controller uses this timestamp, if more recent than `lastBackup`, to calculate the next scheduled backup time. + +This "consume and reset" pattern for `skipImmediately` ensures that after skipping one immediate backup, the schedule returns to normal behavior for subsequent runs without requiring user intervention. + +## API GroupVersion + +Schedule belongs to the API group version `velero.io/v1`. + +## Definition + +Here is a sample `Schedule` object with each of the fields documented: + +```yaml +# Standard Kubernetes API Version declaration. Required. +apiVersion: velero.io/v1 +# Standard Kubernetes Kind declaration. Required. +kind: Schedule +# Standard Kubernetes metadata. Required. +metadata: + # Schedule name. May be any valid Kubernetes object name. Required. + name: a + # Schedule namespace. Must be the namespace of the Velero server. Required. + namespace: velero +# Parameters about the scheduled backup. Required. +spec: + # Paused specifies whether the schedule is paused or not + paused: false + # SkipImmediately specifies whether to skip backup if schedule is due immediately when unpaused or created. + # This is a one-time flag that will be automatically reset to false after being consumed. + # When true, the controller will skip the immediate backup, set LastSkipped timestamp, and reset this to false. + skipImmediately: false + # Schedule is a Cron expression defining when to run the Backup + schedule: 0 7 * * * + # Specifies whether to use OwnerReferences on backups created by this Schedule. + # Notice: if set to true, when schedule is deleted, backups will be deleted too. Optional. + useOwnerReferencesInBackup: false + # Template is the spec that should be used for each backup triggered by this schedule. + template: + # CSISnapshotTimeout specifies the time used to wait for + # CSI VolumeSnapshot status turns to ReadyToUse during creation, before + # returning error as timeout. The default value is 10 minute. + csiSnapshotTimeout: 10m + # resourcePolicy specifies the referenced resource policies that backup should follow + # optional + resourcePolicy: + kind: configmap + name: resource-policy-configmap + # Array of namespaces to include in the scheduled backup. If unspecified, all namespaces are included. + # Optional. + includedNamespaces: + - '*' + # Array of namespaces to exclude from the scheduled backup. Optional. + excludedNamespaces: + - some-namespace + # Array of resources to include in the scheduled backup. Resources may be shortcuts (for example 'po' for 'pods') + # or fully-qualified. If unspecified, all resources are included. Optional. + includedResources: + - '*' + # Array of resources to exclude from the scheduled backup. Resources may be shortcuts (for example 'po' for 'pods') + # or fully-qualified. Optional. + excludedResources: + - storageclasses.storage.k8s.io + orderedResources: + pods: mysql/mysql-cluster-replica-0,mysql/mysql-cluster-replica-1,mysql/mysql-cluster-source-0 + persistentvolumes: pvc-87ae0832-18fd-4f40-a2a4-5ed4242680c4,pvc-63be1bb0-90f5-4629-a7db-b8ce61ee29b3 + # Whether to include cluster-scoped resources. Valid values are true, false, and + # null/unset. If true, all cluster-scoped resources are included (subject to included/excluded + # resources and the label selector). If false, no cluster-scoped resources are included. If unset, + # all cluster-scoped resources are included if and only if all namespaces are included and there are + # no excluded namespaces. Otherwise, if there is at least one namespace specified in either + # includedNamespaces or excludedNamespaces, then the only cluster-scoped resources that are backed + # up are those associated with namespace-scoped resources included in the scheduled backup. For example, if a + # PersistentVolumeClaim is included in the backup, its associated PersistentVolume (which is + # cluster-scoped) would also be backed up. + includeClusterResources: null + # Array of cluster-scoped resources to exclude from the backup. Resources may be shortcuts + # (for example 'sc' for 'storageclasses'), or fully-qualified. If unspecified, + # no additional cluster-scoped resources are excluded. Optional. + # Cannot work with include-resources, exclude-resources and include-cluster-resources. + excludedClusterScopedResources: {} + # Array of cluster-scoped resources to include from the backup. Resources may be shortcuts + # (for example 'sc' for 'storageclasses'), or fully-qualified. If unspecified, + # no additional cluster-scoped resources are included. Optional. + # Cannot work with include-resources, exclude-resources and include-cluster-resources. + includedClusterScopedResources: {} + # Array of namespace-scoped resources to exclude from the backup. Resources may be shortcuts + # (for example 'cm' for 'configmaps'), or fully-qualified. If unspecified, + # no namespace-scoped resources are excluded. Optional. + # Cannot work with include-resources, exclude-resources and include-cluster-resources. + excludedNamespaceScopedResources: {} + # Array of namespace-scoped resources to include from the backup. Resources may be shortcuts + # (for example 'cm' for 'configmaps'), or fully-qualified. If unspecified, + # all namespace-scoped resources are included. Optional. + # Cannot work with include-resources, exclude-resources and include-cluster-resources. + includedNamespaceScopedResources: {} + # Individual objects must match this label selector to be included in the scheduled backup. Optional. + labelSelector: + matchLabels: + app: velero + component: server + # Individual object when matched with any of the label selector specified in the set are to be included in the backup. Optional. + # orLabelSelectors as well as labelSelector cannot co-exist, only one of them can be specified in the backup request + orLabelSelectors: + - matchLabels: + app: velero + - matchLabels: + app: data-protection + # Whether to snapshot volumes. Valid values are true, false, and null/unset. If unset, Velero performs snapshots as long as + # a persistent volume provider is configured for Velero. + snapshotVolumes: null + # Where to store the tarball and logs. + storageLocation: aws-primary + # The list of locations in which to store volume snapshots created for backups under this schedule. + volumeSnapshotLocations: + - aws-primary + - gcp-primary + # The amount of time before backups created on this schedule are eligible for garbage collection. If not specified, + # a default value of 30 days will be used. The default can be configured on the velero server + # by passing the flag --default-backup-ttl. + ttl: 24h0m0s + # whether pod volume file system backup should be used for all volumes by default. + defaultVolumesToFsBackup: true + # Whether snapshot data should be moved. If set, data movement is launched after the snapshot is created. + snapshotMoveData: true + # The data mover to be used by the backup. If the value is "" or "velero", the built-in data mover will be used. + datamover: velero + # UploaderConfig specifies the configuration for the uploader + uploaderConfig: + # ParallelFilesUpload is the number of files parallel uploads to perform when using the uploader. + parallelFilesUpload: 10 + # The labels you want on backup objects, created from this schedule (instead of copying the labels you have on schedule object itself). + # When this field is set, the labels from the Schedule resource are not copied to the Backup resource. + metadata: + labels: + labelname: somelabelvalue + # Actions to perform at different times during a backup. The only hook supported is + # executing a command in a container in a pod using the pod exec API. Optional. + hooks: + # Array of hooks that are applicable to specific resources. Optional. + resources: + - + # Name of the hook. Will be displayed in backup log. + name: my-hook + # Array of namespaces to which this hook applies. If unspecified, the hook applies to all + # namespaces. Optional. + includedNamespaces: + - '*' + # Array of namespaces to which this hook does not apply. Optional. + excludedNamespaces: + - some-namespace + # Array of resources to which this hook applies. The only resource supported at this time is + # pods. + includedResources: + - pods + # Array of resources to which this hook does not apply. Optional. + excludedResources: [] + # This hook only applies to objects matching this label selector. Optional. + labelSelector: + matchLabels: + app: velero + component: server + # An array of hooks to run before executing custom actions. Only "exec" hooks are supported. + pre: + - + # The type of hook. This must be "exec". + exec: + # The name of the container where the command will be executed. If unspecified, the + # first container in the pod will be used. Optional. + container: my-container + # The command to execute, specified as an array. Required. + command: + - /bin/uname + - -a + # How to handle an error executing the command. Valid values are Fail and Continue. + # Defaults to Fail. Optional. + onError: Fail + # How long to wait for the command to finish executing. Defaults to 30 seconds. Optional. + timeout: 10s + # An array of hooks to run after all custom actions and additional items have been + # processed. Only "exec" hooks are supported. + post: + # Same content as pre above. +status: + # The current phase. + # Valid values are New, Enabled, FailedValidation. + phase: "" + # Date/time of the last backup for a given schedule + lastBackup: + # Date/time when a backup was last skipped due to skipImmediately being true + lastSkipped: + # An array of any validation errors encountered. + validationErrors: +``` diff --git a/site/content/docs/v1.17/api-types/volumesnapshotlocation.md b/site/content/docs/v1.17/api-types/volumesnapshotlocation.md new file mode 100644 index 000000000..e6758f8fa --- /dev/null +++ b/site/content/docs/v1.17/api-types/volumesnapshotlocation.md @@ -0,0 +1,46 @@ +--- +title: "Velero Volume Snapshot Location" +layout: docs +--- + +## Volume Snapshot Location + +A volume snapshot location is the location in which to store the volume snapshots created for a backup. + +Velero can be configured to take snapshots of volumes from multiple providers. Velero also allows you to configure multiple possible `VolumeSnapshotLocation` per provider, although you can only select one location per provider at backup time. + +Each VolumeSnapshotLocation describes a provider + location. These are represented in the cluster via the `VolumeSnapshotLocation` CRD. Velero must have at least one `VolumeSnapshotLocation` per cloud provider. + +A sample YAML `VolumeSnapshotLocation` looks like the following: + +```yaml +apiVersion: velero.io/v1 +kind: VolumeSnapshotLocation +metadata: + name: aws-default + namespace: velero +spec: + provider: aws + credential: + name: secret-name + key: key-in-secret + config: + region: us-west-2 + profile: "default" +``` + +### Parameter Reference + +The configurable parameters are as follows: + +#### Main config parameters + +{{< table caption="Main config parameters" >}} +| Key | Type | Default | Meaning | +| --- | --- | --- | --- | +| `provider` | String | Required Field | The name for whichever storage provider will be used to create/store the volume snapshots. See [your volume snapshot provider's plugin documentation](../supported-providers) for the appropriate value to use. | +| `config` | map string string | None (Optional) | Provider-specific configuration keys/values to be passed to the volume snapshotter plugin. See [your volume snapshot provider's plugin documentation](../supported-providers) for details. | +| `credential` | [corev1.SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#secretkeyselector-v1-core) | Optional Field | The credential information to be used with this location. | +| `credential/name` | String | Optional Field | The name of the secret within the Velero namespace which contains the credential information. | +| `credential/key` | String | Optional Field | The key to use within the secret. | +{{< /table >}} diff --git a/site/content/docs/v1.17/backup-hooks.md b/site/content/docs/v1.17/backup-hooks.md new file mode 100644 index 000000000..9894f8ec3 --- /dev/null +++ b/site/content/docs/v1.17/backup-hooks.md @@ -0,0 +1,126 @@ +--- +title: "Backup Hooks" +layout: docs +--- + +Velero supports executing commands in containers in pods during a backup. + +## Backup Hooks + +When performing a backup, you can specify one or more commands to execute in a container in a pod +when that pod is being backed up. The commands can be configured to run *before* any custom action +processing ("pre" hooks), or after all custom actions have been completed and any additional items +specified by custom action have been backed up ("post" hooks). Note that hooks are _not_ executed within a shell +on the containers. + +As of Velero 1.15, related items that must be backed up together are grouped into ItemBlocks, and pod hooks run before and after the ItemBlock is backed up. +In particular, this means that if an ItemBlock contains more than one pod (such as in a scenario where an RWX volume is mounted by multiple pods), pre hooks are run for all pods in the ItemBlock, then the items are backed up, then all post hooks are run. + +There are two ways to specify hooks: annotations on the pod itself, and in the Backup spec. + +### Specifying Hooks As Pod Annotations + +You can use the following annotations on a pod to make Velero execute a hook when backing up the pod: + +#### Pre hooks + +* `pre.hook.backup.velero.io/container` + * The container where the command should be executed. Defaults to the first container in the pod. Optional. +* `pre.hook.backup.velero.io/command` + * The command to execute. This command is not executed within a shell by default. If a shell is needed to run your command, include a shell command, like `/bin/sh`, that is supported by the container at the beginning of your command. If you need multiple arguments, specify the command as a JSON array, such as `["/usr/bin/uname", "-a"]`. See [examples of using pre hook commands](#backup-hook-commands-examples). Optional. +* `pre.hook.backup.velero.io/on-error` + * What to do if the command returns a non-zero exit code. Defaults to `Fail`. Valid values are Fail and Continue. Optional. +* `pre.hook.backup.velero.io/timeout` + * How long to wait for the command to execute. The hook is considered in error if the command exceeds the timeout. Defaults to 30s. Optional. + + +#### Post hooks + +* `post.hook.backup.velero.io/container` + * The container where the command should be executed. Default is the first container in the pod. Optional. +* `post.hook.backup.velero.io/command` + * The command to execute. This command is not executed within a shell by default. If a shell is needed to run your command, include a shell command, like `/bin/sh`, that is supported by the container at the beginning of your command. If you need multiple arguments, specify the command as a JSON array, such as `["/usr/bin/uname", "-a"]`. See [examples of using pre hook commands](#backup-hook-commands-examples). Optional. +* `post.hook.backup.velero.io/on-error` + * What to do if the command returns a non-zero exit code. Defaults to `Fail`. Valid values are Fail and Continue. Optional. +* `post.hook.backup.velero.io/timeout` + * How long to wait for the command to execute. The hook is considered in error if the command exceeds the timeout. Defaults to 30s. Optional. + +### Specifying Hooks in the Backup Spec + +Please see the documentation on the [Backup API Type][1] for how to specify hooks in the Backup +spec. + +## Hook Example with fsfreeze + +This examples walks you through using both pre and post hooks for freezing a file system. Freezing the +file system is useful to ensure that all pending disk I/O operations have completed prior to taking a snapshot. + +### Annotations + +The Velero [example/nginx-app/with-pv.yaml][2] serves as an example of adding the pre and post hook annotations directly +to your declarative deployment. Below is an example of what updating an object in place might look like. + +```shell +kubectl annotate pod -n nginx-example -l app=nginx \ + pre.hook.backup.velero.io/command='["/sbin/fsfreeze", "--freeze", "/var/log/nginx"]' \ + pre.hook.backup.velero.io/container=fsfreeze \ + post.hook.backup.velero.io/command='["/sbin/fsfreeze", "--unfreeze", "/var/log/nginx"]' \ + post.hook.backup.velero.io/container=fsfreeze +``` + +Now test the pre and post hooks by creating a backup. You can use the Velero logs to verify that the pre and post +hooks are running and exiting without error. + +```shell +velero backup create nginx-hook-test + +velero backup get nginx-hook-test +velero backup logs nginx-hook-test | grep hookCommand +``` + +## Backup hook commands examples + +### Multiple commands + +To use multiple commands, wrap your target command in a shell and separate them with `;`, `&&`, or other shell conditional constructs. + +```shell + pre.hook.backup.velero.io/command='["/bin/bash", "-c", "echo hello > hello.txt && echo goodbye > goodbye.txt"]' +``` + +#### Using environment variables + +You are able to use environment variables from your pods in your pre and post hook commands by including a shell command before using the environment variable. For example, `MYSQL_ROOT_PASSWORD` is an environment variable defined in pod called `mysql`. To use `MYSQL_ROOT_PASSWORD` in your pre-hook, you'd include a shell, like `/bin/sh`, before calling your environment variable: + +``` +pre: +- exec: + container: mysql + command: + - /bin/sh + - -c + - mysql --password=$MYSQL_ROOT_PASSWORD -e "FLUSH TABLES WITH READ LOCK" + onError: Fail +``` + +Note that the container must support the shell command you use. + +## Backup Hook Execution Results +### Viewing Results + +Velero records the execution results of hooks, allowing users to obtain this information by running the following command: + +```bash +$ velero backup describe +``` + +The displayed results include the number of hooks that were attempted to be executed and the number of hooks that failed execution. Any detailed failure reasons will be present in `Errors` section if applicable. + +```bash +HooksAttempted: 1 +HooksFailed: 0 +``` + + +[1]: api-types/backup.md +[2]: https://github.com/vmware-tanzu/velero/blob/v1.17.0/examples/nginx-app/with-pv.yaml diff --git a/site/content/docs/v1.17/backup-reference.md b/site/content/docs/v1.17/backup-reference.md new file mode 100644 index 000000000..220d97acc --- /dev/null +++ b/site/content/docs/v1.17/backup-reference.md @@ -0,0 +1,167 @@ +--- +title: "Backup Reference" +layout: docs +--- + +## Exclude Specific Items from Backup + +It is possible to exclude individual items from being backed up, even if they match the resource/namespace/label selectors defined in the backup spec. To do this, label the item as follows: + +```bash +kubectl label -n / velero.io/exclude-from-backup=true +``` +## Parallel Files Upload +If using fs-backup with Kopia uploader or CSI snapshot data movements, it's allowed to configure the option for parallel files upload, which could accelerate the backup: +```bash +velero backup create --include-namespaces --parallel-files-upload --wait +``` + +## Specify Backup Orders of Resources of Specific Kind + +To backup resources of specific Kind in a specific order, use option --ordered-resources to specify a mapping Kinds to an ordered list of specific resources of that Kind. Resource names are separated by commas and their names are in format 'namespace/resourcename'. For cluster scope resource, simply use resource name. Key-value pairs in the mapping are separated by semi-colon. Kind name is in plural form. + +```bash +velero backup create backupName --include-cluster-resources=true --ordered-resources 'pods=ns1/pod1,ns1/pod2;persistentvolumes=pv4,pv8' --include-namespaces=ns1 +velero backup create backupName --ordered-resources 'statefulsets=ns1/sts1,ns1/sts0' --include-namespaces=ns1 +``` +## Schedule a Backup + +The **schedule** operation allows you to create a backup of your data at a specified time, defined by a [Cron expression](https://en.wikipedia.org/wiki/Cron). + +``` +velero schedule create NAME --schedule="* * * * *" [flags] +``` + +Cron schedules use the following format. + +``` +# ┌───────────── minute (0 - 59) +# │ ┌───────────── hour (0 - 23) +# │ │ ┌───────────── day of the month (1 - 31) +# │ │ │ ┌───────────── month (1 - 12) +# │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday; +# │ │ │ │ │ 7 is also Sunday on some systems) +# │ │ │ │ │ +# │ │ │ │ │ +# * * * * * +``` + +For example, the command below creates a backup that runs every day at 3am. + +``` +velero schedule create example-schedule --schedule="0 3 * * *" +``` + +This command will create the backup, `example-schedule`, within Velero, but the backup will not be taken until the next scheduled time, 3am. Backups created by a schedule are saved with the name `-`, where `` is formatted as *YYYYMMDDhhmmss*. For a full list of available configuration flags use the Velero CLI help command. + +``` +velero schedule create --help +``` + +Once you create the scheduled backup, you can then trigger it manually using the `velero backup` command. + +``` +velero backup create --from-schedule example-schedule +``` + +This command will immediately trigger a new backup based on your template for `example-schedule`. This will not affect the backup schedule, and another backup will trigger at the scheduled time. + +### Time zone specification +Time zone can be specified in the schedule cron. The format is `CRON_TZ= `. + +Specifying timezones can reduce disputes in the case of daylight saving time changes. For example, if the schedule is set to run at 3am, and daylight saving time changes, the schedule will still run at 3am in the timezone specified. + +Be aware that jobs scheduled during daylight-savings leap-ahead transitions will not be run! + +For example, the command below creates a backup that runs every day at 3am in the timezone `America/New_York`. + +``` +velero schedule create example-schedule --schedule="CRON_TZ=America/New_York 0 3 * * *" +``` + +Another example, the command below creates a backup that runs every day at 3am in the timezone `Asia/Shanghai`. + +``` +velero schedule create example-schedule --schedule="CRON_TZ=Asia/Shanghai 0 3 * * *" +``` + +The supported timezone names are listed in the [IANA Time Zone Database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List) under 'TZ identifier'. + + +### Limitation + +#### Backup's OwnerReference with Schedule +Backups created from schedule can have owner reference to the schedule. This can be achieved by command: + +``` +velero schedule create --use-owner-references-in-backup +``` +By this way, schedule is the owner of it created backups. This is useful for some GitOps scenarios, or the resource tree of k8s synchronized from other places. + +Please do notice there is also side effect that may not be expected. Because schedule is the owner, when the schedule is deleted, the related backups CR (Just backup CR is deleted. Backup data still exists in object store and snapshots) will be deleted by k8s GC controller, too, but Velero controller will sync these backups from object store's metadata into k8s. Then k8s GC controller and Velero controller will fight over whether these backups should exist all through. + +If there is possibility the schedule will be disable to not create backup anymore, and the created backups are still useful. Please do not enable this option. For detail, please reference to [Backups created by a schedule with useOwnerReferenceInBackup set do not get synced properly](https://github.com/vmware-tanzu/velero/issues/4093). + +Some GitOps tools have configurations to avoid pruning the day 2 backups generated from the schedule. +For example, the ArgoCD has two ways to do that: +* Add annotations to schedule. This method makes ArgoCD ignore the schedule from syncing, so the generated backups are ignored too, but it has a side effect. When deleting the schedule from the GitOps manifest, the schedule can not be deleted. User needs to do it manually. +``` yaml + annotations: + argocd.argoproj.io/compare-options: IgnoreExtraneous + argocd.argoproj.io/sync-options: Delete=false,Prune=false +``` +* If ArgoCD is deployed by ArgoCD-Operator, there is another option: [resourceExclusions](https://argocd-operator.readthedocs.io/en/latest/reference/argocd/#resource-exclusions-example). This is an example, which means ArgoCD operator should ignore `Backup` and `Restore` in `velero.io` group in the `velero` namespace for all managed k8s cluster. +``` yaml +apiVersion: argoproj.io/v1alpha1 +kind: ArgoCD +metadata: + name: velero-argocd + namespace: velero +spec: + resourceExclusions: | + - apiGroups: + - velero.io + kinds: + - Backup + - Restore + clusters: + - "*" +``` + +#### Cannot support backup data immutability +Starting from 1.11, Velero's backups may not work as expected when the target object storage has some kind of an "immutability" option configured. These options are known by different names (see links below for some examples). The main reason is that Velero first saves the state of a backup as Finalizing and then checks whether there are any async operations in progress. If there are, it needs to wait for all of them to be finished before moving the backup state to Complete. If there are no async operations, the state is moved to Complete right away. In either case, Velero needs to modify the metadata in object storage and that will not be possible if some kind of immutability is configured on the object storage. + +Even with versions prior to 1.11, there was no explicit support in Velero to work with object storage that has "immutability" configuration. As a result, you may see some problems even though backups seem to work (e.g. versions objects not being deleted when backup is deleted). + +Note that backups may still work in some cases depending on specific providers and configurations. + +* For AWS S3 service, backups work because S3's object lock only applies to versioned buckets, and the object data can still be updated as the new version. But when backups are deleted, old versions of the objects will not be deleted. +* Azure Storage Blob supports both versioned-level immutability and container-level immutability. For the versioned-level scenario, data immutability can still work in Velero, but the container-level cannot. +* GCP Cloud storage policy only supports bucket-level immutability, so there is no way to make it work in the GCP environment. + +The following are the links to cloud providers' documentation in this regard: + +* [AWS S3 Using S3 Object Lock](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock.html) +* [Azure Storage Blob Containers - Lock Immutability Policy](https://learn.microsoft.com/en-us/azure/storage/blobs/immutable-policy-configure-version-scope?tabs=azure-portal) +* [GCP cloud storage Retention policies and retention policy locks](https://cloud.google.com/storage/docs/bucket-lock) + +## Kubernetes API Pagination + +By default, Velero will paginate the LIST API call for each resource type in the Kubernetes API when collecting items into a backup. The `--client-page-size` flag for the Velero server configures the size of each page. + +Depending on the cluster's scale, tuning the page size can improve backup performance. You can experiment with higher values, noting their impact on the relevant `apiserver_request_duration_seconds_*` metrics from the Kubernetes apiserver. + +Pagination can be entirely disabled by setting `--client-page-size` to `0`. This will request all items in a single unpaginated LIST call. + +## Deleting Backups + +Use the following commands to delete Velero backups and data: + +* `kubectl delete backup -n ` will delete the backup custom resource only and will not delete any associated data from object/block storage +* `velero backup delete ` will delete the backup resource including all data in object/block storage diff --git a/site/content/docs/v1.17/backup-repository-configuration.md b/site/content/docs/v1.17/backup-repository-configuration.md new file mode 100644 index 000000000..fd6cf0b78 --- /dev/null +++ b/site/content/docs/v1.17/backup-repository-configuration.md @@ -0,0 +1,63 @@ +--- +title: "Backup Repository Configuration" +layout: docs +--- + +Velero uses selectable backup repositories for various backup/restore methods, i.e., [file-system backup][1], [CSI snapshot data movement][2], etc. To achieve the best performance, backup repositories may need to be configured according to the running environments. + +Velero uses a BackupRepository CR to represent the instance of the backup repository. Now, a new field `repositoryConfig` is added to support various configurations to the underlying backup repository. + +Velero also allows you to specify configurations before the BackupRepository CR is created through a configMap. The configurations in the configMap will be copied to the BackupRepository CR when it is created at the due time. +The configMap should be in the same namespace where Velero is installed. If multiple Velero instances are installed in different namespaces, there should be one configMap in each namespace which applies to Velero instance in that namespace only. The name of the configMap should be specified in the Velero server parameter `--backup-repository-configmap`. + + +The users can specify the ConfigMap name during velero installation by CLI: +`velero install --backup-repository-configmap=` + +Conclusively, you have two ways to add/change/delete configurations of a backup repository: +- If the BackupRepository CR for the backup repository is already there, you should modify the `repositoryConfig` field. The new changes will be applied to the backup repository at the due time, it doesn't require Velero server to restart. +- Otherwise, you can create the backup repository configMap as a template for the BackupRepository CRs that are going to be created. + +The backup repository configMap is repository type (i.e., kopia, restic) specific, so for one repository type, you only need to create one set of configurations, they will be applied to all BackupRepository CRs of the same type. Whereas, the changes of `repositoryConfig` field apply to the specific BackupRepository CR only, you may need to change every BackupRepository CR of the same type. + +Below is an example of the BackupRepository configMap with the configurations: +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: + namespace: velero +data: + : | + { + "cacheLimitMB": 2048, + "fullMaintenanceInterval": "fastGC" + } + : | + { + "cacheLimitMB": 1024 + } +``` + +To create the configMap, you need to save something like the above sample to a file and then run below commands: +```shell +kubectl apply -f +``` + +When and how the configurations are used is decided by the backup repository itself. Though you can specify any configuration to the configMap or `repositoryConfig`, the configuration may/may not be used by the backup repository, or the configuration may be used at an arbitrary time. + +Below is the supported configurations by Velero and the specific backup repository. +***Kopia repository:*** +`cacheLimitMB`: specifies the size limit(in MB) for the local data cache. The more data is cached locally, the less data may be downloaded from the backup storage, so the better performance may be achieved. Practically, you can specify any size that is smaller than the free space so that the disk space won't run out. This parameter is for repository connection, that is, you could change it before connecting to the repository. E.g., before a backup/restore/maintenance. + +`fullMaintenanceInterval`: The full maintenance interval defaults to kopia defaults of 24 hours. Override options below allows for faster removal of deleted velero backups from kopia repo. +- normalGC: 24 hours +- fastGC: 12 hours +- eagerGC: 6 hours + +Per kopia [Maintenance Safety](https://kopia.io/docs/advanced/maintenance/#maintenance-safety), it is expected that velero backup deletion will not result in immediate kopia repository data removal. Reducing full maintenance interval using above options should help reduce time taken to remove blobs not in use. + +On the other hand, the not-in-use data will be deleted permanently after the full maintenance, so shorter full maintenance intervals may weaken the data safety if they are used incorrectly. + +[1]: file-system-backup.md +[2]: csi-snapshot-data-movement.md diff --git a/site/content/docs/v1.17/backup-restore-windows.md b/site/content/docs/v1.17/backup-restore-windows.md new file mode 100644 index 000000000..9d700f472 --- /dev/null +++ b/site/content/docs/v1.17/backup-restore-windows.md @@ -0,0 +1,79 @@ +--- +title: "Backup Restore Windows Workloads" +layout: docs +--- + +## Prerequisites + +Velero supports to backup and restore Windows workloads, either stateless or stateful. +To keep compatibility to the existing Velero plugins, Velero server runs in linux nodes only, so Velero requires at least one linux node in the cluster. And it is not recommended to run Velero server in control plane, so a linux worker node is required. For resource requirement of the linux node for Velero server, see [Customize resource requests and limits][1]. + +Velero is built and tested with `windows/amd64/ltsc2022` container only, older Windows versions, i.e., Windows Server 2019, are not supported. + +For volume backups, CSI and CSI snapshot should be supported by the storage. + +## Installation + +As mentioned in [Image building][2], a hybrid image is provided for all platforms, so you don't need to set different images for linux and Windows clusters, you can always use the all-in-one image, e.g., `velero/velero:v1.16.0` or `velero/velero:main`. + +In order to backup/restore volumes for stateful workloads, Velero node-agent needs to run in the Windows nodes. Velero provides a dedicated daemonset for Windows nodes, called `node-agent-windows`. +Therefore, in a typical cluster with linux and Windows nodes, there are two daemonsets for Velero node-agent, the existing `node-agent` deamonset for linux nodes, and the `node-agent-windows` daemonset for Windows nodes. +If you want to install `node-agent` deamonset, specify `--use-node-agent` parameter in `velero install` command; and if you want to install `node-agent-windows` daemonset, specify `--use-node-agent-windows` parameter. + +## Resource backup restore + +Resource backup/restore for Windows workloads are done by Velero server as same as linux workloads. + +Since Velero server is running in linux nodes only, all the existing plugins, i.e., BIA, RIA, BackupStore plugins, could be started by Velero in a cluster with Windows nodes. However, whether or how the plugins are functional to Windows workloads are decided by the plugins themselves. +It is recommended that plugin providers do a well round test with Velero in Windows cluster environments, and: +- If they need to support Windows workloads, make the necessary modification to ensure their plugins work well with Windows workloads +- If they don't want to support Windows workloads, or part of the Windows workloads, they need to ensure the plugins won't cause any failure or crash when they process the undesired Windows workload items + +## Volume backup restore + +Below are the status of supportive of Windows workload volumes for different backup methods: +- CSI snapshot data movement: block volumes (i.e., vSphere CNS Block Volume, Azure Disk, AWS EBS, GCP Persistent Disk, etc.) are full supported; file volumes (i.e., vSphere CNS File Volume, Azure File, AWS EFS, GCP Filestore, etc.) are not tested or officially supported. This is the same with linux workloads +- CSI snapshot backup: block volumes (i.e., vSphere CNS Block Volume, Azure Disk, AWS EBS, GCP Persistent Disk, etc.) are full supported; file volumes (i.e., vSphere CNS File Volume, Azure File, AWS EFS, GCP Filestore, etc.) are not tested or officially supported. This is the same with linux workloads +- native snapshot backup: supported as same as linux workloads +- file system backup: at present, NOT supported + +For volume backups/restores conducted through Velero plugins, the supportive status is decided by the plugin themselves. + +### CSI snapshot data movement + +During backup, Velero automatically identifies the OS type of the workload and schedules data mover pods to the right nodes. Specifically, for a linux workload, linux nodes in the cluster will be used; for a Windows workload, Windows nodes in the cluster will be used. +You could view the OS type that a data mover pod is running with from the DataUpload status's `nodeOS` field. + +Velero takes several measures to deduce the OS type for volumes of workloads, from PVCs, VolumeAttach CRs, nodes and storage classes. If Velero fails to deduce the OS type, it fallbacks to linux, then the data mover pods will be scheduled to linux nodes. As a result, the data mover pods may not be able to start and the corresponding DataUploads will be cancelled because of timeout, so the backup will be partially failed. + +Therefore, it is highly recommended you provide a dedicated storage class for Windows workloads volumes, and set `csi.storage.k8s.io/fstype` correctly. E.g., for linux workload volumes, set `csi.storage.k8s.io/fstype=ext4`; for Windows workload volumes set `csi.storage.k8s.io/fstype=ntfs`. +Specifically, if you have X number of storage classes for linux workloads, you need to create another X number of storage classes for Windows workloads. +This is helpful for Velero to deduce the right OS type successfully all the time, especially when you are backing up below kind of volumes belonging to a Windows workload: +- The PVC is with Immediate mode +- There is no pod mounting the PVC at the time of backup + +For restore, Velero automatically inherits the OS type from backup, so no deduction process is required. + +For other information, check [CSI Snapshot Data Movement][3]. + + +## Backup Repository Maintenance job + +Backup Repository Maintenance jobs and pods are supported to run in Windows nodes, that is, you can take full node resources in a cluster with Windows nodes for Backup Repository Maintenance. For more information, check [Repository Maintenance][4]. + +## Backup restore hooks + +Pre/post backup/restore hooks are supported for Windows workloads, the commands run in the same Windows nodes hosting the workload pods. For more information, check [Backup Hooks][5] and [Restore Hooks][6]. + +## Limitations + +NTFS extended attributes/advanced features are not supported, i.e., Security Descriptors, System/Hidden/ReadOnly attributes, Creation Time, NTFS Streams, etc. That is, after backup/restore, these data will be lost. + + + +[1]: customize-installation.md#customize-resource-requests-and-limits +[2]: build-from-source.md#image-building +[3]: csi-snapshot-data-movement.md +[4]: repository-maintenance.md +[5]: backup-hooks.md +[6]: restore-hooks.md \ No newline at end of file diff --git a/site/content/docs/v1.17/basic-install.md b/site/content/docs/v1.17/basic-install.md new file mode 100644 index 000000000..79c432092 --- /dev/null +++ b/site/content/docs/v1.17/basic-install.md @@ -0,0 +1,73 @@ +--- +title: "Basic Install" +layout: docs +--- + +Use this doc to get a basic installation of Velero. +Refer [this document](customize-installation.md) to customize your installation, including setting priority classes for Velero components. + +## Prerequisites + +- Access to a Kubernetes cluster, v1.16 or later, with DNS and container networking enabled. For more information on supported Kubernetes versions, see the Velero [compatibility matrix](https://github.com/vmware-tanzu/velero#velero-compatibility-matrix). +- `kubectl` installed locally + +Velero uses object storage to store backups and associated artifacts. It also optionally integrates with supported block storage systems to snapshot your persistent volumes. Before beginning the installation process, you should identify the object storage provider and optional block storage provider(s) you'll be using from the list of [compatible providers][0]. + +Velero supports storage providers for both cloud-provider environments and on-premises environments. For more details on on-premises scenarios, see the [on-premises documentation][2]. + +### Velero on Windows + +Velero does not officially support Windows. In testing, the Velero team was able to backup stateless Windows applications only. The File System Backup and backups of stateful applications or PersistentVolumes were not supported. + +If you want to perform your own testing of Velero on Windows, you must deploy Velero as a Windows container. Velero does not provide official Windows images, but its possible for you to build your own Velero Windows container image to use. Note that you must build this image on a Windows node. + +## Install the CLI + +### Option 1: MacOS - Homebrew + +On macOS, you can use [Homebrew](https://brew.sh) to install the `velero` client: + +```bash +brew install velero +``` + +### Option 2: GitHub release + +1. Download the [latest release][1]'s tarball for your client platform. +1. Extract the tarball: + + ```bash + tar -xvf .tar.gz + ``` + +1. Move the extracted `velero` binary to somewhere in your `$PATH` (`/usr/local/bin` for most users). + +### Option 3: Windows - Chocolatey + +On Windows, you can use [Chocolatey](https://chocolatey.org/install) to install the [velero](https://chocolatey.org/packages/velero) client: + +```powershell +choco install velero +``` + +## Install and configure the server components + +There are two supported methods for installing the Velero server components: + +- the `velero install` CLI command +- the [Helm chart](https://vmware-tanzu.github.io/helm-charts/) + +Velero uses storage provider plugins to integrate with a variety of storage systems to support backup and snapshot operations. The steps to install and configure the Velero server components along with the appropriate plugins are specific to your chosen storage provider. To find installation instructions for your chosen storage provider, follow the documentation link for your provider at our [supported storage providers][0] page + +_Note: if your object storage provider is different than your volume snapshot provider, follow the installation instructions for your object storage provider first, then return here and follow the instructions to [add your volume snapshot provider][4]._ + +## Command line Autocompletion + +Please refer to [this part of the documentation][5]. + +[0]: supported-providers.md +[1]: https://github.com/vmware-tanzu/velero/releases/latest +[2]: on-premises.md +[3]: overview-plugins.md +[4]: customize-installation.md#install-an-additional-volume-snapshot-provider +[5]: customize-installation.md#optional-velero-cli-configurations diff --git a/site/content/docs/v1.17/build-from-source.md b/site/content/docs/v1.17/build-from-source.md new file mode 100644 index 000000000..5f617c8ae --- /dev/null +++ b/site/content/docs/v1.17/build-from-source.md @@ -0,0 +1,198 @@ +--- +title: "Build from source" +layout: docs +--- + +## Prerequisites + +* Access to a Kubernetes cluster, version 1.7 or later. +* A DNS server on the cluster +* `kubectl` installed +* [Go][5] installed (minimum version 1.8) + +## Get the source + +### Option 1) Get latest (recommended) + +```bash +mkdir $HOME/go +export GOPATH=$HOME/go +go get github.com/vmware-tanzu/velero +``` + +Where `go` is your [import path][4] for Go. + +For Go development, it is recommended to add the Go import path (`$HOME/go` in this example) to your path. + +### Option 2) Release archive + +Download the archive named `Source code` from the [release page][22] and extract it in your Go import path as `src/github.com/vmware-tanzu/velero`. + +Note that the Makefile targets assume building from a git repository. When building from an archive, you will be limited to the `go build` commands described below. + +## Build + +There are a number of different ways to build `velero` depending on your needs. This section outlines the main possibilities. + +When building by using `make`, it will place the binaries under `_output/bin/$GOOS/$GOARCH`. For example, you will find the binary for darwin here: `_output/bin/darwin/amd64/velero`, and the binary for linux here: `_output/bin/linux/amd64/velero`. `make` will also splice version and git commit information in so that `velero version` displays proper output. + +Note: `velero install` will also use the version information to determine which tagged image to deploy. If you would like to overwrite what image gets deployed, use the `image` flag (see below for instructions on how to build images). + +### Build the binary + +To build the `velero` binary on your local machine, compiled for your OS and architecture, run one of these two commands: + +```bash +go build ./cmd/velero +``` + +```bash +make local +``` + +### Cross compiling + +To build the velero binary targeting linux/amd64 within a build container on your local machine, run: + +```bash +make build +``` + +For any specific platform, run `make build--`. + +For example, to build for the Mac, run `make build-darwin-amd64`. + +Velero's `Makefile` has a convenience target, `all-build`, that builds the following platforms: + +* linux-amd64 +* linux-arm +* linux-arm64 +* linux-ppc64le +* darwin-amd64 +* windows-amd64 + +## Making images and updating Velero + +If after installing Velero you would like to change the image used by its deployment to one that contains your code changes, you may do so by updating the image: + +```bash +kubectl -n velero set image deploy/velero velero=myimagerepo/velero:$VERSION +``` + +To build a Velero container image, you need to configure `buildx` first. + +### Buildx + +Docker Buildx is a CLI plugin that extends the docker command with the full support of the features provided by Moby BuildKit builder toolkit. It provides the same user experience as docker build with many new features like creating scoped builder instances and building against multiple nodes concurrently. + +More information in the [docker docs][23] and in the [buildx github][24] repo. + +### Image building + +#### Build local image + +If you want to build an image with the same OS type and CPU architecture with your local machine, you can keep most the build parameters as default. +Run below command to build the local image: +```bash +make container +``` +Optionally, set the `$VERSION` environment variable to change the image tag or `$BIN` to change which binary to build a container image for. +Optionally, you can set the `$REGISTRY` environment variable. For example, if you want to build the `gcr.io/my-registry/velero:main` image, set `$REGISTRY` to `gcr.io/my-registry`. If this variable is not set, the default is `velero`. +The image is preserved in the local machine, you can run `docker push` to push the image to the specified registry, or if not specified, docker hub by default. + +#### Build hybrid image + +You can also build a hybrid image that supports multiple OS types or CPU architectures. A hybrid image contains a manifest list with one or more manifests each of which maps to a single `os type/arch/os version` configuration. +Below `os type/arch/os version` configurations are tested and supported: +* `linux/amd64` +* `linux/arm64` +* `windows/amd64/ltsc2022` + +The hybrid image must be pushed to a registry as the local system doesn't support all the manifests in the image. So `BUILDX_OUTPUT_TYPE` parameter must be set as `registry`. +By default, `$REGISTRY` is set as `velero`, you can change it to your own registry. + +To build a hybrid image, the following one time setup is necessary: + +1. If you are building cross platform container images + ```bash + $ docker run --rm --privileged multiarch/qemu-user-static --reset -p yes + ``` +2. Create and bootstrap a new docker buildx builder + ```bash + $ docker buildx create --use --name builder + builder + $ docker buildx inspect --bootstrap + [+] Building 2.6s (1/1) FINISHED + => [internal] booting buildkit 2.6s + => => pulling image moby/buildkit:buildx-stable-1 1.9s + => => creating container buildx_buildkit_builder0 0.7s + Name: builder + Driver: docker-container + + Nodes: + Name: builder0 + Endpoint: unix:///var/run/docker.sock + Status: running + Platforms: linux/amd64, linux/arm64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6 + ``` + NOTE: Without the above setup, the output of `docker buildx inspect --bootstrap` will be: + ```bash + $ docker buildx inspect --bootstrap + Name: default + Driver: docker + + Nodes: + Name: default + Endpoint: default + Status: running + Platforms: linux/amd64, linux/arm64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6 + ``` + And the `REGISTRY=myrepo BUILDX_OUTPUT_TYPE=registry make container` will fail with the below error: + ```bash + $ REGISTRY=ashishamarnath BUILDX_PLATFORMS=linux/arm64 BUILDX_OUTPUT_TYPE=registry make container + auto-push is currently not implemented for docker driver + make: *** [container] Error 1 + ``` + +Having completed the above one time setup, now the output of `docker buildx inspect --bootstrap` should be like + +```bash +$ docker buildx inspect --bootstrap +Name: builder +Driver: docker-container + +Nodes: +Name: builder0 +Endpoint: unix:///var/run/docker.sock +Status: running +Platforms: linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v +``` + +Now build and push the container image by running the `make container` command with `$BUILDX_OUTPUT_TYPE` set to `registry`. + +Blow command builds a hybrid image with single configuration `linux/amd64`: +```bash +$ REGISTRY=myrepo BUILDX_OUTPUT_TYPE=registry make container +``` + +Blow command builds a hybrid image with configurations `linux/amd64` and `linux/arm64`: +```bash +$ REGISTRY=myrepo BUILDX_OUTPUT_TYPE=registry BUILD_ARCH=amd64,arm64 make container +``` + +Blow command builds a hybrid image with configurations `linux/amd64`, `linux/arm64` and `windows/amd64/ltsc2022`: +```bash +$ REGISTRY=myrepo BUILDX_OUTPUT_TYPE=registry BUILD_OS=linux,windows BUILD_ARCH=amd64,arm64 make container +``` + +Note: if you want to update the image but not change its name, you will have to trigger Kubernetes to pick up the new image. One way of doing so is by deleting the Velero deployment pod and node-agent pods: + +```bash +kubectl -n velero delete pods -l deploy=velero +``` + +[4]: https://blog.golang.org/organizing-go-code +[5]: https://golang.org/doc/install +[22]: https://github.com/vmware-tanzu/velero/releases +[23]: https://docs.docker.com/buildx/working-with-buildx/ +[24]: https://github.com/docker/buildx diff --git a/site/content/docs/v1.17/code-standards.md b/site/content/docs/v1.17/code-standards.md new file mode 100644 index 000000000..eefdaf781 --- /dev/null +++ b/site/content/docs/v1.17/code-standards.md @@ -0,0 +1,171 @@ +--- +title: "Code Standards" +layout: docs +toc: "true" +--- + +## Opening PRs + +When opening a pull request, please fill out the checklist supplied the template. This will help others properly categorize and review your pull request. + +### PR title + +Make sure that the pull request title summarizes the change made (and not just "fixes issue #xxxx"): + +Example PR titles: + + - "Check for nil when validating foo" + - "Issue #1234: Check for nil when validating foo" + +### Cherry-pick PRs + +When a PR to main needs to be cherry-picked to a release branch, please wait until the main PR is merged first before creating the CP PR. If the CP PR is made before the main PR is merged, there is a risk that PR modifications in response to review comments will not make it into the CP PR. + +The Cherry-pick PR title should reference the branch it's cherry-picked to and the fact that it's a CP of a commit to main: + + - "[release-1.13 CP] Issue #1234: Check for nil when validating foo" + + +## Adding a changelog + +Authors are expected to include a changelog file with their pull requests. The changelog file +should be a new file created in the `changelogs/unreleased` folder. The file should follow the +naming convention of `pr-username` and the contents of the file should be your text for the +changelog. + + velero/changelogs/unreleased <- folder + 000-username <- file + +Add that to the PR. + +A command to do this is `make new-changelog CHANGELOG_BODY="Changes you have made"` + +If a PR does not warrant a changelog, the CI check for a changelog can be skipped by applying a `changelog-not-required` label on the PR. If you are making a PR on a release branch, you should still make a new file in the `changelogs/unreleased` folder on the release branch for your change. + +## Copyright header + +Whenever a source code file is being modified, the copyright notice should be updated to our standard copyright notice. That is, it should read “Copyright the Velero contributors.” + +For new files, the entire copyright and license header must be added. + +Please note that doc files do not need a copyright header. + +## Code + +- Log messages are capitalized. + +- Error messages are kept lower-cased. + +- Wrap/add a stack only to errors that are being directly returned from non-velero code, such as an API call to the Kubernetes server. + + ```bash + errors.WithStack(err) + ``` + +- Prefer to use the utilities in the Kubernetes package [`sets`](https://godoc.org/github.com/kubernetes/apimachinery/pkg/util/sets). + + ```bash + k8s.io/apimachinery/pkg/util/sets + ``` + +## Imports + +For imports, we use the following convention: + +`` + +Example: + + import ( + corev1api "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + corev1listers "k8s.io/client-go/listers/core/v1" + + velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + velerov1client "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1" + ) + +## Mocks + +We use a package to generate mocks for our interfaces. + +Example: if you want to change this mock: https://github.com/vmware-tanzu/velero/blob/v1.17.0/pkg/podvolume/mocks/restorer.go + +Run: + +```bash +go get github.com/vektra/mockery/.../ +cd pkg/podvolume +mockery -name=Restorer +``` + +Might need to run `make update` to update the imports. + +## Kubernetes Labels + +When generating label values, be sure to pass them through the `label.GetValidName()` helper function. + +This will help ensure that the values are the proper length and format to be stored and queried. + +In general, UIDs are safe to persist as label values. + +This function is not relevant to annotation values, which do not have restrictions. + +## DCO Sign off + +All authors to the project retain copyright to their work. However, to ensure +that they are only submitting work that they have rights to, we are requiring +everyone to acknowledge this by signing their work. + +Any copyright notices in this repo should specify the authors as "the Velero contributors". + +To sign your work, just add a line like this at the end of your commit message: + +``` +Signed-off-by: Joe Beda +``` + +This can easily be done with the `--signoff` option to `git commit`. + +By doing this you state that you can certify the following (from [https://developercertificate.org/](https://developercertificate.org/)): + +``` +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +1 Letterman Drive +Suite D4700 +San Francisco, CA, 94129 + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. +``` diff --git a/site/content/docs/v1.17/contributions/ibm-config.md b/site/content/docs/v1.17/contributions/ibm-config.md new file mode 100644 index 000000000..464f53c82 --- /dev/null +++ b/site/content/docs/v1.17/contributions/ibm-config.md @@ -0,0 +1,102 @@ +--- +title: "Use IBM Cloud Object Storage as Velero's storage destination." +layout: docs +--- +You can deploy Velero on IBM [Public][5] or [Private][4] clouds, or even on any other Kubernetes cluster, but anyway you can use IBM Cloud Object Store as a destination for Velero's backups. + +To set up IBM Cloud Object Storage (COS) as Velero's destination, you: + +* Download an official release of Velero +* Create your COS instance +* Create an S3 bucket +* Define a service that can store data in the bucket +* Configure and start the Velero server + +## Download Velero + +1. Download the [latest official release's](https://github.com/vmware-tanzu/velero/releases) tarball for your client platform. + + _We strongly recommend that you use an [official release](https://github.com/vmware-tanzu/velero/releases) of +Velero. The tarballs for each release contain the `velero` command-line client. The code in the main branch +of the Velero repository is under active development and is not guaranteed to be stable!_ + +1. Extract the tarball: + + ```bash + tar -xvf .tar.gz -C /dir/to/extract/to + ``` + + The directory you extracted is called the "Velero directory" in subsequent steps. + +1. Move the `velero` binary from the Velero directory to somewhere in your PATH. + +## Create COS instance +If you don’t have a COS instance, you can create a new one, according to the detailed instructions in [Creating a new resource instance][1]. + +## Create an S3 bucket +Velero requires an object storage bucket to store backups in. See instructions in [Create some buckets to store your data][2]. + +## Define a service that can store data in the bucket. +The process of creating service credentials is described in [Service credentials][3]. +Several comments: + +1. The Velero service will write its backup into the bucket, so it requires the “Writer” access role. + +2. Velero uses an AWS S3 compatible API. Which means it authenticates using a signature created from a pair of access and secret keys — a set of HMAC credentials. You can create these HMAC credentials by specifying `{“HMAC”:true}` as an optional inline parameter. See [HMAC credentials][31] guide. + +3. After successfully creating a Service credential, you can view the JSON definition of the credential. Under the `cos_hmac_keys` entry there are `access_key_id` and `secret_access_key`. Use them in the next step. + +4. Create a Velero-specific credentials file (`credentials-velero`) in your local directory: + + ``` + [default] + aws_access_key_id= + aws_secret_access_key= + ``` + + Where the access key id and secret are the values that you got above. + +## Install and start Velero + +Install Velero, including all prerequisites, into the cluster and start the deployment. This will create a namespace called `velero`, and place a deployment named `velero` in it. + +```bash +velero install \ + --provider aws \ + --bucket \ + --secret-file ./credentials-velero \ + --plugins velero/velero-plugin-for-aws:v1.10.0\ + --use-volume-snapshots=false \ + --backup-location-config region=,s3ForcePathStyle="true",s3Url=,checksumAlgorithm="" +``` + +Velero does not have a volume snapshot plugin for IBM Cloud, so creating volume snapshots is disabled. + +Additionally, you can specify `--use-node-agent` to enable [File System Backup][16], and `--wait` to wait for the deployment to be ready. + +(Optional) Specify [CPU and memory resource requests and limits][15] for the Velero/node-agent pods. + +Once the installation is complete, remove the default `VolumeSnapshotLocation` that was created by `velero install`, since it's specific to AWS and won't work for IBM Cloud: + +```bash +kubectl -n velero delete volumesnapshotlocation.velero.io default +``` + +For more complex installation needs, use either the Helm chart, or add `--dry-run -o yaml` options for generating the YAML representation for the installation. + +## Installing the nginx example (optional) + +If you run the nginx example, in file `examples/nginx-app/with-pv.yaml`: + +Uncomment `storageClassName: ` and replace with your `StorageClass` name. + +[0]: ../namespace.md +[1]: https://cloud.ibm.com/docs/cloud-object-storage/getting-started.html +[2]: https://cloud.ibm.com/docs/cloud-object-storage/getting-started.html#create-buckets +[3]: https://cloud.ibm.com/docs/cloud-object-storage/iam?topic=cloud-object-storage-service-credentials +[31]: https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-uhc-hmac-credentials-main +[4]: https://www.ibm.com/docs/en/cloud-private +[5]: https://cloud.ibm.com/docs/containers/container_index.html#container_index +[14]: http://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html +[15]: ../customize-installation.md#customize-resource-requests-and-limits +[16]: ../file-system-backup.md diff --git a/site/content/docs/v1.17/contributions/img-for-tencent/15ccaacf00640a04ae29ceed4c86195b.png b/site/content/docs/v1.17/contributions/img-for-tencent/15ccaacf00640a04ae29ceed4c86195b.png new file mode 100644 index 0000000000000000000000000000000000000000..61859ca50e9fbafb2948628d79b7e0bf69bd85de GIT binary patch literal 132711 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

IZ`LFqwfbe$eQ6t@&18)&3r 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 literal 0 HcmV?d00001 diff --git a/site/content/docs/v1.17/contributions/img-for-tencent/1d53b0115644d43657c2a5ece805c9b4.png b/site/content/docs/v1.17/contributions/img-for-tencent/1d53b0115644d43657c2a5ece805c9b4.png new file mode 100644 index 0000000000000000000000000000000000000000..57de0cde0607257ac55de3ef30d834db31709587 GIT binary patch literal 74478 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 aL$88LY}It)7mk;}9|c(znS7~dKK~Cm_kk?{ literal 0 HcmV?d00001 diff --git a/site/content/docs/v1.17/contributions/img-for-tencent/69194157ccd5e377d1e7d914fd8c0336.png b/site/content/docs/v1.17/contributions/img-for-tencent/69194157ccd5e377d1e7d914fd8c0336.png new file mode 100644 index 0000000000000000000000000000000000000000..f363eb1a78073b9a07ed91b046293d5f7224a7c8 GIT binary patch literal 32817 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∓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 literal 0 HcmV?d00001 diff --git a/site/content/docs/v1.17/contributions/img-for-tencent/ceaca9ce6bc92bdce987c63d2fe71561.png b/site/content/docs/v1.17/contributions/img-for-tencent/ceaca9ce6bc92bdce987c63d2fe71561.png new file mode 100644 index 0000000000000000000000000000000000000000..36805831bbe57b7118c9bc47bed1a7a7306c4f2c GIT binary patch literal 292269 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

  • bHDT z(zWj?n6WLi#j(hlD${DO)65=J=d}>Mq~O_|B4?c-H~Zt~E3DMxWAm-uI4u;Om>rP4 zX~+FIctsjoB#|`lFU@QfA*`UgPPH2%Nd^)=cr?f9fIdPGP@ri7zUcu6v>Cr(K5IK` zZ8b-zaL1N4qc4dmk-mHz{pZ4Z z5;v#(7{#o3**1r7vSi%NJo+|Z4{SrJz3*?Hs$)m9C?YGHv~{7|c5@MvYJHYV%5aW0=gLenubMv6r?DA?3=bkxvL)6* zj=ShkZ>dKHNqssc_|ttB?zsEA4?f$9B3ZW^WQs}O{CMXME(6ftzqDVdbtTqpvDf45 z<`%!<8V`bT@SnM3DvKF*xVJv;o3U4tOBz)e;Zj`KVAaW{DhHWGaQ)i*# z6>u`|=<57*iIgd>+*7v(qE=*K!MH=igi)eB3Hi7pvb8R5yfZ@4AFt>%pUl;u5Zy{^ ziq5OBy+^&Swf)VZ(SEpe`s(h$q+n%#Yh=|b<-N;TjCfknco5d2GzDIR_}!`f@=lRE zS*W6&v25z$9d_$x54$^-%eh{BUU(Q1!nR99PbbX(kFasj^p8rDKzE3R$A-fIyXZd- zd96K%iZgc-J~EhRL{q(R%5hXHY=ZBmf*dQ!639L3Hd}r2%O;4mqGj<+IC~dio6VU5 zJeTNXI|S~+I4{`LjK5+@KzKjkDLW{Lvo8| zamB9i7c;?V&#?V(FaB|wTcaElH8V`6nonx}}ZlBT~}k}>;4pL@xMjXD)L;XUBB4Lr@X*!7)qyNyJu=42-)^}NB1|!-BGd? z2ogaBf_yAcEhd0mims}v>U0krGELV^-7oap*xG1zIrZIks@@>>I`UfcR|>kvZ$V6J zPW{CKPQ9-WI}MbI=mSj8H6ySEN6{-YKj&OUy)r7IV+g{@8!aB03Sb!8)@JHaf){BH z`IgvsV5S$+&1tj^T(rQnC1Jy5hA(bs;j!!71@t9R2Yp6@=ql*FXH+&?zt$$uF)Fm~ z+2&Lz_;p}{+5{Iqsqtk@G{oV?iGz2*z)Yd17J$+o(*v#Vu)fCENr+477k?x8PRmjt$0^ye8l) zt#B!Q-@dZgJ&05n2vm{ppIQT?Lv5E zkc$KP#r1sJ0xRvY_7@l0iVJFC^qosnI`Caf6a}9Ji;#BEaibG7jdN>1#S4Vqpkmx^ zVF;AvYiq=cwvyL}&=j+~6bE!UXd3PZz6wRRrn{_4ag%LHCRL&CUk&^340@0>Q0qGK z`@p~Yx;<0e3~UiXPCEH6KyZ~28y}!R*Cz)deNHv-fyWxvXm_a*^z_RB$E=x5*&O`< zgN`zUK%)&_UHe1NM4$hA9Z~Ve_XHv-b1wMD5G*@g^L#+YxkYSwen_6KoU;dV(+o3X zC=c!-B6I~fn-ZfD91xS(gQG9||D~too5ybc<`BV)1zM5!30FUZWkjv^3iR;N!#f^_ zKYqN2>CioWW9uDP4!ul$c)&dNjwjB^5mD+leJ>XKUqVGBY<;gd-q`1{-+lr z4<_YxsCKvxSNqxnCrH;03KZ<-Qwq?|QnYAP^+YgfYXRXaT?0{Kk2=1a=kzJV4b_ z${n8E#8Z}M{b*z~#Jg81Nv#(LWM5iz#rT<4XnZ=GvoXTYlfUKq&J9d$m1g?PHo~D$ z-yhF&6~J!jq*EBGj4Rx%3uX;un6B}>4!sN3zMd*>{n7Z`dUJjs&bcs&wv$zt^;SZ~ zoQMoM;fvtjnzsO9bmEo(AnB*2+yMNB%dw_zm!^SFt--LuR?o#t*lHELE+pN(|7+$<<3uLM8Ws zq)=%YP+$xoR>`j*$ePnbHH>?iWzCKR;Mu4-g?(&?{2d)M3GPG#NxhS#(H? zTi5RKNzkFzx*Y^F9GH+ArbfDcuGjGN!xDZwPJdr)M(h$L*s+SVpQx%@O_!!{oK2|W zhRpW^bx72fXO_Niw{oT5uM5l|CVTbU%M!StK$w}!aZrTU@bqwnyDc3C5ijFnE(nDM z&jhDf?n!yK`+)S`%4tfNZ6Ia2r%1mVd3LpExK@sLvEWD|3CMLbS6dovYfJ}FwUAl< z6%r7KVH}=T`4za$Ol_nPQ}RU6(!|kt6npRYghr4cC%wl^$n?#OIWPw=<9yrw)vLVx zdCnA7a!_AZLO@>$FMnJO3!SU7*u7uECLQ!WtMaKivE8w!Kof}PKfJAEa^f&<2WP}U z!jeeWdQJ&a!>$aOc@IUK2d+(Ahw!{t)LC@yNIg?RqDzYiRcMN6l1JwyEVvWxGIXFn zOSUTDDS1Ljov|U~DL!M5Ohw?%t|BXJF01^f6Mi-5NV zqK0X#UOr6PrX^0#!NkS&lG?p3?Q%1(Jn*eDm`!N9fFDR$jD8=Bd>~GjwjIi^3)H!?T`&P*Lb4U`k+LfL+YjK+hd#ERm0H>GEqn$zJOywMPuEDmE%j5fBGMF&>){?|~(~P&xOg7X>8RR8;;8*$xap8klgX+ZlY@XFRX0h}* zF>u1s0wi3Ov-`-h)7fcndO%#UR2AyI*Xlypz9+=}o9ktUefaC!S1+IM{XJQt=KAG; zhU>J&{X1uvWRv}-bL>|aM%O5f_zTOmy&LMaVRwl^aJ?kG3~Tgl5zo~cNxjR`#4&V4 z(xCsPgHe^&oLhNLF>?MEW9dt76UJe66UJ>qY+imnRm0JDO@Wm25*-{s4OuW@oCK_f z@;9T%>;iAP%xl_}?O_#Aw1t{P`X4Fg8hw2!>iEPVLx2ieS_YxeXOUoA|^?Bq~Au z`YSyhSx(geK3W^`ec3)f{cTo}8>tdW&DgP?bM%~s|L^VJn{cM8GY+qmmQAP_VZDx2 zd!jUDG6r0biVsTE;q|xfO&+(T z5rj8dX!0!;ILZDqCTL?n0Y0^CvD^vO`Z7R8;DoCks|D-kyOO%V zTjGKw4u;!0T?MA0DmNHAB9y7C#%~eX*FY0#;)F><*#4_xvs_#+1D%}_jWqg&f3O$a>B*gPs_{l_f!idWt~z3{_Ks(P*do;`@1#hpr&^_IhdJ=&&d0` zR_1|=3=nv=(~+~Gfy@JfYo+jZn-{7lr5J)gjky~cmxz;&T-<-SIoqp3Mnvh{r>3n( z`LFFe^FJpG-zM_^{i36j@!5Ghdza7n?~zB63cx_?>NQmXaNAYJ4s{bfy-@f*6dZyy z{pbWR&R8I;Y<+?3EDRpc-c|0iIL6~c*XzHi`WSfO@oW+?yEL;XmtMWYgNz{(L)bascc?uHNfDVrozj{1Ny# zQ(Py2+k_BjHB{d-p`slNQ<&0KyWT3=k6y83^B5dhFnLjDRY88)Y4$?>x@CA>`{=s| zm}$RJ&cmH&?TTCx1lzDj>OpKBp@M$mHO`@_X0JF3be6>f#-NS1ha+YTv|stth7*Zc z)CmM=kZBK|Tn->TRdhm*oh|S$QnUJDNA=Cq|JjRh5g<74eL4Ak^}lk#;{8Lm3b}sJ zVrx2>dVRIO#1U`!++@a+o|I7p&j8{}m#T-v&iZ-g ztxSZ{DESM+N1lP(s(uH|}*1QJ{&z||{g$tIZv`=;HouqtC> zGk1NvwL)(4&Q@l(J%kEOvc{rO1vWFGQ{T|6t5+j_BfVK(LqHd=6(MB(H}hjTAH-yU zz$oG_0hE&lo4Ma;Fjr@;eqJX?a!9CwO_DC1du7NteV>&tnap3@4LCmmkemT9Nc23Y zONKXYxL%}w5#-or=88_Iww!5k9}kzYxtl%cHF&GBi@OBuO^q@Be!7)#kSLfh13|s_ zVEHYqA(EsYvS%15p{oZ3{cg3>Wy{GRfIEHpM3RRt%hky!#dXdu#x$_4;WwNZ=yKYc zx2hllsZrnsX|pPB^J;@~Iz6bOay)t4{!sSWw`cSO!(g0aGk_=B{1H#o*mvw}&P0WI@52T20Q!Vo!%DjhCmy-k1wgHDv=4AB zE3Lj|ofL$zc?mjc0(#w{>j6p7mA)L1cgkp<7-zz&T8JClPgJBu$O&pD$w{fImIAd@ zcV*1>*tL~T4Y7&W5P(jc4yIgR1&N!c!4h%-llBGGdOGZqz6$`vuX$?bac(w8KL6Q5 zd%zLFg7j=F2chlsc-UTCiK#!Gmjp7LOSVT$cLG7B)%Z}Oq24B8C(D&DQQDIQAbS*J zF6ci9E+h$BcAF}SF+4Ify`|cB%Tu0zUoSwbtW%T0{=)-w7VP4E(~M_&Gp~6-{Q7wo zu^95@^N@R6W=auraDU`RGD#{Kj7_xGPW60e-XAvUAq;G}jwfdg_wDUbCcI$H0BK5& z$`EDd7f8_Akb}Ike277p&Xo+=)B{^@grx((ft;aB=-QD~`s(KKZnw-A2T!&OLc4uI zzuA*?O3s50XT)+h4@qc9jqyO%<>yZWSBg?5$m7PN75wL~mBpil;MGr$Yb9Qjt2gIW zvqsplnFj!5+EUF<_M5<)X~s(m47oLntX1r!Xf8{v{Km0Zw?HN1w0q3F%|N)DrK?~y zdrVMKi9B0`EkjbAKFJ79ngK$U0E6#DKY*8^z;4Rm)t>!Ubhe)}lCm;8P+(T&0pOOg zRVC(VFbz|-JhbEx4bF`U4x;Pz$$np+sO>bP?>Fk#_yQK*ng+pr3MVb*`b&U0JF909 z-!FqJOjltZRXDHt5@4tk#@q?^#$61O^o}#ERXy zVbu`U7rK9jHC)g>*38SOay&x56QEPwH_f%l<1Pa)s>RkDTB~2&+k7n6R2R-*!8kBh zlfB>#sC<);2f#i%@m&D$F3p?snQp3m zSC;1nWRkpxePw64^tt&JxTV>+!%hv)z>&!h8mk1I*iM=j+v$X;hqEQmg49k(#jwwK zI1fvByT;+qM&)9|02rM1bTl%MkXGHZssQnwh_(l`8ei7M{UJnYKoeQ-3sr1Ml9$nD zYuC?q*mr-?=n-c$5A){F_euP&Yhe40S+HefvPuHXmI*R+BTsBr8x&bka$KCgn-}@y z>%0!gy$tTOdIdHu|JBh4?x%$6t_4r~vvtakJ>>6{#Uw@v<#(Bh6~Mmm^L^AGqPto` zzayNUy`8jV|3`{?FIAbu7=Yi2xD43SEiYP`-l*!=Fuhh? z5I*ZQ>JOGcu5(Vi=jO80BANgl_`|-SDyAC^Mep$qgZs3&i1*{O+3Tt3jKB;1@pnbX#PXO$i1AJf)Uo!vbu|-&D$o<8&hmY;` z?uTu%0;d5ea00QoE*l5ZPvW!tDdG?XLj}l-U_%gqyGgxu6)Cdk zjjF+A*-M6H#sl-+Ar5|Ep>HMDQ>q-;1jFET%P;Yg@`4nomQ-XP?FBTDHg9K0=7*{<9j52->+2Zh_UNtcU^VanY!w+vVIth5OthXl20cGT z4>L5vrUP$jgH4c^uLk2@tDE=4_z8vu^%w;ub~a8YJ65(h;g+j%YUe1H9MO~`vppS^ z8Tiv1$Wk)todw4;zcqD#T~YOd=zTk@?;YW z%5VV~d3%sj5fJ2~rwsLrub%L%DNwW7bEg zB@ECQ*a)FJedv21OJwgSkmp#THOy`x3II@e(0#`+{ih74#ps z2a#jF`$p))n;FOul@S*ja*O=e5u@L!N)$5>$WqXcJaWLnjy(t|>Ckx1n#`@=rqnbtg!*32|2krS z>j&~&qnk`Od8K&c_wjWQuVm0ohIIXA=-+t?|NT8I!gQ0Ff%o7E3@3C07M3{<@I zAM_mF9-}g_W#*Qm$hRR4%H+5P&Q?*P7G4{(=2jJYF5h8W)vFqj+yz4@?)^V#b~>_Y z@0C&9rU2~0Z#cMAEaUp|rGJS19t) zl-@`h?mz5R#0*$;2GX)!?dwGPk1zS*(f-Frzs=QFdYolceLUeGV4q?{K^CEtM#2NIyYy_FvwZAd`-yX!z zFH(&_U?LUTb0g~K|KG@i?&t&ofida8O29w3hA;?B;_DsXT-uoF{`ie{Sm516D7*cY z{=qdk!8KaPr23Bj9Si;M?|NU>Qp-hs@;2JiI@i(9TcQ5>Rp15%( zF#Uhs$JfaK+-XN?hH@&#F(AlXu`ioFKEk^)cWmI zIZwM3Ed?(RZfPG2hb|^DpL)l<&f+ZFEPcmr>AIV(?jZvOYh{EOs|y*&;KJH!Dfo!V zwLM;%zx=g=>~^1mkW|1la)B-4?K@s<;f{vB%hbd+qbWp5tM0@LNj*1yw2wb?&Hw#9 zt|L2(opU0GYs>}+t+3UbX%8rMc^X+-*gP8kDt3YTpjc0-{U5B~9GrHA98@L0wW`jJ zpa&eXSxQnubG;R5J~i;|jp5wSE4}8Q$$3sau37yUnT1@-f@gs=-TaKl{I5Iz%?w7V zs@td$e4cuK#9#~uWHE`T_?Wt!)x*_JOT1g8r7R0wlQ6^xL?|siBm{Yz#}y!#+mvn9 ziNC&BYzq2ZnX%tv?sHD&(r}~hj6wcV8lpNtl|-CzaV~C5T%RI%p!rcDcr#z@s>f%x zb0HX(zhm5g@}AlnrsDFQu#~kAWYl2IgSm%a;#GcONJddVZpE<=k{%tFSYQ?DviM25xo~2BN?UBm ziv~Gxfx{{!Qeo}A5ounT26fQK!?pnWk0F9K zghdyS+Z&8uzV#iJTe;`aDuYafLn!sIOET0I@7)pM%_RT(b_W8)nsEU z{)nUaF@IYF8@h$wManB0j24qsH7=k8za6&d|B>qkfDYnDD z@feUoYh)oN%E#WMkd|aRm&=BY6kyF$I@kvg%5`p_Q!j+Oo+7d`cV;2iTP2~B62YR% zzZ@Z4DPhRZ^Ro4?D9k=eEQ3L<7Yi_sf?Z~?fs{Lz^~~WO3tti|u-)h(lf=2F_%?N` z#xT)jnXb3@E=8fHOJzaP9)8qF3njE#rwGn?*S{eGWpVy4ROpT(feOLu6UxyeJ1EV#Zql52=P%0l-koQQSxO5Bqi`!kxJwKC`ciEtii$stOfV<#7FGOga9=kKhT|Mfko z##{RhW*Sz!AT-xyHQmSpGrUs*XjKRy1B+18bj=qS&~{medyEyTWgULN8!tqGj=wU_P`$pH)DI#?q@-0BPQ5~XC7q11Lmg*eXupJ#r}B~ zZpZmZb83O)yqH$|nfH(`Mw!?iMhXiS>gs3LKkmy6)4AHZ2+l9{l_Jyw`BrC@Gr1gc z_i^@jykpfwQb)^B+5C|g7tL*25~Jq*J&Z@+r2Kbp{^Nr6C-#&r7sRPEisQx9ATpm0 ziK`Csp?;+4&Ta2WcN!?e9DCU`f>B<1k!f6T8YiZnyKLs$w|X6h zJ=4>c)M*Wq67?Pu$JP}44Uqx{bIy?o%Sf_^QnHe}7Yjc6K4q+K76ZAMLYwA07sywz zWA{NR57&dpDwl9s?|YO$FH}BuOA7gVCGm;9?B{(!2q&q-ZC+0O>GVa;R~`;GN@(*% zH#!7^>)bh}fhuQR_cX?%+bJ+AU@<}mIHO#KhVopKelctcvN_o?%YJ1GnW&MnIx%Z8^SMqemdNsm`Lj!le8wWV_V_{y>S%_)dX!C>0NPQ zW(dUIzh^5Zy}(QkQ{d=QgYdx)N@#1}WjXM;9p*X|ZVz-Y^^O_a3uzp1N@4Esjx@Cl z3|F7X3}w)WhsGf zmE;#{&6+vCzC$FNrS@&74nsece=dZQjUQ9|_)KT2J5TTh^weu|uZChOR$}DcM&SNs z1=y#zY%>nP$W_LXYswCScvb(*Ok?zTQHqGU5aYy7UYHI$_s#5lW5jV@T`S+uuMh9u zozsPmbJvcOtT2CA_`3Ju3s`@<;?;vf9b3a>zJNS}?%hTTiQv3oj16u`ta7fe>-4E=SM+d0B7@A*;%8RMZNa9g6Y>IXhE+D!4y3CDW8I$r=51q0m=rXI)6^&$LQ+cTNh zorY=@hg=8DD*T278u=0~bTh6^)|8)un`O@v8}5f=WoWp0<6XRR>xJB74Xp{N*c$v@ z;~s9g=cF$!_eHy=U79L1xCD0}s;RMY!e;n2=Jimqepu-8w&}kd%s+DE2+sTkD~H8gk{&D33RyEjF=!U6nVb@I)Pxp8kKaVedAEG|$_72X z{jA0_js4@1t~yG%!9pv|eXhF3;8u)#Xo*poiB%pDv1mOlh4f6)$jgjob+I0~`2q6C z*xJhsO|DvD(Xn3*lEHDs$qqk0octl@1AeP7uuGwB8c>#LqZ!{Sujyx^`@IdobVzep zHYD9x6lz8xShZW5%>x(La;(UpD++U)CO8gngZ2!&`6EO)&idZ6Tz!0Ixqv3it10V^ ztuep0sta1;-VUrEciaAeNJA~JF>}Qpc=_wbs87#M)HSh$af!MzrQ5I*qqG!6poqZ^BQSN!1}I01_~W>m`55^nZhFvWn{vw`WCT)-m9Wi{ z6GBK33}VZjPJVcm@H z9B+sE%dM4L;cp#gy5_Cj{`ubUe7V2dJhfI{OzQ-X;+y%$W4<&c1ZryZT?nR1-VV&` zo@8nKa}Qb?%Du@ZOfeL?so#=J=>w=gf8T#P-JRM z{Hiw64eaMNQ7=hlAa_6~`sT^p531R-&)6H%KT36d;S@HC_byF4uCS5=qh6?7O)Q&e z@*^rKcp`DD_XpdnJAyoo)Kp$;P|kQqB5I)5 zAGA-xJ!jAt!LCiPjh+26i1>}mzeI1t-uF z9BOzh8v!nO?}GxwBUr;UJ^4yE>X4S8782yr{YIN6$JbQ`=3Z zy>MlCYj{n}ajn3U;mX80ffY(9da!T+aryb;4Y>(koCaTuRwyp^a!ae%?{56tUCq!g&qmZA&RPr=p;oRJzxcD2_)ov_ zihWRbw0Vc$hClejgH?foyd&wj-_L{br(gNQC%?T%r5>b%1+|>dd`-OlLR@zR6dAy4 z9v%EAm$(J)BqYk@@wXqg@fV*#qCd~&iiI?C` zI3`N>{X(4a)rXxF1GPfKs$&1(64}|{PE;#I{y`NOV-q;gkM{objWhH0=lyjs`OW$S z1;L&CJ2n2t=u-ck8b5fSf2YO|cJ%Mm_|ez>J2n2D8h?^w|95KqJ2n2D8b3PAZ?V=- zFaBLnejKC!2VSG$fg;aW7Qp|T-AZx(lmq9lm5+fmGadTo?}W9J$9gSJ%NGpAFa*Mu6ikLpYZRsy| z$3#fZK73){Q5#f+Xy3#@K5~T@_WL|&3iJcOBxEZctpg}{2>=Wc8v%e22vY2CpxgOn zy0%tZ1~8O91A(1jpzhz$dl=uTB`wdO=zt|4jCY_OA;*6PJfY83-njKHAcubwxeCPG z8EOZ8k9yAaOVK6ZYqotsay#~%9%0-Gg9#o~pbE{L7KfiP9HkLsWd*fCcb3HNs&h!F)ur7`L2F2o^kNC*;7 zSJqD;g$%2&O&u$% z-}lI?EfB2=V|MtY;K(8S*`c05o!YfeIF# z!Y%7|qljs}KE)Pr)iePD4~^mCdW)sEYbW!+@}7t`obM6~6*D`{&_!3Dnk`~*)LrY* z^LYfHwnW)Au5mT=myb~>zyQ?+8c_8IU&ddDTZ{m7fumU{B%AL{4uBr?OnaYAjb|J~ z3MnphJTtaL)=^_>-Uw?ZEc(dJJ&R&C3;fM)FG!AGu$24`vkbbwHQ9f@LK2`cJX*vX zB^5q!{N+&Gt_|E%4mcF3YG3?Plg<;tv&Y!FdtY0gE2!Pu6&oXL^whb0^u7lmuw|Yt zL1q*7LV`8s&yXxWLR&sViGz_gxU4$!feVz}Ei ze1u8AU!CUuqL>!6{ou*_lx+Z9r^%wUYJuE^-23rX*Ut6P`mNaIF2@k^f!}>BT48F& z3EiLf-hU`fV`XNfhRCsSYk&-V;nCLb#%009uqY->TA52=k^S=6EX?g|EARhfzkNkE z2oP6Z>{|&%qE0yvmhashb~aSqkgm||%9Zn&dJJH;SIeIr;n_FN2k;J`!A$dL*l)WR zE(^j36?gWBuI7x1z(xii)`#tv0LQ+3NtGVhH-<-bhTzU|&hX>e9V4s9R_TmYI?hjS zzI@!xu6n*Rlv6~#U6~dze^AlSgHAY`X1S%6n!8ondGOjG1b){q)4k2l-`MEtkWXC_ zyE_d40Xr+>mCw;zQ}bYM*QN+{l+)}9nE3|E_Z*9Hw#xdp>__Y;GJ!6-&gGcH3tX?& zcSHFh;Q2P~LB?qE_$h!GtDXQ;EDLa_dYIGC(=MGzdUgTuyZ}MKK#a-#J)2tkY9}z9 zj=`k+)JjY2?$3_0;qR#IoBe#@ z`-z6+)u1|;vQU_SqYOn4(=&8NwZtfGx~Hq3U8eyZpim{Eh01x?8oFp0QmSh3^Ux{cdF80LCD*~iaFvl6Fc{2mWmpbQ<1%Nnkj};J zd;zWwL!?L~nO~4q)TC6n9{D5gtB=4#5yfTDFplVILw=+1tpbzoEaa3s}lh}+ZV|)foKlvDz_>8LIJ6WtjVOiCvU_Cu@dm0X-I8t6|?m^pUC3VktSjAY|APE@t zCaM^qf5t5jDOCd}=V>vT;8J6xEQD{l++hJ1ux^teX2hE3{+?z;db<4EY!cP+lCM^o z|Aj2HaVLNpUPWpxr>xsd#0ks*NP!tm`c=hbyrQ*ypZlzU`+@w|3|M*Jg&;_-bLB*7 zsf2S|{POdN_81P%`bR*0e;a9k!fVslxe;W^b@A9II`S&Xy-ikMP@m4~a42e(&MWPA z$h-6@{S76?#5w2prK>qUV*4}3#(J$H^Gk=k2Hw~aq#B`sbeISJkuNtHXO(N>f+(q^ zQOS8W85F?MGsdMP{WeACTo~kRa>#Tl?aLfKo<{Uk&#|kVubi3QSu`mvlwYh{0&vBK z+j%`Y?2f_Q5yYP-$`4NB>!YlF!*fYy?0iUv07a{o%rSU6Saa*MQTqD4M!b zHj^3}aPfBYat{Q3)nLcob-;C1wizHiCjeTKQvEfAVM~S(y=mV?FpWQH6P_f2Kl-2 zb5Z~zGCf)msR#4F6$owTdepM%B->P3?Fp10LEdof2fuvk!l5*FUhlzM%Ww3g(|=DZ zIcwj-!mE_tIS%fqV9T;@#k15ZJqugO%$EMxCwNf=q0{g9TNb0w{3?`DR#^5tU@r-7 z_US`1;xcr{0V^Z7tOBsjX4ENRH%lgBOd=vyo`qyFi&eX}&|XVNMu)72idJS9FluCU z0piv*FiXt4FiOOV$}oBu2W82RKG&*Hed7OEHvi{OnUGY*)(o+CfG7iDJ(_qsDkqb% zD_!ht7IHG|YJQQL^@RfT`lL)3pdDV@KAax5!|ypD&?=(z?zoATkKC!mz1M5DhcPg2 zyJ{f_P5Y;xbP@0`r;?Mit01O3@-JR zt@W51mSUHsHp4Pp3~bgMck4M$;%m3ChOx9IZ|;(Bz0f;|nXkeXfU8x1vOqHKJieN* zV1mEgidV!83Dolkd0^Y4mF%AH7T+APgR|u(%=fsrkatx8%0(Etb;pVj*`~Wb)3J(( zrFDxc0yeOxY%+|xCWqejFeM1Xej^V3j9^bzreSDdZ4tfkjUI_sGvWc}i(5rXbz{CxoL*mNe-Eu+xD6{?=KzPp>jFc zp!AY8C51}J^6Rb*dt3&>;2sWs2xZz(&GyLU`YwR(GgDlA&+d5&eU4R8&oEmCuU)U+ zCMLjP{eai&S_$ws;m!af3D*Pr0AJ{O*agqeI%?qs`1^lZU2(0H;Q^1^Mc$)NZig}Y zr9)Ku@u-v$dQ7nyAtdcoyQYy>MGw=HbSkT8IjRO2JDHk_*UWUWA&#n(a&j5z3&`M zptQa*Bl%M%#9%qzmkvIE0cT{ku_VP?Zz4TnnNPOGvj#5Q?O&l|G^6|0mJ*g)T>^`g z3}%$~TLc1Zc7Etg`;J{LF7E*7f7%_8QQ32M)k1Vh%^6~Jo{S;jP|mi_9H!Sg{dr!U#$ z<(KAqf4HcZb2Q~5sgA4W3KRe>bA^r>3qf>0MX|kjsw*2kQmKUn_^kr3KI_;|A>r$h zws-KlPig?q#t$9#n|@P#fbR3?O^E8_iWCBB*>UXzhs_Sj%jy$XN}aZmt$l5d2%ibu z{|E8Hd&0GZ3@&YdVdy4dEBHcnS8k%$z0@9TjAV5H1TTnWI5V}G@I?{W-&%9c@~me*(?2G*srz*F_p??X!IpmKGthI%ReM3m zvVT_@!Yvh90wQQwmbK$T!X9#z#1;L_65!fJO9hXd0n$*LUzS4xiSbZbsA_;?yFZX@ zM-*DGX^h>@)Qk&Bj=A|QO5z0OhwJ(7gZ}A-uu=d7ZoBkp)xLS`ZTs3LMAsY$3?i1S z?2z$}no0pcY8ltTC+SQE`m#1f+V^flSr6-O1?ma}o#LPI?9ymk|s~-)9?RS z3C~$ynI^*2m78H03nQkaA7ZK5c28_-DA0;4S`c~-T&Xee)F0xUCFc5=0{&tN3O*kF zc_bA(Z%xxeYZZkAW4qv}-3O1K3D8BQFFUtrBao`LtX->an&Rg0gR7G`^ut*fRTeB$ z`TKH(*me(`zfo&EmTg5?aU$ZXx8R*Xs-|Fo>m+>6X#m6hcHX$mZ7Q;8-yO#_4K3w6 z<)p{#=no(5`4Y#utAzCJ12$wdH+fikMaJ;1nP#{C@8}$+0T1nVe*OMvKM+?lAMssj z@Ap}(HD-V;uz;xz==kzT*PzUi!&ytZ@4W=~0#5TY!blDYE^;(R8Wo(#bC5Jh%=$t`M)^Bo1>Y8I$F=3A-KNl}GV22ASKhMcBhV^B%2MUZcO$?|PibddaX%IC7c$$h`obDZ08R(|sv zhoQG_e$jGk|FN~f>LJ_lP}Y~udtQHL+x^Y#YkrpG+26CVxL;YUzP&k?eay=Db$)6` z2$Cs>hXBcQm>JFBn=MbR!D>3o`EwulUD2$JVlRnn&9dwPWyB!CuI#UwhOt4)Lliv) zO5beFN=HukCV&rhvJW$}!V%)Ha+z-Lm}0C3io74hgn&X;W;RA~C(uQuec5ZG1-rX_ zJBy^LbrC9^i2`~{_W)_;TBgGONV#A!dTJ5mVYzD~o}^ijqnV3JpL8x%iAk+vsNSGmoe`wb_C%9?h+7&HXru=^4Cwh&_|9N+fvR*x4FO^&5F%|yqJFMzB` zVW+dSzm44+Sy3nbri4W0Iyo7V`*8CZBxQ}r^jnY(ov>a@h26Wq&24Yt`(aBNTHG-o zvb0;zBjD2=dD0}`mHa2BKn@)NR4a*+G}v1m>B00Npm{s@Y>A0vQPe$aJMxJX<>*_L zquz7rZEVhEgLZ~Ap7b;yct*PA^EmDXrY9Zs1#0ox z>><6PF@C#DFxZSW04sVVn5aIiKe$`FG~B>$RSpQ_W&@4s^8M1f_bgbA^sK*vgu$>= z+`E4JF5zP>5DHUMxF6&e*(Y5qUeJa~n?{&(K~2*p!%mJJ&hgW5_)+|Te7uTZJ0rg7 zxuK+Z;l=Pt3K9%B;8J+t7Y;;WtGhdEYp`t79|*_~cI&^$e_J|d6UczR443Rrxn>;? z0jtQ7>-+@hc z!(>c+j1aSWXDUgG7QDP9`j>~gOD&+s|Anj*RBVv{;RMJ@bL~I0rZzGSrD?u zD1vtZgeFqxj+aFLQ7(dmS2QZ1;?F!-!+V(kt>6(MjiyuZHfV#Ni>K-1 zUx4EMcz2q@#?srg#oE6ekO8ZrnsLL7a@*N=oBTzUBj-PV&$8LYEZ<=g`tt@Pl{{|$9L+A96_XVE`9q)T`dbvTaI1V^~}@wRh(FVlg7Ok9hs57i-qSTZ7#~qdA9bt zvq0=(l~<5`i;B=mY^2G!kqIp3g7_pnS&6q9*~W_6h~U)GQ(T{L1k$m&Ak#^41ZI$O zZvnti$WqFH8IjI=Z~;t?xSP<#M5dULg;JGQHk3Vd=edY#`7j7FYC$th4MV|Vp|XsP z{pMg4heb+L9({EM4rX}BFV$Zrv~9+d@^uA>eF*i0T zjEN(8n8IWOV1i2ycV{FNa)bVWNOTF_1DJ20iaQgyp3A1e1-&%AK^c{Ob-!%7Z|*1v z>a)O~&tH-o`|`MVV+z1AImuuyN7WUDeJlV^x^Ws3*IEvduTrwpd?ni3Plh^%KOZ0Rr4Tm!j?4^GI8u&)S@vh_VkkNtVlu&V&+D-$=`tizD`hSX*! zF;@A^o31K6)UMr$b*~+3^{ScX(EX;75<~*Sgfh?saG7Muyn&-QKVlA@$^qKT+51`ALcEZcQ;A!vnM(brN+V0;q#&a= zUZ8VS9^Shs-1%kVK7jd%owSYpwq^a050kXKI@+wu4wi&<9U>jL{xnVHJG6e@*4d1LOW^@u~U(EG{Q6=;@}+h~m= z2qFbSX3(3P00HZdIg)is3)i@;p2b6NHLinNfW*8XsFBa@i8Uz7ecgD%P}N71Q)|eN zPWCxbTj0DH^S#{pvlm}dl!vGQ-CMZabxzWh=?p1W)#v7cpHGt%E;S=n38Qvuas{-> z19-t&4Y#Ot9 zb{n}!E0TR4yJGvFBl&UA3)bvwmrj) z)vd}BxEGOAv2eYE-#G0PZ;sr1yRRQOovtdn#Cqa#qI;{rKOh>+MWT%Vj2p(l&b5u+ zHX7&i3JbCuX~G<1l`U6>oyWWH&=W&rD|%+PPt7TpT8g3xhMs5PJvBI;{bX8EVmV~p z`T<2>uk$3bPB?eJ!nf4OK?&kQ-9RriKmau0;inA3|+Ip zR~^s0*ZEWf7Ud5>u@COrsxU_ug0a z1|XX8RkWRt_tOHmQ3dwD5pwToa5l?#hPK@$x|Y?+FES^0TrL#pOoY@-BGD$Ao*-x6 z-k&{d??rPQ0XZK++??i!+dwvEikZr@tB=eev12p6x^j8a1Yso7Z~9~J0g=wl4PBnQ z5<%5s1rPCK1;rhg`vLqz@osDYx6ru@GR7lEL(CZ-@ z+-8SPlk=Ay0UEn=rF=TCDzeF?yzB7zo)yH&vbc@Kbd}q7pC)GL(m^8!2bsq|9d_0Pq%_W{1GPW5^wccuJ$x4ofp`C9$P9@Y`}Z) z=2>OyOOT8qHOKCkkntM*_GE?Xh3dZNrpZAwb7=I#O5I`;Mzke$*)|{ z>j#6aNFE8}VX~U_R%V>PWS-?7a})Gl`+fXh8~66@{*qtr2nhaVeE-8U)|c$&si1~c zFXT&;oQoZYUCPc-k9W$`%_&PC)nbQ4IetCmy`*w(2Yc@8zRSPt*1oP>Pcm4Y|DCfP zr^3RrY1j20YVcPz=^s9m>DL}ZttVf|JMsVZrRBd4hRpY1)dpYYp~b=X-?#jqHtjD@ z+O~jChYv2vBoaqV{@?db);|OR;$-13FE9P|=l$8%h$n(|e7sU6=ky=0;}6Gm@VGcI zfE^wxhyO+c-(!8Sr1va6?f=HU?BD~2SugtZ^PlhBAHMa!+_L(6AmcsRF}INWS4q*I z#Yj*9)q@gk--n$yPyLN0)dfrX7CDl1@y|BypUnDSJlNhiaKE{|n)}%gM#lF<;(z<% ztpHfkO9j=%|B2T3&&waModa09^|5RB|HXIw`B(q+S*?=y_sN1Kh-RBd>76B%Rl)aPxxQw@zb&Ruk-lnSp0v-dDLg`Fgo)i!o~3g z0IH0(en-*oasPi<_D>J;hl2r<-MCK$T+f#OrOW+uNBW1i*v_JVSo|&N@OJX=qqO4$ zSO5(&S>U>%?oamgzxa&3xQCpZkC%(&9RAb4{PD=grGSGD^0wE+a{Ucv%xfhqr2mbW*Tsx^Lq~4@4Jm=+nqWz}L{oy0QX?ci$Q8TamcVeCnu=G@mLz90aVSd3(n9-OKjlYpFr!o`f5}}v! ze|Wy1&ca_iBXKk{Vg9f4_`k06zs}?5MEt+b<0nt^U+3|Yr}?k*_{rP;*LnQcdHiG$ zKZoD{I*6>S|+!{FhR_3S? zS6yud?aK%?CtT@U>XeB?zhO>{Qn7bwt7&nz;ec7Ssmu6azhi>Sjl9?Wjs3G`E>iQq zb)@`!uzp&{|M{c(5N4`$6%EyJe)k6S`Q}M|A#Ye>QndppSzVaeQyMg z{cZ)yTaeM3t*K2IUuNBIp5{ez^_i1wYd+ax>xfp{c7^hSfy>sqrBe&T9z*ZIz5jny ze6cFm@Acnt@6h4z<4vtAAV)_P%T2w;cl6WGNv?=IFZmLXnZ1!$H^|yQ^kmT_4>gug z_*@vK@@KWvzh3Bi$j-JU85Qw_-ediRLA~(_6M$29uEAU7V&TXr@rtPP*bhR)vy2lG`qEP>fa1c8x>f2=~F)ZLCaGwAeSSvTqJ93AAfBO1oA~$x?8K0MD z8S4e@A2@Udw>Gz|M8CK-TB_{)>)w(-Y*bteD1q&k`}M!i{|X2=^lgd!zMp`vDFU7< zVTXQ3%Tb=`rDcChlgUJ$|8SdQlK|oXvnQ*6w+^AgdLewBooeSi(c3|y*Q!I~hY9?g zLVf>}pI=xHGPx8U17Y7O*M)(5YCJ~w^;i3&{2s|wC+c_T{KxMJ?(of|JHoz?4F~Tj zT!V5gT`GHG+*O=23n$2G{`@`u(otyR!L!fEctCz%vw$N8V?oA84ZvyY-Q(?%k~}bX zY{VS3G#jXQ%U6r1Epv1{EV-oYAj0PQAg!eBJb}% z{oO+U>1}?pXYe~2de;3j1k;WmD{5pO0K8>yd9;~BjA1rHZ}U#+z^0sWPHyqkyJbd2 zc5F>ms_DIUh5lhrh0Cu|{1u3f^~}obo-e(z*4D-tnsggW>ireuF=LZyK;I|_eAsDhM{)UwM zlqs%-GZv&y8SJDOtJA`33#H>3}>;dxqH7 za;xLlw9e2o&LbQL;s&srtlieD6aNeDi(;$ba?oD^dJ3PrgbsX(WO!Ced&@tmUmsg(8q{KK* z#)LXZ++1}_o3CZK%>w46K9jrH?^IB0R10`T{mgz@4717K69O#$0!PrBA;48#r%3$>@8{5yzv%`CGtG&_nz{X3)e=-q^DWToK=iLPc1JO3 zP#`fbo8f&PHY^W#qZ9;z6|{3NRdl|llKkdcDgu`H6uKl042MK1~|{zOwxM4Yc+YmwfF*o z+3!%bPnsO-pr&bdYe={EalAY&G8s@2tJ+0e(j5+10jm6*jWZzNkCzR{jEk9;ymAfF zu10i7y41Gtlb<>iBspvPc;~D10O~1GzxsZ!EcvZNiim&5)l`!~R&rTbe-1Bj zA=pTK4NyKA;Op62evbO#jL-Z{$`C(~32y5ul6BHDd4>v0zTm&Pl9E%ho*C*7xK}Rc z2K>62O(IJ6%ek$^7mgx3CXjK8g1t$!uZd-Lb&Z}8xv(!@36K8ME>wS;2);ka0+GsA`fjUYK+_d8= zCzU`p-rqs)+Q8je)bpq5qjaFMQLTk`Fp9EOF6XTZgH0>Y|A)A4T>Y88N3<=T*q-2qk?cZ zu^9XTh1DB~^+`;4^6-l%XNG!_>4(VAgz}H?YjqMa5ZuP3MJKm*Rk@v*5v}|7xm)6W znc0}TU;4s8VnLxm1weAYiIb%g1B39W&r`DI4Flo(*lkmAlhh4g6R$?ka zdGy#$Ht9;xx}dsawsmubJT38rPu5(cBZ?vw&&P;t;L`Ew|b zl8@>s=Vxeo>&zT8SQ`O?1&#am%w8l-zP4a}tLy)W{awPQWGw`R+iGIA!P8748$edeBs+{Cf{^qRzPHq2p8@AnCMR{lhW@HL7ndD{I$Vh1RA*NT1y$Y{IJ9VAGg;x zQSsO~<+KnZC7yAIJr08=VL*UMjqv23(b4CX`ZWcwIv z#y!XCmLBD!Zm@3{)!C3+O=5X(c)r~3U#VIXPr&`m_@mvoEC3}v z4OOFA_{Da)=s*CB7Ze938gk#MF!dqFyr>0YdnaU_SKO55Zsqq&Cyv}7F)-R2cs(oe z{B$?1QkZ%f5dhJ&aBtyFQ?Z(kT)6 zijE+ACx}$uDZ-tvo(X6PuJqiEy17rk0W-LR<6+#M2I?pp^sr{@lRTviN~mra?7)XYHhhFUQd2~e&|wC?aBqj$Kk zUlQRRS>Xx35_fDn__sf~AL_PYgMn+?m{+5nHb8(O=19!l3A_Yfa5%1c&?a9maOqCc zw(_sgg#-3 zqnfC0w3h0=UljBE`kXephO3)>bH2QbBmolg=^fYTw}->&Wk_%RO5^zTe|M_H5dkH7u^wGnQ?VW!B_c7(F%VpOXpX+7 zocWM@uQV22*6EyrP3>_t8G6qi5?9vsRxNOuFP{BjWZ7I#7}lhS8MLc(#9bUrQp!G; zaAdU07GEgUVs^8|ti4NzTy?ITj77-yjwZTKnS(z5x+(=RvS%+=V$7vALAtrbDf!+T zHUu4!X_HZl=d8y{PnX+hskJ%*(j}h4T(!$$-ziPUN70s zk7!wjsQZ4l2?BfzbSAqD6Mv;Q7H&xM?7ob;-Xq4>IX@9i!lGpucbFX=I9+~*BKzSu zlcUkgA3IhQ@Y`EtP$E5xXPba9(bZY&N}R;ZZ55g*?c`)RNSIfp-qgFZ>$=7I|ljZs8<_R7GC~V^|FP+P+;3l*Rsh|OPXb)HR#(sOF zH<>AZRhjjj8#1klvhb??EF^i46%@-sxR?gSE((-**axNP?`4th377z@AZk=(M%XfdU} zCs-W1n&<5_*z7cS-j=KvJOVYgLLpB7hN(}3#3X^9oX}H>$OKjlQ?P+c!e`VNPwT(1 zZ@0s44RQSw+)VX{*_5sI6ijwvOS9#=R_hmCY=GE4dEUuy4sk6{?`DZ>k83#bS_<}o z+M`T|DRI&W8Hb@d_|wEQB*bFwk?5n;R?vIF0WmpI2^9bhv-Y9bPa<@_-D06BpBov7AQrBSAqgD+F2pmFhfDQdyPkNIqX6HDKUYx7~D;vBhkFPV`8Cq zUh72M2^26>W7B$M2MFnB*r3ivQ@BqeX?c_MqeRFKJA)=&fpaE}_s<>)Zm-egb!lCX zPT5GWbiA^tuMtO=nM}T`IeBMc`XdM1o_2)<)hav9y03aTw=xCL&ytW+UDwG-ri-6@ z2itNL2*qR>gxQzry}h&IC)j|i99S3Sy(>k`wTRDl!7mI$%d$p=c)1FGO8kGu9`rfX zhfRk#IMBTXXznnKrFT|`sN{0!F{y}-Z#V@ZNe&#jXmAa?Ms&)r%s3-|(WMDX$uZk@ zdk&cn(!pdl3H2pyyOT~XRBf|+r+TC@()CR9vuTZx@8vTNWc0XVxMLuxfZH8ba&GD) zM{|UHrckqh%bEjG)Mac&EpqLn>kPqa(|u%J!uQm%h+)qhbBWMpdm@+22B6O9otCP*} zVyi5!&PsU~4`htAox>N; z(4!SKD*ZV7Wce8C>n?3y$IV%08VTi)4OnB%xv)!jYTEg06@wbe=k%gUtGCh@b^PGW z2KLLZN{1J{KQ7lcyNz6fE~NNvQroYExtOu&AG(DUlpFprKBm5KcMWwTvsh=}8(BQE zf5b3wGuHkDBpM>k0CE=v_Qj52iskYaMkO}<$N59gaJtNxk!S;P*7!sxyE3_%^k`L~ zRtfi8P7%g}OFa)G(X5ydmJi;wJr&Upv(q6;BPi+!g+8Uk<_nIHDd}6IOrt>!45@m- zX)1}c+f+Xm_Mjj=EnLw%>)9KLq1%GHqa~J&0$;@o9Es$l2niJb;s-_;aRHfy$*ga5 zum`v36L7)9X8MBbQBi6v0tpR%CdsWWQhRxii-RP{)l^Vi_(&-3SAoZ}nRYn4HNw;9 zO$Jf+noy;gLCbTs?Nt`lJ4*xIy)ouETigs~h-;1(kjElJJ+h1fFKL+7Y6 z5@b3(??TqzI#d5I<4O)!o%bJ1uud6JxzF!j0cl9LsA!wTV0WZ|vNPEBwi%1XPWGj~ zL`v~oqogmaj>=hbxsxbQxV&#@ct(ow@B?xbr=&xBC#BEQx{T6!Xbh#5uS!zJWii(I ztNYX)iHm1Zr;BP<_c8N+%emwnoLEFG?d)3uZZIKhuNiS(SR45k8qNW|(RGu_%A|(#n8~FQ52R zmXr<51b3`9_6KOOH=;i3m{QUkKa;~wxX7&rtHr*c?7U49SHC|p1;$&8cx#nCy_vH0 zDtUbnU&;^~)|s9wlE!wxBR%Z{pboLhwQaUUQQQ?A1jl=+5OO%ig(DZer!+mJ{zKL> zkK`6_9MHG1=L{}Phs?xuS1}8|Zsn??x|$3XoWV7iQO$tC319Y#Sl`PyNLGw{EULAP zladqS9>W@K@Ul!xK+9pb=6h3B10jJUdRP@vfqkO95&5}pbs(>@%2g^WZl?&u_`fEj zr-%+ zYaRfn@HQOEASjZ{Tr7+NmD!b}*JgAD$nLzQtQ$CyqLO3wM(KN_hDCWVWtQwLD|=Bs z>?c8xc!7?!-!F`kr#hP*^s%PIs~TA~0u8!Z^>ckoQRLol(7*`^xS61&R%`Pu4FP?@ zq$-@d;$X%+hT2XSOEdA%0vH3;TU-A&hP7NbCapy-CT7w%ftY!!d|g3+P*oe-+BYR# zIe_bt+UHDSEO@G^4LG~XjM678R1YOM*IU*3BNfvx2&y1BCnbqFM6^$)`O4SUgGA`< zA#apvIL6%qfG`xeK+L-l!8AhMx@D7e7E&pO(oU4pjP2G=pqdTZWtTCk+~|k`^ok=& zXA`-JNgXOuq#{||Y@(+h2o}oW%yTBXY4RNk$mOmx6b4KD|iR)!+<4)JQXePrXFe()zco&o-5lp9w@@n>4qc?2R|KGoNc3%n*?e z(C3tr^=CWbNG$lZNmJRK7KR>FY?AY1&FNTMpDT5{j!d33q2#%toK|a^C?$yFbPc8Vgg@+M`B?a6$2=aX83rh%s@9Q?%xa0RV^FrD69w3)(el8UC4jTcz`enFu;S)l2qY zA=F~0p<-D`QhH#SSu31B6rFWRj8r@2Y5n`zdQhZ(Z-m*LKS0__*_hx*Y+Gci%x&?Z zonlb%lxf+)g~4S|DjOP`-@kskZ5?!0=hhYUijSOlg>gdCW-^JPugI;@tWz7CZD5#a zR(~bl437s=a?NquW^o=xzoU0Q*F68Y{;&@yG4Y)gvdS9PH60e^gTHE%GPwLHlYFk> zZf&~VNsA%A1oC7a9aGjRtY?PeOf5!K4|HNrpZ6cfm6XQx#e1^8JuS8^bKY!OW1B_s zNPce0ywgxJQ)bYcTC$Zver>jG{93sF(8ppctb+4P>$hH)q(}_@CV#2S~ z>Nv10+hHyIJ8ok9SSKsiJ8+9vSf=Ai__jpM+ITvo)gyr{IlQspiO)%KKpyo4nRe&P z`}%>s?v_{)IHlj1%acB^PoitlYX=Jk)ml$%ue%Hzv9+RqO>|OJi!WX*71Cb_-OHV9 z-CjbSHjQ;EV_vbWpA^I4RV#P3&S%3?fG{Pg8WM`of+b84<)66H(TG~sk1Mm}r+7Pxa zvw75jM1QtUC2v?t$$pq!IZn~HeO#)1B^fYe0P&(vD9!wPNxFk~>CT%k|5Za z$ZxazR5x4HpS7bOHcmutOEjoUe<|KzpOxOM?ZMeDw!ZOJY2)hYgM%N-NsIcAKOd}S zKaLqkYZlk&$u?=VyTsGO%B@UNTFW38d0l{773@C4^o0KM3uNMjlNS}Gg4SE>vV=SC zx@pu-+$XX@l|Mk1@{^ z2*_L4hMgpP`>SCIiiS(Twu?|q~?6cydsm*8;8b2>Ozg#F!kjv83xJIv?)^z zcats>$1X*b$ufI?udV>wAUS;>=$cSAYK5tm@YqIOSj+Mh3X4i0+JN&{<3_(<@BrRi zWiX{A$$mU(Y|%HohdV+w(3~hQv^?KhEJbRU5-!ym6qPKu1TqYiS6-Zk;zu@2lIaqS zTMW{c1!G)k(*~&isGYzRiw;kIV4Ki=dnI;yJ#p@4zQ!7X0sq!4obl(SleNh&>HBb8 z0z1h6fXs~?P6E&imEGowSzED_Gpe?^xP!pHw>!^e6-a|}wZAkwIr2r7!?)Ktt$nN} zTEjt2(B)lpd)mnT-p!c0-5M8Yv&Q(Lie(Up+6^QDl-efbDIDUzx`?Rgq6B~vd_7VjS1X0wUo<$pzOxMoJl4yRMk|EpZ zoKfABq>>9QuVG+ht-VUOlf1ezgVR%!+(Pp*YFlNch&mM1LZ%uQs-%N&2floNb5fn{ zx`J!pr3q_}i=Z+v;D)-Myu&D(bHDocgU=nu@` zXEJ=~IIW7$VuzN>KU>+@tN-pLyLJVHkD~AgDp!-=4|^&ZG3fyp)^Myo?wcy?OG&Np4M2{C{A!r$YlGrr@Xd@C=PV?N{D!yjd4-vblhMQ+6s1sM4#tL2tl z>q>iQWE`D`dUYWQ(gllc4pHvE>}b5!UWCC&7IOVaRIh)?6)^^Lht=s?*tXhhrCS6j06J)gQ~VoP`{+%LvQh{x*5m z>BQ6J5T)@D$=SgJT34^Ay0pP1NQ946hmE_eQqtk{CrTSH&X`E31Yi}4(%CDLd@hoD zPo-g(=~4EoVOwcjj8~3fui})K!1Zvs>w{(**XGg_M9_5sD@m@!Kku89RN;2v!|4dS zyjZ7)Z+#2*7Jr9UBG=EnOY!*VQM`F^_;ybnRt26w{_>ui96vLbf)3kqkej#Hw5PC# zL~ibAUn>hf#UBukBYS5DT$;g0sPKXtiOx{OP#pX29%o{*`nqYk&Pf!DorJRU5NB_h zFSu7+JN&9Q9@7b_VzXTuh0Lcb=`75Z%=nR=ta9ip4~7d67BmhXFaFM8dE;dTCq+s2 zcWCL6)ozVp7l%%r1ZNii9^-Qir=GA;f%@}71U^`bYd}CAEFr&heIaw-Wm5Ml(%X(_ z+ofq=a2+Xn@%-9@m={>L@@exKt6rxY9`NdUxyXljc_*zxq@PbbQLqzaTMU8LB98)` z@Jz8jZM|eTp9q`5MAUJulUuhfRfbjW8g4(Dz`Y*Djvf+)Ezx@poM)8q^FOdf5K%Er|7Ii5>r}4@SF?GE-$?XT&TZB1YHqq zfI2W0nnD2fl>q7DO?_psn`d_c7Mk^SoNKFs2Cf(_!!>UOGKzErxtR10?-hd$bmQY9 zf58@gWc0J&3_?nb&d&oCPlUB*ncn2h;x__m2V%HiLH6N7+O6^P(cRlQuEnAEw9cGL zI)CIG6WmATLY|aL8@ww|pF*NxWJ|4}YjBdsaH*)4vZ6QfqBWpQq$Vu~DY3MoSsqpF|K^<&Ig5vdyaZcsroyZWH>w&#nss($~-I`+&? z_>C_1Pnvf8K)F z#vMRk#N*FsOI`1%&ty|=aS9ZR>Jg3CWdKO#c1(binf{Qz#8Wq@U4JXkv{ivSB+YuP6{Gvo3al)&pQm>o}6l_&v%f=z9 zyx+uJwAj|1T!Lm})!-x7k69R$BQk0w{qf)4i)H(7QT+>;KrnIpVF!}t@R9*xL_UKG ziDzN!65262RoNvl_Nr2E1x5R0i%*}3sm~g)SD_W4RdOWN;cOG_iZlKF#+X-^=Y}a z1k#4xYI*HdBYo3E8{30Z%Vt(}#Um2!iz`goD7UD&=&jMaIx{)ZTXyQL#e57zdNA9B zPt2Bwla5I&BF~|!+)ZJ$&{z5`snFbETI2WVE1m{XJj2F^94{K4#k=mbqW-o6&;vi> zM{OrfoDAGHKjph793WSLo7+t%9Zs@n!&MxMcrms#1M!qow z4hS4!WO2_JamHvSSO)2`e~fzk(4YsF;^sSk(nhcy8avgjpVU!`uB?fDRz6h+v&bYu zdT>`Hr;k-b3Q9AgtXl90)ZFxx2aL2F?~*WQMs@LXP4-e*2aVi=jO2V zd;?!;Au3cup&QMe{tppL5tWE`6G5{T&B-+|JIQ?4$yh{XKJQb30DA}ZRt3xi!XOF45Fs7iS|yJ z=*CEo&iCe9QfE7p zs8`>$yXi>O9dK15?AE@hn|)ZXU#W|x7=Q@=yM9}iB?PQ<}9qdxP|lhQpkb6pv7w@D5784B^r?l z*;&S#UBbGpBSEHMGs zT;%BHs)2$6uo>PMYjBcA*0k!d!J_oZ#7-b@EVw->&jBz5vkG7*qM^vXTw&)C=@c#5 zWktHQ)k+<4#le;6t;?p}rfwqh@!nNb5<7SNc*ZACJFR7@q1rC$S$B>4Y+0=>2z?2g z)&7P$#}=W?Eg{XfTiiOTA_eQYJJGo}(^0hJy)4zfqrJ^Q=Yr%# z$<6uuXE}F?ciY-3TffwhVAYmj1$5WIYY`7tt-cNBmiO0sF0M9iWqX(EQ)d^fs0;h% zOgc?dH0WKcTqoYEH}l*MxjCW>L(>G#uy;f6$)es{ygi>0Th5N4%TZ+*k( zlISASvG{BswQ4d4So%1P~ee3L|y1SmD)6v%}KyXYB@!6h_hn?l=3-%SB zFMrjyQmnt@oI_Om9JX=uDaRW70bV02m}?;a{t)(k@Fj0U|A(&B$cEdTZBaZY zSsmU#`XCa_Wf=6yBRl28eZ_>Mgy^Rl{wz@vuM+&&-(8V??4DSy&+yAv=GgvufhnFl zOH}4M9F?km)K%h!<2%zC|6b8Xg1zw7t>9byYoXsRvH5?jKCX>b+=l%10`|(@xQb=3 z^S++z`RoaPcI3VOJc`Q}IJe!@z}x#rPc@My6fsmpGhO`JX~XbU{8MP1(tG-(T2wSp zXP#X>*&v&(X`MzgMq94&S}D!WOhwiy@sz_mE*WohbUk^fc=;o|8mkfePP#+xkuAQ4 zWabT5-s&O+_+4GajZu?Gklgisi@1nFy|ca+FRZlN#BY^r_tWRcc`@cuw9yOIA1^eW ziau(Cx0%x2tZo=|%vq)Rh_Q;fnGy;yZdF_y_bY=*S3S>WS9k6?pZbvHAOCRZS`W4D zduC`8u~a^@!HDi(Hsd;V+emlqlxv5`WTzo~MT}#|OouerrtwH?sap>n(cA7OzmFQa4|f1@`PZ zb)Y!*LOkcA39&!{LteM1E=62@r}sIpR~aH!&JfrSzI^?d^=*M4B`0riFJW$i(jC$G z)P=lry6$P%9Btt2kRfu1mLZje*K!sjRcAo% ze~DMR=M@r6IOyw8SHJohgu}$_myypS-+UmRmn!Q0)~s&IgkO@@zQ#M{YtYRR@~=n5 zxefqAM>bBq{-O2BN83*M)gI25%@5k} zb~e_lGxw`4GvnXN%_58E5Bn;q&LKxHb*_`8zlw6Hy!I{Nk9$LDdF9D7KSkWF(e$zU~yATPcwp0K}R1UfeH82bqiFf)})qT+r zw#}zm2QjdRMt3d%%87$%_$A&8RVp!n*eu>2r-pi07p_SAlApt8@<;`)(Ri-q=^&Lk z>nDFM%QRpdC%XC6iv1TpqfKxxmu?dGRLw*GsagMfc8$QZgHgARzP61j1p38&Iuy|y zWt;8nzcKHk?tK0HJ}bQ4(AXk|71==-MhlG(g=4Fiz1)zMUZ)A~l&d4PRofC4k5VE} zq4_rsO^4D?kb=J&sPj#Qe~>PI!B~2tq^;5DYY*`M01ufh0`vkcvXa8R`M3en%c+eVtdS{Ld;KgFGk+W8 z*H9zh0&B%DHMJtLRiqPo%Y}qTQxhy7}W;U!;%z zBt=c(TSn_4pTr;MX3r|OIBG5TPJaSdC{N$jBNhcw{1lyp(%VjJbsLO)q0?h~;%+_b z+jiB4+JnL(TA< zKJI|lR#)n=M~~Z9I+c_x^H+}VOPcdtBFgN388LrM(p2PDA@{|&K9LleH44MhsV8!L6${JS4Em7V*ba`ntw_d)Ygt4ZqTinOrh z>96tcUVPxs=U1J2dFuaR?>)n!TC%p`BOpprg5(TMP_m$8P{amAKqM+TNDu@8$uvPE zhlWOyL(;6I;>c)B4L=@ z+uKQoA!Fpbr3gyXB$D#z2T4b=rV`}*Ewpf_up2p!haf>eSBrx=YrR$W#NiIUg?QK5 z29n4av(?h6Lhc@1tKq)z2=xbIa?BX{vMUEn;3mhYya8MqVvu$O1RjtID=Py6#mp z-0h-#5cHU1JD>Fy7P;4fL8dS*fmzr#dQ|Q>#JtY#+^dcin}g&8nUZw?$NlKCohOJl zXTKmoK=HK_#-iM`JC>0S*OU}#`}gxL9}@_cP`Bw3M|Mj4ZJ+>qf>Bu1!JL&N^XGWh zb*7Np$Vw%VH}?1=-Gw^|jNuzQAiMaWO27gP-A9_mlVJ8ptC8%SoB}E9lnsT#fQ`|z+P!>39s4RKf+pge z?i(0l&U%(Xq0ce|zD*KAPh1}(ybde6Vfy!_D^IB#_Xz-`^$!(`|D}VcI(+kHpG};#UEi5NXmTe+k0f?_L{WZ zc$SyEi{?ytOQI)Hw^2mWti9K0i*Fm`D^!?y2toHoZN?UQad0Ta#=mV`Dm`;&dr-^YeZ)I4=p}jN)J0JesJ<<+{pd?~JfGgc9ZvT1{hf=^?#0X@w?T)A zU2AX4HdGv{_gH7UduQ)^zHnamhpbH)eW%=4K9cN?Nu`WUfS;^Kl6mCav)SgFB-dyJ z%1NENKT(B2hZL{QrZ#2LR@yAlNiwuWSJ;(|G4EwZN3{n^o=vM76JJ-s zqdEaLN7_ID(l#I9D-@EV#hy0Tex(0nQvZcPpxMBQzSom!29r6z7D~xO$4J*^NoK>U zTD#LFDf+OmPp+S~&AWsA*;gelt(KGT-(t8LNM+6A-n-y_E6vSavIMLGPZ}nxi3jd5 zq&+wc=D9l3n@;E)EhXPZ@fu&NZjU>PC~8t6FX^TRt*^vJQj|dJPVnm;De@9GL!IrL zZadB(RY6daw%v=A5B3!I*`p&M5R_UnU^%gFX>wTzhQ0R2cU{*MJMD$DM858m81wG(-l=MH4pNDE z&Md5UU-8i9{xnlp@vg&CDKdRGZ*V>NncfCV{DP#4DYJh{%p&!v!A%@)VM09*>dCsn z#hqgFHiR~_II1jaDE_oe-_~TPz18LI_Y49bjkR#k>Ys{Qnjo*PGugD+OgjI2-yJO_ znAXOg=8>;yr30i#rljSSYv%$W1R zF9*9RZdt8%D9G{(NPZriGna+lHGla*H2|L(F<|w~bU*?J;+*kVeGqdnF_GiAK3b8# za6~~zPP-JEDM_c@4X8OI+dT8so=@y9_4U0|y(qPLV=J-Si?h%L=@c0s&2ZU)xac=@ zbE&wc2$hhenSn`vnbmK(lBr%}ikulH2p9(q(kw>q7Nan_S5aYxrOjJ~yw=o3w)AF` zbrr%VvR9W9F=g6cYjUprORF2mX_t~8otNn6m~_Y&rCoxzEP~>C;U|H!H@id+BCTF< z>9%2>H#)at-W2rQ=(KfwY3QF^GqmqCHo(|!Rl^*yFshtG2SE>C@y+76_!v+d$VEtCmtDE`hi| zHv}ydLlcl-FVN-9ss6mDi%Gp160JO24(U+C4LE*z}6>&<4 z$Ag1GD?9~DoapY-@(CyDXIFN+LuELLXPIF4JeG_CAH3wO8!TG2lKtuvA#Z}RlD`UR z^Pby4TWt)Q4>4h^zIT>ClxZ;$Fd84%bTgPhKfA(E)B5h`EZ?~0wub8X_FGFI;nQ;za}Mx>X#48jMR(ersX z%;=ac!lGqA!6CBO<5e7}s%7K5g<{&`i+Yu9^?m2pT&H1Y0s0gla5 z5{DxfD@|ifE<)j{=2e@ct6Rx|X5*1A37=?J?XmZLyHE3U36I-r=n*-_f`C8ZRiS zwu6mtG?xypl#Y3aw^%~Z&8uNe<&oEy;vPwbQAEb{!}Z7!RE56>G4&^#__3 zs=|Wb25EW4wX3yOAEPES>`|qGb4F-Bx1jP$XZdXgZ2cMoS=AG*{<#>bVYn^^(1j-B z&#k_tLy-Ux#@!IPxAtUvz!-{w5 zQYE1+NXfmIB_#Jc*g2EYF2Sq(`r@sQ7Hz}8K`$x{gK5gPV|2elaSx~(>02(7BNjK^ zn{y7tyh0NlXb{sxRT{895c-mS?(X`6j6%4SH@#vD5I@!pWld2YdYG5u2hInP55}^VIV{q<#L-fS`-!3>?w0aQ2p%P!=!hXT^Q{j zc8f;KkHmGzLbFVi?E3XsmGk$IiptIzGrc|XO*&ey9i-@r6Zlp^`KMaRS;PzIErSky z?N9t9OAs=3#gmZ0wwy=rxe%>6GWOd{t?r;Xtqg&o;VT-EXG0_?KF$PG5@H-9v1Ka$ z3`zl0;GlBkIA>lb0C+9 z<#Bub0z>op`08$%3zbi6rf5t0wZ3&9%z|W)Gb$MWc0pk;HzW};1ZDNxAp(R@R<_qW z_h~226%1k-!?qcsGwBA|*h%9QUeU)rDI8p5*%Y%V2vF?G&x!GbC=F=Mfev7s2Z0XX z9BXP@T>~3kU!v)Sy}v%~hWSNXt?cIxu2rP|?VSFLiv4kRC*&5?#vwLU3i33)kG#ab zt~bs+?HhgL#@(=nyCboHpG>Ip3-T)R$<7(al>zp*ExgJ?!S?RrrOXa$`+ns{#D@@!u*r^^0O;!5kE1@3!X8i>;==LrLQDEdA z^Ds}JJ6a9g6h*=e`F8P_0(%q(P4O@bvxeK$Y6r;cCL+r}nv_au>)?j{z^iXV*HQqb6-gl1~EmCJ*O;_JbP$5&>KLR|(ytU}D4Ju%fZ69lzTQq^~C@S7}NEZRa zi&!qW%&>zHy|Mk^M10WM`^f~T5N-xd=r6S`>k`hytdZV$BlNPx`MHx<_hDBGV7STO zFsxNcb;8V#L>`!m*UFmId-liIMb5b)cR*vE4TlxBkB+?{*K62BYJsWAp;hrI-em$S za{ZZPLBcB`_T^8z5&}x}@vZ5d4?M|w*j`~Lg~ngybWwQ{&nC`$mEWN;*%C}Mmx%$j#WhVJ02m!uanLA|3)E)Mlk zvCOZc@=vBGkfY~vDRh++o)v3mgOsB2iq+-WO2o#lYB&cJj$>}>_#9MCWF3cFb#QH_THHUI3Rm%1jb|Fr3@i((d zg4GJVa9s--c0*ozIMQ+WVluvgm;i{;-49J6+u%48Y))=E<{aR33Ci1a#I>)o8ZF+5NnhTmDEGrdA4>;apt7^2#gZL#@LL zTNub&Raw&7i~8uJgWAV6sv8bQuM4=3V1WlaZsKTCOr&mVCI_l2>SeQQ?8((p+{6aB z_w{Op(~yLSNY9SvXNgQT@)c0x)gbe>vf{L-TFv>rT6;uLTG(R>50NX{^UMh(Sei!8^2*( z@eLH&vg#;dpTrcrWQP{o%3+j^kOZ*TS~C?9=FC$2{hbiJ*@pYwYmC-s@Z4kl3up)o79>Fg-;Tp1wk4 zSbbnU6NZ0u^R+Pt+xn01+l3dgcg?WA%4ovrH#ePbC1B$U_o!JSMB)jObu| zR*Q@oI8p?WuuWFtM-OgEYmfLD0bH396>@oE#sgT zPP(l(@>k8O3q124lLD&4nLc7S$OjM}>d>150^dl(-Wn^L{TdL~qO>2Uo7J7i+0x<1 z3#NGx-ZEL)D4rdCjm}9;Y75zKtX<|+-M!}wj_;A>7C8t7v!ml^vc_%oMyo>(tENv- z(%=?TLV{Egm-&Feb(aWpPy%zBARsd>-kL~Fe$Ki+TyC0!BwK$_gb9jk>cs@-ZIYqT z&*h0;)H*nl#q`NW94^`zp&zb=M|b2QEKh<*FG^Yo1=re>IG-c>&$r@LG_3zm*2vFYhis8U2(|y3NQ4 zW!>yJ{}Rt+=pv5Tu}qH}^Morxl%SDRYH}1yUDq^3xuW@tlK-cj`<;+9p1*Z_oAP8w z_EgyCL9#;&?MjE00z*VOiG#(oFfqTLmLe0DVEFrm4@%o-amDTjkCET%JV&0N6Mqog zAg>P}L>915!NKmh(#Bat5|__|jNe8w53sVb-GPiES1J{jO-MhRTnbkOKIKa*+67jsyD7p{6g7Ou+9Fsh=0o& z)g}LWg4kcPjAxgm%@P;VrEGw?gy>h?%(*hkbrdFdbvnLwH_I)Ni8lBZL?4Auda-UQ zkRIyAB(MmVyHA6wxe$P6-CE?{wai&oCQVy_`&V{5@B_#4CB8~F{F0KzaV$}hH)=6z zF@YM@+@r>3ddxtf^jL)uH+I24wl8g($LQ!z4t#wp23}A)Qa@>x9Y%SWdj&G^wKdc)n-BOo*Ksfy z@`z5EDy?7AOfB-p1BQ|j4;v>E7>udun@w}55nruF+1tVbuR-B&qU3Mik{~(hsEp<6 z2%ycl)=R2zi;l#_9YNUU(XVhLfVS%Vji_Cu**NKK#FvTV&WTK4JS8_s!EIb>5hD0N)S+g04xs{mX7F&NT)u@EbexlqAdqjN4RfP;|t+p6Uj!dB^yybn4oGELY zSh8$hMs$o*gLvi{{)2)X|CahfAI!>7weQ*`w>J*tL<8*Vmx4G0 zkgsVT6t!(1U7d46mMVRoeQ5Skp-WmxDSB1m7AJrB_gF5%dFKn$;w0JF8j&>eOd11W z3s|NdLm5D05hE6 zoZKt^rE7r3?t7Wx_>AGrX@LW29FZfKNFf}3!45*QV_@mt#WCSCF!OMEm$7rj29=B! zE3yAdY~E)1aZX3uHP(3ND9WYGWUZ zbF__}SqcaN&C zP4v()0A%QUMUr1FRT6|C?)Y?PnrdRJe4(e+PfP+M-~!sww{upiE%sILEjg^CStYnRBh55o$CDpJh&@BU3~tTK(--dT4l=)mqV5^YNt3}lZgJon z1N>|GGK58^y|SUT@(i9@tm;WGl)Vy29B2Zbe1H=hf-LkKw@coV!=j}IgF!rTd+KM- z1`2!_PsT(pp41rz)fw5{{GpqS>v0NY%iZd)sn#rO*L-^8c5-?$fh)UNL7hC2<8)6L zO_I?ypjrScZaO{aG)1k>liWP2j9C*Wk;n3P5?=2S)cp2aEVFQg{poS{X);2!3()SF zu75{XSIS-eT!$H{%Ys`c6w<@sXWzxoS${NtQR7XQw!Ci%I5q`ajSSca(#r-5WT3Y* zqNDM94T%u1bG6CN=cK5YmRo+BSMMv4WjKw2_s^$F4rI#%U!Z!?)3UYvUkjEX2+`;o^O7*1L^hUq$~|j zGB7TThrB+yadjGZCw7}?6Sw7SZZe2CU#v7XE}l@x!Q=SS#>ot;TrWv5301T5wb8NK z4QUM4UL$OK+@X6dny@W8g&d-=;wF(2#))naH%1n=-M12B$Zu(q5T>Kxim@JZ*a!F* zRb!)`Uq%v$OBrx|RFuO>hn^jI$C^!&5C?|6k6s8VbhytezK+jVDl@8~BEnnquLVK_;YV zNlGT!{UZ1$Xh0=^dg{CDqt)6O?2m0 zJAF`him4>ZgIVq^e`^L^cIsHF$tBk*U)&4t^t(hU|7~@`&wngx`?~F}6xJCsfR3`U zg5~YsPu(*&>S<3}8kC+=|CBJ!$a*MxUEg+di!bcJ(979a5`)rm&8oCuK7K!N*9W8B z)!_|6-yXvZP_H2jQY}Y>W)c?ROaOa}+OvpenhsH4J)U4XOdM(>-pp>i`B$VT(`!NG^sNa8?@iz^lD~w8V4*Pj; z2Hz&iKTN?hCdS3ne*DO4Yq?oe?fZ<4tFc}x>{(G;bYO|P+|-wNbPDoDC$Z2~9ci+4Ljd%ONA>`F_aDjaFaJ&Oz~MYrsc~8-TqkO$ZoM}wkLXv&NwTk79E_}=9({RwC9UxjBB9uJxENb7z&j420nZapuy|*t zfH+U!ty-E)z$2+=*wKsneaqFM#zL|^bf51?Y=+W5>DRlB`)~zB{{=vLv@Y`jCSe#3 zn`Y{+Nu9L|`!nnDKa(9rB&H%?Fy-{iXVMXNh;OA&&z)8jOnr?p6N((Z>UIVpb6E0w z7>F2Z{QaYKGnJmLP{J4dd+n%|LL;wfiZn$Z+;?49ewmK{Fm1*NqPt16tqW7X@2kH> zm;^8RMO+-pAF`@52)cjZmiN+ZE&=#rf3F<*^H+jWXDChrEp0k~-V&p492O8nxsoq? z#ML=ZBd-15%+ik$5bM;xsGCAPtokv<^$@CrqHoEjVZ!iaq{89UYlm=#+&@ej|GS9^ zY?qtjL^iY z4Z)>IgxUA)yrY=)aw(QyB;n7lW=pOwfzQldN4e3@`KGvIymC78!qgvbFaCPJVyw%N zmm%gajUB26=DfGWMfvB$V|0yCs}Gv5pRUZBV)8|kHWk{0p8mglzP@pbwo~Yn)BSz| z={{y*v;#3i*k2nwR$zMfTx@)fx?!zPM z!;6OV^nS77#@j@;?gQ%0_>y)Syy&HA(@r#Vcss74J%+ZK%97~;R&pIGeAZw75V;@Y z`>~z=-PYDn0<-r1S*f)44{7vMr)G(^8(1HqZufRj*y_5a7J=FydGZvvIDDnLZn{Ed zx#DY7JAde&{ku7(;Q;CaO7Ok&=XmZKoFQK>JsNmEy@pQX9xq={ovxuaV$=vHk*R$o zw1D&v1)A!~-Giox|55gT{^Nio)GK0N=y7=G=W_eKCWta_ok(((d06efVy_^*1(&Z= zncvV6TuJ{+lGl=k-IN>2;I8n>jUBlbr=CBQzXHUs}c zs(($l;x8;1;VzePqmhqyLH^HqxY3P65A%qBUZ-WBuh{0p!{k}2dxVyy%GIeJaZ1S( zdomE%+%Z-rV6pZ|BgY5qXV|xeFF(in=dT1Ma8^2pH-fKalw2rSK{eDQ{72PPU zB6Zt1iVt&5J5}B~Ni*ad_c@9%{bpnTHnaX4&jina*XGR}>l#|&P-|gPZpHbe+9S?p z)JVtWfz!jd=0HhX4ciY*0|vI8xBrY!_kZelIM^;~(sU-(_xKV=hT8F%|#c z4y*o<0ys{`DHI2a|7j}zVF>@?$Hs)%Sm{}{%AmZTlKI!J1W)kp9@6_PAf@mBJ4Nz; zF8#mzUBYv$tJn~;&iYrh$3F}|To$O3mI-kO_a#PgMOP1G=|1zrswCsC`>Wyy#B z3+?eAx6D86IX`cpAXXH*o&SoJ_{Ue#M1ie{`}`x_U;C(EKLtf52v||2|2X{e58v_Y z-M{|B_y*8gBm54pWMue??kpDuI5v#pQzg%dkFD>tY7Jm^QPkQE%|W3fvAts6)TmP@pAZuQBIc z8OT$?(XZLxz{DFe79D>46yi(2z8_-RB<;#;u~ydsjuF?0_+fceB*}4o8J?U;v&Ahj=A@F0>wP?X6W!U zEG**Un3HDd3iRg_W<-wlKx0na3{kD1T1w$!2K*8JW<#KSj6V`PP= zMSNi@k+SItpH2&$!wzfz(zp3xzwJzA($DO2!b2S9>f&l$?>U4>`?#Cf_JNVdC*A!f z`p^d#r5@O#0=g-MOTRypT8%^h!y(}pA^8LIT>p|9cDK|H@i0sr)?>nE`ed2-gZUv3tZo7`)s zqP7=sw?%r+tep)BEuTpRHhn!$X zoSssDu8>#2@CeSsrCDsm&|Rfg{lR6zr{emSy?gZ>NHP8S=l|W~3V#FCKt}M|+n+Mb zS@v6qW8ulcw`Q~eU($zjUuvC*IWa0j8jF$t{aNL%F|eqdn{7^mf0y_(XItR)%VpY^ z+G}0MzROpLwsfoRm2)xRwicuEW2FZsAOD5V;O+?n-%<0fBJ!6>;P87STkRm%y{aRT z{EWBV``N9dCr1DMCxBoLDJVUqXDiV9dGlQozd->#{c7|qQOvsW1Z+Csx!K>sH-s^8{`zhon$do2XM*>r2>|7D1sQg>@o zqd7DvEj3f2Y~92mkD=t}g#Cjp`QvX0pmj8{Lva&m&r=7;`T zMuY+E#K4)y`M*em?&MnY#f!U(3B&fJk4ny-yC}V6-_t4+JX3n%F9;lGSbcb#BMZ~7 zL9Pte58Kg}_!3pjXeltG535c(j;KGTmU&)1c)p{@T^Ls{)=4r@#BqGENt<|F{Ru--A>63qf}0_ zd16~~Hi+2yZQYhtkAz#=fAfO>nM6T9Y*BhWSGU1WS)eiS`(~fdi*-{L?LIaP40wIW zIc)ba(z=6^bhA?Op)of3D<>7d2Eq;+TjznF6@TgVvtV0%K2+W(T2n-g%=@I=@A&T2 zy1Q>dbb((+x3n57u|-4mOhrS7J<{j2jS4CG9u#M~0W_shkgP5e12w>*)_n|pnL6#9 zEBPR|dpNe?t@C?UxcE_fD5xQ>8vcNg_GyMvK_2E0$nlcL20-Bz0+=xR32fu9s)5XOL}ZECASZ ziRqf-=JW!+yXC6o-m-_2{^pJ1-$9y|e!>&qVQjvYsvGpD%2H!NLOd!44L!4Vn9{yU z?|bI|p6LcS<|0+LV=f?JtAVXqk7cgI7MwB}9+~XVgSvK|jwDe5&(`dp8}eUWHBqr# zhZ4s)er65IbbIX4JCz1{RmyZrEL4KBLQMfM$X$otoU!tTZM;0}M zH5fr}@)K(I`2b1>!(|Q`Xm~sg3Y#}}8FOKV-c5Pr0zi>9Evx2^!VlLq)TCpl6Oln7 zSx{@sJF964l3T|6b=J1x%lqnn5@!mOP%cj+9HhSrWLUGlWjtURNLd`@fKfAnS4;!^ z2cAW>Vt{ROEsGnQ#NHiyt44Uhz`J;{5f&(OrHLQF$Ehxd$@!3XErA4ma%s0vPj;q~ zJ0M=tU}i*#KDDb@=n-8oV@B(a$S}`UE|uIgI*TGKG8!#e*n20TIc zGSPm3$D;iu^woDO;S)F4TaT}QAn{fcv)mOAK@pqCAFW!-j+Dx_v-l9@ z?qfg??0XN%v2%+H6h0{(8B8eSH8AS7;^Jw1`>%CjwWi5w*e);!=C}A-Rlzv7$gBop z9J!N9@Bg9&IpgZ9lqI>YhtH8|abP;dr_x_Tj!lFH2z*3NM!{-^B)5)p*_Nn3jjZA@|x0Ds$QiW}SKC7hcj%}U!+O7s$)@TMWwg|eEo$mH-W>D)e z4cN)}h6=esEy_lp23;n$hO__1r8F&R#77T+S4#!K#1fHspJRM>Zwt#nWED@W#74Ui zRGIVK(#r)X11c=#lRHKJpc}&cAZg&(0%k-yXh^M0kH(l-xKB>jHbvf?< zMImx6XNM_bN`!nc_NG2hKL#+Jlun{HG_6?jl@C1ua|(TmWdV%hL_!Juhsh^Fu`{M7 zNJI7ucRGrd-dqS_K{_Q}!r$kZ%E%c7k{3aKGL&sdezLgPeO-cbxlsAADRAftft1$P zH0*G2i3opnHR}UBdiI8+O17V=68F(?w|Crh*Q#jIay7OT|FV#fPvNpSF5d=d zl(}3w3Mtjo3fj0#iZe;GTW8JNCEtE6=l+^jSfnR|zf{Zz9sXUR*M(FV#qx!3l=yY?hZ!4+ zwG0^33(~ti{exUSb;rrxGFS?sJ1qIj)J>MF3fZ-05ZS&UPVb4K3rdcc$nn)csjtYU zmq$jckD}u7UZIac6w3px#lf4h={LD-zShlwk}?|%Cv09g%{pmQGjFpL14rrOac@*#TBKH$$1JL9IVbo2eJP%=gP$iV3eFq25o6C*xX(m? zuL%16NG2$Bb{u%R4iz&_0%CP8bpsQRRo5&rUV==#Ur6TX1~Ck2E0LGn02bTtJ^T5h z?ABrO>`+RGU+{3Vl`RG}SZ6r=`Ac!Uk+-|e?ltJuOeQ)8>l>!eF4MVUrI#9z*?2r@ zng@o*ND63MYa_)QW*@K88CyZ#HiRb*S}j6MR>Ot6tk#@PUIfaMXX*yZIbO=h?oCj@ zVIh$c*%Z3^J<&2X5sKSBxFAk)N8~r?%q6rOOGqHgvL!^2PEW~25;S_=&oHgHVA$6K zo#75>QHuY@CQhce6+0CHJtm%@s+|hUMs|PN;ae^7bS1WIy8ytq zXcrreUEMlKFQ8lwbJBG6)(u>-1WI$k`q9*@(EBTXZld6%E*Ax)*nv{KW#NjWLRyw%sGS|87BZBu`k_v zgoezLDL`bP(~Lq7@%1^Z5eaO#0~bo7&fltzFBh~R*8P&+<{VINnOYwr?%=bZSWArz zqFs#3yxA3d+wbQ2o{Rn)1j5f$vgFdjKx5j~G5ShryY*(FcPC$@YU- zPfpmA?_t7DCU2D8;R0_0$DPEb7Qj=~gT_rakIe6|;+608q1c>X>V6 zv#T$_UM^DitDIJN`w+FG?;X6FzyNrIiF*uU2QPuNO6+m5FBNK>lAh29+#DU@NElc< zH^EiF5r#v7Eno8_EYuRgKBd{)fI}{?(GEPWI13T8{@hC1Ow@SKr9$6KCg|{+9xH&|=j|Z>oRZ{zhpGZO zQ^ZRVrdS0+a|0Y&fLukarqR?6+RG)_d~Y~XWpI=E8uvHUp{wfjECXfe2-t_=^_`%X zRLT^ofSAEDT4X|RKflPUr+WR(&4@${+c3OE4tf~cxX>}*vS=3BtNm5HTM*;izN~! zE|w&2#X(n3-y3q#sw9zNn-ScGB$~bc>c}If@MnQCJEyz)^g=Nk;@9FZC zbnwZTpQFmtaWR15k{vh#OwB6MLTo)GApHzG{{H=GDWCn4G(IdWreV%g#vcpwufjnf ztI%^M&5cb-ye2M~HG1?ZFj5DaD*X*#uw*+|&LywCpSH~!!Y{#Nbf1kL=ITtn8fF4X zC5_>1dDUvA)WRCsS4Pq#P749uNXRf-g-0S)Rj}LVe zB|;N`C%JAU*4u3fJYk*-GKZ6g<$Is)HAbD3&S#{lrG8A7jOnMwO)R^ji++LpyqHk} z{Pjz_dS5IP=Un|DQtJ~P`k$}8+ORPM#rUZ64imE{ZNDvo($eW*iNlnvi=;5bn~N7= z>iFu1om0t^3?a`_me&r-K4@UJ#Qht60B31ve7-_nQMv#*#z66Swybz;gTwAvwb$}P zQsZ7YgF&S*>UuYLWxR5keL_e)kL^E&a|80>nV)=>At;& z|Gn`jVWzHL^Wk&kWu`Cr=#0LUyca5Aj0nZEftoE zo45&_++UkSLOBTuJg_al3XtV384@2XsE6OhfR=j4*U@k}Mh3Oi)mAj#3oF4fU{Ty3 zjDphpHqM&E6}XOdOug9A$3%IvklIlzSbN@iN(vd_lXbHlR!mD=wRW*koym-ZNn>>$S~vBno# zZU68<+LG~`&_i;@H^Nf>>+8U`FxYt9L3L?srhrGcO0K_wSXJ1vYc(r0as_$aV_41f z5oF+A@EpQeC$hJA1KF$Om>%VOHC!${>O~R_%XPTXez7#dI5?su&l{pmDqO}b$bAOI z`?S-sJ8?AtIovK#C&htwfG@hdRYL?^hD5@qh>U2WSE)CIlPo))L7#82D32~EUXa03 zWI@nHjHvRbX<;%FLZ6@2UfjjJW+n(Yk($GkK&5Yb?@CT4WC+OhHxa+>?S2G$ZPiLP zV$s3TEL64nW)PP709dfM;_kJaWhdlD1E53dtxQuWeq^YYy>J}Z@+soMk=w96sz-i; z2L*efmR&glQ)Q;bH_1Nn>e+Ew*?b^d7m%`Sw=G^5yNd~%mF87k&*O2(2Y%eGe8@rN zqxOv*$-5Z;)Uzekj7B_yRv`R>&-WPi^NbgBf6|{iK4RG+zii*9UQ~ANgK5y|0sRtu zp_=;95#Pm2-58@&Eh(pyvw&@ARFGL=#5|$ZbZif&m!;L#uEShM%j#Z8rU+dZTL>56 z`)X2zzM0A?*fIxaLf-Q%_h=$6+aoigFC*#`NO;MYOzF22pFddT$_S2C#=CDNl9^hG z*sv6T0MBfpnG5ahwbIYOBI41q_(&vA=*`1RP@ym~s`u>VOVc~YLQnzrtzuhxcAjFX z4Cp|t7oLIz5pTR3yrsp8g-4)C=IUdHtSdzk7_)t(;?s-*fE6PUQLkN)+qWXtW!1m- z(d%gErhZwk@m<^*aMIQrmtS#~9Jy&wmLGxHBk%)uW7c!;y&5cM?WDO9E1&|kVR#&h z^=nx@pF0;FUmkYt--oaKad>8z>&EDIwk*ba3$Wm3hGNMWQ_qb>h&@KaJcmne_V?OV zb$B6p?*bsan4!lItB*-4Vdl3@-7k@Eo2Klx_@0>f_5e7>>))Vv(`K8ziMEchQ3NfO zWcUERjC#6)UoeqVw~0k%o4z8yS-Lr@C+bl7Ic-S43enc?qFLi4(z&gBSBGG5(X#g$ z{aPG*kvITuB=}SSzkuu13j0_MTQ7;0S0#7Y6}@a9?|lx!qan5)#O&>cWb1fFbI?sw z?TN(kfeE>;j}DB?!A$BGXc&?w$|Zn%nkh#}@KOsC`H=p-8+k||WEX@=Tqu>j4hJqs zu12NybaU?Kx=dYQ?(qo%gj(LXi=y8$chP!7=JYD@Ch2QK_61dyw1h_~8EO<0xr?XY z%;_No3fmszt=Vmr{2BGSL>)9Mj8D-&<&y9&p5H}7cQZ{_rxJ||eDe&RH*Au&jz94X zq;TYY>fx59eG-$?l+o*d+P2^`-yU+a<4T$1+?QQ%h~Sp&G2Ufecwi=t(B;CU-WaP7 zoE0Gtvfr3oF?zc!9>OEC`@sMTdvj7L|G^8kAJT%c`e2O5OINu}7r*U1Bi@#IeLvyv zSOBtklvbA>jjXzcPg1t;ZYwsCv&#xS)D|iD_ARDcwe_y4x>zlZb2zkxhCon8K$e`; zBv7ohjn`3x;XX|OFqKwFoA`IF#j8YblYJstp&FT6oS@&eKG!BH^8($L)hw%0D84wI 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 !1-`yjuGc@{h+{c5~#C8bSt>zP{ra{|Pn| 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

    ` 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π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 CkT-R3B0ucAz=veF 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 XSX6k&spaN3z>m7J&Z8nli?{y=vTPGg literal 0 HcmV?d00001 diff --git a/site/content/docs/v1.17/contributions/img-for-tencent/effe8a0a7ce3aa8e422db00bfdddc375.png b/site/content/docs/v1.17/contributions/img-for-tencent/effe8a0a7ce3aa8e422db00bfdddc375.png new file mode 100644 index 0000000000000000000000000000000000000000..28e1bbaad3ae0635df7e394f48b1a1836754d514 GIT binary patch literal 85131 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%0AmC`-4_;Qkg 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 E06hp8s{jB1 literal 0 HcmV?d00001 diff --git a/site/content/docs/v1.17/contributions/img-for-tencent/f0fff5228527edc72d6e71a50d5dc966.png b/site/content/docs/v1.17/contributions/img-for-tencent/f0fff5228527edc72d6e71a50d5dc966.png new file mode 100644 index 0000000000000000000000000000000000000000..b732cf25281e349ac940bafcad1d7d5cdbb7a915 GIT binary patch literal 49558 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 PfFA`JRp}B*1Hb.tar.gz -C /dir/to/extract/to + ``` + + The directory you extracted is called the "Velero directory" in subsequent steps. + +1. Move the `velero` binary from the Velero directory to somewhere in your PATH. + +## Set up server + +These instructions start the Velero server and a Minio instance that is accessible from within the cluster only. See [Expose Minio outside your cluster](#expose-minio-outside-your-cluster-with-a-service) for information about configuring your cluster for outside access to Minio. Outside access is required to access logs and run `velero describe` commands. + +1. Create a Velero-specific credentials file (`credentials-velero`) in your Velero directory: + + ``` + [default] + aws_access_key_id = minio + aws_secret_access_key = minio123 + ``` + +1. Start the server and the local storage service. In the Velero directory, run: + + ``` + kubectl apply -f examples/minio/00-minio-deployment.yaml + ``` + _Note_: The example Minio yaml provided uses "empty dir". Your node needs to have enough space available to store the + data being backed up plus 1GB of free space. If the node does not have enough space, you can modify the example yaml to + use a Persistent Volume instead of "empty dir" + + ``` + velero install \ + --provider aws \ + --plugins velero/velero-plugin-for-aws:v1.2.1 \ + --bucket velero \ + --secret-file ./credentials-velero \ + --use-volume-snapshots=false \ + --backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://minio.velero.svc:9000 + ``` + + * This example assumes that it is running within a local cluster without a volume provider capable of snapshots, so no `VolumeSnapshotLocation` is created (`--use-volume-snapshots=false`). You may need to update AWS plugin version to one that is [compatible](https://github.com/vmware-tanzu/velero-plugin-for-aws#compatibility) with the version of Velero you are installing. + + * Additionally, you can specify `--use-node-agent` to enable File System Backup support, and `--wait` to wait for the deployment to be ready. + + * This example also assumes you have named your Minio bucket "velero". + + * Please make sure to set parameter `s3ForcePathStyle=true`. The parameter is used to set the Velero integrated AWS SDK data query address style. There are two types of the address: [virtual-host and path-style](https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html). If the `s3ForcePathStyle=true` is not set, the default value is false, then the AWS SDK will query in virtual-host style, but the MinIO server only support path-style address by default. The miss match will mean Velero can upload data to MinIO, but **cannot download from MinIO**. This [link](https://github.com/vmware-tanzu/velero/issues/7268) is an example of this issue. + It can be resolved by two ways: + * Set `s3ForcePathStyle=true` for parameter `--backup-location-config` when installing Velero. This is the preferred way. + * Make MinIO server support virtual-host style address. Add the [MINIO_DOMAIN environment variable](https://min.io/docs/minio/linux/reference/minio-server/settings/core.html#id5) for MinIO server will do the magic. + + +1. Deploy the example nginx application: + + ```bash + kubectl apply -f examples/nginx-app/base.yaml + ``` + +1. Check to see that both the Velero and nginx deployments are successfully created: + + ``` + kubectl get deployments -l component=velero --namespace=velero + kubectl get deployments --namespace=nginx-example + ``` + +## Back up + +1. Create a backup for any object that matches the `app=nginx` label selector: + + ``` + velero backup create nginx-backup --selector app=nginx + ``` + + Alternatively if you want to backup all objects *except* those matching the label `backup=ignore`: + + ``` + velero backup create nginx-backup --selector 'backup notin (ignore)' + ``` + +1. (Optional) Create regularly scheduled backups based on a cron expression using the `app=nginx` label selector: + + ``` + velero schedule create nginx-daily --schedule="0 1 * * *" --selector app=nginx + ``` + + Alternatively, you can use some non-standard shorthand cron expressions: + + ``` + velero schedule create nginx-daily --schedule="@daily" --selector app=nginx + ``` + + See the [cron package's documentation][30] for more usage examples. + +1. Simulate a disaster: + + ``` + kubectl delete namespace nginx-example + ``` + +1. To check that the nginx deployment and service are gone, run: + + ``` + kubectl get deployments --namespace=nginx-example + kubectl get services --namespace=nginx-example + kubectl get namespace/nginx-example + ``` + + You should get no results. + + NOTE: You might need to wait for a few minutes for the namespace to be fully cleaned up. + +## Restore + +1. Run: + + ``` + velero restore create --from-backup nginx-backup + ``` + +1. Run: + + ``` + velero restore get + ``` + + After the restore finishes, the output looks like the following: + + ``` + NAME BACKUP STATUS WARNINGS ERRORS CREATED SELECTOR + nginx-backup-20170727200524 nginx-backup Completed 0 0 2017-07-27 20:05:24 +0000 UTC + ``` + +NOTE: The restore can take a few moments to finish. During this time, the `STATUS` column reads `InProgress`. + +After a successful restore, the `STATUS` column is `Completed`, and `WARNINGS` and `ERRORS` are 0. All objects in the `nginx-example` namespace should be just as they were before you deleted them. + +If there are errors or warnings, you can look at them in detail: + +``` +velero restore describe +``` + +For more information, see [the debugging information][18]. + +## Clean up + +If you want to delete any backups you created, including data in object storage and persistent +volume snapshots, you can run: + +``` +velero backup delete BACKUP_NAME +``` + +This asks the Velero server to delete all backup data associated with `BACKUP_NAME`. You need to do +this for each backup you want to permanently delete. A future version of Velero will allow you to +delete multiple backups by name or label selector. + +Once fully removed, the backup is no longer visible when you run: + +``` +velero backup get BACKUP_NAME +``` + +To completely uninstall Velero, minio, and the nginx example app from your Kubernetes cluster: + +``` +kubectl delete namespace/velero clusterrolebinding/velero +kubectl delete crds -l component=velero +kubectl delete -f examples/nginx-app/base.yaml +``` + +## Expose Minio outside your cluster with a Service + +When you run commands to get logs or describe a backup, the Velero server generates a pre-signed URL to download the requested items. To access these URLs from outside the cluster -- that is, from your Velero client -- you need to make Minio available outside the cluster. You can: + +- Change the Minio Service type from `ClusterIP` to `NodePort`. +- Set up Ingress for your cluster, keeping Minio Service type `ClusterIP`. + +You can also specify a `publicUrl` config field for the pre-signed URL in your backup storage location config. + +### Expose Minio with Service of type NodePort + +The Minio deployment by default specifies a Service of type `ClusterIP`. You can change this to `NodePort` to easily expose a cluster service externally if you can reach the node from your Velero client. + +You must also get the Minio URL, which you can then specify as the value of the `publicUrl` field in your backup storage location config. + +1. In `examples/minio/00-minio-deployment.yaml`, change the value of Service `spec.type` from `ClusterIP` to `NodePort`. + +1. Get the Minio URL: + + - if you're running Minikube: + + ```shell + minikube service minio --namespace=velero --url + ``` + + - in any other environment: + 1. Get the value of an external IP address or DNS name of any node in your cluster. You must be able to reach this address from the Velero client. + 1. Append the value of the NodePort to get a complete URL. You can get this value by running: + + ```shell + kubectl -n velero get svc/minio -o jsonpath='{.spec.ports[0].nodePort}' + ``` + +1. Edit your `BackupStorageLocation` YAML, adding `publicUrl: ` as a field under `spec.config`. You must include the `http://` or `https://` prefix. + +## Accessing logs with an HTTPS endpoint + +If you're using Minio with HTTPS, you may see unintelligible text in the output of `velero describe`, or `velero logs` commands. + +To fix this, you can add a public URL to the `BackupStorageLocation`. + +In a terminal, run the following: + +```shell +kubectl patch -n velero backupstoragelocation default --type merge -p '{"spec":{"config":{"publicUrl":"https://:9000"}}}' +``` + +If your certificate is self-signed, see the [documentation on self-signed certificates][32]. + +## Expose Minio outside your cluster with Kubernetes in Docker (KinD): + +Kubernetes in Docker does not have support for NodePort services (see [this issue](https://github.com/kubernetes-sigs/kind/issues/99)). In this case, you can use a port forward to access the Minio bucket. + +In a terminal, run the following: + +```shell +MINIO_POD=$(kubectl get pods -n velero -l component=minio -o jsonpath='{.items[0].metadata.name}') + +kubectl port-forward $MINIO_POD -n velero 9000:9000 +``` + +Then, in another terminal: + +```shell +kubectl edit backupstoragelocation default -n velero +``` + +Add `publicUrl: http://localhost:9000` under the `spec.config` section. + + +### Work with Ingress + +Configuring Ingress for your cluster is out of scope for the Velero documentation. If you have already set up Ingress, however, it makes sense to continue with it while you run the example Velero configuration with Minio. + +In this case: + +1. Keep the Service type as `ClusterIP`. + +1. Edit your `BackupStorageLocation` YAML, adding `publicUrl: ` as a field under `spec.config`. + +[1]: #expose-minio-with-service-of-type-nodeport +[3]: ../customize-installation.md +[17]: ../file-system-backup.md +[18]: ../debugging-restores.md +[26]: https://github.com/vmware-tanzu/velero/releases +[30]: https://godoc.org/github.com/robfig/cron +[32]: ../self-signed-certificates.md diff --git a/site/content/docs/v1.17/contributions/oracle-config.md b/site/content/docs/v1.17/contributions/oracle-config.md new file mode 100644 index 000000000..19871edc5 --- /dev/null +++ b/site/content/docs/v1.17/contributions/oracle-config.md @@ -0,0 +1,248 @@ +--- +title: "Use Oracle Cloud as a Backup Storage Provider for Velero" +layout: docs +--- + +## Introduction + +[Velero](https://velero.io/) is a tool used to backup and migrate Kubernetes applications. Here are the steps to use [Oracle Cloud Object Storage](https://docs.cloud.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) as a destination for Velero backups. + +1. [Download Velero](#download-velero) +2. [Create A Customer Secret Key](#create-a-customer-secret-key) +3. [Create An Oracle Object Storage Bucket](#create-an-oracle-object-storage-bucket) +4. [Install Velero](#install-velero) +5. [Clean Up](#clean-up) +6. [Examples](#examples) +7. [Additional Reading](#additional-reading) + +## Download Velero + +1. Download the [latest release](https://github.com/vmware-tanzu/velero/releases/) of Velero to your development environment. This includes the `velero` CLI utility and example Kubernetes manifest files. For example: + + ``` + wget https://github.com/vmware-tanzu/velero/releases/download/v1.0.0/velero-v1.0.0-linux-amd64.tar.gz + ``` + + **NOTE:** Its strongly recommend that you use an official release of Velero. The tarballs for each release contain the velero command-line client. The code in the main branch of the Velero repository is under active development and is not guaranteed to be stable! + +2. Untar the release in your `/usr/bin` directory: `tar -xzvf .tar.gz` + + You may choose to rename the directory `velero` for the sake of simplicity: `mv velero-v1.0.0-linux-amd64 velero` + +3. Add it to your PATH: `export PATH=/usr/local/bin/velero:$PATH` + +4. Run `velero` to confirm the CLI has been installed correctly. You should see an output like this: + +``` +$ velero +Velero is a tool for managing disaster recovery, specifically for Kubernetes +cluster resources. It provides a simple, configurable, and operationally robust +way to back up your application state and associated data. + +If you're familiar with kubectl, Velero supports a similar model, allowing you to +execute commands such as 'velero get backup' and 'velero create schedule'. The same +operations can also be performed as 'velero backup get' and 'velero schedule create'. + +Usage: + velero [command] +``` + + + +## Create A Customer Secret Key + +1. Oracle Object Storage provides an API to enable interoperability with Amazon S3. To use this Amazon S3 Compatibility API, you need to generate the signing key required to authenticate with Amazon S3. This special signing key is an Access Key/Secret Key pair. Follow these steps to [create a Customer Secret Key](https://docs.cloud.oracle.com/iaas/Content/Identity/Tasks/managingcredentials.htm#To4). Refer to this link for more information about [Working with Customer Secret Keys](https://docs.cloud.oracle.com/iaas/Content/Identity/Tasks/managingcredentials.htm#s3). + +2. Create a Velero credentials file with your Customer Secret Key: + + ``` + $ vi credentials-velero + + [default] + aws_access_key_id=bae031188893d1eb83719648790ac850b76c9441 + aws_secret_access_key=MmY9heKrWiNVCSZQ2Mf5XTJ6Ys93Bw2d2D6NMSTXZlk= + ``` + + + +## Create An Oracle Object Storage Bucket + +Create an Oracle Cloud Object Storage bucket called `velero` in the root compartment of your Oracle Cloud tenancy. Refer to this page for [more information about creating a bucket with Object Storage](https://docs.cloud.oracle.com/iaas/Content/Object/Tasks/managingbuckets.htm#usingconsole). + + + +## Install Velero + +You will need the following information to install Velero into your Kubernetes cluster with Oracle Object Storage as the Backup Storage provider: + +``` +velero install \ + --provider [provider name] \ + --bucket [bucket name] \ + --prefix [tenancy name] \ + --use-volume-snapshots=false \ + --secret-file [secret file location] \ + --backup-location-config region=[region],s3ForcePathStyle="true",s3Url=[storage API endpoint] +``` + +- `--provider` This example uses the S3-compatible API, so use `aws` as the provider. +- `--bucket` The name of the bucket created in Oracle Object Storage - in our case this is named `velero`. +- ` --prefix` The name of your Oracle Cloud tenancy - in our case this is named `oracle-cloudnative`. +- `--use-volume-snapshots=false` Velero does not have a volume snapshot plugin for Oracle Cloud, so creating volume snapshots is disabled. +- `--secret-file` The path to your `credentials-velero` file. +- `--backup-location-config` The path to your Oracle Object Storage bucket. This consists of your `region` which corresponds to your Oracle Cloud region name ([List of Oracle Cloud Regions](https://docs.cloud.oracle.com/iaas/Content/General/Concepts/regions.htm?Highlight=regions)) and the `s3Url`, the S3-compatible API endpoint for Oracle Object Storage based on your region: `https://oracle-cloudnative.compat.objectstorage.[region name].oraclecloud.com` + +For example: + +``` +velero install \ + --provider aws \ + --bucket velero \ + --prefix oracle-cloudnative \ + --use-volume-snapshots=false \ + --secret-file /Users/mboxell/bin/velero/credentials-velero \ + --backup-location-config region=us-phoenix-1,s3ForcePathStyle="true",s3Url=https://oracle-cloudnative.compat.objectstorage.us-phoenix-1.oraclecloud.com +``` + +This will create a `velero` namespace in your cluster along with a number of CRDs, a ClusterRoleBinding, ServiceAccount, Secret, and Deployment for Velero. If your pod fails to successfully provision, you can troubleshoot your installation by running: `kubectl logs [velero pod name]`. + + + +## Clean Up + +To remove Velero from your environment, delete the namespace, ClusterRoleBinding, ServiceAccount, Secret, and Deployment and delete the CRDs, run: + +``` +kubectl delete namespace/velero clusterrolebinding/velero +kubectl delete crds -l component=velero +``` + +This will remove all resources created by `velero install`. + + + +## Examples + +After creating the Velero server in your cluster, try this example: + +### Basic example (without PersistentVolumes) + +1. Start the sample nginx app: `kubectl apply -f examples/nginx-app/base.yaml` + + This will create an `nginx-example` namespace with a `nginx-deployment` deployment, and `my-nginx` service. + + ``` + $ kubectl apply -f examples/nginx-app/base.yaml + namespace/nginx-example created + deployment.apps/nginx-deployment created + service/my-nginx created + ``` + + You can see the created resources by running `kubectl get all` + + ``` + $ kubectl get all + NAME READY STATUS RESTARTS AGE + pod/nginx-deployment-67594d6bf6-4296p 1/1 Running 0 20s + pod/nginx-deployment-67594d6bf6-f9r5s 1/1 Running 0 20s + + NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE + service/my-nginx LoadBalancer 10.96.69.166 80:31859/TCP 21s + + NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE + deployment.apps/nginx-deployment 2 2 2 2 21s + + NAME DESIRED CURRENT READY AGE + replicaset.apps/nginx-deployment-67594d6bf6 2 2 2 21s + ``` + +2. Create a backup: `velero backup create nginx-backup --include-namespaces nginx-example` + + ``` + $ velero backup create nginx-backup --include-namespaces nginx-example + Backup request "nginx-backup" submitted successfully. + Run `velero backup describe nginx-backup` or `velero backup logs nginx-backup` for more details. + ``` + + At this point you can navigate to appropriate bucket, called `velero`, in the Oracle Cloud Object Storage console to see the resources backed up using Velero. + +3. Simulate a disaster by deleting the `nginx-example` namespace: `kubectl delete namespaces nginx-example` + + ``` + $ kubectl delete namespaces nginx-example + namespace "nginx-example" deleted + ``` + + Wait for the namespace to be deleted. To check that the nginx deployment, service, and namespace are gone, run: + + ``` + kubectl get deployments --namespace=nginx-example + kubectl get services --namespace=nginx-example + kubectl get namespace/nginx-example + ``` + + This should return: `No resources found.` + +4. Restore your lost resources: `velero restore create --from-backup nginx-backup` + + ``` + $ velero restore create --from-backup nginx-backup + Restore request "nginx-backup-20190604102710" submitted successfully. + Run `velero restore describe nginx-backup-20190604102710` or `velero restore logs nginx-backup-20190604102710` for more details. + ``` + + Running `kubectl get namespaces` will show that the `nginx-example` namespace has been restored along with its contents. + +5. Run: `velero restore get` to view the list of restored resources. After the restore finishes, the output looks like the following: + + ``` + $ velero restore get + NAME BACKUP STATUS WARNINGS ERRORS CREATED SELECTOR + nginx-backup-20190604104249 nginx-backup Completed 0 0 2019-06-04 10:42:39 -0700 PDT + ``` + + NOTE: The restore can take a few moments to finish. During this time, the `STATUS` column reads `InProgress`. + + After a successful restore, the `STATUS` column shows `Completed`, and `WARNINGS` and `ERRORS` will show `0`. All objects in the `nginx-example` namespace should be just as they were before you deleted them. + + If there are errors or warnings, for instance if the `STATUS` column displays `FAILED` instead of `InProgress`, you can look at them in detail with `velero restore describe ` + + +6. Clean up the environment with `kubectl delete -f examples/nginx-app/base.yaml` + + ``` + $ kubectl delete -f examples/nginx-app/base.yaml + namespace "nginx-example" deleted + deployment.apps "nginx-deployment" deleted + service "my-nginx" deleted + ``` + + If you want to delete any backups you created, including data in object storage, you can run: `velero backup delete BACKUP_NAME` + + ``` + $ velero backup delete nginx-backup + Are you sure you want to continue (Y/N)? Y + Request to delete backup "nginx-backup" submitted successfully. + The backup will be fully deleted after all associated data (disk snapshots, backup files, restores) are removed. + ``` + + This asks the Velero server to delete all backup data associated with `BACKUP_NAME`. You need to do this for each backup you want to permanently delete. A future version of Velero will allow you to delete multiple backups by name or label selector. + + Once fully removed, the backup is no longer visible when you run: `velero backup get BACKUP_NAME` or more generally `velero backup get`: + + ``` + $ velero backup get nginx-backup + An error occurred: backups.velero.io "nginx-backup" not found + ``` + + ``` + $ velero backup get + NAME STATUS CREATED EXPIRES STORAGE LOCATION SELECTOR + ``` + + + +## Additional Reading + +* [Official Velero Documentation](https://velero.io/docs/v1.17.0/) +* [Oracle Cloud Infrastructure Documentation](https://docs.cloud.oracle.com/) diff --git a/site/content/docs/v1.17/contributions/tencent-config.md b/site/content/docs/v1.17/contributions/tencent-config.md new file mode 100644 index 000000000..4ad54aaa8 --- /dev/null +++ b/site/content/docs/v1.17/contributions/tencent-config.md @@ -0,0 +1,168 @@ +--- +title: "Use Tencent Cloud Object Storage as Velero's storage destination." +layout: docs +--- + + +You can deploy Velero on Tencent [TKE](https://cloud.tencent.com/document/product/457), or an other Kubernetes cluster, and use Tencent Cloud Object Store as a destination for Velero’s backups. + + +## Prerequisites + +- Registered [Tencent Cloud Account](https://cloud.tencent.com/register). +- [Tencent Cloud COS](https://console.cloud.tencent.com/cos) service, referred to as COS, has been launched +- A Kubernetes cluster has been created, cluster version v1.16 or later, and the cluster can use DNS and Internet services normally. If you need to create a TKE cluster, refer to the Tencent [create a cluster](https://cloud.tencent.com/document/product/457/32189) documentation. + +## Create a Tencent Cloud COS bucket + +Create an object bucket for Velero to store backups in the Tencent Cloud COS console. For how to create, please refer to Tencent Cloud COS [Create a bucket](https://cloud.tencent.com/document/product/436/13309) usage instructions. + +Set access to the bucket through the object storage console, the bucket needs to be **read** and **written**, so the account is granted data reading, data writing permissions. For how to configure, see the [permission access settings](https://cloud.tencent.com/document/product/436/13315) Tencent user instructions. + +## Get bucket access credentials + +Velero uses an AWS S3-compatible API to access Tencent Cloud COS storage, which requires authentication using a pair of access key IDs and key-created signatures. + +In the S3 API parameter, the "access_key_id" field is the access key ID and the "secret_access_key" field is the key. + +In the [Tencent Cloud Access Management Console](https://console.cloud.tencent.com/cam/capi), Create and acquire Tencent Cloud Keys "SecretId" and "SecretKey" for COS authorized account. **Where the "SecretId" value corresponds to the value of S3 API parameter "access_key_id" field, the "SecretKey" value corresponds to the value of S3 API parameter "secret_access_key" field**. + +Create the credential profile "credentials-velero" required by Velero in the local directory based on the above correspondence: + +```bash +[default] +aws_access_key_id= +aws_secret_access_key= +``` + +## Install Velero Resources + +You need to install the Velero CLI first, see [Install the CLI](https://velero.io/docs/v1.5/basic-install/#install-the-cli) for how to install. + +Follow the Velero installation command below to create velero and node-agent workloads and other necessary resource objects. + +```bash +velero install --provider aws --plugins velero/velero-plugin-for-aws:v1.1.0 --bucket \ +--secret-file ./credentials-velero \ +--use-node-agent \ +--default-volumes-to-fs-backup \ +--backup-location-config \ +region=ap-guangzhou,s3ForcePathStyle="true",s3Url=https://cos.ap-guangzhou.myqcloud.com +``` + +Description of the parameters: + +- `--provider`: Declares the type of plugin provided by "aws". + +- `--plugins`: Use the AWS S3 compatible API plugin "velero-plugin-for-aws". + +- `--bucket`: The bucket name created at Tencent Cloud COS. + +- `--secret-file`: Access tencent cloud COS access credential file for the "credentials-velero" credential file created above. + +- `--use-node-agent`: Enable Velero node-agent daemonset. At present, Velero File System Backup requires this daemonset, so if you are using File System Backup, it needs to be turned on. For the usage and limitation of File System Backup, See [File System Backup](../file-system-backup.md). + +- `--default-volumes-to-fs-backup`: Enable the use of File System Backup to back up all Pod volumes, provided that the `--use-node-agent`parameter needs to be turned on. + +- `--backup-location-config`: Back up the bucket access-related configuration: + + `region`: Tencent cloud COS bucket area, for example, if the created region is Guangzhou, the Region parameter value is "ap-guangzhou". + + `s3ForcePathStyle`: Use the S3 file path format. + + `s3Url`: Tencent Cloud COS-compatible S3 API access address,Note that instead of creating a COS bucket for public network access domain name, you must use a format of "https://cos.`region`.myqcloud.com" URL, for example, if the region is Guangzhou, the parameter value is "https://cos.ap-guangzhou.myqcloud.com.". + +There are other installation parameters that can be viewed using `velero install --help`, such as setting `--use-volume-snapshots-false` to close the storage volume data snapshot backup if you do not want to back up the storage volume data. + +After executing the installation commands above, the installation process looks like this: + +{{< figure src="/docs/main/contributions/img-for-tencent/9015313121ed7987558c88081b052574.png" width="100%">}} + +After the installation command is complete, wait for the velero and node-agent workloads to be ready to see if the configured storage location is available. + +Executing the 'velero backup-location get' command to view the storage location status and display "Available" indicates that access to Tencent Cloud COS is OK, as shown in the following image: + +{{< figure src="/docs/main/contributions/img-for-tencent/69194157ccd5e377d1e7d914fd8c0336.png" width="100%">}} + +At this point, The installation using Tencent Cloud COS as Velero storage location is complete, If you need more installation information about Velero, You can see the official website [Velero documentation](https://velero.io/docs/) . + +## Velero backup and restore example + +In the cluster, use the helm tool to create a minio test service with a persistent volume, and the minio installation method can be found in the [minio installation](https://github.com/minio/charts), in which case can bound a load balancer for the minio service to access the management page using a public address in the browser. + +{{< figure src="/docs/main/contributions/img-for-tencent/f0fff5228527edc72d6e71a50d5dc966.png" width="100%">}} + +Sign in to the minio web management page and upload some image data for the test, as shown below: + +{{< figure src="/docs/main/contributions/img-for-tencent/e932223585c0b19891cc085ad7f438e1.png" width="100%">}} + +With Velero Backup, you can back up all objects in the cluster directly, or filter objects by type, namespace, and/or label. This example uses the following command to back up all resources under the 'default' namespace. + +``` +velero backup create default-backup --include-namespaces +``` + +Use the `velero backup get` command to see if the backup task is complete, and when the backup task status is "Completed," the backup task is completed without any errors, as shown in the following below: + +{{< figure src="/docs/main/contributions/img-for-tencent/eb2bbabae48b188748f5278bedf177f1.png" width="100%">}} + +At this point delete all of MinIO's resources, including its PVC persistence volume, as shown below:: + +{{< figure src="/docs/main/contributions/img-for-tencent/15ccaacf00640a04ae29ceed4c86195b.png" width="100%">}} + +After deleting the MinIO resource, use your backup to restore the deleted MinIO resource, and temporarily update the backup storage location to read-only mode (this prevents the backup object from being created or deleted in the backup storage location during the restore process):: + +```bash +kubectl patch backupstoragelocation default --namespace velero \ + --type merge \ + --patch '{"spec":{"accessMode":"ReadOnly"}}' + +``` + +Modifying access to Velero's storage location is "ReadOnly," as shown in the following image: + +{{< figure src="/docs/main/contributions/img-for-tencent/e8c2ab4e5e31d1370c62fad25059a8a8.png" width="100%">}} + +Now use the backup "default-backup" that Velero just created to create the restore task: + +```bash +velero restore create --from-backup +``` + +You can also use `velero restore get` to see the status of the restore task, and if the restore status is "Completed," the restore task is complete, as shown in the following image: + +{{< figure src="/docs/main/contributions/img-for-tencent/effe8a0a7ce3aa8e422db00bfdddc375.png" width="100%">}} + +When the restore is complete, you can see that the previously deleted minio-related resources have been restored successfully, as shown in the following image: + +{{< figure src="/docs/main/contributions/img-for-tencent/1d53b0115644d43657c2a5ece805c9b4.png" width="100%">}} + +Log in to minio's management page on your browser and you can see that the previously uploaded picture data is still there, indicating that the persistent volume's data was successfully restored, as shown below: + +{{< figure src="/docs/main/contributions/img-for-tencent/ceaca9ce6bc92bdce987c63d2fe71561.png" width="100%">}} + +When the restore is complete, don't forget to restore the backup storage location to read and write mode so that the next backup task can be used successfully: + +```bash +kubectl patch backupstoragelocation default --namespace velero \ + --type merge \ + --patch '{"spec":{"accessMode":"ReadWrite"}}' +``` + + + +## Uninstall Velero Resources + +To uninstall velero resources in a cluster, you can do so using the following command: + +```bash +kubectl delete namespace/velero clusterrolebinding/velero +kubectl delete crds -l component=velero +``` + + + +## Additional Reading + +- [Official Velero Documentation](https://velero.io/docs/) +- [Tencent Cloud Documentation](https://cloud.tencent.com/document/product) diff --git a/site/content/docs/v1.17/csi-snapshot-data-movement.md b/site/content/docs/v1.17/csi-snapshot-data-movement.md new file mode 100644 index 000000000..930fc1be5 --- /dev/null +++ b/site/content/docs/v1.17/csi-snapshot-data-movement.md @@ -0,0 +1,414 @@ +--- +title: "CSI Snapshot Data Movement" +layout: docs +--- + +CSI Snapshot Data Movement is built according to the [Volume Snapshot Data Movement design][1] and is specifically designed to move CSI snapshot data to a backup storage location. +CSI Snapshot Data Movement takes CSI snapshots through the CSI plugin in nearly the same way as [CSI snapshot backup][2]. However, it doesn't stop after a snapshot is taken. Instead, it tries to access the snapshot data through various data movers and back up the data to a backup storage connected to the data movers. +Consequently, the volume data is backed up to a pre-defined backup storage in a consistent manner. +After the backup completes, the CSI snapshot will be removed by Velero and the snapshot data space will be released on the storage side. + +CSI Snapshot Data Movement is useful in below scenarios: +- For on-premises users, the storage usually doesn't support durable snapshots, so it is impossible/less efficient/cost ineffective to keep volume snapshots by the storage, as required by the [CSI snapshot backup][2]. This feature helps to move the snapshot data to a storage with lower cost and larger scale for long time preservation. +- For public cloud users, this feature helps users to fulfil the multiple cloud strategy. It allows users to back up volume snapshots from one cloud provider and preserve or restore the data to another cloud provider. Then users will be free to flow their business data across cloud providers based on Velero backup and restore. + +Besides, Velero [File System Backup][3] which could also back up the volume data to a pre-defined backup storage. CSI Snapshot Data Movement works together with [File System Backup][3] to satisfy different requirements for the above scenarios. And whenever available, CSI Snapshot Data Movement should be used in preference since the [File System Backup][3] reads data from the live PV, in which way the data is not captured at the same point in time, so is less consistent. +Moreover, CSI Snapshot Data Movement brings more possible ways of data access, i.e., accessing the data from the block level, either fully or incrementally. +On the other hand, there are quite some cases that CSI snapshot is not available (i.e., you need a volume snapshot plugin for your storage platform, or you're using EFS, NFS, emptyDir, local, or any other volume type that doesn't have a native snapshot), then [File System Backup][3] will be the only option. + +CSI Snapshot Data Movement supports both built-in data mover and customized data movers. For the details of how Velero works with customized data movers, check the [Volume Snapshot Data Movement design][1]. Velero provides a built-in data mover which uses Velero built-in uploaders (at present the available uploader is Kopia uploader) to read the snapshot data and write to the Unified Repository (by default implemented by Kopia repository). + +Velero built-in data mover restores both volume data and metadata, so the data mover pods need to run as root user. + +### Priority Class Configuration + +For Velero built-in data mover, data mover pods launched during CSI snapshot data movement will use the priority class name configured in the node-agent configmap. The node-agent daemonset itself gets its priority class from the `--node-agent-priority-class-name` flag during Velero installation. This can help ensure proper scheduling behavior in resource-constrained environments. For more details on configuring data mover pod resources, see [Data Movement Pod Resource Configuration][11]. + +## Setup CSI Snapshot Data Movement + +## Prerequisites + + 1. The source cluster is Kubernetes version 1.20 or greater. + 2. The source cluster is running a CSI driver capable of support volume snapshots at the [v1 API level][4]. + 3. CSI Snapshot Data Movement requires the Kubernetes [MountPropagation feature][5]. + + +### Install Velero Node Agent + +Velero Node Agent is a Kubernetes daemonset that hosts Velero data movement controllers and launches data mover pods. +If you are using Velero built-in data mover, Node Agent must be installed. To install Node Agent, use the `--use-node-agent` flag. +Velero built-in data mover doesn't require the host path for pod volumes into Node Agent pods. The installation by default creates it in order to support fs-backup. If you don't use fs-backup and want to remove it from Node Agent, you can specify the `--node-agent-disable-host-path` flag. + +``` +velero install --use-node-agent --node-agent-disable-host-path +``` + +### Configure A Backup Storage Location + +At present, Velero backup repository supports object storage as the backup storage. Velero gets the parameters from the +[BackupStorageLocation][8] to compose the URL to the backup storage. +Velero's known object storage providers are included here [supported providers][9], for which, Velero pre-defines the endpoints. If you want to use a different backup storage, make sure it is S3 compatible and you provide the correct bucket name and endpoint in BackupStorageLocation. Velero handles the creation of the backup repo prefix in the backup storage, so make sure it is specified in BackupStorageLocation correctly. + +Velero creates one backup repository per namespace. For example, if backing up 2 namespaces, namespace1 and namespace2, using kopia repository on AWS S3, the full backup repo path for namespace1 would be `https://s3-us-west-2.amazonaws.com/bucket/kopia/ns1` and for namespace2 would be `https://s3-us-west-2.amazonaws.com/bucket/kopia/ns2`. + +There may be additional installation steps depending on the cloud provider plugin you are using. You should refer to the [plugin specific documentation][9] for the must up to date information. + +**Note:** Currently, Velero creates a secret named `velero-repo-credentials` in the velero install namespace, containing a default backup repository password. +You can update the secret with your own password encoded as base64 prior to the first backup (i.e., [File System Backup][3], snapshot data movements) targeting to the backup repository. The value of the key to update is +``` +data: + repository-password: +``` +Backup repository is created during the first execution of backup targeting to it after installing Velero with node agent. If you update the secret password after the first backup which created the backup repository, then Velero will not be able to connect with the older backups. + +## Install Velero with CSI support on source cluster + +On source cluster, Velero needs to manipulate CSI snapshots through the CSI volume snapshot APIs, so you must enable the `EnableCSI` feature flag on the Velero server. + +To integrate Velero with the CSI volume snapshot APIs, you must enable the `EnableCSI` feature flag. + +From release-1.14, the `github.com/vmware-tanzu/velero-plugin-for-csi` repository, which is the Velero CSI plugin, is merged into the `github.com/vmware-tanzu/velero` repository. +The reasons to merge the CSI plugin are: +* The VolumeSnapshot data mover depends on the CSI plugin, it's reasonabe to integrate them. +* This change reduces the Velero deploying complexity. +* This makes performance tuning easier in the future. + +As a result, no need to install Velero CSI plugin anymore. + +```bash +velero install \ +--features=EnableCSI \ +--plugins= \ +... +``` + +### Configure storage class on target cluster + +For Velero built-in data movement, CSI facilities are not required necessarily in the target cluster. On the other hand, Velero built-in data movement creates a PVC with the same specification as it is in the source cluster and expects the volume to be provisioned similarly. For example, the same storage class should be working in the target cluster. +By default, Velero won't restore storage class resources from the backup since they are cluster scope resources. However, if you specify the `--include-cluster-resources` restore flag, they will be restored. For a cross provider scenario, the storage class from the source cluster is probably not usable in the target cluster. +In either of the above cases, the best practice is to create a working storage class in the target cluster with the same name as it in the source cluster. In this way, even though `--include-cluster-resources` is specified, Velero restore will skip restoring the storage class since it finds an existing one. +Otherwise, if the storage class name in the target cluster is different, you can change the PVC's storage class name during restore by the [changing PV/PVC storage class][10] method. You can also configure to skip restoring the storage class resources from the backup since they are not usable. + +### Customized Data Movers + +If you are using a customized data mover, follow the data mover's instructions for any further prerequisites. +For Velero side configurations mentioned above, the installation and configuration of node-agent may not be required. + + +## To back up + +Velero uses a new custom resource `DataUpload` to drive the data movement. The selected data mover will watch and reconcile the CRs. +Velero allows users to decide whether the CSI snapshot data should be moved per backup. +Velero also allows users to select the data mover to move the CSI snapshot data per backup. +The both selections are simply done by a parameter when running the backup. + +To take a backup with Velero's built-in data mover: + +```bash +velero backup create NAME --snapshot-move-data OPTIONS... +``` + +Or if you want to use a customized data mover: +```bash +velero backup create NAME --snapshot-move-data --data-mover DATA-MOVER-NAME OPTIONS... +``` + +When the backup starts, you will see the `VolumeSnapshot` and `VolumeSnapshotContent` objects created, but after the backup finishes, the objects will disappear. +After snapshots are created, you will see one or more `DataUpload` CRs created. +You may also see some intermediate objects (i.e., pods, PVCs, PVs) created in Velero namespace or the cluster scope, they are to help data movers to move data. And they will be removed after the backup completes. +The phase of a `DataUpload` CR changes several times during the backup process and finally goes to one of the terminal status, `Completed`, `Failed` or `Cancelled`. You can see the phase changes as well as the data upload progress by watching the `DataUpload` CRs: + +```bash +kubectl -n velero get datauploads -l velero.io/backup-name=YOUR_BACKUP_NAME -w +``` + +When the backup completes, you can view information about the backups: + +```bash +velero backup describe YOUR_BACKUP_NAME +``` +```bash +kubectl -n velero get datauploads -l velero.io/backup-name=YOUR_BACKUP_NAME -o yaml +``` + +## To restore + +You don't need to set any additional information when creating a data mover restore. The configurations are automatically retrieved from the backup, i.e., whether data movement should be involved and which data mover conducts the data movement. + +To restore from your Velero backup: + +```bash +velero restore create --from-backup BACKUP_NAME OPTIONS... +``` + +When the restore starts, you will see one or more `DataDownload` CRs created. +You may also see some intermediate objects (i.e., pods, PVCs, PVs) created in Velero namespace or the cluster scope, they are to help data movers to move data. And they will be removed after the restore completes. +The phase of a `DataDownload` CR changes several times during the restore process and finally goes to one of the terminal status, `Completed`, `Failed` or `Cancelled`. You can see the phase changes as well as the data download progress by watching the DataDownload CRs: + +```bash +kubectl -n velero get datadownloads -l velero.io/restore-name=YOUR_RESTORE_NAME -w +``` + +When the restore completes, view information about your restores: + +```bash +velero restore describe YOUR_RESTORE_NAME +``` +```bash +kubectl -n velero get datadownloads -l velero.io/restore-name=YOUR_RESTORE_NAME -o yaml +``` + +## Limitations + +- CSI and CSI snapshot support both file system volume mode and block volume mode. At present, block mode is only supported for non-Windows platforms, because the block mode code invokes some system calls that are not present in the Windows platform. +- [Velero built-in data mover] At present, Velero uses a static, common encryption key for all backup repositories it creates. **This means +that anyone who has access to your backup storage can decrypt your backup data**. Make sure that you limit access +to the backup storage appropriately. +- [Velero built-in data mover] Even though the backup data could be incrementally preserved, for a single file data, Velero built-in data mover leverages on deduplication to find the difference to be saved. This means that large files (such as ones storing a database) will take a long time to scan for data deduplication, even if the actual difference is small. + +## Troubleshooting + +Run the following checks: + +Are your Velero server and daemonset pods running? + +```bash +kubectl get pods -n velero +``` + +Does your backup repository exist, and is it ready? + +```bash +velero repo get + +velero repo get REPO_NAME -o yaml +``` + +Are there any errors in your Velero backup/restore? + +```bash +velero backup describe BACKUP_NAME +velero backup logs BACKUP_NAME + +velero restore describe RESTORE_NAME +velero restore logs RESTORE_NAME +``` + +What is the status of your `DataUpload` and `DataDownload`? + +```bash +kubectl -n velero get datauploads -l velero.io/backup-name=BACKUP_NAME -o yaml + +kubectl -n velero get datadownloads -l velero.io/restore-name=RESTORE_NAME -o yaml +``` + +Is there any useful information in the Velero server or daemonset pod logs? + +```bash +kubectl -n velero logs deploy/velero +kubectl -n velero logs DAEMON_POD_NAME +``` + +**NOTE**: You can increase the verbosity of the pod logs by adding `--log-level=debug` as an argument to the container command in the deployment/daemonset pod template spec. + +If you are using a customized data mover, follow the data mover's instruction for additional troubleshooting methods. + + +## How backup and restore work + +CSI snapshot data movement is a combination of CSI snapshot and data movement, which is jointly executed by Velero server, CSI plugin and the data mover. +This section lists some general concept of how CSI snapshot data movement backup and restore work. For the detailed mechanisms and workflows, you can check the [Volume Snapshot Data Movement design][1] and [VGDP Micro Service For Volume Snapshot Data Movement design][18]. + +### Custom resource and controllers + +Velero has three custom resource definitions and associated controllers: + +- `DataUpload` - represents a data upload of a volume snapshot. The CSI plugin creates one `DataUpload` per CSI snapshot. Data movers need to handle these CRs to finish the data upload process. +Velero built-in data mover runs a controller for this resource on each node (in node-agent daemonset). Controllers from different nodes may handle one CR in different phases, but finally the data transfer is done by a data mover pod in one node. + +- `DataDownload` - represents a data download of a volume snapshot. The CSI plugin creates one `DataDownload` per volume to be restored. Data movers need to handle these CRs to finish the data upload process. +Velero built-in data mover runs a controller for this resource on each node (in node-agent daemonset). Controllers from different nodes may handle one CR in different phases, but finally the data transfer is done by a data mover pod in one node. + +- `BackupRepository` - represents/manages the lifecycle of Velero's backup repositories. Velero creates a backup repository per namespace when the first CSI snapshot backup/restore for a namespace is requested. You can see information about your Velero's backup repositories by running `velero repo get`. +This CR is used by Velero built-in data movers, customized data movers may or may not use it. + +For other resources or controllers involved by customized data movers, check the data mover's instructions. + +### Backup + +Velero backs up resources for CSI snapshot data movement backup in the same way as other backup types. When it encounters a PVC, particular logics will be conducted: + +- When it finds a PVC object, Velero calls CSI plugin through a Backup Item Action. +- CSI plugin first takes a CSI snapshot to the PVC by creating the `VolumeSnapshot` and `VolumeSnapshotContent`. +- CSI plugin checks if a data movement is required, if so it creates a `DataUpload` CR and then returns to Velero backup. +- Velero now is able to back up other resources, including other PVC objects. +- Velero backup controller periodically queries the data movement status from CSI plugin, the period is configurable through the Velero server parameter `--item-operation-sync-frequency`, by default it is 10s. On the call, CSI plugin turns to check the phase of the `DataUpload` CRs. +- When all the `DataUpload` CRs come to a terminal state (i.e., `Completed`, `Failed` or `Cancelled`), Velero backup persists all the necessary information and finish the backup. + +- CSI plugin expects a data mover to handle the `DataUpload` CR. If no data mover is configured for the backup, Velero built-in data mover will handle it. +- If the `DataUpload` CR does not reach to the terminal state with in the given time, the `DataUpload` CR will be cancelled. You can set the timeout value per backup through the `--item-operation-timeout` parameter, the default value is `4 hours`. + +- Velero built-in data mover creates a volume from the CSI snapshot and transfer the data to the backup storage according to the backup storage location defined by users. +- After the volume is created from the CSI snapshot, Velero built-in data mover waits for Kubernetes to provision the volume, this may take some time varying from storage providers, but if the provision cannot be finished in a given time, Velero built-in data mover will cancel this `DataUpload` CR. The timeout is configurable through a node-agent's parameter `data-mover-prepare-timeout`, the default value is 30 minutes. +- Velero built-in data mover launches a data mover pod to transfer the data from the provisioned volume to the backup storage. +- When the data transfer completes or any error happens, Velero built-in data mover sets the `DataUpload` CR to the terminal state, either `Completed` or `Failed`. +- Velero built-in data mover also monitors the cancellation request to the `DataUpload` CR, once that happens, it cancels its ongoing activities, cleans up the intermediate resources and set the `DataUpload` CR to `Cancelled`. +- Throughout the data transfer, Velero built-in data mover monitors the status of the data mover pod and deletes it after `DataUpload` CR is set to the terminal state. + +### Restore + +Velero restores resources for CSI snapshot data movement restore in the same way as other restore types. When it encounters a PVC, particular logics will be conducted: + +- When it finds a PVC object, Velero calls CSI plugin through a Restore Item Action. +- CSI plugin checks the backup information, if a data movement was involved, it creates a `DataDownload` CR and then returns to Velero restore. +- Velero is now able to restore other resources, including other PVC objects. +- Velero restore controller periodically queries the data movement status from CSI plugin, the period is configurable through the Velero server parameter `--item-operation-sync-frequency`, by default it is 10s. On the call, CSI plugin turns to check the phase of the `DataDownload` CRs. +- When all `DataDownload` CRs come to a terminal state (i.e., `Completed`, `Failed` or `Cancelled`), Velero restore will finish. + +- CSI plugin expects the same data mover for the backup to handle the `DataDownload` CR. If no data mover was configured for the backup, Velero built-in data mover will handle it. +- If the `DataDownload` CR does not reach to the terminal state with in the given time, the `DataDownload` CR will be cancelled. You can set the timeout value per backup through the same `--item-operation-timeout` parameter. + +- Velero built-in data mover creates a volume with the same specification of the source volume. +- Velero built-in data mover waits for Kubernetes to provision the volume, this may take some time varying from storage providers, but if the provision cannot be finished in a given time, Velero built-in data mover will cancel this `DataDownload` CR. The timeout is configurable through the same node-agent's parameter `data-mover-prepare-timeout`. +- After the volume is provisioned, Velero built-in data mover starts a data mover pod to transfer the data from the backup storage according to the backup storage location defined by users. +- When the data transfer completes or any error happens, Velero built-in data mover sets the `DataDownload` CR to the terminal state, either `Completed` or `Failed`. +- Velero built-in data mover also monitors the cancellation request to the `DataDownload` CR, once that happens, it cancels its ongoing activities, cleans up the intermediate resources and set the `DataDownload` CR to `Cancelled`. +- Throughout the data transfer, Velero built-in data mover monitors the status of the data mover pod and deletes it after `DataDownload` CR is set to the terminal state. + +### Backup Deletion +When a backup is created, a snapshot is saved into the repository for the volume data. The snapshot is a reference to the volume data saved in the repository. +When deleting a backup, Velero calls the repository to delete the repository snapshot. So the repository snapshot disappears immediately after the backup is deleted. Then the volume data backed up in the repository turns to orphan, but it is not deleted by this time. The repository relies on the maintenance functionalitiy to delete the orphan data. +As a result, after you delete a backup, you don't see the backup storage size reduces until some full maintenance jobs completes successfully. And for the same reason, you should check and make sure that the periodical repository maintenance job runs and completes successfully. + +Even after deleting all the backups and their backup data (by repository maintenance), the backup storage is still not empty, some repository metadata are there to keep the instance of the backup repository. +Furthermore, Velero never deletes these repository metadata, if you are sure you'll never usage the backup repository, you can empty the backup storage manually. + +For Velero built-in data mover, Kopia uploader may keep some internal snapshots which is not managed by Velero. In normal cases, the internal snapshots are deleted along with running of backups. +However, if you run a backup which aborts halfway(some internal snapshots are thereby generated) and never run new backups again, some internal snapshots may be left there. In this case, since you stop using the backup repository, you can delete the entire repository metadata from the backup storage manually. + + +### Parallelism + +Velero calls the CSI plugin concurrently for the volume, so `DataUpload`/`DataDownload` CRs are created concurrently by the CSI plugin. For more details about the call between Velero and CSI plugin, check the [Volume Snapshot Data Movement design][1]. +In which manner the `DataUpload`/`DataDownload` CRs are processed is totally decided by the data mover you select for the backup/restore. + +For Velero built-in data mover, it uses Kubernetes' scheduler to mount a snapshot volume/restore volume associated to a `DataUpload`/`DataDownload` CR into a specific node, and then the `DataUpload`/`DataDownload` controller (in node-agent daemonset) in that node will handle the `DataUpload`/`DataDownload`. +By default, a `DataUpload`/`DataDownload` controller in one node handles one request at a time. You can configure more parallelism per node by [node-agent Concurrency Configuration][14]. +That is to say, the snapshot volumes/restore volumes may spread in different nodes, then their associated `DataUpload`/`DataDownload` CRs will be processed in parallel; while for the snapshot volumes/restore volumes in the same node, by default, their associated `DataUpload`/`DataDownload` CRs are processed sequentially and can be processed concurrently according to your [node-agent Concurrency Configuration][14]. + +The prepare process of mounting the snapshot volume/restore volume may generate multiple intermediate objects, to make a control of the intermediate objects, you can configure the [node-agent Prepare Queue Length][20]. + +You can check in which node the `DataUpload`/`DataDownload` CRs are processed and their parallelism by watching the `DataUpload`/`DataDownload` CRs: + +```bash +kubectl -n velero get datauploads -l velero.io/backup-name=YOUR_BACKUP_NAME -w +``` + +```bash +kubectl -n velero get datadownloads -l velero.io/restore-name=YOUR_RESTORE_NAME -w +``` + +### Restart and resume +When Velero server is restarted, if the resource backup/restore has completed, so the backup/restore has excceded `InProgress` status and is waiting for the completion of the data movements, Velero will recapture the status of the running data movements and resume the execution. +When node-agent is restarted, Velero tries to recapture the status of the running data movements and resume the execution; if the resume fails, the data movements are canceled. + +### Cancellation + +At present, Velero backup and restore doesn't support end to end cancellation that is launched by users. +However, Velero cancels the `DataUpload`/`DataDownload` in below scenarios automatically: +- When Velero server is restarted and the backup/restore is in `InProgress` status +- When node-agent is restarted and the resume of an existing `DataUpload`/`DataDownload` fails +- When an ongoing backup/restore is deleted +- When a backup/restore does not finish before the item operation timeout (default value is `4 hours`) + +Customized data movers that support cancellation could cancel their ongoing tasks and clean up any intermediate resources. If you are using Velero built-in data mover, the cancellation is supported. + +### Support ReadOnlyRootFilesystem setting +When the Velero server pod's SecurityContext sets the `ReadOnlyRootFileSystem` parameter to true, the Velero server pod's filesystem is running in read-only mode. Then the backup deletion may fail, because the repository needs to write some cache and configuration data into the pod's root filesystem. + +``` +Errors: /error to connect repo with storage: error to connect to repository: unable to write config file: unable to create config directory: mkdir /home/cnb/udmrepo: read-only file system +``` + +The workaround is making those directories as ephemeral k8s volumes, then those directories are not counted as pod's root filesystem. +The `user-name` is the Velero pod's running user name. The default value is `cnb`. + +``` yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: velero + namespace: velero +spec: + template: + spec: + containers: + - name: velero + ...... + volumeMounts: + ...... + - mountPath: /home//udmrepo + name: udmrepo + - mountPath: /home//.cache + name: cache + ...... + volumes: + ...... + - emptyDir: {} + name: udmrepo + - emptyDir: {} + name: cache + ...... +``` + +At present, Velero doesn't allow to set `ReadOnlyRootFileSystem` parameter to data mover pods, so the root filesystem for the data mover pods are always writable. + +### Resource Consumption + +Both the uploader and repository consume remarkable CPU/memory during the backup/restore, especially for massive small files or large backup size cases. + +For Velero built-in data mover, Velero uses [BestEffort as the QoS][13] for data mover pods (so no CPU/memory request/limit is set), so that backups/restores wouldn't fail due to resource throttling in any cases. +If you want to constraint the CPU/memory usage, you need to [Customize Data Mover Pod Resource Limits][11]. The CPU/memory consumption is always related to the scale of data to be backed up/restored, refer to [Performance Guidance][12] for more details, so it is highly recommended that you perform your own testing to find the best resource limits for your data. + +During the restore, the repository may also cache data/metadata so as to reduce the network footprint and speed up the restore. The repository uses its own policy to store and clean up the cache. +For Kopia repository, the cache is stored in the data mover pod's root file system. Velero allows you to configure a limit of the cache size so that the data mover pod won't be evicted due to running out of the ephemeral storage. For more details, check [Backup Repository Configuration][17]. + +### Node Selection + +The node where a data movement backup/restore runs is decided by the data mover. + +For Velero built-in data mover, it uses Kubernetes' scheduler to mount a snapshot volume/restore volume associated to a `DataUpload`/`DataDownload` CR into a specific node, and then the data movement backup/restore will happen in that node. +For the backup, you can intervene this scheduling process through [Data Movement Backup Node Selection][15], so that you can decide which node(s) should/should not run the data movement backup for various purposes. +For the restore, this is not supported because sometimes the data movement restore must run in the same node where the restored workload pod is scheduled. + +### BackupPVC Configuration + +The `BackupPVC` serves as an intermediate Persistent Volume Claim (PVC) utilized during data movement backup operations, providing efficient access to data. +In complex storage environments, optimizing `BackupPVC` configurations can significantly enhance the performance of backup operations. [This document][16] outlines advanced configuration options for `BackupPVC`, allowing users to fine-tune access modes and storage class settings based on their storage provider's capabilities. + +### RestorePVC Configuration + +The `RestorePVC` serves as an intermediate Persistent Volume Claim (PVC) utilized during data movement restore operations, providing efficient access to data. +Sometimes, `RestorePVC` needs to be configured to increase the performance of restore operations. [This document][19] outlines advanced configuration options for `RestorePVC`, allowing users to fine-tune access modes and storage class settings based on their storage provider's capabilities. + + +[1]: https://github.com/vmware-tanzu/velero/pull/5968 +[2]: csi.md +[3]: file-system-backup.md +[4]: https://kubernetes.io/blog/2020/12/10/kubernetes-1.20-volume-snapshot-moves-to-ga/ +[5]: https://kubernetes.io/docs/concepts/storage/volumes/#mount-propagation +[7]: https://docs.microsoft.com/en-us/azure/aks/azure-files-dynamic-pv +[8]: api-types/backupstoragelocation.md +[9]: supported-providers.md +[10]: restore-reference.md#changing-pv/pvc-Storage-Classes +[11]: data-movement-pod-resource-configuration.md +[12]: performance-guidance.md +[13]: https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/ +[14]: node-agent-concurrency.md +[15]: data-movement-node-selection.md +[16]: data-movement-backup-pvc-configuration.md +[17]: backup-repository-configuration.md +[18]: https://github.com/vmware-tanzu/velero/pull/7576 +[19]: data-movement-restore-pvc-configuration.md +[20]: node-agent-prepare-queue-length.md + diff --git a/site/content/docs/v1.17/csi.md b/site/content/docs/v1.17/csi.md new file mode 100644 index 000000000..53843841d --- /dev/null +++ b/site/content/docs/v1.17/csi.md @@ -0,0 +1,136 @@ +--- +title: "Container Storage Interface Snapshot Support in Velero" +layout: docs +--- + +Integrating Container Storage Interface (CSI) snapshot support into Velero enables Velero to backup and restore CSI-backed volumes using the [Kubernetes CSI Snapshot APIs](https://kubernetes.io/docs/concepts/storage/volume-snapshots/). + +By supporting CSI snapshot APIs, Velero can support any volume provider that has a CSI driver, without requiring a Velero-specific plugin to be available. This page gives an overview of how to add support for CSI snapshots to Velero. + +## Notice +From release-1.14, the `github.com/vmware-tanzu/velero-plugin-for-csi` repository, which is the Velero CSI plugin, is merged into the `github.com/vmware-tanzu/velero` repository. +The reasons to merge the CSI plugin are: +* The VolumeSnapshot data mover depends on the CSI plugin, it's reasonabe to integrate them. +* This change reduces the Velero deploying complexity. +* This makes performance tuning easier in the future. + +As a result, no need to install Velero CSI plugin anymore. + +## Prerequisites + + 1. Your cluster is Kubernetes version 1.20 or greater. + 1. Your cluster is running a CSI driver capable of support volume snapshots at the [v1 API level](https://kubernetes.io/blog/2020/12/10/kubernetes-1.20-volume-snapshot-moves-to-ga/). + 1. When restoring CSI VolumeSnapshots across clusters, the name of the CSI driver in the destination cluster is the same as that on the source cluster to ensure cross cluster portability of CSI VolumeSnapshots + +**NOTE:** Not all cloud provider's CSI drivers guarantee snapshot durability, meaning that the VolumeSnapshot and VolumeSnapshotContent objects may be stored in the same object storage system location as the original PersistentVolume and may be vulnerable to data loss. You should refer to your cloud provider's documentation for more information on configuring snapshot durability. Since v0.3.0 the velero team will provide official support for CSI plugin when they are used with AWS and Azure drivers. + +## Installing Velero with CSI support + +To integrate Velero with the CSI volume snapshot APIs, you must enable the `EnableCSI` feature flag. + +```bash +velero install \ +--features=EnableCSI \ +--plugins= \ +... +``` + +To include the status of CSI objects associated with a Velero backup in `velero backup describe` output, run `velero client config set features=EnableCSI`. +See [Enabling Features][1] for more information about managing client-side feature flags. + +## Implementation Choices + +This section documents some of the choices made during implementing the CSI snapshot. + + 1. VolumeSnapshots created by the Velero CSI plugins are retained only for the lifetime of the backup even if the `DeletionPolicy` on the VolumeSnapshotClass is set to `Retain`. To accomplish this, during deletion of the backup the prior to deleting the VolumeSnapshot, VolumeSnapshotContent object is patched to set its `DeletionPolicy` to `Delete`. Deleting the VolumeSnapshot object will result in cascade delete of the VolumeSnapshotContent and the snapshot in the storage provider. + 2. VolumeSnapshotContent objects created during a `velero backup` that are dangling, unbound to a VolumeSnapshot object, will be discovered, using labels, and deleted on backup deletion. + 3. The Velero CSI plugins, to backup CSI backed PVCs, will choose the VolumeSnapshotClass in the cluster based on the following logic: + 1. **Default Behavior Based On Annotation:** + You can specify a default VolumeSnapshotClass for VolumeSnapshots that don't request any particular class to bind to by adding the snapshot.storage.kubernetes.io/is-default-class: "true" annotation. + For example, if you want to create a VolumeSnapshotClass for the CSI driver `disk.csi.cloud.com` for taking snapshots of disks created with `disk.csi.cloud.com` based storage classes, you can create a VolumeSnapshotClass like this: + ```yaml + apiVersion: snapshot.storage.k8s.io/v1 + kind: VolumeSnapshotClass + metadata: + name: test-snapclass-by-annotation + annotations: + snapshot.storage.kubernetes.io/is-default-class: "true" + driver: disk.csi.cloud.com + ``` + Note: If multiple CSI drivers exist, a default VolumeSnapshotClass can be specified for each of them. + 2. **Default Behavior Based On Label:** + You can simply create a VolumeSnapshotClass for a particular driver and put a label on it to indicate that it is the default VolumeSnapshotClass for that driver. For example, if you want to create a VolumeSnapshotClass for the CSI driver `disk.csi.cloud.com` for taking snapshots of disks created with `disk.csi.cloud.com` based storage classes, you can create a VolumeSnapshotClass like this: + ```yaml + apiVersion: snapshot.storage.k8s.io/v1 + kind: VolumeSnapshotClass + metadata: + name: test-snapclass-by-label + labels: + velero.io/csi-volumesnapshot-class: "true" + driver: disk.csi.cloud.com + ``` + Note: For each driver type, there should only be 1 VolumeSnapshotClass with the label `velero.io/csi-volumesnapshot-class: "true"`. + + 2. **Choose VolumeSnapshotClass for a particular Backup Or Schedule:** + If you want to use a particular VolumeSnapshotClass for a particular backup or schedule, you can add a annotation to the backup or schedule to indicate which VolumeSnapshotClass to use. For example, if you want to use the VolumeSnapshotClass `test-snapclass` for a particular backup for snapshotting PVCs of `disk.csi.cloud.com`, you can create a backup like this: + ```yaml + apiVersion: velero.io/v1 + kind: Backup + metadata: + name: test-backup + annotations: + velero.io/csi-volumesnapshot-class_disk.csi.cloud.com: "test-snapclass" + spec: + includedNamespaces: + - default + ``` + Note: Please ensure all your annotations are in lowercase. And follow the following format: `velero.io/csi-volumesnapshot-class_ = ` + + 3. **Choosing VolumeSnapshotClass for a particular PVC:** + If you want to use a particular VolumeSnapshotClass for a particular PVC, you can add a annotation to the PVC to indicate which VolumeSnapshotClass to use. This overrides any annotation added to backup or schedule. For example, if you want to use the VolumeSnapshotClass `test-snapclass` for a particular PVC, you can create a PVC like this: + ```yaml + apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: test-pvc + annotations: + velero.io/csi-volumesnapshot-class: "test-snapclass" + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + storageClassName: disk.csi.cloud.com + ``` + 4. The VolumeSnapshot objects will be removed from the cluster after the backup is uploaded to the object storage, so that the namespace that is backed up can be deleted without removing the snapshot in the storage provider if the `DeletionPolicy` is `Delete`. + +## How it Works - Overview + +Velero's CSI support does not rely on the Velero VolumeSnapshotter plugin interface. + +Instead, Velero uses a collection of BackupItemAction plugins that act first against PersistentVolumeClaims. + +When this BackupItemAction sees PersistentVolumeClaims pointing to a PersistentVolume backed by a CSI driver, it will choose the VolumeSnapshotClass with the same driver name that has the `velero.io/csi-volumesnapshot-class` label to create a CSI VolumeSnapshot object with the PersistentVolumeClaim as a source. +This VolumeSnapshot object resides in the same namespace as the PersistentVolumeClaim that was used as a source. + +From there, the CSI external-snapshotter controller will see the VolumeSnapshot and create a VolumeSnapshotContent object, a cluster-scoped resource that will point to the actual, disk-based snapshot in the storage system. +The external-snapshotter plugin will call the CSI driver's snapshot method, and the driver will call the storage system's APIs to generate the snapshot. +Once an ID is generated and the storage system marks the snapshot as usable for restore, the VolumeSnapshotContent object will be updated with a `status.snapshotHandle` and the `status.readyToUse` field will be set. + +Velero will include the generated VolumeSnapshot and VolumeSnapshotContent objects in the backup tarball, as well as +upload all VolumeSnapshots and VolumeSnapshotContents objects in a JSON file to the object storage system. **Note that +only Kubernetes objects are uploaded to the object storage, not the data in snapshots.** + +From v1.16, when Velero synchronizes backups into a new cluster, the VolumeSnapshotClass that is chosen to take +snapshot will be synced into the cluster, so that Velero can manage backup expiration appropriately. + + +The `DeletionPolicy` on the VolumeSnapshotContent will be the same as the `DeletionPolicy` on the VolumeSnapshotClass that was used to create the VolumeSnapshot. Setting a `DeletionPolicy` of `Retain` on the VolumeSnapshotClass will preserve the volume snapshot in the storage system for the lifetime of the Velero backup and will prevent the deletion of the volume snapshot, in the storage system, in the event of a disaster where the namespace with the VolumeSnapshot object may be lost. + +When the Velero backup expires, the VolumeSnapshot objects will be deleted and the VolumeSnapshotContent objects will be updated to have a `DeletionPolicy` of `Delete`, to free space on the storage system. + +**Note:** The AWS, Microsoft Azure, and Google Cloud Platform (GCP) Velero plugins version 1.4 and later are able to snapshot and restore persistent volumes provisioned by a CSI driver via the APIs of the cloud provider, without having to install Velero CSI plugins. See the [AWS](https://github.com/vmware-tanzu/velero-plugin-for-aws), [Microsoft Azure](https://github.com/vmware-tanzu/velero-plugin-for-microsoft-azure), and [Google Cloud Platform (GCP)](https://github.com/vmware-tanzu/velero-plugin-for-gcp) Velero plugin repo for more information on supported CSI drivers. +From v1.14, no need to install the CSI plugin, because it is integrated into the Velero code base. + +[1]: customize-installation.md#enable-server-side-features diff --git a/site/content/docs/v1.17/custom-plugins.md b/site/content/docs/v1.17/custom-plugins.md new file mode 100644 index 000000000..5ac7eedd6 --- /dev/null +++ b/site/content/docs/v1.17/custom-plugins.md @@ -0,0 +1,121 @@ +--- +title: "Plugins" +layout: docs +--- + +Velero has a plugin architecture that allows users to add their own custom functionality to Velero backups & restores without having to modify/recompile the core Velero binary. To add custom functionality, users simply create their own binary containing implementations of Velero's plugin kinds (described below), plus a small amount of boilerplate code to expose the plugin implementations to Velero. This binary is added to a container image that serves as an init container for the Velero server pod and copies the binary into a shared emptyDir volume for the Velero server to access. + +Multiple plugins, of any type, can be implemented in this binary. + +A fully-functional [sample plugin repository][1] is provided to serve as a convenient starting point for plugin authors. + +## Plugin Naming + +A plugin is identified by a prefix + name. + +**Note: Please don't use `velero.io` as the prefix for a plugin not supported by the Velero team.** The prefix should help users identify the entity developing the plugin, so please use a prefix that identify yourself. + +Whenever you define a Backup Storage Location or Volume Snapshot Location, this full name will be the value for the `provider` specification. + +For example: `oracle.io/oracle`. + +``` +apiVersion: velero.io/v1 +kind: BackupStorageLocation +spec: + provider: oracle.io/oracle +``` + +``` +apiVersion: velero.io/v1 +kind: VolumeSnapshotLocation +spec: + provider: oracle.io/oracle +``` + +When naming your plugin, keep in mind that the full name needs to conform to these rules: +- have two parts, prefix + name, separated by '/' +- none of the above parts can be empty +- the prefix is a valid DNS subdomain name +- a plugin with the same prefix + name cannot already exist + +### Some examples: + +``` +- example.io/azure +- 1.2.3.4/5678 +- example-with-dash.io/azure +``` + +You will need to give your plugin(s) the full name when registering them by calling the appropriate `RegisterX` function: + +## Plugin Kinds + +Velero supports the following kinds of plugins: + +- **Object Store** - persists and retrieves backups, backup logs and restore logs +- **Volume Snapshotter** - creates volume snapshots (during backup) and restores volumes from snapshots (during restore) +- **Backup Item Action** - executes arbitrary logic for individual items prior to storing them in a backup file +- **Restore Item Action** - executes arbitrary logic for individual items prior to restoring them into a cluster +- **Delete Item Action** - executes arbitrary logic based on individual items within a backup prior to deleting the backup +- **Item Block Action** - executes arbitrary logic for individual items to determine which items should be backed up together + +Plugin binaries are discovered by recursively reading a directory in no particular order. Hence no guarantee is provided for the +order in which item action plugins are invoked. However, if a single binary implements multiple item action plugins, +they may be invoked in the order in which they are registered but it is best to not depend on this +implementation. This is not guaranteed officially and the implementation can change at any time. + +## Plugin Logging + +Velero provides a [logger][2] that can be used by plugins to log structured information to the main Velero server log or +per-backup/restore logs. It also passes a `--log-level` flag to each plugin binary, whose value is the value of the same +flag from the main Velero process. This means that if you turn on debug logging for the Velero server via `--log-level=debug`, +plugins will also emit debug-level logs. See the [sample repository][1] for an example of how to use the logger within your plugin. + +## Plugin Configuration + +Velero uses a ConfigMap-based convention for providing configuration to plugins. If your plugin needs to be configured at runtime, +define a ConfigMap like the following: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + # any name can be used; Velero uses the labels (below) + # to identify it rather than the name + name: my-plugin-config + + # must be in the namespace where the velero deployment + # is running + namespace: velero + + labels: + # this value-less label identifies the ConfigMap as + # config for a plugin (the built-in change storageclass + # restore item action plugin) + velero.io/plugin-config: "" + + # add a label whose key corresponds to the fully-qualified + # plugin name (for example mydomain.io/my-plugin-name), and whose + # value is the plugin type (BackupItemAction, RestoreItemAction, + # ObjectStore, or VolumeSnapshotter) + : + +data: + # add your configuration data here as key-value pairs +``` + +Then, in your plugin's implementation, you can read this ConfigMap to fetch the necessary configuration. + +## Feature Flags + +Velero will pass any known features flags as a comma-separated list of strings to the `--features` argument. + +Once parsed into a `[]string`, the features can then be registered using the `NewFeatureFlagSet` function and queried with `features.Enabled()`. + +## Environment Variables + +Velero adds the `LD_LIBRARY_PATH` into the list of environment variables to provide the convenience for plugins that requires C libraries/extensions in the runtime. + +[1]: https://github.com/vmware-tanzu/velero-plugin-example +[2]: https://github.com/vmware-tanzu/velero/blob/v1.17.0/pkg/plugin/logger.go diff --git a/site/content/docs/v1.17/customize-installation.md b/site/content/docs/v1.17/customize-installation.md new file mode 100644 index 000000000..fde2c5280 --- /dev/null +++ b/site/content/docs/v1.17/customize-installation.md @@ -0,0 +1,523 @@ +--- +title: "Customize Velero Install" +layout: docs +--- + +## Plugins + +During install, Velero requires that at least one plugin is added (with the `--plugins` flag). Please see the documentation under [Plugins](overview-plugins.md) + +## Install in any namespace + +Velero is installed in the `velero` namespace by default. However, you can install Velero in any namespace. See [run in custom namespace][2] for details. + +## Use non-file-based identity mechanisms + +By default, `velero install` expects a credentials file for your `velero` IAM account to be provided via the `--secret-file` flag. + +If you are using an alternate identity mechanism, such as kube2iam/kiam on AWS, Workload Identity on GKE, etc., that does not require a credentials file, you can specify the `--no-secret` flag instead of `--secret-file`. + +## Enable file system backup + +By default, `velero install` does not install Velero's [File System Backup][3]. To enable it, specify the `--use-node-agent` flag. + +If you've already run `velero install` without the `--use-node-agent` flag, you can run the same command again, including the `--use-node-agent` flag, to add the file system backup to your existing install. + +## CSI Snapshot Data Movement + +Velero node-agent is required by [CSI Snapshot Data Movement][12] when Velero built-in data mover is used. By default, `velero install` does not install Velero's node-agent. To enable it, specify the `--use-node-agent` flag. + +For some use cases, Velero node-agent requires to run under privileged mode. For example, when backing up block volumes, it is required to allow the node-agent to access the block device. To enable it set velero install flags `--privileged-node-agent`. + +If you've already run `velero install` without the `--use-node-agent` or `--privileged-node-agent` flag, you can run the same command again, including the `--use-node-agent` or `--privileged-node-agent` flag, to add CSI snapshot data movement to your existing install. + +## Customize the kubelet root path of the node-agent +When installing with the `--use-node-agent` flag, the node-agent will mount the default kubelet paths `/var/lib/kubelet/pods` and `/var/lib/kubelet/plugins` (hostPath). To customize these kubelet mount paths, use the `--kubelet-root-dir` flag. + +## Default Pod Volume backup to file system backup + +By default, `velero install` does not enable the use of File System Backup (FSB) to take backups of all pod volumes. You must apply an [annotation](file-system-backup.md/#using-opt-in-pod-volume-backup) to every pod which contains volumes for Velero to use FSB for the backup. + +If you are planning to only use FSB for volume backups, you can run the `velero install` command with the `--default-volumes-to-fs-backup` flag. This will default all pod volumes backups to use FSB without having to apply annotations to pods. Note that when this flag is set during install, Velero will always try to use FSB to perform the backup, even want an individual backup to use volume snapshots, by setting the `--snapshot-volumes` flag in the `backup create` command. Alternatively, you can set the `--default-volumes-to-fs-backup` on an individual backup to to make sure Velero uses FSB for each volume being backed up. + +## Enable features + +New features in Velero will be released as beta features behind feature flags which are not enabled by default. A full listing of Velero feature flags can be found [here][11]. + +### Enable server side features + +Features on the Velero server can be enabled using the `--features` flag to the `velero install` command. This flag takes as value a comma separated list of feature flags to enable. As an example [CSI snapshotting of PVCs][10] can be enabled using `EnableCSI` feature flag in the `velero install` command as shown below: + +```bash +velero install --features=EnableCSI +``` + +Another example is enabling the support of multiple API group versions, as documented at [- -features=EnableAPIGroupVersions](enable-api-group-versions-feature.md). + +Feature flags, passed to `velero install` will be passed to the Velero deployment and also to the `node-agent` daemon set, if `--use-node-agent` flag is used. + +Similarly, features may be disabled by removing the corresponding feature flags from the `--features` flag. + +Enabling and disabling feature flags will require modifying the Velero deployment and also the node-agent daemonset. This may be done from the CLI by uninstalling and re-installing Velero, or by editing the `deploy/velero` and `daemonset/node-agent` resources in-cluster. + +```bash +$ kubectl -n velero edit deploy/velero +$ kubectl -n velero edit daemonset/node-agent +``` + +### Enable client side features + +For some features it may be necessary to use the `--features` flag to the Velero client. This may be done by passing the `--features` on every command run using the Velero CLI or the by setting the features in the velero client config file using the `velero client config set` command as shown below: + +```bash +velero client config set features=feature1,feature2... +``` + +This stores the config in a file at `$HOME/.config/velero/config.json`. + +All client side feature flags may be disabled using the below command + +```bash +velero client config set features= +``` + +### Colored CLI output + +Velero CLI uses colored output for some commands, such as `velero describe`. If +the environment in which Velero is run doesn't support colored output, the +colored output will be automatically disabled. However, you can manually disable +colors with config file: + +```bash +velero client config set colorized=false +``` + +Note that if you specify `--colorized=true` as a CLI option it will override +the config file setting. + + +## Set priority class names for Velero components + +You can set priority class names for different Velero components during installation. This allows you to influence the scheduling and eviction behavior of Velero pods, which can be useful in clusters where resource contention is high. + +### Priority class configuration options: + +1. **Velero server deployment**: Use the `--server-priority-class-name` flag +2. **Node agent daemonset**: Use the `--node-agent-priority-class-name` flag +3. **Data mover pods**: Configure through the node-agent configmap (see below) +4. **Maintenance jobs**: Configure through the repository maintenance job configmap (see below) + +```bash +velero install \ + --server-priority-class-name= \ + --node-agent-priority-class-name= +``` + +### Configuring priority classes for data mover pods and maintenance jobs + +For data mover pods and maintenance jobs, priority classes are configured through ConfigMaps that must be created before installation: + +**Data mover pods** (via node-agent configmap): +```bash +kubectl create configmap node-agent-config -n velero --from-file=config.json=/dev/stdin <}} +|Setting|Velero pod defaults|node-agent pod defaults| +|--- |--- |--- | +|CPU request|500m|N/A| +|Memory requests|128Mi|N/A| +|CPU limit|1000m (1 CPU)|N/A| +|Memory limit|512Mi|N/A| +{{< /table >}} + +For Velero pod, through testing, the Velero maintainers have found these defaults work well when backing up and restoring 1000 or less resources. +For node-agent pod, by default it doesn't have CPU/memory request/limit, so that the backups/restores won't break due to resource throttling. The Velero maintainers have also done some [Performance Tests][13] to show the relationship of CPU/memory usage and the scale of data being backed up/restored. + +For repository maintenance job, it's no limit on resources by default. You could configure the job resource limitation based on target data to be backed up, some further settings please refer to [repository maintenance job][14]. + +You don't have to change the defaults all the time, but if you need, it's recommended that you perform your own testing to find the best resource limits for your clusters and resources. + +### Install with custom resource requests and limits + +You can customize these resource requests and limit when you first install using the [velero install][6] CLI command. + +``` +velero install \ + --velero-pod-cpu-request \ + --velero-pod-mem-request \ + --velero-pod-cpu-limit \ + --velero-pod-mem-limit \ + [--use-node-agent] \ + [--default-volumes-to-fs-backup] \ + [--node-agent-pod-cpu-request ] \ + [--node-agent-pod-mem-request ] \ + [--node-agent-pod-cpu-limit ] \ + [--node-agent-pod-mem-limit ] \ + [--maintenance-job-cpu-request ] \ + [--maintenance-job-mem-request ] \ + [--maintenance-job-cpu-limit ] \ + [--maintenance-job-mem-limit ] +``` + +### Update resource requests and limits after install + +After installation you can adjust the resource requests and limits in the Velero Deployment spec or node-agent DaemonSet spec, if you are using the File System Backup. + +**Velero pod** + +Update the `spec.template.spec.containers.resources.limits` and `spec.template.spec.containers.resources.requests` values in the Velero deployment. + +```bash +kubectl patch deployment velero -n velero --patch \ +'{"spec":{"template":{"spec":{"containers":[{"name": "velero", "resources": {"limits":{"cpu": "1", "memory": "512Mi"}, "requests": {"cpu": "1", "memory": "128Mi"}}}]}}}}' +``` + +**node-agent pod** + +Update the `spec.template.spec.containers.resources.limits` and `spec.template.spec.containers.resources.requests` values in the node-agent DaemonSet spec. + +```bash +kubectl patch daemonset node-agent -n velero --patch \ +'{"spec":{"template":{"spec":{"containers":[{"name": "node-agent", "resources": {"limits":{"cpu": "1", "memory": "1024Mi"}, "requests": {"cpu": "1", "memory": "512Mi"}}}]}}}}' +``` + +Additionally, you may want to update the the default File System Backup operation timeout (default 240 minutes) to allow larger backups more time to complete. You can adjust this timeout by adding the `- --fs-backup-timeout` argument to the Velero Deployment spec. + +**NOTE:** Changes made to this timeout value will revert back to the default value if you re-run the Velero install command. + +1. Open the Velero Deployment spec. + + ``` + kubectl edit deploy velero -n velero + ``` + +1. Add `- --fs-backup-timeout` to `spec.template.spec.containers`. + + ```yaml + spec: + template: + spec: + containers: + - args: + - --fs-backup-timeout=240m + ``` + +### Ephemeral-storage Requests and Limits + +Velero does not set ephemeral-storage limits during installation. Limits and requests can be edited after install for clusters that monitor and restrict ephemeral-storage usage. + +Plugins will use ephemeral-storage. There needs to be a sufficient requests and limit set to account for plugins and the additional ephemeral-storage used to maintain credentials and cache space for datamovers. Object storage plugins will fit comfortably into an allocation of 100MB of ephemeral-storage. + +## Configure more than one storage location for backups or volume snapshots + +Velero supports any number of backup storage locations and volume snapshot locations. For more details, see [about locations](locations.md). + +However, `velero install` only supports configuring at most one backup storage location and one volume snapshot location. + +To configure additional locations after running `velero install`, use the `velero backup-location create` and/or `velero snapshot-location create` commands along with provider-specific configuration. Use the `--help` flag on each of these commands for more details. + +### Set default backup storage location or volume snapshot locations + +When performing backups, Velero needs to know where to backup your data. This means that if you configure multiple locations, you must specify the location Velero should use each time you run `velero backup create`, or you can set a default backup storage location or default volume snapshot locations. If you only have one backup storage location or volume snapshot location set for a provider, Velero will automatically use that location as the default. + +#### Set default backup storage location +currently, Velero could set the default backup storage location as below: +- First way: Set a default backup storage location by passing a `--default` flag when running `velero backup-location create`. + + ``` + velero backup-location create backups-primary \ + --provider aws \ + --bucket velero-backups \ + --config region=us-east-1 \ + --default + ``` +- Second way: Set a default backup storage location by passing a `--default` flag when running `velero backup-location set`. + ```bash + velero backup-location set backups-primary --default + ``` + We also could remove the default backup storage location by this command, below is one example + ```bash + velero backup-location set backups-primary --default=false + ``` +- Third way: Set a default backup storage location by passing `--default-backup-storage-location` flag on the `velero server` command. + ```bash + velero server --default-backup-storage-location backups-primary + ``` +Note: Only could have one default backup storage location, which means it's not allowed to set two default backup storage locations at the same time, the priorities among these three are as follows: +- if velero server side has specified one default backup storage location, suppose it's `A` + - if `A` backup storage location exists, it's not allowed to set a new default backup storage location + - if `A` does not exist + - if using `velero backup-location set` or `velero backup-location create --default` command + - it could be successful if no default backup storage location exists. + - it would fail if already exist one default backup storage location. (So it need to remove other default backup storage location at first) +- if velero server side has not specified one default backup storage location + - if using `velero backup-location set` or `velero backup-location create --default` command + - it could be successful if no default backup storage location exists. + - it would fail if already exist one default backup storage location. (So it need to remove other default backup storage location at first) +#### Set default volume snapshot location +You can set a default volume snapshot location for each of your volume snapshot providers using the `--default-volume-snapshot-locations` flag on the `velero server` command. + +``` +velero server --default-volume-snapshot-locations=":,:" +``` + +## Do not configure a backup storage location during install + +If you need to install Velero without a default backup storage location (without specifying `--bucket` or `--provider`), the `--no-default-backup-location` flag is required for confirmation. + +## Install an additional volume snapshot provider + +Velero supports using different providers for volume snapshots than for object storage -- for example, you can use AWS S3 for object storage, and Portworx for block volume snapshots. + +However, `velero install` only supports configuring a single matching provider for both object storage and volume snapshots. + +To use a different volume snapshot provider: + +1. Install the Velero server components by following the instructions for your **object storage** provider + +1. Add your volume snapshot provider's plugin to Velero (look in [your provider][0]'s documentation for the image name): + + ```bash + velero plugin add + ``` + +1. Add a volume snapshot location for your provider, following [your provider][0]'s documentation for configuration: + + ```bash + velero snapshot-location create \ + --provider \ + [--config ] + ``` + +## Generate YAML only + +By default, `velero install` generates and applies a customized set of Kubernetes configuration (YAML) to your cluster. + +To generate the YAML without applying it to your cluster, use the `--dry-run -o yaml` flags. + +This is useful for applying bespoke customizations, integrating with a GitOps workflow, etc. + +If you are installing Velero in Kubernetes 1.14.x or earlier, you need to use `kubectl apply`'s `--validate=false` option when applying the generated configuration to your cluster. See [issue 2077][7] and [issue 2311][8] for more context. + +## Use a storage provider secured by a self-signed certificate + +If you intend to use Velero with a storage provider that is secured by a self-signed certificate, +you may need to instruct Velero to trust that certificate. See [use Velero with a storage provider secured by a self-signed certificate][9] for details. + +## Additional options + +Run `velero install --help` or see the [Helm chart documentation](https://vmware-tanzu.github.io/helm-charts/) for the full set of installation options. + +## Optional Velero CLI configurations + +### Enabling shell autocompletion + +**Velero CLI** provides autocompletion support for `Bash` and `Zsh`, which can save you a lot of typing. + +Below are the procedures to set up autocompletion for `Bash` (including the difference between `Linux` and `macOS`) and `Zsh`. + +#### Bash on Linux + +The **Velero CLI** completion script for `Bash` can be generated with the command `velero completion bash`. Sourcing the completion script in your shell enables velero autocompletion. + +However, the completion script depends on [**bash-completion**](https://github.com/scop/bash-completion), which means that you have to install this software first (you can test if you have bash-completion already installed by running `type _init_completion`). + +##### Install bash-completion + +`bash-completion` is provided by many package managers (see [here](https://github.com/scop/bash-completion#installation)). You can install it with `apt-get install bash-completion` or `yum install bash-completion`, etc. + +The above commands create `/usr/share/bash-completion/bash_completion`, which is the main script of bash-completion. Depending on your package manager, you have to manually source this file in your `~/.bashrc` file. + +To find out, reload your shell and run `type _init_completion`. If the command succeeds, you're already set, otherwise add the following to your `~/.bashrc` file: + +```shell +source /usr/share/bash-completion/bash_completion +``` + +Reload your shell and verify that bash-completion is correctly installed by typing `type _init_completion`. + +##### Enable Velero CLI autocompletion for Bash on Linux + +You now need to ensure that the **Velero CLI** completion script gets sourced in all your shell sessions. There are two ways in which you can do this: + +- Source the completion script in your `~/.bashrc` file: + + ```shell + echo 'source <(velero completion bash)' >>~/.bashrc + ``` + +- Add the completion script to the `/etc/bash_completion.d` directory: + + ```shell + velero completion bash >/etc/bash_completion.d/velero + ``` + +- If you have an alias for velero, you can extend shell completion to work with that alias: + + ```shell + echo 'alias v=velero' >>~/.bashrc + echo 'complete -F __start_velero v' >>~/.bashrc + ``` + +> `bash-completion` sources all completion scripts in `/etc/bash_completion.d`. + +Both approaches are equivalent. After reloading your shell, velero autocompletion should be working. + +#### Bash on macOS + +The **Velero CLI** completion script for Bash can be generated with `velero completion bash`. Sourcing this script in your shell enables velero completion. + +However, the velero completion script depends on [**bash-completion**](https://github.com/scop/bash-completion) which you thus have to previously install. + + +> There are two versions of bash-completion, v1 and v2. V1 is for Bash 3.2 (which is the default on macOS), and v2 is for Bash 4.1+. The velero completion script **doesn't work** correctly with bash-completion v1 and Bash 3.2. It requires **bash-completion v2** and **Bash 4.1+**. Thus, to be able to correctly use velero completion on macOS, you have to install and use Bash 4.1+ ([*instructions*](https://itnext.io/upgrading-bash-on-macos-7138bd1066ba)). The following instructions assume that you use Bash 4.1+ (that is, any Bash version of 4.1 or newer). + + +##### Install bash-completion + +> As mentioned, these instructions assume you use Bash 4.1+, which means you will install bash-completion v2 (in contrast to Bash 3.2 and bash-completion v1, in which case kubectl completion won't work). + +You can test if you have bash-completion v2 already installed with `type _init_completion`. If not, you can install it with Homebrew: + + ```shell + brew install bash-completion@2 + ``` + +As stated in the output of this command, add the following to your `~/.bashrc` file: + + ```shell + export BASH_COMPLETION_COMPAT_DIR="/usr/local/etc/bash_completion.d" + [[ -r "/usr/local/etc/profile.d/bash_completion.sh" ]] && . "/usr/local/etc/profile.d/bash_completion.sh" + ``` + +Reload your shell and verify that bash-completion v2 is correctly installed with `type _init_completion`. + +##### Enable Velero CLI autocompletion for Bash on macOS + +You now have to ensure that the velero completion script gets sourced in all your shell sessions. There are multiple ways to achieve this: + +- Source the completion script in your `~/.bashrc` file: + + ```shell + echo 'source <(velero completion bash)' >>~/.bashrc + + ``` + +- Add the completion script to the `/usr/local/etc/bash_completion.d` directory: + + ```shell + velero completion bash >/usr/local/etc/bash_completion.d/velero + ``` + +- If you have an alias for velero, you can extend shell completion to work with that alias: + + ```shell + echo 'alias v=velero' >>~/.bashrc + echo 'complete -F __start_velero v' >>~/.bashrc + ``` + +- If you installed velero with Homebrew (as explained [above](#install-with-homebrew-on-macos)), then the velero completion script should already be in `/usr/local/etc/bash_completion.d/velero`. In that case, you don't need to do anything. + +> The Homebrew installation of bash-completion v2 sources all the files in the `BASH_COMPLETION_COMPAT_DIR` directory, that's why the latter two methods work. + +In any case, after reloading your shell, velero completion should be working. + +#### Autocompletion on Zsh + +The velero completion script for Zsh can be generated with the command `velero completion zsh`. Sourcing the completion script in your shell enables velero autocompletion. + +To do so in all your shell sessions, add the following to your `~/.zshrc` file: + + ```shell + source <(velero completion zsh) + ``` + +If you have an alias for kubectl, you can extend shell completion to work with that alias: + + ```shell + echo 'alias v=velero' >>~/.zshrc + echo 'complete -F __start_velero v' >>~/.zshrc + ``` + +After reloading your shell, kubectl autocompletion should be working. + +If you get an error like `complete:13: command not found: compdef`, then add the following to the beginning of your `~/.zshrc` file: + + ```shell + autoload -Uz compinit + compinit + ``` + +## Advanced configuration through external ConfigMaps + +Velero supports to configure its some advanced behaviors by external ConfigMaps. +Velero itself isn't responsible for creating and maintaining these ConfigMaps, instead the users should do that. + +By far, `velero install` supports the following parameters to specify the external ConfigMap names: +* --backup-repository-configmap: [backup repository configuration document][15] +* --node-agent-configmap: [node-agent concurrency configuration document][16], and there are some other documents specify other parts of node-agent-config. +* --repo-maintenance-job-configmap: [repository maintenance configuration document][17] + +From v1.17, Velero adds verification for the ConfigMaps in CLI and server side, which means `velero install` CLI will fail and velero server and node-agent pod will exit if the specified ConfigMaps don't exist or are invalid. + +The change's aim is validating the ConfigMaps and fail early instead of finding the ConfigMaps are not valid during running data mover pod or repository maintenance job. + +However, there means the user cannot just running `velero install` CLI then get a working environment, when the external ConfigMaps are involved. + +The new workflow is: +* Create the needed namespace: `kubectl create ns velero` +* Add PSA labels to the namespace: `kubectl label ns velero pod-security.velero.io/enforce=privileged` +* Create the needed ConfigMaps. +* Run the `velero install` CLI: + ``` bash + velero install \ + --provider aws \ + ...... + --backup-repository-configmap=... \ + --node-agent-configmap=... \ + --repo-maintenance-job-configmap=... + ``` + + +[1]: https://github.com/vmware-tanzu/velero/releases/latest +[2]: namespace.md +[3]: file-system-backup.md +[4]: on-premises.md +[6]: velero-install.md#usage +[7]: https://github.com/vmware-tanzu/velero/issues/2077 +[8]: https://github.com/vmware-tanzu/velero/issues/2311 +[9]: self-signed-certificates.md +[10]: csi.md +[11]: https://github.com/vmware-tanzu/velero/blob/v1.17.0/pkg/apis/velero/v1/constants.go +[12]: csi-snapshot-data-movement.md +[13]: performance-guidance.md +[14]: repository-maintenance.md +[15]: backup-repository-configuration.md +[16]: node-agent-concurrency.md +[17]: repository-maintenance.md diff --git a/site/content/docs/v1.17/data-movement-backup-pvc-configuration.md b/site/content/docs/v1.17/data-movement-backup-pvc-configuration.md new file mode 100644 index 000000000..11f6d6bc7 --- /dev/null +++ b/site/content/docs/v1.17/data-movement-backup-pvc-configuration.md @@ -0,0 +1,71 @@ +--- +title: "BackupPVC Configuration for Data Movement Backup" +layout: docs +--- + +`BackupPVC` is an intermediate PVC to access data from during the data movement backup operation. + +In some scenarios users may need to configure some advanced options of the backupPVC so that the data movement backup +operation could perform better. Specifically: +- For some storage providers, when creating a read-only volume from a snapshot, it is very fast; whereas, if a writable volume + is created from the snapshot, they need to clone the entire disk data, which is time consuming. If the `backupPVC`'s `accessModes` is + set as `ReadOnlyMany`, the volume driver is able to tell the storage to create a read-only volume, which may dramatically shorten the + snapshot expose time. On the other hand, `ReadOnlyMany` is not supported by all volumes. Therefore, users should be allowed to configure + the `accessModes` for the `backupPVC`. +- Some storage providers create one or more replicas when creating a volume, the number of replicas is defined in the storage class. + However, it doesn't make any sense to keep replicas when an intermediate volume used by the backup. Therefore, users should be allowed + to configure another storage class specifically used by the `backupPVC`. +- In SELinux-enabled clusters, such as OpenShift, when using the above-mentioned readOnly access mode setting, SELinux relabeling of the + volume is not possible. Therefore for these clusters, when setting `readOnly` for a storage class, users must also disable relabeling. + Note that this option is not consistent with the Restricted pod security policy, so if Velero pods must run with a restricted policy, + disabling relabeling (and therefore readOnly volume mounting) is not possible. + +Velero introduces a new section in the node agent configuration ConfigMap (the name of this ConfigMap is passed using `--node-agent-configmap` velero server argument) +called `backupPVC`, through which you can specify the following +configurations: + +- `storageClass`: This specifies the storage class to be used for the backupPVC. If this value does not exist or is empty then by +default the source PVC's storage class will be used. + +- `readOnly`: This is a boolean value. If set to `true` then `ReadOnlyMany` will be the only value set to the backupPVC's access modes. Otherwise +`ReadWriteOnce` value will be used. + +- `spcNoRelabeling`: This is a boolean value. If set to `true`, then `pod.Spec.SecurityContext.SELinuxOptions.Type` will be set to `spc_t`. From + the SELinux point of view, this will be considered a "Super Privileged Container" which means that selinux enforcement will be disabled and + volume relabeling will not occur. This field is ignored if `readOnly` is `false`. + +The users can specify the ConfigMap name during velero installation by CLI: +`velero install --node-agent-configmap=` + +A sample of `backupPVC` config as part of the ConfigMap would look like: +```json +{ + "backupPVC": { + "storage-class-1": { + "storageClass": "backupPVC-storage-class", + "readOnly": true + }, + "storage-class-2": { + "storageClass": "backupPVC-storage-class" + }, + "storage-class-3": { + "readOnly": true + } + "storage-class-4": { + "readOnly": true, + "spcNoRelabeling": true + } + } +} +``` + +**Note:** +- Users should make sure that the storage class specified in `backupPVC` config should exist in the cluster and can be used by the +`backupPVC`, otherwise the corresponding DataUpload CR will stay in `Accepted` phase until timeout (data movement prepare timeout value is 30m by default). +- If the users are setting `readOnly` value as `true` in the `backupPVC` config then they must also make sure that the storage class that is being used for +`backupPVC` should support creation of `ReadOnlyMany` PVC from a snapshot, otherwise the corresponding DataUpload CR will stay in `Accepted` phase until +timeout (data movement prepare timeout value is 30m by default). +- In an SELinux-enabled cluster, any time users set `readOnly=true` they must also set `spcNoRelabeling=true`. There is no need to set `spcNoRelabeling=true` +if the volume is not readOnly. +- If any of the above problems occur, then the DataUpload CR is `canceled` after timeout, and the backupPod and backupPVC will be deleted, and the backup +will be marked as `PartiallyFailed`. diff --git a/site/content/docs/v1.17/data-movement-node-selection.md b/site/content/docs/v1.17/data-movement-node-selection.md new file mode 100644 index 000000000..f89b9a778 --- /dev/null +++ b/site/content/docs/v1.17/data-movement-node-selection.md @@ -0,0 +1,260 @@ +--- +title: "Node Selection for Data Movement" +layout: docs +--- + +Velero node-agent is a DaemonSet hosting the data movement modules to complete the concrete work of backups/restores. +Varying from the data size, data complexity, resource availability, the data movement may take a long time and remarkable resources (CPU, memory, network bandwidth, etc.) during the backup and restore. + +Velero data movement backup and restore support to constrain the nodes where it runs. This is helpful in below scenarios: +- Prevent the data movement from running in specific nodes because users have more critical workloads in the nodes +- Constrain the data movement to run in specific nodes because these nodes have more resources than others +- Constrain the data movement to run in specific nodes because the storage allows volume/snapshot provisions in these nodes only + +Velero introduces a new section in the node-agent ConfigMap, called ```loadAffinity```, through which users can specify the nodes to/not to run data movement, in the affinity and anti-affinity flavors. + +**Important**: Currently, only the first element in the `loadAffinity` array is used. Any additional elements after the first one will be ignored. If you need to specify multiple conditions, combine them within a single `loadAffinity` element using both `matchLabels` and `matchExpressions`. + +### Example of Incorrect Usage (Multiple Array Elements) + +The following configuration will NOT work as intended: + +```json +{ + "loadAffinity": [ + { + "nodeSelector": { + "matchLabels": { + "environment": "production" + } + } + }, + { + "nodeSelector": { + "matchLabels": { + "disk-type": "ssd" + } + } + } + ] +} +``` + +In this example, you might expect data movement to run only on nodes that are BOTH in production AND have SSD disks. However, **only the first condition (environment=production) will be applied**. The second array element will be completely ignored. + +### Correct Usage (Combined Conditions) + +To achieve the intended behavior, combine all conditions into a single array element: + +```json +{ + "loadAffinity": [ + { + "nodeSelector": { + "matchLabels": { + "environment": "production", + "disk-type": "ssd" + } + } + } + ] +} +``` + +If it is not there, a ConfigMap should be created manually. The ConfigMap should be in the same namespace where Velero is installed. If multiple Velero instances are installed in different namespaces, there should be one ConfigMap in each namespace which applies to node-agent in that namespace only. The name of the ConfigMap should be specified in the node-agent server parameter ```--node-agent-configmap```. +The node-agent server checks these configurations at startup time. Therefore, users could edit this ConfigMap any time, but in order to make the changes effective, node-agent server needs to be restarted. + +The users can specify the ConfigMap name during velero installation by CLI: +`velero install --node-agent-configmap=` + +## Node Selection manner + +### Affinity +Affinity configuration means allowing the data movement to run in the nodes specified. There are two ways to define it: +- It could be defined by `MatchLabels`. The labels defined in `MatchLabels` means a `LabelSelectorOpIn` operation by default, so in the current context, they will be treated as affinity rules. In the above sample, it defines to run data movement in nodes with label `beta.kubernetes.io/instance-type` of value `Standard_B4ms` (Run data movement in `Standard_B4ms` nodes only). +- It could be defined by `MatchExpressions`. The labels are defined in `Key` and `Values` of `MatchExpressions` and the `Operator` should be defined as `LabelSelectorOpIn` or `LabelSelectorOpExists`. In the above sample, it defines to run data movement in nodes with label `kubernetes.io/hostname` of values `node-1`, `node-2` and `node-3` (Run data movement in `node-1`, `node-2` and `node-3` only). + +### Anti-affinity +Anti-affinity configuration means preventing the data movement from running in the nodes specified. Below is the way to define it: +- It could be defined by `MatchExpressions`. The labels are defined in `Key` and `Values` of `MatchExpressions` and the `Operator` should be defined as `LabelSelectorOpNotIn` or `LabelSelectorOpDoesNotExist`. In the above sample, it disallows data movement to run in nodes with label `xxx/critial-workload`. + +## How to create the LoadAffinity ConfigMap and apply to the NodeAgent + +To create the ConfigMap, save something like the above sample to a json file and then run below command: +``` +kubectl create cm -n velero --from-file= +``` + +To provide the ConfigMap to node-agent, edit the node-agent DaemonSet and add the ```- --node-agent-configmap``` argument to the spec: +1. Open the node-agent daemonset spec +``` +kubectl edit ds node-agent -n velero +``` +2. Add ```- --node-agent-configmap``` to ```spec.template.spec.containers``` +``` +spec: + template: + spec: + containers: + - args: + - --node-agent-configmap= +``` + +## Examples + +### LoadAffinity +Here is a sample of the ConfigMap with ```loadAffinity```: +```json +{ + "loadAffinity": [ + { + "nodeSelector": { + "matchLabels": { + "beta.kubernetes.io/instance-type": "Standard_B4ms" + }, + "matchExpressions": [ + { + "key": "kubernetes.io/hostname", + "values": [ + "node-1", + "node-2", + "node-3" + ], + "operator": "In" + }, + { + "key": "xxx/critial-workload", + "operator": "DoesNotExist" + } + ] + } + } + ] +} +``` + +This example demonstrates how to use both `matchLabels` and `matchExpressions` in the same single LoadAffinity element. + +### LoadAffinity with StorageClass (Note: Only First Element Used) + +``` json +{ + "loadAffinity": [ + { + "nodeSelector": { + "matchLabels": { + "beta.kubernetes.io/instance-type": "Standard_B4ms" + } + } + }, + { + "nodeSelector": { + "matchExpressions": [ + { + "key": "kubernetes.io/os", + "values": [ + "linux" + ], + "operator": "In" + } + ] + }, + "storageClass": "kibishii-storage-class" + } + ] +} +``` + +This sample demonstrates how the `loadAffinity` elements with `StorageClass` field and without `StorageClass` field setting work together. If the VGDP mounting volume is created from StorageClass `kibishii-storage-class`, its pod will run Linux nodes. + +The other VGDP instances will run on nodes, which instance type is `Standard_B4ms`. + +### LoadAffinity interacts with BackupPVC + +``` json +{ + "loadAffinity": [ + { + "nodeSelector": { + "matchLabels": { + "beta.kubernetes.io/instance-type": "Standard_B4ms" + } + }, + "storageClass": "kibishii-storage-class" + }, + { + "nodeSelector": { + "matchLabels": { + "beta.kubernetes.io/instance-type": "Standard_B2ms" + } + }, + "storageClass": "worker-storagepolicy" + } + ], + "backupPVC": { + "kibishii-storage-class": { + "storageClass": "worker-storagepolicy" + } + } +} +``` + +Velero data mover supports to use different StorageClass to create backupPVC by [design](https://github.com/vmware-tanzu/velero/pull/7982). + +In this example, if the backup target PVC's StorageClass is `kibishii-storage-class`, its backupPVC should use StorageClass `worker-storagepolicy`. Because the final StorageClass is `worker-storagepolicy`, the backupPod uses the loadAffinity specified by `loadAffinity`'s elements with `StorageClass` field set to `worker-storagepolicy`. backupPod will be assigned to nodes, which instance type is `Standard_B2ms`. + +### LoadAffinity interacts with RestorePVC + +``` json +{ + "loadAffinity": [ + { + "nodeSelector": { + "matchLabels": { + "beta.kubernetes.io/instance-type": "Standard_B4ms" + } + }, + "storageClass": "kibishii-storage-class" + } + ], + "restorePVC": { + "ignoreDelayBinding": false + } +} +``` + +#### StorageClass's bind mode is WaitForFirstConsumer + +``` yaml +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: kibishii-storage-class +parameters: + svStorageClass: worker-storagepolicy +provisioner: csi.vsphere.vmware.com +reclaimPolicy: Delete +volumeBindingMode: WaitForFirstConsumer +``` + +If restorePVC should be created from StorageClass `kibishii-storage-class`, and it's volumeBindingMode is `WaitForFirstConsumer`. +Although `loadAffinityPerStorageClass` has a section matches the StorageClass, the `ignoreDelayBinding` is set `false`, the Velero exposer will wait until the target Pod scheduled to a node, and returns the node as SelectedNode for the restorePVC. +As a result, the `loadAffinityPerStorageClass` will not take affect. + +#### StorageClass's bind mode is Immediate + +``` yaml +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: kibishii-storage-class +parameters: + svStorageClass: worker-storagepolicy +provisioner: csi.vsphere.vmware.com +reclaimPolicy: Delete +volumeBindingMode: Immediate +``` + +Because the StorageClass volumeBindingMode is `Immediate`, although `ignoreDelayBinding` is set to `false`, restorePVC will not be created according to the target Pod. + +The restorePod will be assigned to nodes, which instance type is `Standard_B4ms`. diff --git a/site/content/docs/v1.17/data-movement-pod-resource-configuration.md b/site/content/docs/v1.17/data-movement-pod-resource-configuration.md new file mode 100644 index 000000000..9dfab4a32 --- /dev/null +++ b/site/content/docs/v1.17/data-movement-pod-resource-configuration.md @@ -0,0 +1,129 @@ +--- +title: "Data Movement Pod Resource Configuration" +layout: docs +--- + +During [CSI Snapshot Data Movement][1], Velero built-in data mover launches data mover pods to run the data transfer. +During [fs-backup][2], Velero also launches data mover pods to run the data transfer. +The data transfer is a time and resource consuming activity. + +Velero by default uses the [BestEffort QoS][2] for the data mover pods, which guarantees the best performance of the data movement activities. On the other hand, it may take lots of cluster resource, i.e., CPU, memory, and how many resources are taken is decided by the concurrency and the scale of data to be moved. + +If the cluster nodes don't have sufficient resource, Velero also allows you to customize the resources for the data mover pods. +Note: If less resources are assigned to data mover pods, the data movement activities may take longer time; or the data mover pods may be OOM killed if the assigned memory resource doesn't meet the requirements. Consequently, the dataUpload/dataDownload may run longer or fail. + +Refer to [Performance Guidance][3] for a guidance of performance vs. resource usage, and it is highly recommended that you perform your own testing to find the best resource limits for your data. + +Velero introduces a new section in the node-agent configMap, called ```podResources```, through which you can set customized resources configurations for data mover pods. +If it is not there, a configMap should be created manually. The configMap should be in the same namespace where Velero is installed. If multiple Velero instances are installed in different namespaces, there should be one configMap in each namespace which applies to node-agent in that namespace only. The name of the configMap should be specified in the node-agent server parameter ```--node-agent-config```. +Node-agent server checks these configurations at startup time. Therefore, you could edit this configMap any time, but in order to make the changes effective, node-agent server needs to be restarted. + +### Sample +Here is a sample of the configMap with ```podResources```: +```json +{ + "podResources": { + "cpuRequest": "1000m", + "cpuLimit": "1000m", + "memoryRequest": "512Mi", + "memoryLimit": "1Gi" + }, + "priorityClassName": "high-priority" +} +``` + +The string values in ```podResources``` must match Kubernetes Quantity expressions; for each resource, the "request" value must not be larger than the "limit" value. Otherwise, if any one of the values fail, the entire ```podResources``` configuration will be ignored (so the default policy will be used). + +To create the configMap, save something like the above sample to a json file and then run below command: +``` +kubectl create cm node-agent-config -n velero --from-file= +``` + +To provide the configMap to node-agent, edit the node-agent daemonset and add the ```- --node-agent-config``` argument to the spec: +1. Open the node-agent daemonset spec +``` +kubectl edit ds node-agent -n velero +``` +2. Add ```- --node-agent-config``` to ```spec.template.spec.containers``` +``` +spec: + template: + spec: + containers: + - args: + - --node-agent-config= +``` + +### Priority Class + +Data mover pods will use the priorityClassName configured in the node-agent configmap. The priorityClassName for data mover pods is configured through the node-agent configmap (specified via the `--node-agent-configmap` flag), while the node-agent daemonset itself uses the priority class set by the `--node-agent-priority-class-name` flag during Velero installation. + +#### When to Use Priority Classes + +**Higher Priority Classes** (e.g., `system-cluster-critical`, `system-node-critical`, or custom high-priority): +- When you have dedicated nodes for backup operations +- When backup/restore operations are time-critical +- When you want to ensure data mover pods are scheduled even during high cluster utilization +- For disaster recovery scenarios where restore speed is critical + +**Lower Priority Classes** (e.g., `low-priority` or negative values): +- When you want to protect production workload performance +- When backup operations can be delayed during peak hours +- When cluster resources are limited and production workloads take precedence +- For non-critical backup operations that can tolerate delays + +#### Consequences of Priority Class Settings + +**High Priority**: +- ✅ Data mover pods are more likely to be scheduled quickly +- ✅ Less likely to be preempted by other workloads +- ❌ May cause resource pressure on production workloads +- ❌ Could lead to production pod evictions in extreme cases + +**Low Priority**: +- ✅ Production workloads are protected from resource competition +- ✅ Cluster stability is maintained during backup operations +- ❌ Backup/restore operations may take longer to start +- ❌ Data mover pods may be preempted, causing backup failures +- ❌ In resource-constrained clusters, backups might not run at all + +#### Example Configuration + +To configure priority class for data mover pods, include it in your node-agent configmap: + +```json +{ + "podResources": { + "cpuRequest": "1000m", + "cpuLimit": "2000m", + "memoryRequest": "1Gi", + "memoryLimit": "4Gi" + }, + "priorityClassName": "backup-priority" +} +``` + +First, create the priority class in your cluster: + +```yaml +apiVersion: scheduling.k8s.io/v1 +kind: PriorityClass +metadata: + name: backup-priority +value: 1000 +globalDefault: false +description: "Priority class for Velero data mover pods" +``` + +Then create or update the node-agent configmap: + +```bash +kubectl create cm node-agent-config -n velero --from-file=node-agent-config.json +``` + +**Note**: If the specified priority class doesn't exist in the cluster when data mover pods are created, the pods will fail to schedule. Velero validates the priority class at startup and logs a warning if it doesn't exist, but the pods will still attempt to use it. + +[1]: csi-snapshot-data-movement.md +[2]: file-system-backup.md +[3]: https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/ +[4]: performance-guidance.md \ No newline at end of file diff --git a/site/content/docs/v1.17/data-movement-restore-pvc-configuration.md b/site/content/docs/v1.17/data-movement-restore-pvc-configuration.md new file mode 100644 index 000000000..8e786b2e1 --- /dev/null +++ b/site/content/docs/v1.17/data-movement-restore-pvc-configuration.md @@ -0,0 +1,30 @@ +--- +title: "RestorePVC Configuration for Data Movement Restore" +layout: docs +--- + +`RestorePVC` is an intermediate PVC to write data during the data movement restore operation. + +In some scenarios users may need to configure some advanced options of the `restorePVC` so that the data movement restore operation could perform better. Specifically: +- For a volume with `WaitForFirstConsumer` mode, theoretically, the data mover pod should not be created until the restored is scheduled to a node; and the data movement should happen in that node only (because the pod may not run in every node because of topology constraints). This significantly degrades the parallelism of data movement restores; and this also prevents Velero from restoring a volume without a pod mounted. On the other hand, users must know their topology constrains if they have, or they must know in which nodes their restored workload pods can be scheduled. Therefore, in the backup/restore context, it is fine not to strictly follow the rule of `WaitForFirstConsumer` mode, instead, users should be allowed to configure to ignore the rule if they are aware that there is no topology constraints in their environments or they know how to select the nodes for restore pods to run appropriately. + +Velero introduces a new section in the node agent configuration ConfigMap (the name of this ConfigMap is passed using `--node-agent-configmap` velero server argument) called `restorePVC`, through which you can specify the following configurations: + +- `ignoreDelayBinding`: If this flag is set, the data movement restore will ignore the delay binding requirements from `WaitForFirstConsumer` mode, create the restore pod and provision the volume associated to an arbitrary node. When multiple volume restores happen in parallel, the restore pods will be spread evenly to all the nodes. + + +The users can specify the ConfigMap name during velero installation by CLI: +`velero install --node-agent-configmap=` + +A sample of `restorePVC` config as part of the ConfigMap would look like: +```json +{ + "restorePVC": { + "ignoreDelayBinding": true + } +} +``` + +**Note:** +- If `ignoreDelayBinding` is set, the restored volume is provisioned in the storage areas associated to an arbitrary node, if the restored pod cannot be scheduled to that node, e.g., because of topology constraints, the data mover restore still completes, but the workload is not usable since the restored pod cannot mount the restored volume +- At present, node selection is not supported for data mover restore, so the restored volume may be attached to any node in the cluster; once node selection is supported and enabled, the restored volume will be attached to one of the selected nodes only. In this way, node selection and `ignoreDelayBinding` can work together even though the environment is with topology constraints diff --git a/site/content/docs/v1.17/debugging-install.md b/site/content/docs/v1.17/debugging-install.md new file mode 100644 index 000000000..e6a75e525 --- /dev/null +++ b/site/content/docs/v1.17/debugging-install.md @@ -0,0 +1,74 @@ +--- +title: "Debugging Installation Issues" +layout: docs +--- + +## General + +### `invalid configuration: no configuration has been provided` +This typically means that no `kubeconfig` file can be found for the Velero client to use. Velero looks for a kubeconfig in the +following locations: +* the path specified by the `--kubeconfig` flag, if any +* the path specified by the `$KUBECONFIG` environment variable, if any +* `~/.kube/config` + +### Backups or restores stuck in `New` phase +This means that the Velero controllers are not processing the backups/restores, which usually happens because the Velero server is not running. Check the pod description and logs for errors: +``` +kubectl -n velero describe pods +kubectl -n velero logs deployment/velero +``` + + +## AWS + +### `NoCredentialProviders: no valid providers in chain` + +#### Using credentials +This means that the secret containing the AWS IAM user credentials for Velero has not been created/mounted properly +into the Velero server pod. Ensure the following: + +* The `cloud-credentials` secret exists in the Velero server's namespace +* The `cloud-credentials` secret has a single key, `cloud`, whose value is the contents of the `credentials-velero` file +* The `credentials-velero` file is formatted properly and has the correct values: + + ``` + [default] + aws_access_key_id= + aws_secret_access_key= + ``` + +* The `cloud-credentials` secret is defined as a volume for the Velero deployment +* The `cloud-credentials` secret is being mounted into the Velero server pod at `/credentials` + +#### Using kube2iam +This means that Velero can't read the content of the S3 bucket. Ensure the following: + +* A Trust Policy document exists that allows the role used by kube2iam to assume Velero's role, as stated in the AWS config documentation. +* The new Velero role has all the permissions listed in the documentation regarding S3. + + +## Azure + +### `Failed to refresh the Token` or `adal: Refresh request failed` +This means that the secrets containing the Azure service principal credentials for Velero has not been created/mounted +properly into the Velero server pod. Ensure the following: + +* The `cloud-credentials` secret exists in the Velero server's namespace +* The `cloud-credentials` secret has all of the expected keys and each one has the correct value (see [setup instructions][0]) +* The `cloud-credentials` secret is defined as a volume for the Velero deployment +* The `cloud-credentials` secret is being mounted into the Velero server pod at `/credentials` + + +## GCE/GKE + +### `open credentials/cloud: no such file or directory` +This means that the secret containing the GCE service account credentials for Velero has not been created/mounted properly +into the Velero server pod. Ensure the following: + +* The `cloud-credentials` secret exists in the Velero server's namespace +* The `cloud-credentials` secret has a single key, `cloud`, whose value is the contents of the `credentials-velero` file +* The `cloud-credentials` secret is defined as a volume for the Velero deployment +* The `cloud-credentials` secret is being mounted into the Velero server pod at `/credentials` + +[0]: azure-config.md#create-service-principal diff --git a/site/content/docs/v1.17/debugging-restores.md b/site/content/docs/v1.17/debugging-restores.md new file mode 100644 index 000000000..3320349cd --- /dev/null +++ b/site/content/docs/v1.17/debugging-restores.md @@ -0,0 +1,105 @@ +--- +title: "Debugging Restores" +layout: docs +--- + +## Example + +When Velero finishes a Restore, its status changes to "Completed" regardless of whether or not there are issues during the process. The number of warnings and errors are indicated in the output columns from `velero restore get`: + +``` +NAME BACKUP STATUS WARNINGS ERRORS CREATED SELECTOR +backup-test-20170726180512 backup-test Completed 155 76 2017-07-26 11:41:14 -0400 EDT +backup-test-20170726180513 backup-test Completed 121 14 2017-07-26 11:48:24 -0400 EDT +backup-test-2-20170726180514 backup-test-2 Completed 0 0 2017-07-26 13:31:21 -0400 EDT +backup-test-2-20170726180515 backup-test-2 Completed 0 1 2017-07-26 13:32:59 -0400 EDT +``` + +To delve into the warnings and errors into more detail, you can use `velero restore describe`: + +```bash +velero restore describe backup-test-20170726180512 +``` + +The output looks like this: + +``` +Name: backup-test-20170726180512 +Namespace: velero +Labels: +Annotations: + +Backup: backup-test + +Namespaces: + Included: * + Excluded: + +Resources: + Included: serviceaccounts + Excluded: nodes, events, events.events.k8s.io + Cluster-scoped: auto + +Namespace mappings: + +Label selector: + +Restore PVs: auto + +Preserve Service NodePorts: auto + +Phase: Completed + +Validation errors: + +Warnings: + Velero: + Cluster: + Namespaces: + velero: serviceaccounts "velero" already exists + serviceaccounts "default" already exists + kube-public: serviceaccounts "default" already exists + kube-system: serviceaccounts "attachdetach-controller" already exists + serviceaccounts "certificate-controller" already exists + serviceaccounts "cronjob-controller" already exists + serviceaccounts "daemon-set-controller" already exists + serviceaccounts "default" already exists + serviceaccounts "deployment-controller" already exists + serviceaccounts "disruption-controller" already exists + serviceaccounts "endpoint-controller" already exists + serviceaccounts "generic-garbage-collector" already exists + serviceaccounts "horizontal-pod-autoscaler" already exists + serviceaccounts "job-controller" already exists + serviceaccounts "kube-dns" already exists + serviceaccounts "namespace-controller" already exists + serviceaccounts "node-controller" already exists + serviceaccounts "persistent-volume-binder" already exists + serviceaccounts "pod-garbage-collector" already exists + serviceaccounts "replicaset-controller" already exists + serviceaccounts "replication-controller" already exists + serviceaccounts "resourcequota-controller" already exists + serviceaccounts "service-account-controller" already exists + serviceaccounts "service-controller" already exists + serviceaccounts "statefulset-controller" already exists + serviceaccounts "ttl-controller" already exists + default: serviceaccounts "default" already exists + +Errors: + Velero: + Cluster: + Namespaces: +``` + +## Structure + +Errors appear for incomplete or partial restores. Warnings appear for non-blocking issues, for example, the +restore looks "normal" and all resources referenced in the backup exist in some form, although some +of them may have been pre-existing. + +Both errors and warnings are structured in the same way: + +* `Velero`: A list of system-related issues encountered by the Velero server. For example, Velero couldn't read a directory. + +* `Cluster`: A list of issues related to the restore of cluster-scoped resources. + +* `Namespaces`: A map of namespaces to the list of issues related to the restore of their respective resources. diff --git a/site/content/docs/v1.17/development.md b/site/content/docs/v1.17/development.md new file mode 100644 index 000000000..6d0fa5227 --- /dev/null +++ b/site/content/docs/v1.17/development.md @@ -0,0 +1,49 @@ +--- +title: "Development " +layout: docs +--- + +## Update generated files + +Run `make update` to regenerate files if you make the following changes: + +* Add/edit/remove command line flags and/or their help text +* Add/edit/remove commands or subcommands +* Add new API types +* Add/edit/remove plugin protobuf message or service definitions + +The following files are automatically generated from the source code: + +* CRDs +* Documentation +* Protobuf/gRPC types + +You can run `make verify` to ensure that all generated files (CRDs, docs) are up to date. + +## Linting + +You can run `make lint` which executes golangci-lint inside the build image, or `make local-lint` which executes outside of the build image. +Both `make lint` and `make local-lint` will only run the linter against changes. + +Use `lint-all` to run the linter against the entire code base. + +The default linters are defined in the `Makefile` via the `LINTERS` variable. + +You can also override the default list of linters by running the command + +`$ make lint LINTERS=gosec` + +## Test + +To run unit tests, use `make test`. + +## Using the main branch + +If you are developing or using the main branch, note that you may need to update the Velero CRDs to get new changes as other development work is completed. + +```bash +velero install --crds-only --dry-run -o yaml | kubectl apply -f - +``` + +**NOTE:** You could change the default CRD API version (v1beta1 _or_ v1) if Velero CLI can't discover the Kubernetes preferred CRD API version. The Kubernetes version < 1.16 preferred CRD API version is v1beta1; the Kubernetes version >= 1.16 preferred CRD API version is v1. + diff --git a/site/content/docs/v1.17/disaster-case.md b/site/content/docs/v1.17/disaster-case.md new file mode 100644 index 000000000..6b73e6716 --- /dev/null +++ b/site/content/docs/v1.17/disaster-case.md @@ -0,0 +1,44 @@ +--- +title: "Disaster recovery" +layout: docs +--- + +*Using Schedules and Read-Only Backup Storage Locations* + +If you periodically back up your cluster's resources, you are able to return to a previous state in case of some unexpected mishap, such as a service outage. Doing so with Velero looks like the following: + +1. After you first run the Velero server on your cluster, set up a daily backup (replacing `` in the command as desired): + + ``` + velero schedule create --schedule "0 7 * * *" + ``` + + This creates a Backup object with the name `-`. The default backup retention period, expressed as TTL (time to live), is 30 days (720 hours); you can use the `--ttl ` flag to change this as necessary. See [how velero works][1] for more information about backup expiry. + +1. A disaster happens and you need to recreate your resources. + +1. Update your backup storage location to read-only mode (this prevents backup objects from being created or deleted in the backup storage location during the restore process): + + ```bash + kubectl patch backupstoragelocation \ + --namespace velero \ + --type merge \ + --patch '{"spec":{"accessMode":"ReadOnly"}}' + ``` + +1. Create a restore with your most recent Velero Backup: + + ``` + velero restore create --from-backup - + ``` + +1. When ready, revert your backup storage location to read-write mode: + + ```bash + kubectl patch backupstoragelocation \ + --namespace velero \ + --type merge \ + --patch '{"spec":{"accessMode":"ReadWrite"}}' + ``` + +[1]: how-velero-works.md#set-a-backup-to-expire diff --git a/site/content/docs/v1.17/enable-api-group-versions-feature.md b/site/content/docs/v1.17/enable-api-group-versions-feature.md new file mode 100644 index 000000000..20ae9bf66 --- /dev/null +++ b/site/content/docs/v1.17/enable-api-group-versions-feature.md @@ -0,0 +1,115 @@ +--- +title: "Enable API Group Versions Feature" +layout: docs +--- + +## Background + +Velero serves to both restore and migrate Kubernetes applications. Typically, backup and restore does not involve upgrading Kubernetes API group versions. However, when migrating from a source cluster to a destination cluster, it is not unusual to see the API group versions differing between clusters. + +**NOTE:** Kubernetes applications are made up of various resources. Common resources are pods, jobs, and deployments. Custom resources are created via custom resource definitions (CRDs). Every resource, whether custom or not, is part of a group, and each group has a version called the API group version. + +Kubernetes by default allows changing API group versions between clusters as long as the upgrade is a single version, for example, v1 -> v2beta1. Jumping multiple versions, for example, v1 -> v3, is not supported out of the box. This is where the Velero Enable API Group Version feature can help you during an upgrade. + +Currently, the Enable API Group Version feature is in beta and can be enabled by installing Velero with a [feature flag](customize-installation.md/#enable-server-side-features), `--features=EnableAPIGroupVersions`. + +For the most up-to-date information on Kubernetes API version compatibility, you should always review the [Kubernetes release notes](https://github.com/kubernetes/kubernetes/tree/master/CHANGELOG) for the source and destination cluster version to before starting an upgrade, migration, or restore. If there is a difference between Kubernetes API versions, use the Enable API Group Version feature to help mitigate compatibility issues. + +## How the Enable API Group Versions Feature Works + +When the Enable API Group Versions feature is enabled on the source cluster, Velero will not only back up Kubernetes preferred API group versions, but it will also back up all supported versions on the cluster. As an example, consider the resource `horizontalpodautoscalers` which falls under the `autoscaling` group. Without the feature flag enabled, only the preferred API group version for autoscaling, `v2` will be backed up. With the feature enabled, the remaining supported versions, `v1` will also be backed up. Once the versions are stored in the backup tarball file, they will be available to be restored on the destination cluster. + +When the Enable API Group Versions feature is enabled on the destination cluster, Velero restore will choose the version to restore based on an API group version priority order. + +The version priorities are listed from highest to lowest priority below: + +- Priority 1: destination cluster preferred version +- Priority 2: source cluster preferred version +- Priority 3: non-preferred common supported version with the highest [Kubernetes version priority](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/#version-priority) + +The highest priority (Priority 1) will be the destination cluster's preferred API group version. If the destination preferred version is found in the backup tarball, it will be the API group version chosen for restoration for that resource. However, if the destination preferred version is not found in the backup tarball, the next version in the list will be selected: the source cluster preferred version (Priority 2). + +If the source cluster preferred version is found to be supported by the destination cluster, it will be chosen as the API group version to restore. However, if the source preferred version is not supported by the destination cluster, then the next version in the list will be considered: a non-preferred common supported version (Priority 3). + +In the case that there are more than one non-preferred common supported version, which version will be chosen? The answer requires understanding the [Kubernetes version priority order](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/#version-priority). Kubernetes prioritizes group versions by making the latest, most stable version the highest priority. The highest priority version is the Kubernetes preferred version. Here is a sorted version list example from the Kubernetes.io documentation: + +- v10 +- v2 +- v1 +- v11beta2 +- v10beta3 +- v3beta1 +- v12alpha1 +- v11alpha2 +- foo1 +- foo10 + +Of the non-preferred common versions, the version that has the highest Kubernetes version priority will be chosen. See the example for Priority 3 below. + +To better understand which API group version will be chosen, the following provides some concrete examples. The examples use the term "target cluster" which is synonymous to "destination cluster". + +![Priority 1 Case A example](/docs/main/img/gv_priority1-caseA.png) + +![Priority 1 Case B example](/docs/main/img/gv_priority1-caseB.png) + +![Priority 2 Case C example](/docs/main/img/gv_priority2-caseC.png) + +![Priority 3 Case D example](/docs/main/img/gv_priority3-caseD.png) + +## Procedure for Using the Enable API Group Versions Feature + +1. [Install Velero](basic-install.md) on source cluster with the [feature flag enabled](customize-installation.md/#enable-server-side-features). The flag is `--features=EnableAPIGroupVersions`. For the enable API group versions feature to work, the feature flag needs to be used for Velero installations on both the source and destination clusters. +2. Back up and restore following the [migration case instructions](migration-case.md). Note that "Cluster 1" in the instructions refers to the source cluster, and "Cluster 2" refers to the destination cluster. + +## Advanced Procedure for Customizing the Version Prioritization + +Optionally, users can create a config map to override the default API group prioritization for some or all of the resources being migrated. For each resource that is specified by the user, Velero will search for the version in both the backup tarball and the destination cluster. If there is a match, the user-specified API group version will be restored. If the backup tarball and the destination cluster does not have or support any of the user-specified versions, then the default version prioritization will be used. + +Here are the steps for creating a config map that allows users to override the default version prioritization. These steps must happen on the destination cluster before a Velero restore is initiated. + +1. Create a file called `restoreResourcesVersionPriority`. The file name will become a key in the `data` field of the config map. + - In the file, write a line for each resource group you'd like to override. Make sure each line follows the format `.=,` + - Note that the resource group and versions are separated by a single equal (=) sign. Each version is listed in order of user's priority separated by commas. + - Here is an example of the contents of a config map file: + + ```cm + rockbands.music.example.io=v2beta1,v2beta2 + orchestras.music.example.io=v2,v3alpha1 + subscriptions.operators.coreos.com=v2,v1 + ``` + +2. Apply config map with + + ```bash + kubectl create configmap enableapigroupversions --from-file=/restoreResourcesVersionPriority -n velero + ``` + +3. See the config map with + + ```bash + kubectl describe configmap enableapigroupversions -n velero + ``` + + The config map should look something like + + ```bash + Name: enableapigroupversions + Namespace: velero + Labels: + Annotations: + + Data + ==== + restoreResourcesVersionPriority: + ---- + rockbands.music.example.io=v2beta1,v2beta2 + orchestras.music.example.io=v2,v3alpha1 + subscriptions.operators.coreos.com=v2,v1 + Events: + ``` + +## Troubleshooting + +1. Refer to the [troubleshooting section](troubleshooting.md) of the docs as the techniques generally apply here as well. +2. The [debug logs](troubleshooting.md/#getting-velero-debug-logs) will contain information on which version was chosen to restore. +3. If no API group version could be found that both exists in the backup tarball file and is supported by the destination cluster, then the following error will be recorded (no need to activate debug level logging): `"error restoring rockbands.music.example.io/rockstars/beatles: the server could not find the requested resource"`. diff --git a/site/content/docs/v1.17/examples.md b/site/content/docs/v1.17/examples.md new file mode 100644 index 000000000..d774b387d --- /dev/null +++ b/site/content/docs/v1.17/examples.md @@ -0,0 +1,70 @@ +--- +title: "Examples" +layout: docs +--- + +After you set up the Velero server, you can clone the examples used in the following sections by running the following: +``` +git clone https://github.com/vmware-tanzu/velero.git +cd velero +``` + +## Basic example (without PersistentVolumes) + +1. Start the sample nginx app: + + ```bash + kubectl apply -f examples/nginx-app/base.yaml + ``` + +1. Create a backup: + + ```bash + velero backup create nginx-backup --include-namespaces nginx-example + ``` + +1. Simulate a disaster: + + ```bash + kubectl delete namespaces nginx-example + ``` + + Wait for the namespace to be deleted. + +1. Restore your lost resources: + + ```bash + velero restore create --from-backup nginx-backup + ``` + +## Snapshot example (with PersistentVolumes) + +> NOTE: For Azure, you must run Kubernetes version 1.7.2 or later to support PV snapshotting of managed disks. + +1. Start the sample nginx app: + + ```bash + kubectl apply -f examples/nginx-app/with-pv.yaml + ``` + +1. Create a backup with PV snapshotting. `--csi-snapshot-timeout` is used to setup time to wait before CSI snapshot creation timeout. The default value is 10 minutes: + + ```bash + velero backup create nginx-backup --include-namespaces nginx-example --csi-snapshot-timeout=20m + ``` + +1. Simulate a disaster: + + ```bash + kubectl delete namespaces nginx-example + ``` + + Because the default [reclaim policy][1] for dynamically-provisioned PVs is "Delete", these commands should trigger your cloud provider to delete the disk that backs the PV. Deletion is asynchronous, so this may take some time. **Before continuing to the next step, check your cloud provider to confirm that the disk no longer exists.** + +1. Restore your lost resources: + + ```bash + velero restore create --from-backup nginx-backup + ``` + +[1]: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#reclaiming diff --git a/site/content/docs/v1.17/file-system-backup.md b/site/content/docs/v1.17/file-system-backup.md new file mode 100644 index 000000000..02dc2f78d --- /dev/null +++ b/site/content/docs/v1.17/file-system-backup.md @@ -0,0 +1,769 @@ +--- +title: "File System Backup" +layout: docs +--- + +Velero supports backing up and restoring Kubernetes volumes attached to pods from the file system of the volumes, called +File System Backup (FSB shortly) or Pod Volume Backup. The data movement is fulfilled by using modules from free open-source +backup tools [restic][1] and [kopia][2]. This support is considered beta quality. Please see the list of [limitations](#limitations) +to understand if it fits your use case. + +Velero allows you to take snapshots of persistent volumes as part of your backups if you’re using one of +the supported cloud providers’ block storage offerings (Amazon EBS Volumes, Azure Managed Disks, Google Persistent Disks). +It also provides a plugin model that enables anyone to implement additional object and block storage backends, outside the +main Velero repository. + +If your storage supports CSI (Container Storage Interface) snapshots, Velero also allows you to take snapshots through CSI and then optionally move the snapshot data to a different storage location. + +Velero's File System Backup is an addition to the aforementioned snapshot approaches. Its pros and cons are listed below: +Pros: +- It is capable of backing up and restoring almost any type of Kubernetes volume. Therefore, if you need a volume snapshot +plugin for your storage platform, or if you're using EFS, AzureFile, NFS, emptyDir, local, or any other volume type that doesn't +have a native snapshot concept, FSB might be for you. +- It is not tied to a specific storage platform, so you could save the backup data to a different storage platform from +the one backing Kubernetes volumes, for example, a durable storage. + +Cons: +- It backs up data from the live file system, in which way the data is not captured at the same point in time, so is less consistent than the snapshot approaches. +- It access the file system from the mounted hostpath directory, so Velero Node Agent pods need to run as root user and even under privileged mode in some environments. + +## Relationship with Volume Snapshots + +It's important to understand that File System Backup (FSB) and volume snapshots (native/CSI) are **mutually exclusive** for the same volume: + +- When FSB is performed on a volume, Velero will **skip** taking a snapshot of that volume +- When FSB is opted out for a volume, Velero will **attempt** to take a snapshot (if configured) +- This prevents duplicate backups of the same data + +This behavior is automatic and ensures optimal backup performance and storage usage. + +**NOTE:** hostPath volumes are not supported, but the [local volume type][5] is supported. +**NOTE:** restic is under the deprecation process by following [Velero Deprecation Policy][17], for more details, see the Restic Deprecation section. + +## Setup File System Backup + +### Prerequisites + +- Understand how Velero performs [file system backup](#how-backup-and-restore-work). +- [Download][4] the latest Velero release. +- Kubernetes v1.16.0 or later are required. Velero's File System Backup requires the Kubernetes [MountPropagation feature][6]. + +### Install Velero Node Agent + +Velero Node Agent is a Kubernetes daemonset that hosts controllers for File System Backup. +To install Node Agent, use the `--use-node-agent` flag in the `velero install` command. See the [install overview][3] for more +details on other flags for the install command. + +``` +velero install --use-node-agent +``` + +When using FSB on a storage that doesn't have Velero support for snapshots, the `--use-volume-snapshots=false` flag prevents an +unused `VolumeSnapshotLocation` from being created on installation. + +At present, Velero FSB supports object storage as the backup storage only. Velero gets the parameters from the +[BackupStorageLocation `config`](api-types/backupstoragelocation.md) to compose the URL to the backup storage. Velero's known object +storage providers are include here [supported providers](supported-providers.md), for which, Velero pre-defines the endpoints; if you +want to use a different backup storage, make sure it is S3 compatible and you provide the correct bucket name and endpoint in +BackupStorageLocation. Velero handles the creation of the backup repo prefix in the backup storage, so make sure it is specified in BackupStorageLocation correctly. + +Velero creates one backup repo per namespace. For example, if backing up 2 namespaces, namespace1 and namespace2, using kopia +repository on AWS S3, the full backup repo path for namespace1 would be `https://s3-us-west-2.amazonaws.com/bucket/kopia/ns1` and +for namespace2 would be `https://s3-us-west-2.amazonaws.com/bucket/kopia/ns2`. + +There may be additional installation steps depending on the cloud provider plugin you are using. You should refer to the +[plugin specific documentation](supported-providers.md) for the most up to date information. + +**Note:** Currently, Velero creates a secret named `velero-repo-credentials` in the velero install namespace, containing a default backup repository password. +You can update the secret with your own password encoded as base64 prior to the first backup (i.e., FS Backup, data mover) targeting to the backup repository. The value of the key to update is +``` +data: + repository-password: +``` +Backup repository is created during the first execution of backup targeting to it after installing Velero with node agent. If you update the secret password after the first +backup which created the backup repository, then Velero will not be able to connect with the older backups. + +### Configure Node Agent DaemonSet spec + +After installation, some PaaS/CaaS platforms based on Kubernetes also require modifications the node-agent DaemonSet spec. +The steps in this section are only needed if you are installing on RancherOS, Nutanix, OpenShift, VMware Tanzu Kubernetes Grid +Integrated Edition (formerly VMware Enterprise PKS), or Microsoft Azure. + + +**RancherOS** + + +Update the host path for volumes in the node-agent DaemonSet in the Velero namespace from `/var/lib/kubelet/pods` to +`/opt/rke/var/lib/kubelet/pods`. + +```yaml +hostPath: + path: /var/lib/kubelet/pods +``` + +to + +```yaml +hostPath: + path: /opt/rke/var/lib/kubelet/pods +``` + +**Nutanix** + + +Update the host path for volumes in the node-agent DaemonSet in the Velero namespace from `/var/lib/kubelet/pods` to +`/var/nutanix/var/lib/kubelet`. + +```yaml +hostPath: + path: /var/lib/kubelet/pods +``` + +to + +```yaml +hostPath: + path: /var/nutanix/var/lib/kubelet +``` + +**OpenShift** + + +To mount the correct hostpath to pods volumes, run the node-agent pod in `privileged` mode. + +1. Add the `velero` ServiceAccount to the `privileged` SCC: + + ``` + oc adm policy add-scc-to-user privileged -z velero -n velero + ``` + +2. Install Velero with the '--privileged-node-agent' option to request a privileged mode: + + ``` + velero install --use-node-agent --privileged-node-agent + ``` + + +If node-agent is not running in a privileged mode, it will not be able to access pods volumes within the mounted +hostpath directory because of the default enforced SELinux mode configured in the host system level. You can +[create a custom SCC](https://docs.openshift.com/container-platform/latest/authentication/managing-security-context-constraints.html) to relax the +security in your cluster so that node-agent pods are allowed to use the hostPath volume plugin without granting +them access to the `privileged` SCC. + +By default a userland openshift namespace will not schedule pods on all nodes in the cluster. + +To schedule on all nodes the namespace needs an annotation: + +``` +oc annotate namespace openshift.io/node-selector="" +``` + +This should be done before velero installation. + +Or the ds needs to be deleted and recreated: + +``` +oc get ds node-agent -o yaml -n > ds.yaml +oc annotate namespace openshift.io/node-selector="" +oc create -n -f ds.yaml +``` + +**VMware Tanzu Kubernetes Grid Integrated Edition (formerly VMware Enterprise PKS)** + +You need to enable the `Allow Privileged` option in your plan configuration so that Velero is able to mount the hostpath. + +The hostPath should be changed from `/var/lib/kubelet/pods` to `/var/vcap/data/kubelet/pods` + +```yaml +hostPath: + path: /var/vcap/data/kubelet/pods +``` + +## To back up + +Velero supports two approaches of discovering pod volumes that need to be backed up using FSB: + +- Opt-in approach: Where every pod containing a volume to be backed up using FSB must be annotated +with the volume's name. +- Opt-out approach: Where all pod volumes are backed up using FSB, with the ability to opt-out any +volumes that should not be backed up. + +The following sections provide more details on the two approaches. + +### Using the opt-out approach + +In this approach, Velero will back up all pod volumes using FSB with the exception of: + +- Volumes mounting the default service account token, Kubernetes Secrets, and ConfigMaps +- Hostpath volumes +- **Volumes explicitly excluded using annotations** (see below) + +**Important:** When you exclude a volume from FSB using annotations, Velero will attempt to back it up using volume snapshots instead (if CSI snapshots are enabled and the volume is a CSI volume or if properly configured with a compatible VolumeSnapshotLocation). + +It is possible to exclude volumes from being backed up using the `backup.velero.io/backup-volumes-excludes` +annotation on the pod. + +Instructions to back up using this approach are as follows: + +1. Run the following command on each pod that contains volumes that should **not** be backed up using FSB + + ```bash + kubectl -n YOUR_POD_NAMESPACE annotate pod/YOUR_POD_NAME backup.velero.io/backup-volumes-excludes=YOUR_VOLUME_NAME_1,YOUR_VOLUME_NAME_2,... + ``` + where the volume names are the names of the volumes in the pod spec. + + For example, in the following pod: + + ```yaml + apiVersion: v1 + kind: Pod + metadata: + name: app1 + namespace: sample + spec: + containers: + - image: k8s.gcr.io/test-webserver + name: test-webserver + volumeMounts: + - name: pvc1-vm + mountPath: /volume-1 + - name: pvc2-vm + mountPath: /volume-2 + volumes: + - name: pvc1-vm + persistentVolumeClaim: + claimName: pvc1 + - name: pvc2-vm + claimName: pvc2 + ``` + to exclude FSB of volume `pvc1-vm`, you would run: + + ```bash + kubectl -n sample annotate pod/app1 backup.velero.io/backup-volumes-excludes=pvc1-vm + ``` + +2. Take a Velero backup: + + ```bash + velero backup create BACKUP_NAME --default-volumes-to-fs-backup OTHER_OPTIONS + ``` + + The above steps uses the opt-out approach on a per backup basis. + + Alternatively, this behavior may be enabled on all velero backups running the `velero install` command with + the `--default-volumes-to-fs-backup` flag. Refer [install overview][10] for details. + +3. When the backup completes, view information about the backups: + + ```bash + velero backup describe YOUR_BACKUP_NAME + ``` + ```bash + kubectl -n velero get podvolumebackups -l velero.io/backup-name=YOUR_BACKUP_NAME -o yaml + ``` + +### Using opt-in pod volume backup + +Velero, by default, uses this approach to discover pod volumes that need to be backed up using FSB. Every pod +containing a volume to be backed up using FSB must be annotated with the volume's name using the +`backup.velero.io/backup-volumes` annotation. + +**Note:** Volumes not annotated for FSB will be considered for volume snapshots if: +- `--snapshot-volumes` is not set to `false` +- The volume supports snapshots (either CSI or native) +- Either the volume is a CSI volume and CSI snapshots are enabled or there is a compatible VolumeSnapshotLocation configured + +Instructions to back up using this approach are as follows: + +1. Run the following for each pod that contains a volume to back up: + + ```bash + kubectl -n YOUR_POD_NAMESPACE annotate pod/YOUR_POD_NAME backup.velero.io/backup-volumes=YOUR_VOLUME_NAME_1,YOUR_VOLUME_NAME_2,... + ``` + + where the volume names are the names of the volumes in the pod spec. + + For example, for the following pod: + + ```yaml + apiVersion: v1 + kind: Pod + metadata: + name: sample + namespace: foo + spec: + containers: + - image: k8s.gcr.io/test-webserver + name: test-webserver + volumeMounts: + - name: pvc-volume + mountPath: /volume-1 + - name: emptydir-volume + mountPath: /volume-2 + volumes: + - name: pvc-volume + persistentVolumeClaim: + claimName: test-volume-claim + - name: emptydir-volume + emptyDir: {} + ``` + + You'd run: + + ```bash + kubectl -n foo annotate pod/sample backup.velero.io/backup-volumes=pvc-volume,emptydir-volume + ``` + + This annotation can also be provided in a pod template spec if you use a controller to manage your pods. + +1. Take a Velero backup: + + ```bash + velero backup create NAME OPTIONS... + ``` + +1. When the backup completes, view information about the backups: + + ```bash + velero backup describe YOUR_BACKUP_NAME + ``` + ```bash + kubectl -n velero get podvolumebackups -l velero.io/backup-name=YOUR_BACKUP_NAME -o yaml + ``` + +## To restore + +Regardless of how volumes are discovered for backup using FSB, the process of restoring remains the same. + +1. Restore from your Velero backup: + + ```bash + velero restore create --from-backup BACKUP_NAME OPTIONS... + ``` + +1. When the restore completes, view information about your pod volume restores: + + ```bash + velero restore describe YOUR_RESTORE_NAME + ``` + ```bash + kubectl -n velero get podvolumerestores -l velero.io/restore-name=YOUR_RESTORE_NAME -o yaml + ``` + +## Limitations + +- `hostPath` volumes are not supported. [Local persistent volumes][5] are supported. +- At present, Velero uses a static, common encryption key for all backup repositories it creates. **This means +that anyone who has access to your backup storage can decrypt your backup data**. Make sure that you limit access +to the backup storage appropriately. +- An incremental backup chain will be maintained across pod reschedules for PVCs. However, for pod volumes that +are *not* PVCs, such as `emptyDir` volumes, when a pod is deleted/recreated (for example, by a ReplicaSet/Deployment), +the next backup of those volumes will be full rather than incremental, because the pod volume's lifecycle is assumed +to be defined by its pod. +- Even though the backup data could be incrementally preserved, for a single file data, FSB leverages on deduplication +to find the difference to be saved. This means that large files (such as ones storing a database) will take a long time +to scan for data deduplication, even if the actual difference is small. +- Velero's File System Backup reads/writes data from volumes by accessing the node's filesystem, on which the pod is running. +For this reason, FSB can only backup volumes that are mounted by a pod and not directly from the PVC. For orphan PVC/PV pairs +(without running pods), some Velero users overcame this limitation running a staging pod (i.e. a busybox or alpine container +with an infinite sleep) to mount these PVC/PV pairs prior taking a Velero backup. +- Velero File System Backup expects volumes to be mounted under `/` (`hostPath` is configurable as mentioned in [Configure Node Agent DaemonSet spec](#configure-node-agent-daemonset-spec)). Some Kubernetes systems (i.e., [vCluster][11]) don't mount volumes under the `` sub-dir, Velero File System Backup is not working with them. +- File system restores of the same pod won't start until all the volumes of the pod get bound, even though some of the volumes have been bound and ready for restore. An a result, if a pod has multiple volumes, while only part of the volumes are restored by file system restore, these file system restores won't start until the other volumes are restored completely by other restore types (i.e., [CSI Snapshot Restore][12], [CSI Snapshot Data Movement][13]), the file system restores won't happen concurrently with those other types of restores. + +## Customize Restore Helper Container + +Velero uses a helper init container when performing a FSB restore. By default, the image for this container is same with the Velero server container. +You can customize the image that is used for this helper by creating a ConfigMap in the Velero namespace with the alternate image. + +In addition, you can customize the resource requirements for the init container, should you need. + +The ConfigMap must look like the following: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + # any name can be used; Velero uses the labels (below) + # to identify it rather than the name + name: fs-restore-action-config + # must be in the velero namespace + namespace: velero + # the below labels should be used verbatim in your + # ConfigMap. + labels: + # this value-less label identifies the ConfigMap as + # config for a plugin (i.e. the built-in restore + # item action plugin) + velero.io/plugin-config: "" + # this label identifies the name and kind of plugin + # that this ConfigMap is for. + velero.io/pod-volume-restore: RestoreItemAction +data: + # The value for "image" can either include a tag or not; + # if the tag is *not* included, the tag from the main Velero + # image will automatically be used. + image: myregistry.io/my-custom-helper-image[:OPTIONAL_TAG] + + # "cpuRequest" sets the request.cpu value on the restore init containers during restore. + # If not set, it will default to "100m". A value of "0" is treated as unbounded. + cpuRequest: 200m + + # "memRequest" sets the request.memory value on the restore init containers during restore. + # If not set, it will default to "128Mi". A value of "0" is treated as unbounded. + memRequest: 128Mi + + # "cpuLimit" sets the request.cpu value on the restore init containers during restore. + # If not set, it will default to "100m". A value of "0" is treated as unbounded. + cpuLimit: 200m + + # "memLimit" sets the request.memory value on the restore init containers during restore. + # If not set, it will default to "128Mi". A value of "0" is treated as unbounded. + memLimit: 128Mi + + # "secCtxRunAsUser" sets the securityContext.runAsUser value on the restore init containers during restore. + secCtxRunAsUser: 1001 + + # "secCtxRunAsGroup" sets the securityContext.runAsGroup value on the restore init containers during restore. + secCtxRunAsGroup: 999 + + # "secCtxAllowPrivilegeEscalation" sets the securityContext.allowPrivilegeEscalation value on the restore init containers during restore. + secCtxAllowPrivilegeEscalation: false + + # "secCtx" sets the securityContext object value on the restore init containers during restore. + # This key override `secCtxRunAsUser`, `secCtxRunAsGroup`, `secCtxAllowPrivilegeEscalation` if `secCtx.runAsUser`, `secCtx.runAsGroup` or `secCtx.allowPrivilegeEscalation` are set. + secCtx: | + capabilities: + drop: + - ALL + add: [] + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + runAsUser: 1001 + runAsGroup: 999 + +``` + +## Troubleshooting + +Run the following checks: + +Are your Velero server and daemonset pods running? + +```bash +kubectl get pods -n velero +``` + +Does your backup repository exist, and is it ready? + +```bash +velero repo get + +velero repo get REPO_NAME -o yaml +``` + +Are there any errors in your Velero backup/restore? + +```bash +velero backup describe BACKUP_NAME +velero backup logs BACKUP_NAME + +velero restore describe RESTORE_NAME +velero restore logs RESTORE_NAME +``` + +What is the status of your pod volume backups/restores? + +```bash +kubectl -n velero get podvolumebackups -l velero.io/backup-name=BACKUP_NAME -o yaml + +kubectl -n velero get podvolumerestores -l velero.io/restore-name=RESTORE_NAME -o yaml +``` + +Is there any useful information in the Velero server or daemon pod logs? + +```bash +kubectl -n velero logs deploy/velero +kubectl -n velero logs DAEMON_POD_NAME +``` + +**NOTE**: You can increase the verbosity of the pod logs by adding `--log-level=debug` as an argument +to the container command in the deployment/daemonset pod template spec. + +### Verifying backup methods used + +To understand which backup method was used for your volumes: + +1. Check if volumes were skipped for FSB: + ```bash + velero backup logs BACKUP_NAME | grep "skipped PVs" + ``` + This will show volumes opted out of FSB, which may still be backed up via snapshots. + +2. Verify volume snapshots were created: + ```bash + velero backup describe BACKUP_NAME --details + ``` + Look for the "Velero-Native Snapshots" or "CSI Snapshots" sections. + +3. Check PodVolumeBackups for FSB: + ```bash + kubectl -n velero get podvolumebackups -l velero.io/backup-name=BACKUP_NAME + ``` + +**Note:** A volume appearing in the "skipped PVs" summary doesn't mean it wasn't backed up - it may have been backed up via volume snapshot instead. + +## Backup Method Decision Flow + +When Velero encounters a volume during backup, it follows this decision flow: + +1. **Is the volume opted out of FSB?** (via `backup.velero.io/backup-volumes-excludes`) + - Yes → Skip FSB, attempt volume snapshot (if configured) + - No → Continue to step 2 + +2. **Is the volume opted in for FSB?** (via `backup.velero.io/backup-volumes` or `--default-volumes-to-fs-backup`) + - Yes → Perform FSB, skip volume snapshot + - No → Attempt volume snapshot (if configured) + +3. **For volume snapshots to succeed:** + - CSI snapshots must be enabled for CSI volumes or compatible VolumeSnapshotLocation must be configured + - Volume type must be supported by the snapshot provider + - `--snapshot-volumes` must not be `false` + +## How backup and restore work + +### How Velero integrates with Kopia +Velero integrate Kopia modules into Velero's code, primarily two modules: +- Kopia Uploader: Velero makes some wrap and isolation around it to create a generic file system uploader, +which is used to backup pod volume data +- Kopia Repository: Velero integrates it with Velero's Unified Repository Interface, it is used to preserve the backup data and manage +the backup storage + +For more details, refer to [kopia architecture](https://kopia.io/docs/advanced/architecture/) and +Velero's [Unified Repository & Kopia Integration Design](https://github.com/vmware-tanzu/velero/blob/v1.17.0/design/Implemented/unified-repo-and-kopia-integration/unified-repo-and-kopia-integration.md) + +### Custom resource and controllers +Velero has three custom resource definitions and associated controllers: + +- `BackupRepository` - represents/manages the lifecycle of Velero's backup repositories. Velero creates +a backup repository per namespace when the first FSB backup/restore for a namespace is requested. The backup +repository is backed by kopia, the `BackupRepository` controller invokes kopia internally, +refer to [kopia integration](#how-velero-integrates-with-kopia) for details. + +You can see information about your Velero's backup repositories by running `velero repo get`. + +- `PodVolumeBackup` - represents a FSB backup of a volume in a pod. The main Velero backup process creates +one or more of these when it finds an annotated pod. Each node in the cluster runs a controller for this +resource (in a daemonset) that handles the `PodVolumeBackups` for pods on that node. `PodVolumeBackup` is backed by kopia, +the data mover pod invokes kopia internally, refer to [kopia integration](#how-velero-integrates-with-kopia) for details. + +- `PodVolumeRestore` - represents a FSB restore of a pod volume. The main Velero restore process creates one +or more of these when it encounters a pod that has associated FSB backups. Each node in the cluster runs a +controller for this resource (in the same daemonset as above) that handles the `PodVolumeRestores` for pods +on that node. `PodVolumeRestore` is backed by kopia, the controller or data mover pod invokes kopia internally, +refer to [kopia integration](#how-velero-integrates-with-kopia) for details. + +### Backup + +1. Based on configuration, the main Velero backup process uses the opt-in or opt-out approach to check each pod +that it's backing up for the volumes to be backed up using FSB. +2. When found, Velero first ensures a backup repository exists for the pod's namespace, by: + - checking if a `BackupRepository` custom resource already exists + - if not, creating a new one, and waiting for the `BackupRepository` controller to init/connect it +3. Velero then creates a `PodVolumeBackup` custom resource per volume listed in the pod annotation +4. The main Velero process now waits for the `PodVolumeBackup` resources to complete or fail +5. Meanwhile, each `PodVolumeBackup` is handled by the controller on the appropriate node, which: + - has a hostPath volume mount of `/var/lib/kubelet/pods` to access the pod volume data + - finds the pod volume's subdirectory within the above volume + - creates a data mover pod which mounts the pod volume's subdirectory as a host path + - waits the data mover pod until it reaches to a terminal state + - updates the status of the custom resource to `Completed` or `Failed` +6. Kopia modules are launched inside the data mover pod and back up data from the host path mount +7. As each `PodVolumeBackup` finishes, the main Velero process adds it to the Velero backup in a file named +`-podvolumebackups.json.gz`. This file gets uploaded to object storage alongside the backup tarball. +It will be used for restores, as seen in the next section. + +### Restore + +1. The main Velero restore process checks each existing `PodVolumeBackup` custom resource in the cluster to backup from. +2. For each `PodVolumeBackup` found, Velero first ensures a backup repository exists for the pod's namespace, by: + - checking if a `BackupRepository` custom resource already exists + - if not, creating a new one, and waiting for the `BackupRepository` controller to connect it (note that + in this case, the actual repository should already exist in backup storage, so the Velero controller will simply + check it for integrity and make a location connection) +3. Velero adds an init container to the pod, whose job is to wait for all FSB restores for the pod to complete (more +on this shortly) +4. Velero creates the pod, with the added init container, by submitting it to the Kubernetes API. Then, the Kubernetes +scheduler schedules this pod to a worker node. If the pod fails to be scheduled for +some reason (i.e. lack of cluster resources), the FSB restore will not be done. +5. Velero creates a `PodVolumeRestore` custom resource for each volume to be restored in the pod +6. The main Velero process now waits for each `PodVolumeRestore` resource to complete or fail +7. Meanwhile, each `PodVolumeRestore` is handled by the controller on the appropriate node, which: + - has a hostPath volume mount of `/var/lib/kubelet/pods` to access the pod volume data + - waits for the pod to be running the init container + - finds the pod volume's subdirectory within the above volume + - launches kopia modules inside the node-agent pod to run the restore + - creates a data mover pod which mounts the pod volume's subdirectory as a host path and wait until it reaches to a terminal state + - on success, writes a file into the pod volume, in a `.velero` subdirectory, whose name is the UID of the Velero + restore that this pod volume restore is for + - updates the status of the custom resource to `Completed` or `Failed` +8. Kopia modules are launched inside the data mover pod and restore data to the host path mount +9. The init container that was added to the pod is running a process that waits until it finds a file +within each restored volume, under `.velero`, whose name is the UID of the Velero restore being run +10. Once all such files are found, the init container's process terminates successfully and the pod moves +on to running other init containers/the main containers. + +Velero won't restore a resource if a that resource is scaled to 0 and already exists in the cluster. If Velero restored the +requested pods in this scenario, the Kubernetes reconciliation loops that manage resources would delete the running pods +because its scaled to be 0. Velero will be able to restore once the resources is scaled up, and the pods are created and remain running. + +### Backup Deletion +When a backup is created, a snapshot is saved into the repository for the volume data under the both path. The snapshot is a reference to the volume data saved in the repository. +When deleting a backup, Velero calls the repository to delete the repository snapshot. So the repository snapshot disappears immediately after the backup is deleted. Then the volume data backed up in the repository turns to orphan, but it is not deleted by this time. The repository relies on the maintenance functionalitiy to delete the orphan data. +As a result, after you delete a backup, you don't see the backup storage size reduces until some full maintenance jobs completes successfully. And for the same reason, you should check and make sure that the periodical repository maintenance job runs and completes successfully. + +Even after deleting all the backups and their backup data (by repository maintenance), the backup storage is still not empty, some repository metadata are there to keep the instance of the backup repository. +Furthermore, Velero never deletes these repository metadata, if you are sure you'll never usage the backup repository, you can empty the backup storage manually. + +Kopia uploader may keep some internal snapshots which is not managed by Velero. In normal cases, the internal snapshots are deleted along with running of backups. +However, if you run a backup which aborts halfway(some internal snapshots are thereby generated) and never run new backups again, some internal snapshots may be left there. In this case, since you stop using the backup repository, you can delete the entire repository metadata from the backup storage manually. + +### Parallelism +By default, one `PodVolumeBackup`/`PodVolumeRestore` request is handled in a node at a time. You can configure more parallelism per node by [node-agent Concurrency Configuration][19]. +By the meantime, one data mover pod is created for each volume to be backed up/restored, if there is no available concurrency quota, the data mover pod has to wait there. To make a control of the data mover pods, you can configure the [node-agent Prepare Queue Length][20]. + +### Restart and resume +When Velero server is restarted, the running backups/restores will be marked as `Failed`. The corresponding `PodVolumeBackup`/`PodVolumeRestore` will be canceled. +When node-agent is restarted, the controller will try to recapture and resume the `PodVolumeBackup`/`PodVolumeRestore`. If the resume fails, the `PodVolumeBackup`/`PodVolumeRestore` will be canceled. + +### Cancellation + +At present, Velero backup and restore doesn't support end to end cancellation that is launched by users. +However, Velero cancels the `PodVolumeBackup`/`PodVolumeRestore` in below scenarios automatically: +- When Velero server is restarted +- When node-agent is restarted and the resume fails +- When an ongoing backup/restore is deleted +- When a backup/restore does not finish before the timeout (specified by Velero server parameter `fs-backup-timeout`, default value is `4 hours`) + +## 3rd party controllers + +### Monitor backup annotation + +Velero does not provide a mechanism to detect persistent volume claims that are missing the File System Backup annotation. + +To solve this, a controller was written by Thomann Bits&Beats: [velero-pvc-watcher][7] + +## Support ReadOnlyRootFilesystem setting +When the Velero server/node-agent pod's SecurityContext sets the `ReadOnlyRootFileSystem` parameter to true, the Velero server/node-agent pod's filesystem is running in read-only mode. +If the user creates a backup with Kopia as the uploader, the backup will fail, because the Kopia needs to write some cache and configuration data into the pod filesystem. + +``` +Errors: Velero: name: /mongodb-0 message: /Error backing up item error: /failed to wait BackupRepository: backup repository is not ready: error to connect to backup repo: error to connect repo with storage: error to connect to repository: unable to write config file: unable to create config directory: mkdir /home/cnb/udmrepo: read-only file system name: /mongodb-1 message: /Error backing up item error: /failed to wait BackupRepository: backup repository is not ready: error to connect to backup repo: error to connect repo with storage: error to connect to repository: unable to write config file: unable to create config directory: mkdir /home/cnb/udmrepo: read-only file system name: /mongodb-2 message: /Error backing up item error: /failed to wait BackupRepository: backup repository is not ready: error to connect to backup repo: error to connect repo with storage: error to connect to repository: unable to write config file: unable to create config directory: mkdir /home/cnb/udmrepo: read-only file system Cluster: +``` + +The workaround is making those directories as ephemeral k8s volumes, then those directories are not counted as pod's root filesystem. +The `user-name` is the Velero pod's running user name. The default value is `cnb`. + +``` yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: velero + namespace: velero +spec: + template: + spec: + containers: + - name: velero + ...... + volumeMounts: + ...... + - mountPath: /home//udmrepo + name: udmrepo + - mountPath: /home//.cache + name: cache + ...... + volumes: + ...... + - emptyDir: {} + name: udmrepo + - emptyDir: {} + name: cache + ...... +``` + +## Priority Class Configuration + +For Velero built-in data mover, data mover pods launched during file system backup will use the priority class name configured in the node-agent configmap. The node-agent daemonset itself gets its priority class from the `--node-agent-priority-class-name` flag during Velero installation. This can help ensure proper scheduling behavior in resource-constrained environments. For more details on configuring data mover pod resources, see [Data Movement Pod Resource Configuration][data-movement-config]. + +## Resource Consumption + +Both the uploader and repository consume remarkable CPU/memory during the backup/restore, especially for massive small files or large backup size cases. +Velero node-agent uses [BestEffort as the QoS][14] for node-agent pods (so no CPU/memory request/limit is set), so that backups/restores wouldn't fail due to resource throttling in any cases. +If you want to constraint the CPU/memory usage, you need to [customize the resource limits][15]. The CPU/memory consumption is always related to the scale of data to be backed up/restored, refer to [Performance Guidance][16] for more details, so it is highly recommended that you perform your own testing to find the best resource limits for your data. + +Some memory is preserved by the node-agent to avoid frequent memory allocations, therefore, after you run a file-system backup/restore, you won't see node-agent releases all the memory until it restarts. There is a limit for the memory preservation, so the memory won't increase all the time. The limit varies from the number of CPU cores in the cluster nodes, as calculated below: +``` +preservedMemoryInOneNode = 128M + 24M * numOfCPUCores +``` +The memory perservation only happens in the nodes where backups/restores ever occur. Assuming file-system backups/restores occur in ever worker node and you have equal CPU cores in each node, the maximum possibly preserved memory in your cluster is: +``` +totalPreservedMemory = (128M + 24M * numOfCPUCores) * numOfWorkerNodes +``` +However, whether and when this limit is reached is related to the data you are backing up/restoring. + +During the restore, the repository may also cache data/metadata so as to reduce the network footprint and speed up the restore. The repository uses its own policy to store and clean up the cache. +For Kopia repository, the cache is stored in the node-agent pod's root file system. Velero allows you to configure a limit of the cache size so that the node-agent pod won't be evicted due to running out of the ephemeral storage. For more details, check [Backup Repository Configuration][18]. + +## Restic Deprecation + +According to the [Velero Deprecation Policy][17], restic path is being deprecated starting from v1.15, specifically: +- For 1.15 and 1.16, if restic path is used by a backup, the backup still creates and succeeds but you will see warnings +- For 1.17 and 1.18, backups with restic path are disabled, but you are still allowed to restore from your previous restic backups +- From 1.19, both backups and restores with restic path will be disabled, you are not able to use 1.19 or higher to restore your restic backup data + +From 1.17, backup from restic path is not allowed, though you can still restore from the existing backups created by restic path. +Velero could automatically identify the legacy backups and switch to restic path without user intervention. + +### How Velero integrates with Restic +Velero integrate Restic binary directly, so the operations are done by calling Restic commands: +- Run `restic init` command to initialize the [restic repository](https://restic.readthedocs.io/en/latest/100_references.html#terminology) +- Run `restic prune` command periodically to prune restic repository +- Run `restic restore` commands to restore pod volume data + +For a restore from restic path, restic commands are called by the node-agent itself; whereas, for kopia path backup/restore, the data path runs in the data mover pods. +Restore from restic path is handled by the legacy `PodVolumeRestore` controller, so Resume and Cancellation are not supported: +- When Velero server is restarted, the legacy `PodVolumeRestore` is left as orphan and contineue running, though the restore has already marked as `Failed` +- When node-agent is restarted, the `PodVolumeRestore` is marked as `Failed` directly + +### Restic Repository +To support restic repository, the BackupRepository CR should be specially configured: + - You need to set the `resticRepoPrefix` value in BackupStorageLocation. For example, on AWS, `resticRepoPrefix` is something like + `s3:s3-us-west-2.amazonaws.com/bucket` (note that `resticRepoPrefix` doesn't work for Kopia). + +Velero still effectively manage restic repository, though you cannot write any new backup to it: +- When you delete a backup, the restic repository snapshots (if any) could be deleted from restic repository +- Velero backup repository controller periodically runs mainteance jobs for BackupRepository CRs representing restic repositories + + + +[1]: https://github.com/restic/restic +[2]: https://github.com/kopia/kopia +[3]: customize-installation.md#enable-file-system-backup +[4]: https://github.com/vmware-tanzu/velero/releases/ +[5]: https://kubernetes.io/docs/concepts/storage/volumes/#local +[6]: https://kubernetes.io/docs/concepts/storage/volumes/#mount-propagation +[7]: https://github.com/bitsbeats/velero-pvc-watcher +[8]: https://docs.microsoft.com/en-us/azure/aks/azure-files-dynamic-pv +[9]: https://github.com/restic/restic/issues/1800 +[10]: customize-installation.md#default-pod-volume-backup-to-file-system-backup +[11]: https://www.vcluster.com/ +[12]: csi.md +[13]: csi-snapshot-data-movement.md +[14]: https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/ +[15]: customize-installation.md#customize-resource-requests-and-limits +[16]: performance-guidance.md +[17]: https://github.com/vmware-tanzu/velero/blob/v1.17.0/GOVERNANCE.md#deprecation-policy +[18]: backup-repository-configuration.md +[19]: node-agent-concurrency.md +[20]: node-agent-prepare-queue-length.md +[data-movement-config]: data-movement-pod-resource-configuration.md diff --git a/site/content/docs/v1.17/how-velero-works.md b/site/content/docs/v1.17/how-velero-works.md new file mode 100644 index 000000000..0f2fa10b9 --- /dev/null +++ b/site/content/docs/v1.17/how-velero-works.md @@ -0,0 +1,117 @@ +--- +title: "How Velero Works" +layout: docs +--- + +Each Velero operation -- on-demand backup, scheduled backup, restore -- is a custom resource, defined with a Kubernetes [Custom Resource Definition (CRD)][20] and stored in [etcd][22]. Velero also includes controllers that process the custom resources to perform backups, restores, and all related operations. + +You can back up or restore all objects in your cluster, or you can filter objects by type, namespace, and/or label. + +Velero is ideal for the disaster recovery use case, as well as for snapshotting your application state, prior to performing system operations on your cluster, like upgrades. + +## On-demand backups + +The **backup** operation: + +1. Uploads a tarball of copied Kubernetes objects into cloud object storage. + +1. Calls the cloud provider API to make disk snapshots of persistent volumes, if specified. + +You can optionally specify backup hooks to be executed during the backup. For example, you might +need to tell a database to flush its in-memory buffers to disk before taking a snapshot. [More about backup hooks][10]. + +Note that cluster backups are not strictly atomic. If Kubernetes objects are being created or edited at the time of backup, they might not be included in the backup. The odds of capturing inconsistent information are low, but it is possible. + +## Scheduled backups + +The **schedule** operation allows you to back up your data at recurring intervals. You can create a scheduled backup at any time, and the first backup is then performed at the schedule's specified interval. These intervals are specified by a Cron expression. + +Velero saves backups created from a schedule with the name `-`, where `` is formatted as *YYYYMMDDhhmmss*. For more information see the [Backup Reference documentation](backup-reference.md). + + +## Backup workflow + +When you run `velero backup create test-backup`: + +1. The Velero client makes a call to the Kubernetes API server to create a `Backup` object. + +1. The `BackupController` notices the new `Backup` object and performs validation. + +1. The `BackupController` begins the backup process. It collects the data to back up by querying the API server for resources. + +1. The `BackupController` makes a call to the object storage service -- for example, AWS S3 -- to upload the backup file. + +By default, `velero backup create` makes disk snapshots of any persistent volumes. You can adjust the snapshots by specifying additional flags. Run `velero backup create --help` to see available flags. Snapshots can be disabled with the option `--snapshot-volumes=false`. + +![19] + +## Restores + +The **restore** operation allows you to restore all of the objects and persistent volumes from a previously created backup. You can also restore only a [filtered](resource-filtering.md) subset of objects and persistent volumes. Velero supports multiple namespace remapping--for example, in a single restore, objects in namespace "abc" can be recreated under namespace "def", and the objects in namespace "123" under "456". + +The default name of a restore is `-`, where `` is formatted as *YYYYMMDDhhmmss*. You can also specify a custom name. A restored object also includes a label with key `velero.io/restore-name` and value ``. + +By default, backup storage locations are created in read-write mode. However, during a restore, you can configure a backup storage location to be in read-only mode, which disables backup creation and deletion for the storage location. This is useful to ensure that no backups are inadvertently created or deleted during a restore scenario. + +You can optionally specify [restore hooks][11] to be executed during a restore or after resources are restored. For example, you might need to perform a custom database restore operation before the database application containers start. + +### Restore workflow + +When you run `velero restore create`: + +1. The Velero client makes a call to the Kubernetes API server to create a [`Restore`](api-types/restore.md) object. + +1. The `RestoreController` notices the new Restore object and performs validation. + +1. The `RestoreController` fetches the backup information from the object storage service. It then runs some preprocessing on the backed up resources to make sure the resources will work on the new cluster. For example, using the [backed-up API versions](#backed-up-api-versions) to verify that the restore resource will work on the target cluster. + +1. The `RestoreController` starts the restore process, restoring each eligible resource one at a time. + +By default, Velero performs a non-destructive restore, meaning that it won't delete any data on the target cluster. If a resource in the backup already exists in the target cluster, Velero will skip that resource. You can configure Velero to use an update policy instead using the [`--existing-resource-policy`](restore-reference.md#restore-existing-resource-policy) restore flag. When this flag is set to `update`, Velero will attempt to update an existing resource in the target cluster to match the resource from the backup. + +For more details about the Velero restore process, see the [Restore Reference](restore-reference.md) page. + +## Backed-up API versions + +Velero backs up resources using the Kubernetes API server's *preferred version* for each group/resource. When restoring a resource, this same API group/version must exist in the target cluster in order for the restore to be successful. + +For example, if the cluster being backed up has a `gizmos` resource in the `things` API group, with group/versions `things/v1alpha1`, `things/v1beta1`, and `things/v1`, and the server's preferred group/version is `things/v1`, then all `gizmos` will be backed up from the `things/v1` API endpoint. When backups from this cluster are restored, the target cluster **must** have the `things/v1` endpoint in order for `gizmos` to be restored. Note that `things/v1` **does not** need to be the preferred version in the target cluster; it just needs to exist. + +## Set a backup to expire + +When you create a backup, you can specify a TTL (time to live) by adding the flag `--ttl `. If Velero sees that an existing backup resource is expired, it removes: + +* The backup resource +* The backup file from cloud object storage +* All PersistentVolume snapshots +* All associated Restores + +The TTL flag allows the user to specify the backup retention period with the value specified in hours, minutes and seconds in the form `--ttl 24h0m0s`. If not specified, a default TTL value of 30 days will be applied. + +The effects of expiration are not applied immediately, they are applied when the gc-controller runs its reconciliation loop every hour by default. If needed, you can adjust the frequency of the reconciliation loop using the `--garbage-collection-frequency +` flag. + +If backup fails to delete, a label `velero.io/gc-failure=` will be added to the backup custom resource. + +You can use this label to filter and select backups that failed to delete. + +Implemented reasons are: +- BSLNotFound: Backup storage location not found +- BSLCannotGet: Backup storage location cannot be retrieved from the API server for reasons other than not found +- BSLReadOnly: Backup storage location is read-only + +## Object storage sync + +Velero treats object storage as the source of truth. It continuously checks to see that the correct backup resources are always present. If there is a properly formatted backup file in the storage bucket, but no corresponding backup resource in the Kubernetes API, Velero synchronizes the information from object storage to Kubernetes. + +This allows restore functionality to work in a cluster migration scenario, where the original backup objects do not exist in the new cluster. + +Likewise, if a `Completed` backup object exists in Kubernetes but not in object storage, it will be deleted from Kubernetes since the backup tarball no longer exists. +`Failed` or `PartiallyFailed` backup will not be removed by object storage sync. + +[10]: backup-hooks.md +[11]: restore-hooks.md +[19]: /docs/main/img/backup-process.png +[20]: https://kubernetes.io/docs/concepts/api-extension/custom-resources/#customresourcedefinitions +[21]: https://kubernetes.io/docs/concepts/api-extension/custom-resources/#custom-controllers +[22]: https://github.com/coreos/etcd diff --git a/site/content/docs/v1.17/image-tagging.md b/site/content/docs/v1.17/image-tagging.md new file mode 100644 index 000000000..64e9310b5 --- /dev/null +++ b/site/content/docs/v1.17/image-tagging.md @@ -0,0 +1,24 @@ +--- +title: "Image tagging policy" +layout: docs +--- + +This document describes Velero's image tagging policy. + +## Released versions + +`velero/velero:` + +Velero follows the [Semantic Versioning](http://semver.org/) standard for releases. Each tag in the `github.com/vmware-tanzu/velero` repository has a matching image, `velero/velero:v1.0.0`. + +### Latest + +`velero/velero:latest` + +The `latest` tag follows the most recently released version of Velero. + +## Development + +`velero/velero:main` + +The `main` tag follows the latest commit to land on the `main` branch. diff --git a/site/content/docs/v1.17/img/README.md b/site/content/docs/v1.17/img/README.md new file mode 100644 index 000000000..85c071c63 --- /dev/null +++ b/site/content/docs/v1.17/img/README.md @@ -0,0 +1 @@ +Some of these diagrams (for instance backup-process.png), have been created on [draw.io](https://www.draw.io), using the "Include a copy of my diagram" option. If you want to make changes to these diagrams, try importing them into draw.io, and you should have access to the original shapes/text that went into the originals. diff --git a/site/content/docs/v1.17/img/backup-process.png b/site/content/docs/v1.17/img/backup-process.png new file mode 100644 index 0000000000000000000000000000000000000000..7d4f10d5602a3a9798f449e4f9a7be0b74923a9e GIT binary patch literal 33630 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

    Oa*AXK>A{SCkTGAeMuLb#W122eJe?g{aj^h2pED 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 literal 0 HcmV?d00001 diff --git a/site/content/docs/v1.17/img/gv_priority1-caseA.png b/site/content/docs/v1.17/img/gv_priority1-caseA.png new file mode 100644 index 0000000000000000000000000000000000000000..a1940453fa10f8805d45fa04e2aab30afdb62000 GIT binary patch literal 57254 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%0AiOVZ8uZL* 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

    cX7&Ax)%Cv}<}XKs|EJy;pA%#0ff_JIQN)SY zJ8o0(+x3xSeiVO;zb9P$^kDjB!h0C(Wo65ckK%Usa~)v4?XYJ08bw9ca=_K7NH$#wrBcn3k>@Zx9Qd1MqvpQRd|*}8&{6tc{?X73 z=2-dmDz*{St4>4o&(gbJf(@Xw4Yu?@`y_ZdTlH;e~xPJfhdZT{uvtmA2srs zcn!*e78}M!flBb8aA@oU3PgMeAwz7eG`;i{z|WGvUcOdp;^Jf*8msd`77WXm6*XP= z{yhlx%YqW@CMfL`P#!7Cpn&X6<}}a~_XBF5rJ%#+dqKx7Q=pf3u^SXQ9phAAeRADJ z;}yRWDKrpkmuQyFd6oo{o&A9JXNBO=B?0D(n3bOAxiL^nPJQ5Rn?g(&={N+ zI;Vg@l4KmGJHY}(?rVThYh%5ijEcq3Y{`oy(}My2R*TyQ!T&7)dXP2X47V3{4(L_8@C3*9_!*-Qn=rZkP}h6V#|SfYYjukc`2Z=qz0tO z6K}3BVNn98iLwkS6{-hQU>omlXbY4TT!1GM_j}}981d&~fVV0gk7Y`@13AhX$aR%AU^6$X4`{7cP0)=g_^pzCHgB<* z3l{a+;a|0@t=0f8#|w6>m9@Zwq32cLJ|8ARy8A}C?+NJsM)=L9#dTo)xiDaF_`Vtd zf3DMF???`2?FK71p99F31Ej*LvYOGU>^~-e#7SWjLz?>t!VyDlO8EEJ=mMJA8emP- zzqiy@SO*75P?PLLb0(Nib1oO^IAHXR%>vUb$gmVCFVKM&M!*46t+YHj9@Aebz@3gY zCF1g+mwnqK{ME|M!!VY2RSTYO9%IR~AZpic9bh=H2J9&~w_(-Qn`(E^usQHwDXTd!q&jCNSXNE<;RrfS4>N? zfBge=R}r2fbv>7kB)6SfkER|9868sOkw75;@_2}qJ?V&od*8v`D+Vxp*GXL`f|_-H z`o42;-VG3S8-T=YzNzRpYt5qXNn?1A+e4Phngzg1RrJ>qn_CRQu<(rc!xMexT)$ks zriiNQCZaHHRrmXe7*)SeaBflNf)BkFu(RA8O z>-y4=X>+wiXany8BF}czZg$SRJZj@7172~)iv_K>xyo6>6*vf{Q#IK7xuDF;DnyMr>g5uGwqvl58ku%qWREG=jlG)gB@jSaUJaZIaFK(hKm*c zJufs>HvJes*Q9N9CHk)QF!?&pLw2t z!FvCa)R$V2vn;iX&-$lc!aOS}xbfnlXPrH23~QwQZ_JPSt`KFq zOjPL#TQ-wZ9SHntqoO|%ybB(;f*1@Fsn<{|XOS)g!_Pi7=6CcwA-{eBdUCm?&`A8d z(5J$~Shm*c$@P|rSmClw4EWE6UqdyI7@_SA8InO&HIbKR6D^OQa$j|nc6ihsp;n~Y z6jWxt%2Ucg%vwHQQD1nM1!BCQEmwn=6rpZ@eke~~VBMZ5{rjcH7v=U^KsDDKf0Nvn znd|-nC%mIOn4Qho5vbF+0mzz#gU2hM%h~eNw9bc#@xeqhf}xBS=xV@-W(9WHfV4Yf zXMu_GMYRCOKhZqid=pR#q1VeaW8%FZ>O=|5)s_4{Pb1Mke=qgHd~s>YD2f+gK-H%u zspzi-)g4oC#vmElOx&^3(nAs9%dpEGF^lVc@K>60#XAnE(MXsTxG1KIPtx2!Kp#K= z`MVMgkZIS*@^?f({CZix^T4uHkZkyq#4}it!CZP@dcr-nn&x?FA?7KW%CF!c|jS|t;QkF7Z=Mc0yL&_!|iP_G2zHIXZt+9 zQ}P1j5=Kx8?gq4#p;Tmb)5Ja(FC<<4A|Z7d;rDnCNK-FdS`tspjZ=Y#;gtpY^aa23 zhzfvU_*5M@%fS>MA#MQ7FCo3G)jVKGFC#`9Zt?zUhhe0FhmNd}0_7!s-k+CWWPVp( zIjoFE_c(5ik=qD}D{MC2=lb1McPL@3J6jIBgu2^M!5^36q776YT>$I18EA`F=Gvyd zueWCG9R>`4{DYxStuyikD=mT@&vJ}|K8BR#jq<)WTz%d};QJUc4#FRm0CNuV;b$CH zmjMp`8cw*UV626;2vr~L&?XBF`EyJ)qCC&V3I{f&e5Tr;vD-7K{NDNy#40*8_bSk= zS5l`-CgMkyHd5a)(}=@Grx($XjM}9r7+L1mnP`!TD~t%fO^if3HMFQ>G73bj|9p_J ze;S~YT;jg_N{*Y=oB7I2rv~ag>$k3ozP* zdy5Brve3jcGr&NDY_#bh7 zcw}I5e=$5&rB5vM)VLM4q3)BdFR@j;i9ZS2w20izQkz zi4H<4N(VAzby7a=>{DNvYP&lUy$)3A)j(eEDp*;K@F`ZA_)2R<`)@of4=A9s?31W z!vb9;ccbtGn$J()@NgeW(8f57PKb@k8spS7g(D?C0#av(j%M0|So5Ul_q1$G^gBpY zki*$3HYWM8;~ELU+yv3R<~!2iS5u2*FWXsYA%t_gN*q?|!3tVyv@nC@tGNe=&MhOt z83#Hy&U2*a)MLuK4X1j{j0hpP)n)p$B*UHOu~>3St1S~m_!R@fhw}6jZwu9PBj0_U z(IpMO47LX9lENwJ=PQwd&pqCrdJ{=vR2lgV1Zp&wYa58?jz{rLtmgKx2=c|#HC!F^ zW@T0}y_(8K!EJpYNc4`VB@YtfbGM!seWJp@mdBV79)Ol2Sm4nTOPZ&bmqM)`K$Q0e zER>U5)E+Bk`TEgD9c&h`j#<*N)WOpIS3gaH1)dfSGPa;$33j<@JXL!$N!6C@CO#U| zfoT>(!jS*n`xqV{Az6=}VIIKWVb&@f*{2YfmHuXRYr zN8dq(^WVy-vSNCiPY8c2if&R@&3XGdyiwMUI0~!rgPG?NzY*gU2$|7B(Kc&tc~rMX zD5Ddn{J~AZUlz`=xd8Hni!D)<^CF~v7<{=}9ivy@o>CUXK71W-Gii54;z!75^?R)1 zC5^UKH?`qJPyQNu>|LqmN|I|E9M8p87OWY{tGGn(vd&LzBFG1FgDgxhV!o(YhS?Cc z3~SMJIFj^GPkdP#ORLgM1ooE6E0-d`(b4h}IjpDbS95d=BV56sxk;BuqQ?!vl5`;d zRi;+XUcbc^F%az|C?=|58+#m{Y6>|!og)N{wR0k$@n~cL#goJ%Aob!?oUn&gDWFY0 zhw+>ZmrO0+QOhz^)+$~K-VMQMoA^+T{eI@FA+q*$uv$>V6EvqSUIGIV&3vW!BdGm(^Z zg~%3R?sM|178Ze%mCu^Rp(F3|aV;z}9DMN_`XZ+nF#Mu;bgHf9wkm;RUhP9+&tL~- zJjkMM3ogwCkPvA!0XJ)lPc&cAk?*B^G{?;zE9DJh<}gZQD@B3dYcf2S)8fOZu$ou4 z+KS3{OQG|cik2r|Vq{X`gKbF69$XjkXIm24S)&x9 zOkT1*fzOomFhdMfNsPt?@tF@7=n%}cuam9E|rqbq34!Oe5 z*%^^z-@U} zO|dJZpe=@uHSP-5N7Lf`?F1K3#t55Jn*-w?p>OT|~ZQH1WT>qiN- zhz2qSVSHz;LXnvNL|VyKxSy`WQNp(p&P}0!?pZoPb@?_=a@xR{GPX=vP4`~$sd33* z(KspcL{X5_Y!-eAnA!`6vG7^VEbG|{LF9`JFt4=WqRzt3MnvF;AXvVN{e!A;Y@*X zr~Em}qmQ3Kqr^0$%>QIZ`ikro`iUHhL&^PFf*~(KdP0IyxfXkV+4?@?mwzqczp1g( zGx&5qRvHYD90F>)M`{~M6{_YWB0@BmJtd+h&q*Z+5sK&Q(6 zf7Pj?7%`IQf!*)F%lOw1>CN3H|ExRWQD|etg%ou*sMeR?Xs2#pEkFGeqWUP#P3XKo zafi^j$>X8^^6w5xC)v#}H{jYtZ}GuYk!zhuGR{`9bxg#C?F0re0-2l(k%Rn!U{UZl zTK5_2wl&P*8LWgMHP63{VQ~DA{}UdwM8IQJH>f37Acp_=;7b5B29-?j$sZ5nQ-y%X zw7pO?JpX*kU|P^#DA?>^b^q^{Li`}E%>ev|3dN9F#QymO66Onh5EA6TxIaUZUWo9^ znMgy5P5U$I4*@+U9I37MAGHOQADRHFTno4&Qm^7apF|vm0IYDNy_byttgtB@d{K4G z;JwQ5=Tl;Ur67It9@n20u5bWfz%B@z5B}pRQ2{(eVBnnaXN6}3!55a-mIDz$RO-_Lm*esM4CN@dH5cx~t;3|$Buhe98dB?e z5C3Dkv1W-+o}o4SXM{$U*M;>r5UCek&k$V?(}xpJ%$!6wvp&JKPN0vgw|L^!tB!Yn z^@f%E2KBHSu!{Yl7TTs+Ln$=AuSGl}`XUPDnHXzLeJIaT>+7H)$7*qczKZ&JoubG6zojcoH2ie%UU{?X2Va z{c)dK13!P9o@k%&ZL1t4I)a}A-!qcZJ`~}a-52v#-jJ>C7Z&&V`{<<6*W?zEG!L~y z;IW)&sIG6_DRP($EXeiyKg+Q|9A`?46D%h*`_}c{%?6ql-yCj2i(#|L%y2T31Y^i( z&M9O1LZsR@_a=2~)6qfx+5~K;B5TWT zkT*xuE@E81IQ16Gl|n4iY2nbDc(3vNM5ug|i8bM-aScR zYv`K!D*VT#C%~Es`*C5`Y~0mvXWYgQ?svI>Lp}H=7i`MOxz{-FI7|nS=rnJYUb1D& z#SN^1hvMwQ6P;$En{}GK@nS0Ty1lL@_grBGp33?hz|ZcxW;*-|(%>+8A1(jF#bH$E zg-Sqi-I{BDVEta}Tp#td6R+I>XZ>y*0~k$?AKSEhuk`t2(!}3gy{2)$8uo+$1cl13 zRW|468{eirZ+hISuGLuGo@CEWOh{5=eIk3~RnKWJ;a}s5&wJF)2)BV`kDY*Q-FnBh zA-_{@p#T3$vvB3W#U+imN zqX$cF_VKdjZ2$;aod6vWc-O}Egxkc1ey4E~yMEL4a424;{~mjzMX>}G5sJ}lLvL}- z%vSkr#>wNr=HqD-{q8WYPtzv5bN%P*$yO^ZO)F?A7HDbCdDjur$mePFKIs)L7w{>r ztQK!`>&c?SbK80MUaFHHyL=7XoU(e$&uD};9{D{JbV&SpGv_inx7KjV5Kmc5V-8}j zZMUYmo^(8^-AhW=MBL&u%6dUjVC@f|D$S}ro~-YCnv-HoDPsRA?K3=bll&Ja@n8^#MrThgmG_bzNvt!_5=7 zdFx54{x5O*27+1UBU(FRs(c()?-`UW9pjOX&#x+!gbAR@|x3b{e%hEXY zaIG>fjmwCJ=JEQyq!z9`9K-$Q>r*a$kCUSFqc;Bc{+G0e0evjgw!ccVFR^+P(i$(@ z#cO=sPJRdVM`emmTgOr51y&*_d*PD|Qhx|d*xO-V8;fSf`H8ygaq!z@4T-aidj)$m zNnOwV&B1ZD%fT>u-_>D1G~$AG(58e9%f~VAyI`X7>73!A>;7Gn1Yp)PA}er3L{&Dg zeFf8OWyuokJDX$P%;k34d_SS-rV!1;P9fS|3%}Cs8#0`nRxXGVBeU*o;u`pI-FXP% z{|(rN7|r-7{J<_$n_bN7HiZ1TSyyfDESzpVAt%){`yr#V0ouVA(yqka#*5~Hs?8p? zW@^`Q2jZJEKahy>MCF55hNPY8((hQ>MjrR&7f)pI7!vp{gOhTs0ej6P5Rb+R9rap% z&mS>0YLWX?PHN4`b00TFGtx`XLxI$QM!WTLhsH8M>T0TBvhzeM!Oxx#`G(#n1{I5x zEX~z5nK%>efk-z?sXU&t%f(PZ<(fH{QKh5QL`juxdkTM|6p3DU!IX!KW*UE`82m1> z72=E_aG*$`z-G6k@tQ3c_eF-xR&RiVyP$T+bgx;v_&rFeeJ2ZBL6VOo?#$$al7&=A z>VO?(?m!)z^R6Jd<*h2V$OBJcb=kC6Kk|w>zVPA-DoaH2Zpo@{)ltZ(E+<#NsQiRN z&1N?1mTm1m=RkD31S|1QXVMJ=N92!nQK3<+O4!LZ1F!61=I^@#PFv5u@QNRSL|y_o z0toj3DuAOk-}Z^=}hYVW>CQJaNrwDP*# zwl>`9g?Ud&G)#mI422)k43UG=tV^{>z^WNpl@F|9Qu-T47!eVx-VH#8O^r~qKN@Q! zS^Q{ZJ&x1&uZu#Hm8JdGVI+cVtznt?%7^f~mCIaOic=JL(M7@Yea78vA3 z@W$3MwFs4B!!_*Z%j;y;9Xp<4N(4i@FpaT@Cwb4~MZ^|DRu7hF|z5 z)7fNYVPx31NX2mr^(t#OB|Cc4SUeyz=sirx&l0zfv*?dlVDPEehadAYzv`>W^nIn`?({kK@VGm8L+mtq!8w zW^-)uz zBPhXElJyO%5NdyVTOa#_aGVZ-6oSaZHa9SdRWb~j^!9IwR(XZ`fJ7M8D&C2L*qr?* zEp*Kfn3Y$+_3P1_!NL1tZGSDrxbd4m=Y2PBI2qKaXFZ|ko3{~x-XgomxXH_)M7&D3 z@v)tEsjpDlmw$8SBIr~#zm{x-Yv2uS0f>l$H4=jsMA4&m{JSHQ}_B9Y0ttr<_J@<;nO^zn%{Jdx&3pW|?jHM@`T z16^7}>7&yvrzqvYdqKQOHYG)`5Ez>~D#wgR-#){1I3AT_q4iXrslyl|<(Ldod=oVa zW7tNA!$y&aWi>4oGFiQk)+SEo>fN>|FltrNNDOOHdA1AF`JiABv2j592`B3Mg?5Dx zP#TQJv()sr^&Mm)@XWt6@%-i$S;Ne?ZKoPP+9%HZTz9OdJ$3wLbD^KK3dyH_ZHBTS zk72^F)wG{LhAL-1pE^$KgDo>-t44qG%Ik`oODk9xUK|g*r*|_Z>d*qiYaR|$PLSc% zf|tbU@Tn9$ZZtTg*t1ggHe4lEQz_N$?xZXayv84~j{ zJ_86`)rsc|8$Byplp=~%;9^6;Xwv_Q_y8K|%ETOJs!zw!I_GxlcM@C}rsFV{IipJ{ zaQjId85N7)HJU+@0h_|q&w9*`*{*x(PXFULTwaD$`#MeIW1POuhN{pALB*-5;MFIP z>k|HfjUZ~i{KDE#KE^{}Nilo0aESERt{|sN1e!HfH%Q_L4G*GmnYAd{k1b1EdJ6fy zs?KYacHv}bS80DFI^x%MLc#IC4>zUmtBdk&%gUXs&iH{tHuDp)Jq){VeT<73h6Lpa zQ$3IRsGRx;PCo1wI&rw|*nOPid%vnWSzb=i%UWMC4S}<^`R-GIWdR{RMxKNM|8@oO zX08m4o$v2?Bg@O6Lc7Hh(kwlBV z=iH~HDY{qHCRJT;r6tVZ!-9&HWN5)&u4+Ri*e(;I$y!t5Uvr4WR}?;vX}DY7#bLv}>lGGL zn$jtmB^_UQx%19IfEXO}(HQS?l;PIT1ht^$cK!M55ICsBOE9E9bQ8T{b)&P&pDyVF z?ZeknX0W~NJ4fIQ+BO2wsW>qVn%9554T@jzyq$w!Oe8vZaIvN9hS`;*CwF{b3~nHG06tIq z9N36mE)OAc?zhajhIbphe6Y8n$76*T7JAD5WixZ3FTgzi2H%u{>5Crkt(>JxmCJso zZk`MGloJ8W=*9O)b5xM0&Q~?`-6LFWJYUoHd+MUGmdtBFPV77OLODO&HDkH;IqfwV z1PYr8<%M=qFQjI670;R})`4rdK>x2>a?jyQ*DIZqNPk_8ejybJA^Z3~tB4HG<;bR6 zQDxN5rss#>m-1F0M{@Ihygmpk#-7j};2904_$JaB(3TpnQ6RGLL-#pcfXQO)IMn|< z3s8qhRNv0xq>#;sYJBfZ$1Bht{UrVXxr)lxK5v1(X)}Dr7q6n$)NOce)7wp(k-s-S zMSR$@>y0)ZFZ;Z!K_+&GBKniiWv|o{hIjW#A8*te(zT=BC2zo!DEGMBc&(tL@gv5N zM2x^`R)pVji(8}rZuM<*@EeNL-CU2WZjop0psrw^5G20}sI9TV_rB%bCM4l<<$K6B zuov(A1;j=Tb?D@=WfSxZL$)LWuP97FLSNUi+pcOXdp!Ed!ebQ@g6OFK{Nw?+MB^^L z^?zUw+5oC5Eu0YU1&pJA0y(MxE-63>uKp8yNG}9v*pwPHb@e|G9wvZ_s3Et*{wV3u zkQxGE$>$yX@E`Xl2B=6r(z4}$AT0R^gk?POKjFJ{EP#rrA^}znVkY_@AAtG+gvGqS z{6EN(N&x^aVe)oP`m7I%uS({}q*q6h3{E>5U=wFm92M`V9~ zuV(rp_?SVJ)#U&O8ABWi1>YM970{qC#A$<&u#9kNtt9`)@4%0_Ovpr?d9lLhf&cY) z|Mm4pNu&Tybo^>M#I^r@iOLsHimF_y`ya)0(+y=o*t!(sEsvuQe%R3b_kI6$Z6H3% z;L-HAk6#0bI-hecVWQxZWnvs{3}>-f``BjH>A$8$@-Zh&-`>zVZ!3mgVc_`W-6xB& zM3;M$uLbYs|JNh@T@9ZHD2(9(-Zg(bVR{~_5?Q|1!7s{x-d!9QJmLfK**~68Nfngx z|3gE0x5nQIhW$G(|9YsrS4aV+d5;wv|7h=D_~M3r$nBQ@GX@|Ws*k-}HO4xk>24Nw$sk!@)ekY#Zg9xt9#V@Kqia`Ux z#eO#H`_JyHWQ+(do5um}KZ~LD1N|56ftAGHed%9c=W>BknBqiTg8o^|M+xv2+`+B> z>kazvOH>j-DPQE$e*Dp5-LxRM$U)kFL?uri1h?m#;`|@MeUAvPcN^;;QBi#Yg1b7x zu=__bTp+lR<|UFp+KY)01oy-5Xs17lAqNfizs>%?&Hn#vZ?_L?J%blF1p?<$dU{Q( zZkxM!%G>X8z(r3{!Nm-WTFvVJP?Z+>AZx-O@6?e7X_V3NZH~h!oiQ%F)479{5R` zQVd({pvJJsg%oGwy4NU4+#V%*^T_>Zn1MBp&R!idscnK2bx{YmHYe){{cYAR zXVu^^5gu2!?L2(fB#>RyMTn(haiN|S=OI`dToBZ39ptw`w0H2IB->n-45PuZRW(Si zyAGC4gm!T2x63@vVDUz{sxI{0_}zG7-xw5KIMGmkabeo39^5emKCO9|^}ovUeIebrf(FGL7p7S*I_Oj%D*E5Bk!L5r zJFw~0To2%1a2M+189g%8eH)yeW|inVB|14zM(uGGVl%dc9*}RLIm%i+PasWZcviCK zdl(eKuf>kdEuZ!Js*JUx?j}&X)h>1(oV-p1e0n=ees{v_w?b9Um1e-%kEUd1?F4NJ zCTTR%WS;&dy{}<`aI2c>)sIa^kzxYje4DwVbrqXE%o}gcz*eeNDo%%h+U@EmBAFGa zX_D~Mm~7$Mqm+}UdIsERieiV!hcgD(mC@Bnsft3|V}_9e5FBt=lSR#8(QP1ctbTTj zz6#l-Zgtu_%@?uI;`*n;M|)X@w;rcQtL-2OXs!V|aw|!aHPOY12R|aKu~a#^fRPo+ z^-9C_yVqFnf$NG5=tDtXJGFK%*I1(pQ6tT$UCw-#Ko`KRUT|?DbBs4^dn3n2J)vbc z9w==5riWzcZ!dtKLyMni@X1gxlWnsrq1FvlC)3bsj)7-h{S#2dJ|A?N-W{xfVNk^5k+jEsT(0!0e;>+Ng7Dv3M=K0WpaHhToXWz~RL zT)I^B?MTD5o$$J9xrpM{zO|j>0HTE2 z>aarV^R(Of_4O#R{g{3T_1e1IPGj`3epgA&rPifKp{0N`-PO_PpkdEb20WNWrDnYA z=2Q63q4^1An-N@OSVa;XqPyL$wOw7zed~Hmp-!S?F0@;tusum52HkXu7*}%?8x%b@ zXuCF!(;O*o+TR@YY}id2yxgr_OK#xnVWgjQJ=#z%$BokG{#J1^)plDLRE<7f%)TEb zbv;#XBIfnkc+O!W_cHp5RNq<6vYkN2#*03J=W`dc7dR|fcKh2p4fG`}X2dn|z;5Pg zm)o-xhFd-jYfHS-^DgW0wNxl>lL@_27Jj{_@SzQ;jak8IJo}WEAAUA+bQJZvxE1+F6;5vI*@%$!-N3yefD0O(;1WG zjseKMhMlyd;;hYMy_@1)yITEfpWHxrol{F~&Ur(_$*i%r8?>-Abb->dX33mTk;kym z8*_`+oZ1Baa|LcV=HE7al~9x!{+eq zd5Xc+zPb4wBhRqz``4W-U!&!>%C3**x{jTfMIz_kqQh1xU^rB;h^(HaMSkb;bq!LO zSv2v&on?UMugym2}b`>}xB+%B&D3VipJ49xu@N#?7D|v1=;<%a< zO0RvZvR&LNdV3_fWBn!iPk7nHhr;uN#o3z>~ImXw7x5bgE!}uGf1ZAGJYE%L+vpub+*?Q z)yfCkHs_9P3xwY8mhD|n()bsPx-k@3)6Y_{E;yV@=ldkGCb?vjw}uUh+?VGp`(^+Q zLZp;r=7=+%@+`sFEn}{Kj0)dKMm^&*9h2eyl;&{+Ioq34w^%b!*B0C}n}Y7%nTxui zg51oP9`Pidtmb%#+yKk%@{bu5+c@Ll;P}ru3eTH!_FkRIsqP;-I#pUKBzW&{c}87E zFlEr+jhP%W2#O{8nsyW-YqR1|fl*YW5GkZ>bSsx7l1?xNz8bM2As(hzXpSj~WT z%@kM`a3_9erT1%Hq2+i)pyAa}siRZ)-8VU~Q`3POs%ozOH#o(0l z@XI&O*I#mcpE@pKLD7v%*$3xtn{O{FGsF;M5RHhA8Fyrq@JKOE#1hDxtZnpr;flXCWULo zW214BeEr<%wj4{jDH9SsFSo5KqqA|fh7^Z^yLYl~pOs(i`BhQqDuJd(7 zwfkTMQ5Qp+Yc^G_aNpPo?W`@lGQ(+CwkZ*gb+6k?VMACU|LGtesiE`{3e)}KYrX*p|pgdwJO6>CKg~w&%%DlzI1hLL)bpms*nr-e6$5~IPb{%I~To*9; zUGqbx@j3`$P*w|se6Ynq@#FUKVrdL!|Lyr}n4uM%R1VL~)2;u#25TeBE-0*NE&JB4 z4lD1UNE(lmlraJr%SqBFFUx7&!g>?D4YU{>ND3wOvFtUbxc3T~v zyw3H~{ql{PfB~@~MZ53gIP(j!a7?!9Rj>>ktUmoJrRwGa>%U$1Fgnh7ExNy9!0ojZ zDRjHy@#gqm!>uW-;$~AUlHg>{&FPf%GHR25rY}oIEYmXXjgIZ_{3^AdRqYlNUeV>_ zP{ZDS{u4V^zYd9XLe#+DFCKA5j;rZ%{sGd)Rvx*Rp?XK z`sV~~=3Xn|Rg+S9Q|L52odRJZ9I~gU=WF|Ey9uizwd(qAZBcSpMx0`uURCxyz?(1m z=CHr|qO;dfuO8A{x7k$wIz}u(X(D_I3$kzh-B|s&X?$X~+4#DnuN|6IcEXk?ncEOA zE0_Hyajcekc|yN>p`d+y@+c|58SF(`^Cy(GErtVr9BQh>zSn{lG=4b9DK4%yE?Y9- zCKTDd3cGClKkdDDR8w8w{%N}v6;K3`BB1opyL9wcKzc8sN=aw|1OcV12ucy8B=jP^ zBcVwRQiTvYp$RCxBfSP@=Xsy^o%`p^KeN`XHNQ3M@h?`uljNLz_SyS;UEk{iDJpTE z>qP5GYpX_gqZAK%N*a#FB7`P&6oRZxk{&;MdM^z?+2}rnmW9xfMBUbviDn5C_L>iBZ|aV@-;!Op?=t#+O|?koNbzAulrM={bbC_U#l2Ar+PE}sXeKy` z7HWBZ_db{#4;;?rPQCEi#T+v{FvLtXYR1DMMIgH#!;_F7mPRyYroCQ8bdAyG5HOO=k@d49loa-^iZxSU-iRVzltBO zYV>TwZoVStrR$*l$m6~7Hs=q7QU9yflFM>uVasM1DIho0V>Dhqa)ViFp zxYn8P%V_m6=gTX+wGE9Y+oJE*j@2>ZqF9aGNY|ql+)B48lY!S7&JVn-F!?0g^sS2K0 z9%n}Rqql1RElhgU7e?6R+EjP6&Yl-9SP zw|GYJ+T3H_s8pp&AhyrK2wLOdxL28wc`Py z?#ywk62b~o8GftaI^TNE*Z4W@eX;h{vLh|}*U{KAr&>bs?|y8_rFe05?#~?uGlx%E zJ}%~zj5pIJ@BK}TpKrLd-*9|9Cowr7C`O~b#~yE;{(I7!i6-&Nve`~vuq|J;pWqCu zpM#74@v9YXc#;ipzwHs?u4(I{!WMC?XXY$AM(U;QPEytTpievB?u&YqKIxphUy^0U;BTsBipX?~wc5X0YNV{)w2a1ls(WI~H+p=q^ z={tc>$~ifm8VXv;K9^hjzWJyY!(UENgD%LchDHMNN~Z52E#zUMk$-Jq0BJEObpXZ0}=9SsJjt1p8bUykq=mQSNC z>dfkY*mhaGUu6;-vBiG*5#mt&E7&eOp`Vv>(uqE?bq1eU>>^P)4!>@0+%PXmf2AXH zE-BVzEEkcpjXJGQcZs1$dw_tvGts@5fk{U{Ia`|9sth+f&MC(zPnAp0m6uIm-(DB# z?rM9UY)L;eP+CaZ@r5|SGvCAd*h`uFEZx529dL@*v0?%U{6QAVcgjm->~5g9CqGuvvOnO ztYqETTZY^Mx%uKif3p>LL0Fr5{$jj_Us>R)YVcoAp(qF6J*gOtWhx#Sf}>N_TG zp5jX}!u6D*n85li^!7>y@0jsnV|~?oQ1$45i)^^C86+3wsg({W8pfL0yF>_ucZ-b2 zvfQX$Em!-x7GCQE-w+oTD$Ux&yH@-J zd(zQA#3$vvfd3LMyVr7_X7D1rx=3gFJY7KztvBzZ0m=PLZZ4HBE9o}z)nnx8;SKj6 zvm%M!zu$P*X6X{bPiIOw$Ke+4YJ6?CBRqw6uDAM=kRD#L{-MIsY&6O0@C_}S;5HWF z3dRK+f3*-tp!)VFdmVPc46RsG*KqzvGTWt}Q>AT&h8@v%ayF z#ePD2sU!c)XZ-ugjn|Kx1Mirx6BK;=ogyY)?!0^((*{=E51vL&0Q+W>{2g-($20Tm zSM8ixpy6vb7cD{zXD+O;mv&ViDgBBsc;M)ovl)eV$Jmqw(d{nEjAl9|W%Vgy%(wO{ zebM)i`U29sADO`OeM9PVl17nV$DOP3IbhOQKNiUP=#dj^?^x67ajLm!9K4LEw@@h) zq0h^TFG@lg+xd52s`N8awjJxxd7AtGMJm_2jl9B)?lPlWe&2mh)Y?qB`48MbPBoHD1dBn}(l7T~_bN=yq6p->R=c%G z>~dMFfRSlB?NdljMBO%T1ShrefB`2V%-gRgx*!YCP*5lt3|{J*v;ALLC^{pC6g3 zub%Pn2G!?awU%KFOX#$&I=wpZ#ILKbAa#pdNy z{%f=Hm>6GT*fMYwv_L+L;C zvwH$hZY?g7TIG<0$>0qe_-*Fn>G!upLj8x320M0#=}ZmI)K`Xy#Wh`IV}3zlFNSPw z-!m=W_1^!;tRfr&hFoDr>=3Mmd=d|G8T3~ZRkyjT;PK*$58^YBy?6h=wZhy>=TVvZ z>2V#be+YJ4K$yb{vt0V)Wo4iS7CsS-R{BH7n*%y2%0_|YkC%}^YcveDWRL#iTXq6D zkf$f?<{vL}0VT8aR;w!e9~xu~2RKX$?f-o0f7=Cg-vWh`EhJv`@BdTvB-#KtHNat{ zh5!DCC4l%N_^woK%2dMf#1g?j90Qsu;4q%>cmF=>fB!Gdt3aJaa>9kK{+Imv-@i_i z28Y?|A|YPwf4pznEpW!TwYsct{h|GOg2T+kQ(XAtWi}v`{^!L1=fwZ-HR5IL=eJxX z$Co+gJb%glFLw#CoPYjO%2Jt%1>`y;EYPYMY~=-7ZUTFZqAC8ujDkBR3EU4u><`EL zDz@I64E-`LJI#Mi z`~N2{rvIHz`@^23W1`iJ>tUK=1mo@RY|wv|&0kTZtufSfUbF)>y7^0S7KrY^fZGoP7{4}dg-y8}A<<6Z@` zT&j8U6BrT5^9KT=S7x^*#pfJsKfwTE{pxm)od3bjfX4fvRX3g+^5eh5*`7YR7LFrB&m#f*rWDb~Vvh<(>hK#5cTsIGkgwAW zd=z&9aH&UL&f!F8sLVq0;Ng6-@Yz@n&(0T zBK+uY)`Pgib#q}PE@?IeL`*b+9HhCe5`a4+n@n%|3ZM>0yUa@fZ(Z^0^Ls|u_zH7% zPrW*0L}_48Ws2|K=p)yUlFPXkfQCV?MSJ@OZsc@3^$hV{k&*i<^?)>p#xXst2l?C0 zUz*A3K|p!l7rc>!=&X`(Ly@)Z?~yY_BR<|7$;GsQrdujJ6e5oc(EU-ppqL?xsNcm~ zqzALxQ{&DJiwOII5Whpxica&px{OK&tQ$&a9oxoE)odRE6dLas*?txP06Ln-7xLJx!>w~L1B8ZhC%JY)EG9h{$Tq9PT=MI7 zs{lCd9g%s>zkrn2hr(sJmq&gwt5Oqp0i7*U*};R-G>qT7Z8#Ppm>TUJV0Npr|)3 zUiDW#h$+l~D{JB;&$~RIyR7#vFDu)gTheiV_uVUAgY2zz*a&q_t&W0;AY*wW^ne`jFanT_&V6Dvk4TQS_Nsdv zY}85%;)UitL)Ri8bh~@~mG+tPzo(!Z^=P5&!}zy`p~HjJ3Vx-&0`mQ^@7{34&!+9$ z&8=2w(t&s^ca`CMX*Vj5zbGX_T4H-EPrAjX{qp0L4anR+a7LIH>D4UN85~ye9Q-1d zam3HNKXvR0OLYcLhg0TKXtrc>c~h=>Y0MLMW=Ga)c*Z~lV1UMJC{= z4n$jz!6O)tcrrCJVV9G9QUe_;eE(qOg`XP#)*=ADnqk;!%Rop7#$0D%QbEZdb+OsSVR&0a{aYsX7 z-eBm#;K;p+OA5S9RrLOM;Cwil${$~gU&GuHUH3H9&?BU&Sc{C|;#tlT zr9gfmrP$KtsO3tW+pw9>rhG)R0^UJPW$Cbtb`$d~vm1fxB#fwfE$rd?sv;lbpq4D&LmqCYA|)1VoI5_L1?q{xpmnNU79 z=G8PXvyxyNfEY)dp6+A3>Fin3g}JN!aByvcb|2bS59QgT93xi=RW2X!G?3{P=9SlC z@RNYhYdzY!p64$pm;5uSJP{ z`u`eCj(V?$|fr2ab2KsFxa`i9W)Yd{%lqyEG9(~-+TNJhucHZ4H zn@iu{2G=~HZ5b09W6ZN{XcLN$ty{=ICdqHprn#!ZSR+fuZ`$al;M~mkD z)&+L&o1BmDU?aY(|>!S3hTQjHUzwSbMD-B{_cZOJo3HzFHbs6b0Vd0j}#=DswZd z|06#JD8}`SvFZqkq8tnC2wibIlc0%@9m?W%GcgTVP*TnwrNl2~tT2n&wzehtai$n1 z)p^@Iz4A#J-23bDBVvZGh64zkD=}9|Wo>Rdf9_CgL4J;-bpi#$k9By*Y=E_!heZDg zm?(WPDOm#9b3+@sA6T!jfZ2wwQW`rT4g#j>(nBuNb&O7CzMt|xn~-XzE7vr2nhz0D z64F=Xs~I^ocrUnwpiRIQ0_Ps`H{GQ^;oQ;dkWi%@sOpfsG2e1*^ioWbqIRa$!h>vz zLtC-O#kSCLE^M6*TPM@)w)O9|%WqSz;z;Zo(>{bA2KPLUDN9}u4Sf`ULalc$2E*xp zG>WdDH=BQd*Y&9mDQuEVjpeCnm)CmP7_{T_BdrRXgf}16*FYMDuCp;DY-@bA{?5!( zrZQ{Q?NC_!U26%ja5QBsLPv5Rb$#CeFo$)E?PZu*HKdq0eNY$i%cn%ZU8!+4J|2TT z!5f+##;m4?1vSme`7&$bpiuwt!WcOB6FwSPu-Xw#yHab(FODfDI4jvGKZ^qs^@;Y6 z7oX~wde-Ks%6qU>s#AAzeYK8^9V>=J;^vMUrXLg+X52pAjPM`ahqZ_&FgOMc@Q;V3 zGCAVAU_&X~YoR>RPGSBZMe!eU{03zO*Zg}MIMy&VAhkQdy@u|D)xW&C6Lps@gQT)+ z*uPyvJqG#tK6>zmue!WGbB0RJ?UDylT!pxEcxStf{Jm1B4HgRK0h;*wS;C+~&kUQK z{S9-9oTDt6Ffd$8Hkbyh24)eLd|&@u62edFO01cNxa%mcVWY|(-ImKfTdG-pyLZ#h z*+JL<6->jiFWc#rozxHz?}m2cv`J2zg;kwG#p-Z0$HKN5n~zX|(cPC}CpJfiPC1N4 zV8!?iwR+??VaVs@;dp5Np~rO;{WKOfYLg|kRa}#%apnUuvKufjLD2CIp+~7$zGwVb zQfpfB2{lshw13V*8FfWt-9WW%Se-tZ)O^0W$KGc5v~SX;;(-{wk;dO^rUkw^?ivyt zFyf^>KCY;el3YWgLS2!*a7$@udz~xxTH?!+iG>V=>~2H&T8_2-gNeEmQpbI8+g9FU z11s)(=M!5=Kn}dqS76p}zIa3WC&O3k9kJhAqWjXZPdP@KHWRc73+78lONIQM7ogB#%bBq=Z4xjJi7;d z0J~|6)YHFOIa_I`>+&fB3T;1UYLPCEsFYS1dX8|f|EBZpw<%J~jyg|KTfq^|Khov) z6?~5$Uq9iLFBwxah&*Q-c7ncoc5JW*T`I1_ibvu;eBI=u4UTfxr=42N=Wdb+eZ;Y4 z%zneO=PA#I$0V7l?|L*(#@)4YIjD3ESH@(7Yfg$+{_uTc{F>trkpWemGkw>Xdc-l3 z?WI{YERff=BzYl&@({r>!F))Ya3ZoN8OS?1}7v)JwZk5<`O;x z@F>Mg`A&ws;bF$+@oLn%K@}wiQtvBOt}Ti8W1@RL6kf?O{ht$yF1Poe&3Q^sHKSa% zlplts;o>O3qRF{(Jk+^4MZU7#p+(tY`dz)A1p9l=p?(|5@#>g|$TBHOjCa_Wem&)o zA5eQ=(7(|(X^wPNHvW6)t4N}vKIGqoEh7)tdDqw&)|)X&8=*% zLRP#sC@tV`G^!B?ds6S5Q}A>tFpuC+l7Au$vU~hI4>tVI=$&mCXAtRKk>d)4G>XxK z_z0n;N@Z3Fovb;F%7}sbw#Xy5uR?|W7RCfV?#BhMYP?Kg>EV8ELeV7@Zn&1b?S5ok zK>&9S8>TcmP2*m<5jz8{SCCJy-xV*uy$2dESnI7*+OzB{&Cw|yq@M~CH;ts1x6dVr z>eQ>?9dK#!eQf*q+w6kL>$3S}g$oACPh6K0Q{-`o@1rT{;U7Nt#Mmm}N%t=aFaEkH z-2r%W!Mo!n6;n%De27xM6UYu6>^+ zSoU+tP9;H+42gAvjPwMFzJ4BIr(aX$LM*JOzS6vTf*0ve38J{?`4{i!u$3mbXyypj z%VA|QPm8`zhpazXul{h&dPiSmVo}aF=0ZLc>yC%EM;xJ&lEg(`zzjvNPpuk3X%kxe zf*rV2)9bjtq}H1*G3mJBsjSBl=tyazld<~#xYIS6FWK8vAk~XjiZ4mm~XW1wYLr1Sx~Ps zg;6&4rJb7XDmYg3m~~D~r6ud3y}l{-%UT(u*_l*i!&m#i8rfn^raPli$V8VAuR(A{ z!_ty%vIabds~m@d@?>p2bC)B**x3yvT5QuBES($bdg?lvkPYn(dm zPJ%0&{}?V>)6i~Ump{?BuZ;WjspJFacGqHk!5(7Vv1-@3Yq|DaLcD4%^Bjs?r@Vp6 zQ#PR^Z?8PrL$VXfYAW0?U+_N09}M%$Urc?5ljBS0qBH%zsH%^Y0KuGvTbW5iDneOk{gec-9_x;Szb|BXS zKc*6Lr@o6v{-xB)Hn1iZBL2FEd8utfcvKNf--H!Pgp|0)JF*wSu`gHr5(2q9^Pz_F z2=7hl`h%i&Y1-u`R`q@t6?Q>%w{_F7IsQpm1I3+YqxbpnWP;@Nm3xEfSq(IH23y6> zsE$s@LVEP2{2t?6*|=Mj(KJ7871->vXNQ{e!gf4w4}G>J(|Oac8bvYs-BoQWF*@*P zTthdmH#*Tu<47$9n_uGINH9(oOyW(>A5}$67*nuEy43g};B9k}fqj`}Zx}Ge8}yy- zqIJ`nMq)3tdN9lNDMgt>c>Sd~7p5DrdJ!=}Nst@68(T}1_w5Wad5n;-$+CXsQ}uaM zR8B_Lj3GytxZ%V#cS+1qa<>MzMCkKwtF)bvS%cFZvI*Nr1JAw%4TNS7mj6&Sd(L2F z(OPDJD#xoH{jDQmS*g5`*I#~Yk;YuwW4BtPs>}SikcU#dO zH97TsM&YsLmGOHySq2G@Vgwm*)a=O$P8Bg)*h7(~cn_mJYxYxL1%BU>QD;%-gpY$l z)EyI@u&e@KE+cdlO3%g4E(KoP^7xoD%Fa3vYc<4G2;VCA;a%72i2e-qOKdHI!4i0f z5U%|dH7R>64G9tht7r(tw+5X>O!VorXRW8ft0A(|aQDY^%=32DRz{n-S!q#ft{o*P zeTO!Flz}k2AVNB%ez|H3a@~7cuf>k~Zxu_r+Yov(_l;sLF!ut+@=w8tSODY>h5Opf+OpLV@;h8b>a zAjGC%MXAA)G<~Y>gq@(&_I39mN^Td?!uAt48(}e{wN~SP;9K&d%tQYa4X&TY(a8FX zsa0C-AC@^{4|mPiKBPDf4O@FBq3#oJWCukB!EhCiid9obZ8xK(&q&ferM#mQ-wCW2 z+|p3yrBP*}PiuY1rdgR)fh(5l#ZW=vQM%h!N(2w648-q-&1TV$kHdNLpOXcaUdvKt z{D=G$^y-3^g|0%mw2zi?cflK7pOff>aVcIF07bw~|95LBHrfyc}=B zDSKCId4qSMkD(Wb3k!>v#@iFVNrC;64|Vy>RZ5Gjs{+l2OVb?N|B%2Q)4c)R27SCy z4tWh!ZIkuh@4?iF?se_I&s*|cY7uDK!-tMf~xy4Dgsd zGQa%vpC1f-#%EtxUpI*xQeXf3k8A*%9pFB>;tRrf|5wre&9^8Z9z28cko*x<@T?bD zaPIEFUSA@HT-*gH84D2pNDfT@%QxBfe{!t?%n>!f*5JQj`D#gvnLSL3g*@?!`R0Ir zqggO?4cmv597BEy{7d!K-H|1>C`Q&C0F2Ry1E8K}zzC9j+FxRn4v0e@z1u-6ci-Hf zi{~Ba_6S!Ww)Fa^8d5C(WHFp_adeX=_$G+km?k08b$+D+hAjV4I+a*e>>jG2K$-lk4>dNT{-3pd3yPC>^FiAsK$CfluKY z2NCa4Y5WHH;RMT%A&rndvIVV#c`EOkRvPa$lFl@ysnXq~>AJd@fgx@>2pgctPC^$? z3^ZREZlkqH5&+$lOOyLY@yV++eYV5C;;klHyoiXaseM20V0W^4b*I@r`6U!_%m z-w@KZaRVQebjoL2ZQSz&yz$#pKcEv;&d>~=e-GZuJ_y%e(kVR1v!PcX^zRstMdtHs zkmG&K83Qr9KGoC2J};}u$e~E|VWH7mJODvXy%z(ps&}o_#yqz17N~))d9?=+gKn0$U>%~>(l(Y3#V=$q>IC+RCe(5L`F5)H`{(GbmmwL%Z@OJ4-0Kd|6S zRLBYV(?a+IbKKD?qMnT;2#detVsd1i05N06qOZ)!^F<`uG`U&F{vVc`bbb zpJj;99$lQ75g)O*wdF(D9exigh;k=DA|VA%az9dPMxZ05c>{P4ihscrz?yuWO(p`8 zsfsc>1U5}z9;2|>K)~gZu)XXTDNlWs-mzS(w|{j}5MdT-nr6BLgJ3Lfj?p*CSa zH7Z4zcY#>KmG0uL`Z3+p(sZ5wuGr+O8G$Z=qC2;dzVq-ni=gKKiFCZRqwlVFOr@8K zbe1_zSc6O#*Y6qePl4e+wJ$^@Q&R*s2HYSo>kO9}V%{FKT}I#+_^?pNSMNV$I|nemuLO3Onl?X5zkAIrmZ z=(8kqp$OhoebZL5>`SYG|5_0CK70nGpXk8I1a}kq;+6LhN539A54leB6Je`!WT!>Z zCiFlEbiivBjjCYQd*A}}Ct3b+(@TE0@hDb2=)haTsJY~MSCD@;FYC6)p*rz1mEj(| zD=GDH_V}wM$5rGO1fK|*z266p&GqJ?823I&h^Wp}LQVbbvTK~{!f@9oMS{^$i)77u zJ8BoN3N4K9*V18}OE0Y4DS%`7CQ{c!^WuC#4CwA+$oErVpv9|tK8J%wCwG}bNF?I| zV5*s7vZFXbaV92gqflL8Mj5tK6DnU?>K39^1R@dJ$ z(GeR$pHlH8s-jMs3Kkb8oT3=y>GcrA03ej^FvxJ87L+K%V4!F}%gft9<3$xm$Ef zPaf$C&)ek=5Jx;-N*T94T9}BAxR|dTwVX&!a@WkWL6bQjG zg}A$IX`+ckTMk}=ia}i5$oSLDb3h}RTyIy{l1W~U zUZ&~aZHBWE5^$P_X#qF^ygCrV6L9bc-}6uM!XeJe-17!0om^p2gu=3J*U{asJRdd# zA$0&;D_IqeH860zJTwr4es&psa;Qo^NTo%?whh>avpw5D5!T}#%eEe}+KlMg0)uza z-PkcMDaIQTto?K_dz4gHt!Ekt>>HlJAqMEv?D3RzA@<&3jc9lNf|HQSi(1{BRkuRy zW@YHbLXDgQcDnM&H0dLUQ-*}2#UaL3{i*;u$Fbmy%3Oh27D${VjBV-{>oLw^IGf=v z#6k0<*8P5jOW&(Rq(249(-DCe*3}g=rk&o9C(|5LX7(R0=x#q>Auiq*CO3SUjJWn| zPS(9IU`WZCE-=Q}9wa^D%I5!OT>Bn|(Pjz3WF3GxNRP-EC3_(3XB+f{;d`!aTkL15 z`Zzf0vKJe=;V=uV=E?q${h+Q{DyM>*jD+{ZTF zl{b)1tN$@6|8atcmVVhagEE4`?sz5Z@XQ3TtPqT7M;#9f-Xqb>IqD^nAEI>p6XYYo zWA^xDUvi~z2IB}#Ije*rPNg=?YnP~SW&IJ!Wx1!PM#~k=I3_723+oUGA$dyuZ!*s5t@h%kPF^aqplz}KLOJ^bF10e+h*|3Ofx~Ns0 zwZm@L+>jomN4swDGhS8QO}k5kBtz2hiNy~9{;G0>wPdFrWF@q^8rOtB+bDv3@;hU9QId1fQPNv_jOhhK#z|9ZM z{OGt#dKIs8G>M{VCO8-PJEwbsviw zyU39vqdK-gle|~h(P~wfB5QvZwm1Gg6(Zd*_0$g$Q~Rv|=XNP;xGQU;9tiWhGS=uL z&~(EBxwF4!n>q)iZ6+sRn7GICa7-gl#(qqSrFw@!8G18j$!kq131Bm2e2!B0&X1ur zrZ_m|@S`LETxTT^SpKbmht?>k+)qtMhEuAPONl7`Y*X%UW|0Cfnr%x z&VK(1VZ;CB#u)wW16?z-;7k~tPBp7Wc8G(nRxs}u4ZS(gl% za8nm~YiDZzJ{!K0ALTE#yd@Vvc1_iD`T?Q9k^MFMh-VbBVqf*j)qu>H!LvDz9$QFs z%l`6;mPo~%l>Oe6Z&KsiSCKB%>C7Fg=LZ{mqrbW0RokP`x5tz0(N}|n+jrXczR31a zJvNM1AKod$a@jq=rGWKYmo5Da}P>cX{13o}>#nB7#!w z4{#CR-alMn_#F@t_VmKP9MA}eQb3H*InZ$~8!!F_ zeb!5U?VCeOmGM!}!TR&$c}bpf`t30aTmcU=&#zXuGWJL#O7#h z`jFC{8JvR-Si*2x6)xbG^?A-lWLpH5th8tcexdyo8@Mp)-$!_g;uOlfmmFZ@WyOO< z-*ql0PD`;e!s@W7zy~yMm9b;1FJB6VxwBSMXzkSRLctmTuB(+Pdc#DrZ}yhU8toqf>b-#~4McVrXopiPiHe z5vWKC{B*i7na3e}VjRAy&1b|nM2c!qvumULVOb#Q0Dr~O63-3^>vK+N%I%KZVx_)g z_Udzwp|WS$T(+H{(J3EGEpwzQ`Z6TYAf!ma3FfHT`FRa@9o+(9GsIg&3nwN#LIxTM zM)~X~R2V|4uf(%;!;2@}5?b|U6AB$W?NDh2!Y@Yi(iLWnxUFbZY<E)89S78VE=730AraNh^Juh2e}EcV3 zB8S`9tCiQ|6wFeLD=19um||p$k4XfYM|=^%v=@-e#FG@h_JGw)tUg1JKIw2cck8}vV{q_=N z_{H|GJIX5gy2Y+w1Mz`rMh>!Qbc8rIu5V~rF|zdC>fmTk_0zqgmAVM30I~kE56e(} zt=-6&jzuE2nTg~BCb~Uy)d(Gnl36lX09RsXl*(PQ!pGnuU!NW1S|o&LOGxmrg- z`w=1_398`u)J(;8uIoUdx&I}uCDDS-+@p9w4tpCZ$Q@p|#XU}LofZAEgf<7g1~phg z(ITz^C~*cUin@_t>CA{C%z%(7& z?2q2PF7!(Drwd3n|AKnQizo zXwa(wkLFO&=e%VomMr91DU-_gxX>A&mpj^3VjexDb{uZz7!N~jPNC5pvE-C6wc);3 zGM-@;Naw`7ybhrZ+4%G+^l$FRVy=Ax?`ZPEI}No(crtsKpV& zonNp%PA-wmgGDJnwUT3mFv3&Pe*dCmzT6(K^gc`c&K7Z!K&U}k&EoXW_|*u@s7hogiPX`|ZXBEGXuf~Dl_kQHq)g^EtU1KNz+Aurpy zM(Z}RdUjyj?+dNJHoY}=IXCXbXIiou-G%(T`dOQ z`m_uk4i)s%_@|Q4uau#jIcvAK)L-;#lx?GzVme-w9qobY#2`W}moEq4KQq8@er%jISb0FPBDb6uQS}N+JKJ0#!JVdT8ca3fJ(&!CX8KhLh z-SrOjr7VRh_}-_mxbJ1O;yGUkTO2H>M1%-Ui z{(Xchy3AtfIo3&kwu4Gh@kMjij4-YP3-IQx_D2uX-uIU`H4)3jxs<)PC{}Jh5amgq zOE(g-3Xz|{sF#;0VtHVn?yb3L96PMa|5Q<{xG&oSVOV>kEoqdUldT-&9JRDuHI43` zIM)Z82u)G5+l75L^0Q-TepUU;mL<+;pTc}Hhll@F0RerkfQjAId&*ZeRbQXiW=z~#KOQnZ}dQrh$B z(n`{$H6>+ysJ;by*|sa?s{mpDq)AleanHoGSFC9ddGP6lMXp##*#HNrXOv!36K zFT=LA>d}y=)LiT^dFC9VwQ{KJvzWSykDil@bD}lQzQ;{&twy^l%BADkM^bgWyqD$r ziFH$}b$X2HQ_?|w=F%uf7OG-|sb(B=*!HwqEN1#+F$q@R5fR3+LfaY5+xB^D@c02L zXY5LaZ^wR3zmi;rpmh5ikaO+w^EvzN|I!a0R^58abr*VUU#myL?3{RRZdgq60_cIA zP(260t)y{_{}4fl(gtbXrOPJmqM7rTs{j3)+w9Md1ARTSP=(V$(idW;J{iEDlD^5m z`Ao@PPdUNo&wg5^*KB!gZ+`umYOF_WVa>|y;P^vxhyq%K%7x}XGn4a)y~D~%(HeiK zAZ*0m;Y&e(Mg!~J2Ti}oDE8Dpv=L>H6U}p#^v~eoe9&-E%EhK8`^T4$0g8#?Et<(c zUe*Oo6;}VZ-xVB&Rp8Ii5Vz>2Y?=UMk zOjP6VKLVfAxWE}J(C(k5{G&-&2^{AC(TP80%H=T%y(lv@h(BLk?gF6I=Ai>?;-Q6J&2=4Cg?(XjH?oM#$PL96oe1G7wX4W&- z-P6_6)w_0Wf@P&e5nyp(K|nwd#C{0LgMfg?f`EXLz(4_4GUR1`fPlbmntlH+EB5_6 zk*vLqv6-b22*{7%_(W*M*kKIc!;jhTg1!(Cc>x>I(jZ^I)J^647X^?;$qGusz&ab+ zK`KKcBg?ATDhYMZ=MSlWhEqnvy@ymoi#ycs4jg&$6J1(&+3+}APaF0;e0Q-ZRgn6mQ+0b2nkNU7q~8YvAtO#3i?wG)zTh9ARG}G$0&#+v#-$m>kh!)BFhd~~2nZto=9JPY zX@8BD8((0VL#zse3+78<#}T6l@`LSnMnuN0$i4jjey85I`dSG;!`XVwG<#CZGS&PTpLu#Uzf$W3y5VIKJ*|XIZDC6zKUeR2 z*DT91k0m~fOjMCl3ldNZ_vlYBh%(`-BoNRp!aZ6xe{c&Zp1~i&7zmoErVwDWSoFr6 zlGVVty?aJ?K3HnjjxHL*<$&$gI~d;_h9=eW=G$Gbxq1?As->DXw{xs& z5J;pU(={HNJdWPYr2TkWvD~wrs6a@()We}*@C@`rx`ON;ibTxu!?%TM=z^TCu6Y`* zr3lqC3U(mtQ50ZH4_@QoO{d*a*O)oCJhKE%YU`X8-LdMMYY&){9zUtMCl-C;u{RMn zaT?wSsly=7CLB9~cLC-93X+u{OC7r>c{&yAgT)Vl#t)9e4~+$)p!;j@5Ms?2Gscbx z23(GafCfsF2qc*wEWs~c7oQTMUl(o(s-(+W78=pFcZ<>#lA;US7E}|Iy$k>9^R1u2 z6-wC82VK0MM0i4hMNv?BaM%JEQTTnn+(bH*SRuYU*`$={C<08TWOW2ofg@Q|rbvoN zZ}9j*6a0x;1V_AcNC@9;vL+c|$-7xpaoGY7yWx{QL3hht5p$qx!ya}+UXeGURQy8f zroF;`g!P2J@Ym@vp!AjJFV4P|Ri=ar`33u(EK6P%WzJj?xdcop)Lf`Ow?(#5)~g74 zj)Db4N_ci!*_7Q8gcE06m|nP2Br&UW3VMq6$l*xi$orP^88o(;Lf3%7Y!!7C*;4uvxg~T1G?y=a@3t)t2V5E# z9sFRo(JrhVmu--3p&h%Oe^aC@WE(^JQSBF;)fnZ%BTe1LT z*8t5P;~s56u5C`eC$d3>pb+Y)w*(XmJ)^u4Z8vC30L?ys9`}{=E3S_+Y$y{6JjsNW+NU zNb(5T2y{ICSES-C#V{pLC08m)DkmxvC8#3G63}?zefdR&2l+__XfxH6PvKG$x#+Wq zvn^)1B~&GdC5$DbN~KCNCHKYIb7AvK=Gf+`^ARQMN-x}^9*7QzJ`)4q!X2z9p0apV z)+N#_wevReyhYz?p|pBcNVIYlbCq_h$<=2y9sCZM#xjJ zlJod$i}8sP&d<)kO~oFcPoFN}F0xNYE=(@k%=lRHv*=>wVa4G(;)LOx-~?h-uvjv9 z>IyOFV|@y1z;(j*Vqjy8VBOGNGv_wUvF>3TW;SDRGZbgLW6?5Kw{TyDw-{iMU|%(J z?!{wsVZlsNN!4lerA?y=z~G{Fr(sN>OCTOqAJwLgL7$}>Ea@)UR3GPD;@oVRf1c;= zb^CN9e&{s*V!Ue_t5>^tkX;^Pm1Wgo)q0N0<-k>;RljcKQPZCJhV#PqvWSR*=ozGi z_<&a&@g)Kmj|;z(^Bb2~8cup(IzoDEnnjuiHj4;HZh+l1T+i)hSXB!O3kdj{U5`edOtls0#zm-b|` z@fgd&mjh}WT$^B*+6U+aY76wzUg-VZONG7J^U@vMbB+C%KABDW`O0paxy@;xUp}HB zT#qOW zzk&74u1V~1=1K=s7c+pqNc)PWhfUu|NQIQuUTm*>=s|8nE;W}xBvoWIhs%JHF_`g= zkx<`De^mcv=b*nlq!pzSn?B4&qKmAL^h^Rv#q-`d}xl zpCVB&@unq{5oQh@ zx3M4&^|4i z1T`ryG)`I^S7+qJq6{<9V(4NTjAo-mj!VWA@6*fp21yDz4|i*lj0O{^=`m?LQ!FxC z86Vs-bT(wDr>L8#IaN-|H5+Su&>iM8=BG~f=F=_U7tqSEHBUS5yEu1RZk-mdt*%F} zH_IcnHnp>~sv2~+xIQj%VA0{oezoJSv7NmWytQAwT!i1_x>&v{_ffZKS}JJDz2*mK z*grw95>ojjEydLod(_SzXlYbw2x(j-xF--$D$tEm<1XRU)aR#ZYb(B6uf|vmzfA8@ zb|)J*$P2L%sP)23-hzr3EMh34?eW|3VXLTrgfoEwp2chbQDTa*xq}?sT+Axd3YF=( zMX1f`Hv-qT+V%4GCzVs3hs-H1IWPIUy#s|l1;|2j>BDq_)6XtpX<|IgQ_Xod+sjS0 zjgzz-i(b4(ul;b|m=n&7t$okMb{}{CY0$e!i@ZJD zRPJTBO*_F0u`8Qn-WDegCtS;yvp#obd$U2{YkrBH53Ha!WeGBxQ@J&5$>vv0)Oafi2j9O4)H zWE}EP>=*tQ*vD4MhgYAHKbOo&V_l%HUhfoGig=c9v*rl^;#D?M6*HES0-*wqVL(8G z%s?Q3BT!(+0d@c!#{_~v1HUN1E|dlK@4Mi!S>XRZ1|#|Vpn$@6F)`p*!NA_g$lAfw z#?hEb&;zJy!Aw!rQB_Kk)4;}xPS4Or--yoD%Jy#&5N=ma;Lys*QIE*g%F^0_)0Kz# zA5U-s$A2%=6BGU85l0IiVpSMBMg<#+>p(BL6B5obeEw zIy%~N($l-RxX`&U)7jXY&@+Df_Klu_iJpmx7I=cz!OhxH&z08Nf#jc+{JS0@BL@R} zGh0V98*8G!_3G){I63kV6aQ`KKY#yxPa{{e|F&f9@ULzG9i;zzhn|s+f&M>r14X(2 zUgeZEb2YM56*98|%mcK+`;C#6`ybE$KX?Ay;y+6&IT+c0x3K~WI`aP4zW*xxe{cS8 z!GAQV_TMI1S=j$?lmF+=ze;k`|LytzvBW>k{Ew@Eoq1uo>Hjlkys)JrtH9U74!e28YU6-O5;X z&-Kw=JF)Kau(96W`mpYC>63Bj<#KtkXX9*gIF|Npb^z7n=!Y-F|87K}e#0n_`6?(x zp#Qs7K~PFw3;e&=e@OcF80s6s^MjH8@1_?s3GylGe>Q%7Ff?*h5(AL`ZGZ?AHr5mB zf8WR#0tMAHl>-9&KlQNCf}T;{Pm2;JH*UC(dcNH)7JLsvEKn$vHtvSRv{WY-{`zRs z`DWbla>2!XUN@U^f4+)IrZEQnDT*H))wI`(9Jk3?jpbj>4@GtPf`X4lixQZ5zds#f zR9Dn5s2>2Qj8?1mX)TaxIGT^Uk$hz!pZrj)_lBaOoCHPx_S6j}3s~SBv0dgNHhez3 zZnpf9QvU1?s^F{05u5fgDJoY(_y9vq!`-GAfZoLNnMhk$ZD8D!bPUfJL8Z=E$2OGO8o(D;~E~X`FjQwZ_`-wVi5_HXmDMw6jwTs#w z$uF0ke6^1(Ic^8ZgWPv>3Q&`bT3#rW_8Mw%IY@l3Rn0dOTyJ>=DdtqO`4X7^CNJwQ zo2>L5kNO9KL77-G=F(f$g9OaDR&~)&rDT%(08;pBNM>fs-2{(a=_$gd0a+6<&7q7N^9b}j< zA#kcC#gc<@(i*RN;1cI(GX#(uVnpJbKO*qC8irJ69!SPI9S69vtA@Ed!>XJiLe`WQ ze)hPZmLGQF)?iF}93-2F$HaH@US@b){CR(Wxr{k|mE!_KC6~N9g*l&Uf7nRn{3Dku z65m(DK#raIt;q}j8YHkGQ$eP_C{++ht&D+B!?r~Jo-J;Isgdtir zKl3EF1Kn~@?P`Hks^*UM!4He42(;$%u@~&F=OIx-uQ?gxkGBW*(u$Un4_peS&jy`v zX=S;~O2tY-C&eJHa`MaS=r5%|Id&#-L%{Y;@AI0SueBYWQa76e)$+GlM!FJLZIG)hhy39X?rA0`hhuSECL&JI&# zp4E!*%;&xUQ;=KD(}8+rOu4)mdTx8%Xs?givd zTl%2W4MuicsUynq56l?rqNcMUN^QW2_wzA@&z^jxkz1N|%kh{b^LU(5TseUXNy1my z6GW~vU53>{L?gb3HHY%*bfA<1{ml>J4lJInwO_?+Ny z2tIaMg?@IvaDV66Qu5Z_2(E(Qf-gNR3WQl-sKR~~{Qx|)u+Z%mN|I56ntIu0?*hIf z>1PoTs+p6l4S!Z^z~mec*$R~0Y&3o%=G0min^hO%cby0?OAVAs)VFWI6gjA9y)fUV zn1EF2N2mIDB$$c@`NRSRcjaLrk(Hzfk zROFc1^|Nm}B~2UyJ+sfk&q8LDjfXkm1eiu&19?L*#^*lf|MvHne48%+tZ#<3T%w{@Z!bXOf2rak-N0mzrXrEcsG3q`ZMY5daK7iOu+CHI=<$lIiujD(ewfpXhu^RpdY1BEkIe zdV_n`xyQ-w`Eaqmu7N(ON3&HkN>}@0*e!S%ryy;1kmexWYC=Bes3(j#V5RN4{VT+- z7@D2WY{cJnjpL^g4xe}1vg53jRYrB^VmSLokr=L8;i1kT&)exreW}}Nd1F~;qPF`m zP3u`r!h?BfdBT!D6)ze?87S{(upoHsox;p}2xZgi54>wJldv)~rbR86bXH4HiC|Yc zlT<6VkL3V$>@e*x0v=8_x`$-(7fo~hq;DGrkvwPK_D5%WQ!vbyLlj~BR!!T1@3n=K zL=mzk6^7?%1BrC)xAL{86|F0WXeHW|T<=$&cphif&Qk(6D9&Z~_@6?VFD>d#sr`+L z5?DEhQmq=2brvyoJgYMy%IsR4Di3R*Rvu8fi`n?PA4|LrN)ZUhWES?}1|qwgHrhRK zS@(WjlHYsx*>%3%Guw1L88iGa?)+$q6$ftPM5$7C-3lJ@Xeb)9s82! z+17R83Qv;n?e>0ks?kQLb+1^{+pTgKhGp_vHi0FKA0-#X+V$)kS!KvuEGtU}OU;Fq z2VGCpr3v7`YZo>Bv2nB`ms-c1tREY!R$CfJG9-47f|K3(tit)uIG*-mJt)#0V<>(q zE_2w;j?1K6L+rvN93Q0GM8qHJelr9&O?`+a5lsl-JFDtFyKDOBlh+Y@q^@Wpww_Xa z7t*B?qYnoqc@jTAdJRrOcueujGqcM<0dUN9BT zZ!`L%8REM&jKQ*jrXVRNPod`q*Bba5k|1EHOz64=YIDDA5{dpm*LsH1Okq-g`NI&( zU=3KPkB#}@76kmc^qdIV$idaD*;Fua^L1p~NM(C{UYw05B8xt(<0u z-eFG9>F~xhr+d&Gu>JW$0e5TfIvo;;#5T9X^hSNPKT^9LHFEU}nv2;PKNkBS zW}Ktk?@spFS(tjaf?KrVLb^px+HNLpdIMN{OxrXM10z?Dv~9Z~i#hw4Jhr?Zw}Y&& zX(!fSv!*IxdtfcEJnx@5DJSX|#=1E1s;~1ZOpM{oL1j{|3 zc14>Xlr5cL!qxkwxP}zy2ZDpn4iWpX>C-7ZUFs#OE|jz-7`-ZvMk28wK%LRu0{22& zJ4(hI6cb&Up(y?+iB$KiK{S}LH)i72{y^UR$@NNU*&4f&{=h?K?`TVu5tHeVy z=n|%b;(6>ZAdD8c(O0+f>eX*N(21m+1$@uB0LOxb`(Ftg*R}f=xrP(SGMJ#+;!_jc? z8+&O=;xdX_-D@^xP@TkO6i>P3(kX)n5eN&X`-jTd4&38-s@s5BKas)_RK;q&#KRl8VVkdW9oD&`+KmC zTrom;?TQO2%M2FgI$Pxoo4B>3byM4lcwQo_MP2;L!f#l6vGpUT2bk?aC$+=D@Ya8h zq{QEm%vn(H!8;#VHpx5>$7Y6VJb!T;CQEe9@mAfLv_h&yA&({qfMU09YqU!%YDf(5 zcs?#9@!#*SOL-nhAlI!l3X+8^$5*R8N&G(NeXgwXnQj|tg-LE=Ttbzw3n9@Z6Uwal zX`1Q8F8de8wPAP}Uo3zZ2{oiDvZ{ieeJh$j$tGD|JU^^ONUtHH;9y!=+M@Bi$cD&; z$CXuoHT(S?d{mg-GhYPLyrF_2K)TdY02#f$JwlpAWNod6zbo9{+Ix+`Zq(m(or5ZV zSm~1pPrqGd`@OoDoAZX-AxC!`5KqJhfTy-;Vf5?)4eP{Qic8i~D&XkVI2=wWt8(6q zF_S29u-X95*hwt8Vbj~A9o^kAvzTQvpDUHt!hjpbLJ#pLp>gIKOO`tRe$_`=S?lfF z=t@qFKkm|?b2#h5)f)*uO!~fNic6lR=l%sc0BuuQ6<_N%svB*|5?#Fiu~uZdJZ*SA ztj8>KGbFP9$zEbS^0$dvi1ZkfPr~E%bQQySd%lAkm$}M$k*06j`q{nue#xDztgtED z?364B$ugp6d$nRwd1rX;7MHl><*R;c7Bx)CreRtA3;zm^dI$h(Iz0ikv3hYSr#Qcc z4@xdE@}*V;1i^!(vsar!;u|pj>$ zYG#g0vihX3ENlq4w^y+d)UaIn5R zSCvNn$h9VJtt>sH#sq&b2L((~!GCx+w>Tclv#GL9=3|9k&4Tic-6l9(wm)bG<2-!{ z!b3TJ1ENW~;MTOQ;%ME#S^TZyx@xx-7ok}Rdm4La~N;)7(-bQN6Q%j;(K zudejj8(I?r9=e6;&QxxjpXns@P|g#%z89XJj_kvohjN8F?F3VZxKGBKvEH3eB!pyl z4ZRMwZy)4q5@um|;p{DsBV}N}c9V?Vf9rwN{u#i1 z(bo35Qz9X$dcU-%aEmY0OtHHdw#>UkD43A5*~e?}j+$24griv>Nx}PYiI&l|Ls7Pb zMk27J^=sLul<(L#!1b_^!d_!wqB=9tS-5^aw3CkEPONOZ78i?~`9k}I|N4a)Zb7|D zTScPhStGLQ-t}oe@l=N7d)x)h6f4y<=~ddz6qpFUM1)F_qlx8K4>$@L~%?GA{SQFMD7WlGX( zbi1Ly$~%Su=5h;FBpt)OWDm69hc45z&&Nw9vXWqJHx%v?Vui)M`hp)eqaZ52-WFoR zj;iCdFt|$T$Jg3WvKP@2_d22ImV+u}Sw&%kUz4TW)hP74pI&|jJMnD>jmQO9p zd@nnFYV1oX@X@~I1LON+=E8+JGQ@cr@X{k;- zeU;#d70*aZWtiFNc3QNxaWo^BPK%;8`(jcs4YT0!*a^MJF)3BwiDfa|S^_29zEtgb8= z_&bNP{o_T;MeQW7gU@x_Fif3Q&2>$a5e&a=pAKFSwm73Dsz(BHcx+L1UodAiVPkDD zHml1mi?rc-i&L$~v7UhuM>Vk;qiV)}agr+}lKxQN1+vS-x{F3;QhDqhCDdYX+Ul3j z^JJ}&ib;IhrTCy{$NQWxFLuVEvAl^(d}B^a8Z;;08#WBVA%OmmXfQfP^_xZ~rDZ?g*$jzoNUqn#EU-Uw7D1;+_vz9GIGbMW z?W^a?_}65m>DRL>S64w-pHfP;u%uk3^%&mFyD5<++&LbEF;6h)J2BmYqo9Ao`C4?j zzr7ZSi7)4(OegLB*rc1F^h=Drqv*;lfr4tBbTRv+q$jV;iBXolN2FJP;`Ad7>)Rjt zL43#u@T)v3Fxl)LQPr?X)jPZMDn)t1P;r)H2kf-3UGSiFpL5bw*=UlRb=;5hzqg0v zi+*rs@R_prIbB`0An`tSy{WMu)|*p@4zw&hi9L@&6K3UY-_T`JOO7<4iiD{`)~=Ow zenA^q5lw}z)2PAVR76-zkB2WAf`W@;S72|?yQ9@eNG6Hk=z$&o4P85cRh7`r7Owh@ zP5+5|K{6vXNc_;6Fi+VlMcfT`V=#;4S-PfSW&_1yLV*5tT?n8Z+2o7{zm_Dm-?wjr z`?AW*O7#-7%KAH@s~hNKU@x!MueaO3QD`#K`N2py5W!iV-$0KM}!nz(KL8r!a;tjAf*kvRUIFHB{bx@~) zb9!F(Ne)~=P4o%zy>0z12Nh}|=vg8eKp=_{?lgTJd$$_}dV1yAj6ksB|9yjx4ZM8 zX{5eb$xlPtn$EURKY0Tl7cfZWI2;2sbFuXG7SD(+jH}6~obUD=>W;Zn?OjBMhr7a)73}Rkt8y?4t2tdRcA)NI{7O z(cM7Ha6R2IX{~SQDv!gd#Rnwk$eXjR7cHYh-c967gTBs40T%FvqXaD?G}(nx14x6s z;gLTnoCJNDW1ZyX#*A4&UDh!dJoD|6ekoy^SfxDEUL%)O{3F!tPqpb-PP6U#^lpQt z?hd&6x6RMQN7rAj25@auOS?Ih^iy9_i1jj#>4A6_6R@~s#AMm{aSRAKY1!Ctq8%>G~euKcdr$75$fC%`9=7HZ`gelcA9nXJg1sY z-MgmZwr%v#J5-a_w`^2S%JVZ~rrQBFE+kZjNEnu$`|Z)T=<$Sjk9(^{`pUyz+TQq_ zSV_sOmdpA)V#l_|N~g~Uibca`;%q-g!=cYNO9qj`6%>)Np!a4wvN@T=$d8rKT6vm` z^rTU~APZb4L&ht@TQ~&61J$O}b_=pqtXfkh;J0(vv)@d44`U=22xQ*YB-1$u~Er_yr(DxZU{@l*Wtgd1W zyKtq*>ACXY`~9PHGjidG@h(pcRe6Y)ddT=;lS90}MHbn2HFi37r`lwp!wbYkw62Xy z+=h2xNJKwV{dwqtqhGp5txYJI4iI3!^5Z{7geMhC^-3YFJ8Fc1C^}FNP}e0WA@)Uz z<}6Cfv#Xf)7eOZP?p}AWUu&|v-!1gi)UyZpgX&YlTY|`CWd1_1m!jg{7R9kS;ZHFq zl^CLD6a}?}3@m^Z>rz{W0N{6I)E)QT|Q@qebByPHSAWgD{*)$N1Z#BqvO)ZC`GDM(2yi>$g0DX(X+ zg)$I30eJGSH$dQWJlQ9DZ-zo*;Hyl|uU8XK?K`X@(`DuAlx`BES}hGvXyqh~Mn3CI zSw%2`k3Y{tA!od(kEf(re_zYT3(x}Id9v9Z0KfXSS?&dPr{u)&2Z@z-?4mc14+@vT zB6xf%dj`s>0ifEJXsY{Aa7eF@oDmuIkw95&67TVcxpdqHH*v~FUNUC zp*zF!q?qLUcxA9r(iz>sFXluo#}g=59i%m$zD8x=w0qmv;w{T{#)n_)bE+E9q;6a` zPK~$J$k{|wNfN@%Iqe$Vr?x5BpP4uzSQ!H{Ae)gDIOzLCks`;lkG8HewtwBeW;~mY zUzIbQU@T`DYiQ{OtP>u-oUm)rMOod9IF3>&fmW&AQt$Dij*nD4p~^fub0e036W`;S z1{3ePuVFnJ@yE%7Di5igA=v3+qj~x^@+rhUtVE}+8p1D+$Ja_zs z$z6n^c;V24ML#E?VbhFnyxv*~b}v} z781^rL~`q20N8!^0`7D|`|T>sB}W2Cc;F*;IWFiq`=B?d^7U6tei3$0d@n2zJ9|)2n!9)AMFL ze1h}KPawmxuG1UDv{=jViTSzcdl-y?5Fy5W$bqIs-V$F~+6oREXi#;=VTMNqd4E@J zHsVW>RsFoO^EuLWmcRI55V zs>r{#2~6waQ>YbZ)hx+d)+5qL=pONKHZ6BHv`avd<5k-c#CQ#>Ayce>0sz(lgjAV5!vO`6jYKT zG7`jcMC5_y^~%N^@I0(3u)(T1sP5>%ue<&YCd9B9Wp{@Y@G{2G5+3JUVrXr|Ut9TN zxD~89(n5c!$prkFVqrZm%5_ZOmg|NSQM>j4I1ajCjfPKGhLvnGoMvS2SKm4NHzerW z_k!&RWfsDhZS@(efAKvCCS3l;wOMilh^9SunFVkt_^VUK3$6qc?-I9z?vj-&w;K^I zdgbq42d>b2ZydE(;3ZXCr`;H8Oa>&Z5hdRcYlM* zXCqW8xK-!iKv}V7p`lx$*}+&NkPe+W{0>w-I%{q7=|X|`odb$88q>-84&g1tn;r`( zL6C#6DiHm z=V~-slRc%I6(n;f(_S0ikHpry+;3zF`1iz6HIp-Ik^M1UuIzk&M)6Vm_&iT-18^ot zZ>X$UG2GiONt@r1cvzS;MDgr|#PGKK5v4QeiW#1O?5JxxmkZr6#p5UruFL|O8&k^V zFpcA|SM`zVH5a`eO4=0i%;A@DWH7Hd)LyQQG=~Xn9KI2N<;Hbqx;YL84V`jPFgDD| zxvvD~`XjPP8jxfYO1Lph7fBjp<`Y|;){R%j<+a)PP3TX@WU#oit_I}vxT`zPgUwBc zdEmM4PZuX+y$s$?-QZ$}3d>6GXJ_xh-J;JMY`LOGPm{$oHf6Z~2!+-Rmt{Bhz)~+c z!)@;9Y9K(l>f~s~wC$}I3J}EZQK*u`#tIORzoY^{f1#b$4KS-2&Nn#^OGd#;!lo(` z-i0IhL1g}!J&H$HvT$(0EKA+B9sh#_VR%A_*iUcg&P<;P2!+)`QBT-QL-q5rEjQNf zh0<+mhRLIsyJ-?|5lMR7TJw5HuSrhQvwLDvU3f&Hh0EYP^qYF(R%U@~1#u9dYY)!>N|NB!RQpb~Vm4%1X6(6ivq=;_q0gCwZ zhfCO+nsw8yTADu-j*u^8rU*6tV0WqQT7} zgb$<|8m`u`r5Rz6kJ(FcW$7`fbG)00qWbMV!$f{NNE+$}g)wur{`1rNN02@*^ckl2T#eFjL+#v`RR1PKZ1Ef zqmN!APG|tVEqa~{C2a96JlSyEVtPfKJ(FWHg*5@rbeRz~cFrh0vu?8OpmpU6Cz7C+ zE^{E1q(jc4qPbvF=M+@5?t4waqz9mOcq5{&Y^%A%1pi)dYyHju14S_3Li3jjGxex! z+JPWL*MffjT-dKS6!u zx46;FSrW~4EE^)SzU4RFX!L{~U0ys9#GM7~d-gSp%Jx?#K43jqa1Hm#mX^_dLz6U$ zo8#@Rr-Ygj@)~+(WIipcB^O5t#JiI0*+SUhLBQM>)^j_6B z!>zEyXCKLPf0c_GPe+n2_~DX|idEpdZ`cGN_ykqEGBk{R_uX*zvR^87aJs)A?5Bk> z>#gMSujC#8x;|&8|1PI7Ue0YYg!P`VzaywBEA*bCe3XjMEW?d`az4;y*M72=DifDt zLfC4q?d^WmnNYP3m4Oo~bl8*-VCiW`pe#x&kl7by77lZk4ZZwbb8nhC+1zza3xWc@?#9BTnT4~pu&HDPRybk&13HS)r6^6ki*pG90)@fQ1wvur8`gSgm=<%{xaoaxJxbrG z{YCM6R{_bt6*;DKU~4#e%_ph(R`Os=BLa|OM4#)0U}L17X-umbamo>Ubmb4NSCL)d zeDlnv`2H=x0W>H8GIV}pa3PKQ1bP;`&&kMq`M&3disEZt&Z*{MJ|BPUlE3>`MF0Se zbB|aj_4jWw|B>UQ1Oe}UP;8M}GLQ_i+D{RhxR5?+I`~aoFe3zr$6 zA^PW574V6zwpXX*J<=Epf-SwE^pHg?oq$_>ttO;a)cF(iMrt(cPLk?K5th6m_HTI> zPBdV8kus%(;Q!TY*^_r|@27z>yZ^72%2WstS>aYItC9cjouOo)vi~0xDUgKWet+CO z$cvR`Qqgi!BL4$P@(pkbW4teC1{>Zl=Ue4Mot+==9yc2vm&ttZk0f#&?&N;%6byi_ z>ITS?C97z=P#qf))m%WYilVjfU;{vRZGk7}88_JY&}B5y^f18z`tTRyQkc!SE6vcMcF2HYSnN z&>Z`53L&2;NL7FZAnACqGPC=}2axroemhKK?o+X&I|rm%%1M8D=P_YSEyDsJRkLFl z@y$#OggMr+pPWIr3q*#OAxR+O6*YSXpr1}dw4(6r*?|~Klu1q-kX_Zf{LSPMTM8fW z^Ga^aNYI}L6CDp9Ro%G&8PJs`qkyq@Z(wn0n@HzcZE?MuS0ULgaoh#ufPf;w%3?Pm zc~X3XdLuDe0e4YO6klnYo+pZ*1UX7N`{OK_fy{!22I0~eukrTFNtY>DUgv%p}_Zi(Y!mEA4T1sJ`k#tY6H@u?eX?XuZFYU z56=&mmz}-r8?FX9KXa^C8f|QP0j<|{a8E|X_*#(XQ^+bl0OOAnrmC;Ce%bk9T^l@&E%^ZiOREt-N1^AmgQ&*-N_+tM zQB@8GMWUzP9ENp@SwXdCm+?63A`2XCT~xCD$k%h8F#$><*OM*_)5WJ^O32MfSe}#p}0yF$P=uUpq!*v%YrIih}!M|0MZf6GiZTrap`i^1= zo4SaQJ=Y@d+Ca*9GJ|Ivn$T0X6vYZuWMaC)5`eSb8bIoC@{w6`T=lSA?V!pAl*JiC z%TZ3p;;_7NgK5>ewfq|(?^I_lB{TaTFVo`ZJn#dG;myRXqWORc_)evQb>53Ix|B7n z_W6*KvL$v10I>u(0yzh_=-u8L8OVwajs1JJRs*1RT&4+OP}?hGvLTvksi9GbB=${a zQd2mLBpnXw_W*JtJen@+f2DO=KyEstjIhdEczvXO{pygIVa1-%WzCLuBqaGqnBd88 zRuLb-O&nvq+k)omUaeLeh-QA%j@-&D>T`w0cZ{N-`jP#oubHx>kxg3-?(?9BFrS&I zDYb|sk`nR}ApR*o3};&@DseqwwWS@=DNPo$3Y`uN7&rdCjfRv0%2c!;jAPlZtfqC? zy4J`)C(OfGpgfZ?di`54?jgw_qWUSt9TF>d~nd}&U{ zGyN5@K>wZIkXgr>Zr`eHKY;nk4vbdSUlr4x@+=`^Z4)3SOa{o`$(pD|2KxmNpz|*i zT$f3}j2y1;hXv#Q(}x=F$zS%~;rZy_Xz(V&6OPZd@NA^jFDN2II#mK;*fr61J0rn{ z1PG3TmI0xp#vb%(Y4y7}r=z4rM!^mvi>N=~VSj0EaryJEQ88rDRi>3TChAy$!*~4zo}#wMBt? z<5HMVFbk);8KRLhi>iAC$S!sVAt9QVGthvbd&@HE_R zY5FNCCK-Ml7iOlF#!B1amsHI+aa}a^LIqt><>t-{^;ZEff|ZEqG&daQLCvDPex%@c zcl$8;u1P&jo^o5T5m6NwY|uR(cv$)QoGng*`P6(Mh@#f~6=K+*KD*u^Bz8cBTBWUo z6^K~4)hN@6^aoZ^eMR?V#Y8|0LXF-I{Rbza&(@bl?g zRX?QmkFfi$7JOsYT~%^?Zr3U|Ks$r5kfwW!|NKx|RuiIC7|i;0KMgC5QNOJx;-Z(B z7UHWaU*9H%hNYa-(@1`}#}A}a3P#wc^Ty3UchTgj>8>Ei_n(OPeZX)}y=Sih6ucc3 zAl@s2YCI_^O=&vCs6vF>7KtRV8t=>9m?}P>&K1om|6Jt+cJeua@=wsFepC-l?HChO z?Ix~Gn_bmXc4uwTqX z0^X&2;Vf*R5pWE5QS0$M`nde-oho|IFp>tHx|woNJ^ym~d}k8SqXAg`{V!n;;`p!Y zKoGkC_Vu2)Ka8^>d)a=JR^qkT=OL+Jy{O^UG*@>X1q|%o@(t>EIwPxGBo#6hwJJSL6yb!-c3zr-w;CB3X;@F;PsHG+G)UF>>2jEb=G zke{Cu*AbGWY5>PVmB+5Evv@!-8!P;(Do~yvb%@VQk!QJ=BBl$Vv5tb}QirZo9b~P~ zKb1|3<)UB{Sn%XCMoMJQ5)=85+VKK%i7QXX63&m3F6;8al2%b$@f1aeQ1EG!Kj*F$Tag&>e*pg@Rs z1#zzZZu?Z_mOYg;GUs_^^pad1|(<7y@YWFuX$?G9MJku|?Kb64+FvlOyaU4R0{~94$TkP8h-`Lvg*!@zC$-x|V~7+osv`t>%`xBxM!Sdc z>ShesCaV8o$3D7JDPtI<24rHRl@GxG-i>)@$_ zGZyRnr*J`d%cW(UxI_2qxt2Z@i6vIqE1Ch;Gf5&E&K_bKOrOYJRW^NB6`gQ4@Xa7%E5teDVxT=RYgDnV5kv|XYEP-C-dW3XJ0BGfS^U1N!` z&r64(wV9NKNqjcQS{Qd~<2Q4}-~Hf-%T|-o#$ZN*#wx77t1;@sYbPc5G6!*M0*KRZ z>f@~}5HrJW%(d$a?HHSGpg{SI8C4Rtvr>{0Cb*n20HN7M z3EcA1*JGs{=56_LeeXeX+laB2?wDOO7;=wW%vZwe_JdZE9EU8~vcCE?z}6lVaUI`c z&wb61D6>eIh)C7?z%$?79SAQixp*5&Lv3SDTJClKT2?Hw!LUkge2T9VFH`DPK{c2$ z0i8j?9ctS9Crx(%ua+%o9?4uHv|)iKv#5JSVy#3Q9% z57Rb&a3xK~a>h~|h^O40*=h}Pl%bMBOAW0lmy8|IrlC_d{k*4+kYuuw*o|%uWb|Qt zup}05C1BM+a$p5Jj1sP3sa2Ff;-&H9{iX4TL_^nA9*NPVL}7iumzgHd@o+qawnySGPm?*M$0N~SY>MVI^S+!;d_tWxiK#o@yMR^oaFNziRH8AIl zoI; zFd0lBSRIaxOO6nQeQ3q_kyG5}&2HT&Mo1{{%fn?ebuAL}xqk_*i-|)xCcn!RCa8VB z_}VBgioEgWqMqO_x7D|) z3X?;N@sn=D&kBBsDSFX+aHmh|($+`z!yP0_6V6)+~& z&nyuCjVtb`bLXR<1_~CI0yHuc8T91uzusMbk7pmrR)Eh&w;PsJ4-H@Z=Tcqdx!dyc zrzeP7+)90+?U5#@!Dc7~^BP?x>F1{S1T6{Mc*MzLtNHmA#c8!*uE-#|6AzHG`n5st zQZ3(_t+$(?vtYZ@#$Qf&aGHw;Ro>^TJZzOHQSYRKVmE}u-Ffi><;_&Pz1?2H@*{rU zAwGy9*a}f-l{l~OL#w19qQ;c#eN^l=*&8k=K&+_Fyb#R^dcH5qA+u0ivxZ6qPmk#z zw%3e#o+OS`^LqGshjXXFV)ts(gDi@Ne1hO#{%raGvG>+*QGMO}xF8BhgCGr(igb6U zw9=hJgGeadAd=FZB1m^hBi-GNba(UJm=%sFT8z1CjqUiZ4s zBlv~V7c7_|J+%ooIf>$NjPc3@zrIB(C(>Tq&Nz4HGT>+o)u~~FZU*J09{%E-l&cT| zNa>N|)pH+G4Eu|V<;)-fMOBpf&>Om3$2&{Ctoo-+%SC2dfG+dJR(x(yTxaDIcZMO| zmJ8k4X7J}{6HITYbFID*9lh6Y-K+6tfuv;;LJZ2aKmz6-#oXEM^ zBO(DUf;g>a&V|F$6HWColWAZ91B*82E0kNqfaPe@`*r&m28MK_bUEv=9sAp;M@^D|eM*I6a`vE@WvqdNAt?mi}eAT2QpPIF2+eDGvvC?b~BpljxRdF>PwBOeV zBoLw%Ee6V53y;vLjHSPqwiSWFHRtJu94sVGLx|lkmWaozm(U)fqemS!7^+BZ%djV* zg$%o;blY~7YF*Kb^~pe@Rc1?H#!=jrbsDNH@b!7jlCy>#Xno?&(k{Y7UN?VN^Kf20 zN`2(>p98HB*IOF$exxf`w*AU#6r(}azKueVVC~2kr>iTcF*R8uPH3DhzP7(dUQ14| z1Uu&GQa|SkvQI^T?GZ&TNrOQC=Bsr*DS26YLs?A?_@L5B4w?JnN{sC)d#eoGC8kOC zEWo5mAJ=Fd_G{D3f9p#*NShS=ZrZfi{lRub2H_b|YXW;UW1g)wXa1!pCzwYmK%B}5l0!q<8s&<@I>NG@?4j<)H2EX6C%l@Ud zp&~N;ymUN1b2+G1r*Q7m6D-F$w{?B(5`5Ldy67!_>)MYtLpaN~O$kccsxOjxefVC8 zNit=8R>9OBN_`do~T2JzwBnuSSKHHhdA$+%{hV1hPF;cii{JD!?M(Q3Et zcjKBP$vmy8mTIM=KfHmcO`7F^7kUBQ!IjRqiXOo~%Fd(fp;w=CJBtFjhsXhGSU(la47q7RrBRYEe$R zLA~>Vi@t(ZmDnu$mF63qgZ~&lWO`E)G052K6g1ogXhLuG?!rzR$JlXYyb|kmHn=^S;bgp~+rf_deewdur+aLxBM@JtU+q))bdq({=6OMjn-uZfN0{8pY z@h!~;r=t-hr!LJI1v}OAFt;u3~)U z&|+22!n9p-^XNs{i?a6U)wsWh<}9AE3DGN}@FO5*;N;6O8hWBWQF>3)hp*DjT}kCR z9o^5{B*TI)o6{nMf`CeH%P6bUzZnC|_$p1M9y5sl{H|iAxwnyKS*)Kw_gWChE#@z=i^@1MEc}t9| z;9*m3-_}6)5^J92(O08QL+z`Z=IVtS-=bsGah!U$e#Cx5HjwN%GaTIaroxJ8ZTkNC zRpsz7r2xJMj`4VP1aaA&KTdtfn*w@-h}@%uD7@Qs>BUAJi-t|cGdMU#oIF_cX8kGlZqh|QnO3l|mhxjmk<5SWygLPo)T6`FKgpuUumdGbhNGj{F7}v+lt>RfZn|3`#GU zno#vI_i19_n;)4_+R_Cvlc$(#sVpc|(T-Irjzv+^TjU_?Xquf(ITr3DGm{2>A#XGQ?2i-cBpjjj!0TGJ|H{U~i#t&}`j`o#L{(Q1}fYW|yY5Nk&dzqZr8mbNCLk>y2>Bmr^5Wr-}&v5w2GvC)Dk0Wpn< z!8EUmRP)EO4Kz>SLCrnh(OCbK7s|g(xiE0QTV%Hb-xl z3VU?N^lwNYa66mGGd^Oc`v6g3Hwl#?*+wOilKx8zfS_XJQ-#H^B+ElRJqps^rHAP% zhVZC_8=8|S$3YfQ?oYj+gSbMVifYgm?K!U*{}Df=P5SuzcDa3}YSFXHIO87}**ALp zZBO5-Q84Z)OFhW7Z)BSaCFB~GpRah3{LAiFp<4{!`ptm;@x11cq6F?-v6-c{ z3YB%>UFk+%_b~iUO{6s+C%gSjW4Y1>ys*R&^UM(Tqs9*FS@o!?kfP~h^9E>MG8RKl zTPOFr+AW9Cqi)<8c#lfr>&~bWaWT5cjALJnvLO1}7sCR<-CCegQvB>QD?H&l&(rl# zDgjWGp=&Wvy-h#rRM+7`^1+2>atPC6vEu`k8ZBx9iJ4TjL+D~(* zD=DqII;h{S^aUm9V!9f1+~L`aSX-AJ#-b~1k&ofoP*JF_0q(t0P zC*#Y@sJR%Nw7Y;DxW3s3eg>u7SQ>sIEO>TuSkF!qF$&|%Vq&lDcD5QV{Lx$H(^!8x5%K}4XocJTz?3MdZgs?eY z4UV2RH$3%o(MJ=Jd}Mrh%Ev1<80zsz8se5W!MwE|lf37k*}5_jTIxE6Uf6zx}{)y{>*J>^nSl ze(W$P1n!syoR$hnimWz%Iz}rXTbHdUCqC!qQK}riPY33cJV?{Mgkl3w zrzMJoXFN^hdiPyQ8w;p?l-V0iUuivyMQTyXb>YxCCrped*BzcZ9mGM!XYIu58BfWl zI|4Z9ZnERFS&F@|TgpdOANrnkbI_Da?!jR6TYY}1`DlTpBa11@*k%@cykiS8fBRIvPI!Epmcds;Eg_0?u zL3G|KH#aQ0eIz$t7DHf1pXPy9{>_w}-Y{$FN#mU3%+!sr!l;~{(hd5Rw?kN1VhmC* z=-Aaj^L|oXGaYtC*dmp%;|Ht+Biv3{>MPCr}E?d zm#2^PMd1;Q)?VatrcbQIlxXN<2CB|jo5Dmy-TM<*9~jxsnqZ%~dZ+eknV+2D#v<`{ zY*t5!-tD8+sp?-M{-^|q=*QB28rp>3d6A*w7kH#1{Gz}5?Pf+ny>3487s{7iVN7d{ zxN-;IgNh5BQH{9XTrFGQE-=g*>r%HSUnG8h8T)`{OX-l2{Pw6Y==SqxMWaK@4rA>; z4pupQb=T|VubB!fKWI`XV@*`gI#NTDQZ@yMz=ar4}(6E{@ew{ zZfsra-u6!MA(c2=9-f3}irMAHSb3$*tA@9ziRmNN&96t#czfHs#2XzUFI2vAIk#Ar zuAx1A6rF_Ic4(yg9Wx!XjPykn?s`eHV(cd@qRtlqiXDKsI1*Wr;eLhS)BK2a1D^P! z-V}yfNL9jB@3PadYqi7_Qf~~RF@}TWxk`}T6j}RKTbX9RaT^kgYMkr{cL&Bk>iiE1 zdTTtU_j#upp?+7bJa|cgg_U#fdZNGHY(y0R(lg}%cenRB?lfA4%D%YOz{-2C^=gL& zGK?D184{;bvl{Bhq_4LyFMZH`V2Da?aB<34HB<($A&WzWo9BYZ&n=Sqf>&F+YGo5A zu;e(?DbOyy_$Cr?$`YAfm`|gIWX>wm@=YIo-tyqGG2YKwdSg|?_`vI`wM@55IZ|b~ zl=8I5sfa2JUjpQ$Aq;yMR;jqDWv5>Ifok8wu*;{J|CmB+d=RwQj=)TEf;eBVsCFy2 zWXn56BS4UV;uQ*>b~3tW2|<2lE57JXB(6!3s1j2zUr=|PS6efXMw!=mF+$eriBu?I zr3~Y-Uw0fD@=z1Li8CC*jMCOr>sM$o{WU1^@9OMB_UKR-X~}+vhr1;&ev$tBrfR zb#Zq6V<@FAhbr~m$XY&W)XpuS?7oc((wt{?Adz{?od~(PIIN`m=@L+hu4(eqEoSzj z^kd-x-yl1-CSy&~V7uNmI__~qXh~u@Usz9pm|#tKd8oIo(ugD63Mgqb1%4cA@Q+r# zRpwTK;@*Rm&|jBzzyGGW_x4gl);F#>eJihSu$&&Nez|VCJ5UH^;)7gd|!82hZchV>2^4 z?d}zg{Zv!4|A)s?45x>yfRd<>F8@e+`6aPeOlx#o54oKvkjM}mm9=tWJkDI}AjtKk zMgEKW^Z-#wXtDcMQF*%YOSDH_G@RpPFZ{YR6d?E%i|9=a$_i}$SUutWL@5z}YZVFF zVTGUOiX*?)KrnzSsL>x4+I%T9E=0)`6e1x=&;bhE&4tERb(p21fAfYY!jqsJBI@D<3zEDvKX;NM5KJOQic|Mi;|qakzO%jbXb$NrRX z^5P~1Z4Rh3f$D#9mi|8Ol>wT`)ywhq-T!8P{rM&h6{N-aKCcaM{w62=b;J~!7Z!-e zk^D1Jf1D`iA)q2{r$xkx{rkuZd=NSR-|hV0?EK$i`+wVx)i!BZFBy;!6GALE8~K*T zWmpMJZp+Ve-RU$!c`fp{CmyxBDs)2r)G(Mi0nO~WHAh^Oe_Qxp zZ-90iOJv{|CgAo2alM>z`H*@zih#1uXvzbVUGssYm(V{HBnGCvCKPS^&%ZY{f`4z9 z@Pd;hrT20su*^)bm`%tM__u+R!lXX%lOlQa4~z6~hq4SDBVO#&TX3?!h28#ma{Hx)BDw<@aO{RtTXAR`Hy+268W-vP^@tJr0CWKPc=#Rl6FH zGt1O%+pzlpcTMYkn84pB{wxNDs$|Qj2KYl$GFZd*U?$L0%rYX&k-RyW?qfDln7lch z6@f_$dH+<9qnqbCa_Mswg40Q+I zTu@b^!nzlO07tR_j3qWGDPLDXG+qKwD*%bs5Rf42XM5%VY2j5J&`sK_$!>!V!!VYo zV~aNuz1o=#xC7Z#K_TJyo&}`X&6Z!On%t<~W*Q1YFGo^-5fF(v0E;p+L@(9tj0v=& z#9|jeMkO?*N_9Ot!Fa|>;kydeDBEy%*?_aIoPs>|KI!9FuvFGyqDif4wOogC#sD?5 ztS-{v25foC=$;8Yj}yCVUZ3~)^{o(3?*oCk$=_0PfF8*V?Y5jUVr+8UDd|W6eI7mM z>!`&Aplj>yv`&t($^Q&0*~A8zS5`V*jPsA74R>CzV#NT*`2{^pPIWF1P!_YwHU#aR zRWxbN+F_szIjsh0l=OlUiZufrV9tH}us;v+L19;5SOYxZs+J9Wi+p`l&cz2Vw_yGm zK_btFK3q9%{%QoESsrV4;FegR+#;^!PvpIzW6TQBlX%NO$#D7|`W_UZ1Zo&WEIqVk zam0MiYWk{vvrt|SG9L5KV8B#@vQi!0$d|opt)l=#uGLitv*j4<^Ghy#CxaqZmkRVb zRgdQYqtFl#^=$lhpgL)}oh@ib4^Gu`;GuohkZH4QHi4T1pPG$~AWI3um3g~yWqkxq>wgcuL0%aZ2D=H6EHIAgJK%@gL zxB5lvU!2#n)d=YXz_pU9KL8Bta2S|!jE|{H2Zbmk{Ie-g6+H-0OetCa*ch}rxOM}m z1MJeKBHdi5#nG9qE)HUX;(?n`10ltRG27w2mBtprg2!y`H=!mX-v^5TIqP}mY=eMt zK?jJ=o6$xZ++4Qhl}v6e7Ci3jNmSq@T(regZY@gXMg*P-^~^6=|Jc2;NI(rGE1$Y1 z^Yok7HBI;9-MqLo`#}w)pAsj&$r2D)Z+*``6E(H7iB0-(iKRa@kF_)?{}%b=;tq{_ zgY^CiKt0P{!I{*sH6F6Z3}tZh4inlF%iMeNK+BMwKmO67Xp{94{G|%}0VfE@H3Z0f zuiV8J&yIgaeuOKxerKsPfoz3OM2h2`EG+XPkK6c`1gQ0|jL7inAXxE$Q zi}JgMn>02#>MY5Y-5YtS*--;%1(mHQ9z*m_BXsUVCKA+CG8y^1Fnes81 zXYQdj?D+tAsLsr3kYj2eUv?6*xS0j!gY^#8@4W|Vp#Yna$Hd5~s?4<2JQN)h9{>hw zhA^t>6Zm)4QOX#E z_x##P3Bs>W<#V$E<^x%1M1=(t<$lM;QI}$v#?Y@f0v0z3zC5U&-?(l_k)sy-m5d!7 z#RYrvyKs*CWWo@Ce+gO+z@EqklambPPv2ch=0|#Ue?`z-13+x)6dt3VXDS^Ae*sNi zusgv`vwkwlsNzViajf=uZZ5QqNnE^UcUmk2$*E?iw5J!)t*ySY7z2ldPP`o^=4Q`q-JV>=rGYREdLzwU1smhIgE{vyGwN=bm4y7pK=M0kFlYN>w zQEyY{Q`3W)kxNVVnE@TV!N`))v?QE>gNbsZzxiNv z(YUxPcf3b0k`0-H$c@~`R2*{O3pN!CE}(k%_=2@mr%e{$Pb zLuD>H^S{oQN+81uz4Nt$Z$f|UGAk^IeX8uzXflv;Hiw4FzC<-$DuT-O^QuD+3pu!1 zpN@iXn#j`S>6(U}C(1)J^FI8C=IBj_b6%%fM2yG;dLmrj#*Pz_D-At3jhhKRfYOzi znWFw0w7hs@dR7Pozi%Z)7H?VtTrPQX3zwY$f<}F{b_evc(R8du?%sFp4#k`s+`)CN z%{g+6vRWS=2_aZs1q?akmIjvc=Cr(67NmaEVydB9=!&ZzP(p?~SAAu#Y5UJE||1b$oGL0RsSe_1!1^2M!u7a`mp`pQ+o^P*1vk>Xd zhrGS~vVP`LoS|nqj6Q+vT%41mfWhn|pziWrNE4a;l7mdnoUh5>QqNO1hHY|6Lfw$~ zOPN&cNEBCRr6p|LlmZCd*p(bg8NmuY6(%*^L=&c@4aoHwq_B9mBcEd_>?cW-pOgC* zMrn*gJ6#HyC8tVFVpr`spK6o0!ml;>7V^Ek!K@AdRR?_YK@E0HNke@+HksCn{K|KO zF#t7_yUMkBO85ffA+AcnHXy&9n5ZfetGPQQzZ#@5nGL8=qYER(m`}!YTv_4*@zyp* zlM4#W5uh=bUrz}C0-ix2tXJV3I>Ih>3{F$?Yc^KqpPxc*QBW|{avW!b)!N4$(`WS} zL(+O1o$>X8G}lOHnA_G19+QLUq?snF4MdDNXs~KL2-p+Xdp`zp4FXGuc;4sNfOSfv z`cA>aj~knt4Qwni&D_Ke1~r2z2J9H9-c-J9OgV-VZIeMv_d>UbsGIt?1J$-G!MJlJ zTk;0D9UE>4Ee1q`x#G{@geyapefiinM3>W^|iy)2z=>;2QP)P(Jg#OH-o?7j+DfPtM&@(J;wE}bM!5C ze?1m7r2aFQX&iS51l&)7+$L{keTyFUyh*RCo7jTmlDPDV&e?K@LdJw6`DVR0LJ z63?XXlr%QgDK6XODyrI}<2UjTEv32%X{kLp5MeIWhM}RmAPwxW%+>hz8?nKkUZZ4r zJqiP2o#jSG z_g57gec}aKO<&1G)wtFVMTUv!@zKQ-qiDRj%955s!m%lyJ=|`zZKzYwH~W zNMO+LsY$iP5Ox#e?iZXpMwUfceq;eRve0WA> z6ULt18Vlk-GUXm;-dq$He9BKfF`D}}PtRp=joFutP?myQcWA^QD}VO%?B|0xD^=rf zY~`}PBq%{vul2g{$G@NAhnixEDO73_ba5*rR^pN$-$GINvjp7xk_l1Lb0e#qkXKUi znUgV3V+1fU-fc4}HmMwGk+7R+BBDlur0s=#+B|;UQP%feZP!k*g3uaK-1dzLnpo^{3 z(s)e1Zo@Vj@`{*JAV8~B7Fu5i!lehr3t0pl+#U#dsL4D#+27oab|dTAKzkM%)s3>} z=rwxWP|4c~kg^asf~KVrY2I(7X|A?^g=S)ik+>h<_TxUl>>0kZ(JG<<+xvIzAC8pz zto%EaLG{E-%c$(>x1$Hn!GQk#K(invt=wM}|xVgFOjE z?d3%E?VZk1t&c}1w|nQ(xOb??jA+R+Vu|hE4Dvmz~ZRfcHB4Gx>9qkVR zgY>xoy8V~z7XtcACkZ(_)5WEGiVT+>IXCIF;ET1%&y@!bg5=`2NiV!#hU&{Siz}&H zX`z#8!^?GIwHQ8b!Jb@_clx|U&Vf6Cg=y+vnTgjOS3LdJB>>`k6lE23^U-J<4eg<{ zGaAdM4Do%mhQJDyZ4PsE$x5_CBMW2#Vhto*&X$z2xR;_ywa<)ao2e)&ff~cbr4XUP z(&&KAf$u|0A+j43*el)@HMGLM#`u_aC1`~R9*(kAz1$i_#m;~T{w9QT6bjt~4t`3BCVaDA z{5+Nw@{e=cEp$!490v>6bv?vWkj53qr06$Ez^R4w3$zU4o>l+6`;y_bq|5LDmfYe+ z075ZcC5zDfmuHGg41ut}TDY&k-%ZKGyO(_Uif=6PAPQx?RzDtphGKI*0zV!(Vyfbr zYNrv8 zAB_|I&mS2av}=sD%RmOZoXyF%yF+q1AKM&qAg;bno1aE~5?RBK8k_`&pD0+*_Ax}8 zfR+ex6wM1_%9D^De0uy-Z2jq0$z;(H=#Z_@41!8Jt7tody0>{cDn1d?ez>3`+*ZME z8e_cn919huDL3rt_#&J3qmm{H1%*E+2G3B z_7@`b2WCs^_4qm1^n_?4+W!3D@8ez?P)J*PS|;e<7&N{wz-JzRm&Eb;_Yrfcv=C}~ zS??YzH^l@!WRd@Yb`%(44fl9CZ9}K2P?z9v?Pd!58K7W1D}fitKW7<^05Rj%E(Hn@ z33B~8jy+>c`(O+DNb{5PHk>KLG|GJ85O z9QiM#4Q$;{sov@vlK%JQ0#wWz97z0er~W@(#gb6$jK&gK^uKRJ5Vj90ZDThfAT9sz zBj3T&lllLj6xLwI%RBg$z8Jm_j7YSl!RpR6%6)I;!)WaLi0x)yLMkfQnE?jkkbWH4 zdkZ>z*ZN9q@CJ^bq^d%~|GE7m(gToPBmgLak9BMJ!)z<vrN=?1b*E$kX6=-t9THmpA$6{oPsBf79g;Hj z8_5EYRxfV|ExGHjv5CGM#mv3|EGl2|AAOZPiBoG@lfkab-v_U&5%izBA6b*u+DvuO z*7VXqI_q1>k6Q@9r1nWHR?h4*A2U=(#XF6Mt^r`ml>Y%O6IjKqSRXHcsrEX~>_Z@1 zjE!at9=qRCTWPC1OV>(!is)bHnCgC3Q*%~(A0MrvJ;2M) ztReaOGftVyK;uCK=-O!OJ09SN=s4dYmaU-HM~c6FaW73<5_fr(Xw!>w|AUQHmnPV8 zgRv|gJOe`b*2uv&rDna{45;qXs*81f1ZK7s*934HbM^%T%@Iv*H4?X*z{|S;l3pMS z^|pi3U>s_1X_PRg0R7newx)u|c`XE?TuRG4ZN5P3yMrgvfArdgDZt}lRwHk#%yFDL zWZM+TcEob}1u@jL5IU|NKE4$jdzE<5!vN_V#DHYVRwp-@J^Mq@G-Y!}5%j~3K z-m?S7685i z6Vr`P_lrDxCFj>C^Hk@qIsykzj(1~8;@BqC*v`x2pswZ+F~7{6!|wheTA~Qr{6Oz$ zgWDlXFX3-c{0S^Nl?MilC4D?PmtJGNWg>^w4@Y;I3FNvVfq|=4fKygXTP(QU`&@2j zuX>ZfNt}G*nELq8?xrLl_GGEud+T;llVh6&~#Ek%P}f1&-d#i56@+HUQs*% zvS(yKzci5D4@fW(=c7iu##r02V_-I1z&Bx^DbJfSJWsYfW6XWOt}S9TH_yqk&uf?H zFrnUKzu=1HvcD$e)0cVQfNt2)U==EG$jWjov)h**u%pXF%d2O!_Vq1LxV9_~jfZS~ z@55HrvG|top2n_U{kGSBq#~$}V?C*iU?WY}V}%ZKa?J4B@HkK1F+QuepXZdxu9rVi zR`Xte&3^HeBR;mH&iuHs^=xLVpmQaI47aGbrF0FX=}c(+CplC3niH6fG&0sza}?<; zays3%!~%EZcEFh8s}`IlWH@%qAuA!{9B!3~6gk3f7lG6g@#JBgIbSUe7o0Vff&vm% zv)rdE65DA3#15HAuHsn>Z0Nxu&Pektmunr5P)tH z<@8?X3nVu5n*vSwb;F+_KRn>eSS8R2534*D>U%*xXgcFRUth^Sm{z^g|J)Js=Jx2f zFohU3qw`77T81=z6&88`iLq{g2IAry9(n53^2Tv?Tb? z-R7(McFOw9RkUoK?0)LQzh1E8w!6Yx??PVokPhnS+;(M2yqHqF3Ipw zco_op)BB8&BbYTWJBp4pYIYhlgi+KeSNyuKdAV-LGNwrp&wSAJr+!53N|4~;Q9 zM93uTO&)1!EdUqVH=8k!=U@ZWs&>F#e>aq^Wv` zKFs*}eo2C4=Exu_@7`E7-Yh$De4gPPtt=Fs%I3%I9;W`$*o01%FbTIC5?!_D<=M=> z!7s|sED%DTqPj|B@Ti%f1crv2;n|NP1(mj9D{#>Wqw+;o&KE5dd;9hKLY1>4GAtq5 z;i0AJH|J=LBcy~$-w?4wFwO;5pFP{^-)}f?;5yq_rc*j+=>oAkGwd^6Zb9zXEQwam zXN;zqW6gS#ajH5jKXyxf>PPoiS59z#YlJ9#fGZ9*9klu|?V5>Z*QXpiZ70L1_huO_ zo>tARBD#RFW-Mk-x;x-5m78|y3AYTP{la^m`y=VnHO%cE34ZR`XFF%p>!fz46&x4t z@4Wek`>JNGbqM)}=S3P7=jzFlTKYKlc~#=H40l8Ns;d^pX3h{`E^y-Y@J>ftAz9Jf ziEYnx%UAiS?6m@zL%U76@PPz|U_$jhbtPWk$&XV`=GvF`2{!2c>)e96*UeU zTs#fu@07g+Mf|TAmPOw4OX2#a7Q5Wa33Pn(IPkhoC=&1($UPvo8-2b8YHZ9BL~a=* zr{9;+P+%cT4cF#%A&t_p{UyO`C-aULJqRs?zRC_h##9gFl=WBE#9HCG3>~pq@+P!h zYWfypQyVO-fBfS1sff_uV^P1Zm0u8{uwl+~?U04Eprt14H{K0eGO)yxNU5W7?QGyQ z6NgWYNz-#{-nc_rn_9V;ug*b5r|O^w32eF*)WwV5M18q=_Dl<%i&1%ZCzbYUq>=`n zmUu%AX;2j%AR;@Wt_8S#$^cq=L z-*KxPBVGDmU#=ro%JNHGb$^f+K$b>by!#^LW*YCug{wHKE|s$-ED{_FS4yft(`Srf zNQ#V03ys#yo@ikTKW1;7KaVvaBbi8Tci}33jX$R1rqhN9o;f4yk#N zwyswG!0jg8f9SB=2502`a66bgQ`+BjApRXo=pYIjJCs=y%P=byv_(QsR#?vVfCT?xIoDRFkL*B!vzo_60HwjhqMF`(sEkVE3aPh04*G;^31HXPA zESMb-=MM{a`W08ltFhV>6$!HE zzMHo_-Y&|E-6=_CO;adn${`S+fM7UqIp7k$BT@ole24WpcoMcBZjS+OOzHtU)BRwq zIRnM}wC^E(;~=VU`mT^>rCaJvh}$n+;cvgQn@9w~WL;(LbePJ|rjU&$w`b~&pWG9+ zNs);idZo^WpOzvowr|6CQV6+B1o7>Un(2F>P+bYBMV!R#SRdq_zX&cGFIIpN+<`GIIc8L+ek}p3j?t+dCn~P%YW+3dJojZEEK=tkZzy*DYrnx;tn7%PM6Ceh-dX)`xhh)2YJ1C#fe`yy1T3@&#WpM&97gtqlmR-auaam6;=VEA77Hor3d;tn@rASQ~o2PQSqBT9H*R`=54hBiu(B6`iboG2Xr?A5~O04de9o^m8nHm7~lTC~TOf zp;QdJe>d!XxcEsYkopd!)-Pyb)Dry}o$_)v7)m>Z*;9E=;=kT$OvO<>dm`2#t~iw>2)J3jUe~ zhhlx7(m$wKl$^ode-RXid#}r)F3UfrbX<|KmK&7G#$QJP8rJlC+JaovNCMSWEHjyo z0<$$fPSgpZCw-W&fs#hdiCu1_7Dy_4-l1q+fD(&6L)VHtcV8W)zjv+FO7@J+&pv6< z(KBY`tsKpFUZHCTB536Tb3-ikVJlDW69$RjjWtE^G45kY8x?;GvXU*P#)3X^@D`(~ zQhJhjV?I4H-_r1aCI?^FBg-K4&y-Bnv`)TKz}shufCxRnVM3N;p`AnPAzet#T7t;q zi-2p7$#1O=jJ1>X5;i_lz2u?X&GZs2xAd>%rb`W{jH&UMucemxH=|f?wBdm3mUx(m zYxonFau#em%;>(yLREA6Ir-s3YdEDERT6mU$0y&O*qt#%4FcC(?J| zVpCPSp>L*y#ZKF>$VTfwub<7A^<~reY|4dW#B9m0ccN78$XyX7QD{_40-4Ct=VZ?;|?V;xyIGOu^b{^p*X(_Qd;1EE-`YV{$E{w?tbTr8Bo#fk zGVYC+v0HDB@LO8WHdr7SJ!8@+GMfrfQ6E2u-Vqm+fE~jG_{dLw<2@Z?#du`_XC;qf znyXJcQ`Prg5^?&a2YBQ(?--GNhSDG1X%iMKogfIcdOY zxjDMY7f&YrZsR9Y=ez<>r^r6P_!MX`D2e+s8XX&P(>k1g;X1X4)+M%VJq3`{duq;a z7S_2;EFg|+Rb^$za&?hgcal%P6zbz4BP;u5T-+cP#W5bhZ|j`T*#+3SW@}7qltBvW zF3-@N(M#L>xqxH8cvQJosO3XQBAX32JAMDxLF z0*;CEPA3M~XjB2oJA^Dsr;fckW3S$^yyW`oW#=83(NmWeGG$!Kr9abFiiWZGG+&zS?3EKdP zSsI-yW~a=rH$XYv6u6~f{8{EQ=e$y>(ueO|(fFLm!DV;swk@WBGvIW9;Cn>i!Cw8n zqTwj~W3=t9PsNW3@_k8q!NU}VwGKC96EKqx~ag(11*UVtJ%4MhevWjU)|Ke#KhNRCYyu7r?VPjAQpbZDOKk(t$;~ z%_&N&LsAV3UgOV^NZ0ZCwL*&IKuop9Jw8(NdH%5j!Mq&NZHZ(ETZWvP6c2fK^eYPn zE={$1-3C{`C^}8?v`-pdy1{B9)DMxrrq|7tm!_+mmd!Zxvd_3H75dF5ayOH_ zDGN+nDv1Y=pUJ70P3*G2(IT@Izqz>(KMK%!-TUPPOQ7*16_9eymb~`sI|h4Kyo6`L zczj39bAZ)~QaxzfQQe(tePd|okc&0$HM`HOh0um6{k2VcdC1h?IqJvr29<)9kq}}P z8q@s8=;Tse5tMKOMNKwX740^UPDL9}n+pi6rAS#2jB=Ud@h~89(CzWB7gxXo=P?}G z3l?Q3rAO~?e7nrnn4I4}@nJbsqN-myjsp>&GprI-riobW-@gHGY)L)S6S1genVwLL zS7^JK&g)gD*;y13tUWo~8R~oSr8rRt6kjBf!B4SPxEOK%`E9r%qUBU+TYi|Sf1&yQ z%KkJKo>Vb0xiiTjPl?F~77oS;7afqDadN}u$Pg3l)xG)$dS6w8WgI*|9$@KBl6Vn5 zDUjw5x%nDAow_kxlc`9okKN#WYVI!Q1VC|8F9d~nnY4iBoIl8X`DNk+UcDr`8N}BJ$p-XrlVlJS@D-Vk((COeGHn8QY+C_Dw@YTK!#FU`7#bA1%1NirnAE5(whr#6i9|Lv@=eR#l zCvba{$6}9dAwWF3l<)qg&=PNRx~<=ZS144Oock&8Hc7JJy8GQ5WWcun7sf9twwQ+B z8P8&plF2KVz^m-IKee)5CArixoPN9H6egRJtO%E5S19W4%N4LMw!lSd&UbIN(K_C!^+Lac$J-Y=9Q=OV3O;c)QL_WwL<|048-D-PoDyw{l`?7 zAmnRS=}^hNPCmc5MO!hNI>N>vSF4hv%jAWc1+qS!M!Biz`5*GPLzrpIcyupop-{vh zFRx5Nz4iWNW`}7oH!ok>k@dUeYkkjP*+2Z5GM8o0_C(_OcpW7eZf5i}=6GcJc(cD- zHagkiPzgCn8KZoj=UvDqpGEG>RSj_5wUuX=*kzyf*L6Hb*}AO#^$2>ZPt-6pk%wQq zivOvQkv@h64~MDBE>+FR>)R`bM|Q;e4iy%$p>ISBir+xbwP=dfiTx&! z5){>|ZH`rmVW@S}G2hEfX}l@dvf}!t zMbxDlE^Ze=Kf>5d5#9#(hMx%iB9!S>q}RSE8kiEUP{BeiQwI5H+?lNW57uC2B0dQ+ zM-lC@I_}M?f0Iq5x<21Ock8Bn9TiTmT`L(z%-36FJy+Xc?F8kpuVcQ8C7MdNZqqO1 z;$UDl{(E7lOX@XyKVk+CaXz+Na6DS=+7l_$O%sGMo2e|wY|Ih5azut%7l( zHXtej%$PN5!~ZYuL%NA*Ia4V+*kkHKvObVXf*q;f>MsS9GP7jjnH6iY$)R)FNe{Or&}u;89{qzJ{I3+L_F@;DIWIg&qN1SO9U{^Ca?3)@!MW!dk6> zewRAHekL@T(w~pSQr`ntK&T9U<60h`Bcp*i``gCC=bqFxA%2AiHz)HvJjWP5ivNUt zI;8_Vg`pd0qPpQdrBzb^Vx;@X+Ezmuek}V;iX$6|xH{m%BoSbz3U(G5Cwx2EgW>)% z@}?ouV#_IJJRqB)ND7P%Q12UtJiU^@6mfSOX3HhRJ)!)))*_<8S~GGxk^x!qZ>L7_ z+>1`Lvh%A{B=Fi$Ibbrst+70wZgT%3gBP#<=%yl#7VK@+N<708_5XVcDZ&TgP>ClQ zez4O;?{42k5N+QN-x}jDgxe$?uQHHzL>0Ug>lqu@)$Y>u?apMNgU-k%g$kbr8;np!|X`u5~$$0 zWxlO`r@uMa5OTsPgtBhGPt%vchI5`osT;Pb)!EDX&CWuH3Y@4NE>vY|=w!B;NwFuK z8E=GW^FK76mn9cdjeFikca-D`hNiv%VzMVFeA}pHm49gg$fxiQ*QsME6aUyKO0?e@ zR5@B7*xych_J@7nAS%S4n6$q7dngbk^+vw+G20G5%@n+2gw)Y$)KM7FT8!uGI}^L) z9!=J3n!HrZ`1qHfqCh7C{$j{BuNBkB`}^w(y+O+WU^Gt5^Ny`-4THg~=!e zUAbC^&9DA;wcUYywbEm`(Qb1`V2gm((RRR=-rgU||F_3v_ImKNEh?%8(n+(%f5&N@ zAeepo_vjOt4M0a|BoFVN=pxg{vLzM=kKEXr;w&)O6j-je7Q%Q);AQ* z3Mv9!i5y|&mP4~A0L`2io364TzdZVNY}XHstH3K>6j&FPmoZeI^N-gZ+}Yk7H37TT z7mGUZH7X3oSvq^hiwzp4#o+=V**xxA!7aM6p|TZj19n&j{T zgr%-gv$%6kMJoA3%9+YtRzXPC4F--(+vi_dE))Ij%UgkbKcuo=W4G3>Nc|p2kVklS zuMQaw@cdbl7YwC*x7Y*|&$i70cD_+Ffv%K#7q<~jB^P|259TIO61^^#lW8eMn$Wcg zHLZU~SK+&ev|81jio_lAakQG1)~B*>3$<##iXLXX9|@WG4m%|_U1>%aha?4EvtZTn zgYkr2E+Zjv{DN~eGJz_%sF)O0xIK94d-uvkAhRsW#?FYH`HCE=x2V_s2o zuH~GinE6<4fZX{x(lh#q};bzlOlS$#K^#>1Ksh!YPTvLnvW;-p4Rc zg8oHvTfNjbQ!w(q!aT^ryUZ7#6i=naCevR+$WTdE6cLMn8 z2+G%z6ZAwxze*f;6aF!WF6fVskegQj90Ok1lP+y?d{<<{Wd3DZd|C=uI?Zeqb`M_uJXb2Qh5p!*`{eG%JA;4qKXPiL!{ZV*)FM!rv=)(?pMZo{Qrrr`H z;B+465C(Qytd%wo53Erb&W!ut2ILt`w-j)Ei#PtN{Q{mKbFd)g>*xmiZ63ae^43QC zIr^0*bZRwu?rQ5jz!%LHGi~$TPOkleJw)ElC;;MOh=%{WY?fJ2Z@zLf{50q$VsF;^ z7=g~IRBN)?1x?&#|9e*2YfAa{IX;HJ+)kvR2^e!>zsDy3ee1a*dS_d7fEA4p^TuOw z^r5|XvlS)m+mlxwcG3Nhrz(03Wmk~_tTJn;dZ$nWj^KQ z=t^ihoJjY|fwL$hmQG0{uD9!qAVTREuK(+pk%Euet~n$9U#rCx@NA1OFL(GajGN%) zbaeSnS6@5*<)bQ1K$RzyqJFr^@G6dSn+42*Z)e`iu?#|`QF&JvwMKq#PVk} z{ueN^cd(fI6x#(gM7_28X|Ks=ZI7R+!fo>Fd5>Uhf+UY28p0_8ntw2q!H z34^rCkwinP#WK*w%nS7?5`8yEKRSGwKg?Q(pK>}Z$W>}0>|VnpIv!4gc0DYo^Sv{a z(tqc3d0WZ>Td>y4Pv)1+%$57mlb{pBbL7bw)`idGG?HJZey90CNDTdvKB zApCo8`1%X0fdqy!nWXcU=^|AM`SFv`I}apY>g}{CaUAyIBiz6?hv4vvb;ZCE1JL>w zou>Qp)<}%FMx9kuA+O^RHNbgHe%d;77z2kM;Gf7Cuose)i!uMT%7icE@$@mzH)32R zzF@pFp4=#Sv6mhB^@%pdcAY}>Eq&Mdq*G1Ar^t#<_t%2 z`aJVj>2C_;b7d=flh)|{Uh#AhSbevJ@S0zWw3|K+vy$-|kb-GVz-WDjK>ZAyVhCsG z&|iMNTk1!GuE}6#!lUUHC&+Uz%sk*L|JnW*W_y*8=@QMw^WL=iz4zvz=7I+Ftw-g2 zEx}maR3ZWBxpy;aHl`pda~NGji=F6 zK?k92-0qb|clyKOdhJNU<2Y>xG*$r-KUdRH53}RFsJ-iXoj@W;p@{eKa#4$Af9{~K zMYq5Jk_GQObz~g1@+aLb{@=%)ln$`+l6N~vHsDZOQ12lC;dJ6y?wum+F1NpR+fC(s z;0uS9mk|Rx2T^+f-s3%QUp9~4!w*rfFt}lzv$gTR+-NWkMSSRv{Ej5xyqMaH6GD;Z zT3bAo&PM~Vf6@WX0x~-8`k714U2LbbJR;r8Q&%%{D>&c!R7!}8RLY{x7#cfW`Kq;v z)@QhXZV-MO$Y%&lu?Oi_Omr_pHCoJAaMh>^pjo>i?zWG~h3wj_&=>A#Y*u(aH2&i< zfOsfb@Gw`F5A9ci-hApa_?_2$TUaq63WfO{dhi=fM}63DQSVyDI1y4xu-)p3Agt6NS^Z1la4#Q5cS8enFv%%8h zeg%5Uw*)o6eY77zpHvK-(b#nXY@*k$f8IAFSnKE7swb7w^pQv_UPFEgXV*V_cjt22 z5;lia)vV2HCwhT`+NVfIe78IW(kX~fJ4Cvm=E(v>9v3zA!vgMa_Unygr!$y@L+?0r zXx@`{p{#TLwx|+h?dg(R5a53Sm>L#?mhxMMWAtvCDAMZrZkxm_z$Y4%7UFV*iZUYO}Cav-lGgn^O}BNy$pHFJD+xDG~zb3}t+_rU9#=8 z#lC%#eNC&jzTv1;HlDYKjrO0p1Po0==J{`rJtl#0xoV}-m}Pgat}d2Rp%ZT%=?v4l zag*M@*=RsOQQ3`g8TI25#k*wUmOCv<;21c#IbG7IP+G5rg2dHy`L-g34>^Az{@!ts zf{lQ2%li_92tIX06)=KtszkK))6g;AW*rM@6m+VTEZEAvxZJ74FuiK($94@#7asP7 zr`SH{8KR7?cU+*N;2zwN!sl*0K6)FT0Eht6{CJnaT%bla2SjqjcsjV1Dl@*VIh}z9 zd#?l}0h~AGnT=KtuIeqWB`y2s#S3T?z4${ZTK3D&bl;+`&g3h+OZU2j!DX%cZGi+| zFabUh`z5REuNX*__!(S@+R8ZXMOK$;*7e89H+hks9q^I7il)&x+Tu-yAeX`s!R^pqMG>S)lo?)}DR|F`(#@ZyR;K?8Ikd zmT{@qW69H}8$V=?@XQn%9(p8^OVe}4CADo-;-N&nX%ylP-~~hV(}y(>d+?nO|Ay4E zV9)oBUp)^Ss9?W3Q*X-%CEMbJ?DU;)JSo~Pp z3#$X6-4l3iczP=~YPrFl6uqwrr;fQZK8v4TZ3ut0987j-^|bU)YIQ%}3oRT{`+Da0 zzfQd33#^|ObcJiZ{?mgr@H=V+?+bjE5t{tHB)nfh4r2^%+RF);bTUz#Bkd`BUflFu z%BMT;KX=*aa2s}im+Hr+KDDV4+1;c)Z7 z0=|E=b+`<}@XbW;GUpcIKZi9QrT?qFf^fxBiFt-lG&AqVO`>?49RO+)-J$Nx>>bN@ z0DOV*ir+?N;?ZQfBvuhsaZ9XcujQmPJ^W9>g6>m7fMkpDhr=AI=u?TRTsXs$J;v_P z>Sp^e3&vErt{3Z}x@DThJi#?2D6%~vfpLq*3so?_{1=}HDB`)jXH-(4tg(1Uu_2pm1s!i%;3Vk{#DTAt(O^@WN;SfFF+tjQStK z_4hgKCXF;6+yHWIQxYLiSyg~)cC`h^oi{HtuwyfsWN=H!q#vU$aM^SD27YmE|J)#v zH=Z<+Qrtl7%GO{(%dKREqViXpiV(#{cZY`iLR_P+fG{o$vu4y<^D~T_n*?lTYmiU5 z(BtVIEtTep^X|-DbNQU@Y1NoGHpkV{Re4#8vsNOrL*sP*vZ!nNG!H=s(;vkh-j;$y zQ?UcaL-EpA1T7njN4*j;y$G9YUq)kquyXLnRluN=Kwr5 zGh_GlKAbR)UwZfLKp^~Vy_pxiQdP1^c?Yn5T2EEu&FYgf@r$Jh-sz1;|% zl8cHEcc&&1bEkJ&@>EK`0|szux88Y%wriJ7$;sN&fq;=7(=jC}oix=at(aYZEDXSJ zB<0D_KbR&->X#(lc8Y~5;P!Qu3rg+VIt@?-AU zylLVYknbLMf4>Lsa$509+51+e75ky(HD#nOx05A9f{vXx5C|^}z>@v!2+W99lG~-~ zo6Dzva(nowUTqf4YN;l7G$HqM=3P-g0jG^1KMud5XBv|xK;V)E9RVbcbX{p$>h*U< zxAPrpe^`vzIgqnB>;?l79UF+n^edKA+h`)$72k2oqmLnA~t)o1!QwtGrEP!JSv&; z0_XiPlWK063=;%qG(z*UWt!pv?u^6m2PLXywd|r=^l>!G)g1#sg{{Z>56-oJAjfYW zC>|Ni({IZDR*OAagjX960~Wz5%<1yZ*s#26+4{{HrbJiX!A3EQT*8aFq=;W03Fwsyq2OP3ESeCC@E75)NNCiW zk;6S+Pr*a_XT$VB!GaQxTIDxu8f@W=FNdobkcV%4U(;);Egv!8)vdVZfaAC->n=ay z+qurS|Y*+hZ1_%K3_>n)twG$hSyDv``v{E z*G(>gLQfAvni9nmk#8V8n|>^nlEyKBH~c5dtgW&6Ez7Y@;I=5zz5{!Eiv`U;)AB?H z5cv!y4Y1!AtLbcwrqh3wPGHv8aX5I_YFoa$#r^^29GLIbunN?Yq586JRzcsCkmpdDOrf2j^rGyXooVm$8J#LienMinn|8cK$dZ^?VE|7U~$U zRFi;_Lr{fmUP1Ir$djB1@j*F(r)2USY!*|vEm-=;J&yTG{Uj~V`L~r0d+ZHQ9n&BY z&VU!M-kwg!xDDRUd@<^ak7GUzEXx%QUOU}CV<1G?@)3B97DLz@y5|xYIHxjv&-AdQ zkj_Z)DFyLjslqr;fmF4S*!isFDNd10x_>FwywYMmgS>Tz&f~(%+FWjj7EM=8$m4#% z^s7Wvr`W`DtIJo(6@VB+JKtT@R5J1oOKjQHGUi$(14h?JJfpv=!wpo(r7X=*6REx$zu~qUQUx zDH8&dbY7QS?WWn&j1Q%ZLLN6WJFG&plj$8tHR7+k7@4e({kJn>?{ChAkPOM8X&~V+BH#GxaV9RAs87p01Xon0NX`bNw7zRczDIHebw(yG)Fm1r1NX z$%TY_9hq(62PKtt0SCD=%45ZTXp4Bl_f5C3XNt*?0?Ua+%+t!1yKLr7+Kz+2*D#C6 zdJX2t#rY%SG&-|Z;G@Qk>$#Ij5REJ1gzuM6qG*_VD=DL${$CP7lK?|7)GHG2ob~z& z&>CGOtHS*0(&vy0Q#qz@63mF&<@Ngs3)@8y3E&|^d{4Un=+fjZLlS8|NNS)}_+AqG z_ED4hsBYIpmNX!l9|*(k#yldrQ;CkWIvqc1rj*As=thwbI)n*V z+HG3kCpXAk?k|6EWni+Lq63Hn*1#_q3=SFb>?N8Kaf5M_sb@Uk@q;5@on9fup~-O# z-FRH~%x&FQik#HgOE-Nwj3mzwK=}EM>yl?@slYdQYRRQ-uN?HgXAh0d6QUx-1lS^1 z$9ZUjoUfJOn@XlKzb-kS;d3u>uzAczxZ%QS@-py}(DV^#_Uv~Cp^=*5g;G5J0R)V2 zyk(ThKNe5K1agG|yi+vS1rTkADw>v=8l`aP>a6o62WPmP5jZy4uA8hQNrkA6`@#%J zAW?6@3&Wa47)KGmP1WUNW1iC74obIEl(S!Mtl~@EGWslVo|k^~GmTY5s|}Y17+j_d zhz~Ja1iL+ClOF>SU8JG-Z^~aYsL1F{=r0NO(!48PT74DlyGVHTk1X<+ z^Iel8Qf>%DM+MWbAtDWVv`)IocB&c8;w#U#uq%B~@FZN+t1U$}K#t7#=+ zSTK74b%#zJ%kk||J-*iT;xo=cunN6AP0bkZU9=vEG!#M~iy;(MXu?kvH$md6%VwU( zx=lTjU|8EvKTFf9MYD9r>jVX4S!U4ueF0ZA#P{Q~a;t_vdW`jJy-1p6xmg=3{w z*V!#8klYXgCJKg>-;ZyS69IC4R2q*`Nq(oq=rd)-`;E({!KkKVC}A?F7Y>Eq>!l@u`V(|LrtqBRjCm(x zg#BT0DBzxSVtdW2Ox_Kj@Nf^$6qz+5?66O4vJw%(KYX_h1obo>x{RkrY?YbEh=~Pv z-*?_2Vq-N5ZWn3RTDvkdE(|oeo_nd#7wWgL^#AM`lL`{yb>1ve>_6PPE3q$KZ4tCbrs|mE= z3%ECoL57?A*~&iHXeiPXo-Ke;HcKMW*tIB`P;iEb$Zn= zHEK{sKhTiiT;VeCuA4(~1r)fQc$5Qc(@jDza&w2#DQj2U*@UVq$Q-3&+=CKt-xO6rB3vyGZxvHfPQd%%h57Kyno$@I0r&eptpj6HzQw zDJhof^_qeY>*gKg-_{}qkX0h#>#PAZFi8-YKBNy&vyz!uW>a6{HuoqyRLUm{a}KsV9JwuRpi94 z0-rJq`8+zDkVR^=C9|!)lg2X)mo0W+y)7hyGsYSwXqiUmiG4}u11L->nM{U?2@PO&0& zZcPz)N8cNi7$N4Uqb_l3u>!ta3o^k`U>!DiK0r}v)`nK_{&e*H${cSdXLz{OkSi58 zsQ4q&o3IXdpQJQ#Q%xuEhcII`i*DlJIbmRFP05ffj|YACF_DPRm0x#z6E6Yb5G za-8vIi8hf%x2eqsz_BReEuE}-&LVSa!0nm5`{|4c(5%D6k?_Xi%(+Zer?0xmyp72J zorx!wVa^xBPA<>g91_^F1=4^VOz+~3^Yj7n!B>QeF?z`%Qkh0Atv?pz*>pBl?uiGq zB{zQZ&p>?z`Ff8skAl3EUfdt{YpMP&H@Yq62b02w??F~TRbB356gF!4k2z5ox)@p2~cS zo74APUFVay$y}FL4UfHxojTi+sQm>%Aip(DG4u)Sr9XdZ2PQ3S-eBrP<0o( z3VOl-5AdOOjL%sM)4WzU6)T5r6@|V0zoXGO-G0_kB1T=v^T=NX<3 zqhy1le!($ch1S{aWKN_eo0YdkgE7{lM8GP`8>Hv~@CpEV9y;#3Yz+sacN;)V*RA5^ zxW7cD8;(Oqk!}}nxzfrPeFd-W=5+i@vDgTmO1m_fR_)kSM&IM9i_`pjZW?glQ!3xB zht!*zq#A~h@&R9ZgYtzu1`l9``3X*vEGKj%p$Esvq@SX2ty;S%W4DaRA7)DDmMA}~ zYB`9=I0*uA=^Tib;+$8+bFR{9yHvYUzpFQ~Gn)eS7*OdZBjA6jyMlCw)mgv*CYwZ>5&NGa`g7!8ih-YukI`&|ps2*S@=4SW#rmia)B?@`4l$ zox%I_hxD_-4Ou!K07VdS=y=sEasP0oQmijue>`wnak^wNG`%^E6ML>zW8omvfdmL# zE_-QjWM3M{c#osOPdaXzvn4A;BgyRXPg?f=)n-u|mpBo(9Dv{27%CGR0>@vc z8sxQ>^D>9^2jpB^iH1g{hzTCMaU2k5i*L@h7$S>G8ze(88OX=@9};)9@$NzLNu1^( z#TqTWu>%*?scpLfAHFIVZS^8OMh3*Yu9!mcQ*UeAG!)OACJVnf0c+79QEUP*A7}K& z8{oJ4#k&O9oM_+YM>aof4FU1F;E~%8rum|{C?MIhUj%6>ja&strjfSS0!vzbob_uz zai>yob3zCM27oE&i(BqegLquK(^c<)9@O`nbLz|+5BjHTa4$D|aZ8y>)(#1J%BrIw zxoR!Ym0-A^vT2IvL>3{Lb+)f$9&M9DZ|&;2obFF%jE8!SqXoP?T^_=m_zqouRb+R- zgk~^GnheV@5tKEqDHaqOqZ%DYW-)*I4qfHdvzgF8Z7`vS7FyH?KjT zZaaH3YCbGPSlVSo5%$z;KHN2~bdJ?%eC}kpA<}X*tV^CGCg@bQ9THar(brHjfjnr` zM^7=3QFz`6dA1bjaULv_!K?yEu=?~Zcb7$LbbHI5^>Qyxh}!i_Pcr)%!8rW~B?@Pj z8zxmD-8^!203omQ_`cWG180uJTILn@wKm+QGz!x-LJ&GGwA%1xKg;%4u zqcSUiLEJw0y$*_>sph4kZMHS=aJozqY(y>YnpT)H&0m@TWNyj;5H zss4@ohCItX#x~N=@+A%sPN+7?dr~?WE0&mNZsaU6^j%;f!CQv>bC&8~vYej*hsQ0$ zq!4<0*>rh$T&u@ub(0AYcab;zt;;36R`wsK`L{9$?7$7MGKc+efRtC`HaMLzeDeP- z&RM%XBk;K92RbHyH?@;TUWS!2XL;a1Q7v*{N>Ws z4@2^NprE`LzC;(`1DW3Y#+att{zPeUWq@~8R`g8yaR0vay@FN44R_ViqsTg*>l>!c zXPc`PGr0YwUQcn>)!y(ge2pS~AYuD?tXnJxL8EEhJ2p=YMrZMKCK?@v5laj^%J&ku zM~M6LIS6(m!xbm_UQ{gKB*22vIaKPN$JXvCC=zL;`BQAlYt()zz~fd$vmgDU+mi&J z#S!yNqtB`Xa)I${{-we=YRj2I{Ou)&2o;&pL#HUiVJJTT#8=p|qq|P=3Z%9NtZ6Jp zaRYG{@CK_ZfeC0Xn=^HvoM$P>gGw}&w)NJ49GEUXpxePVQkTm1=z})@y_w(r!7uZAJG5m+hl1c2-g~M zcK4Z*@xj7H@8o_sK98-Wc;B{tlHe9lxNz@v0e^o-^F6`NKXXfBE#}z7)VoFKmye*H+xO zBdrg2iDmSCy1~@#nnz()DxuFdMgL%+q26p%plAMi7{5>EQD)Xhznj*1z%w*v>{lvKgw&o~KeiLcU#Mdz9xIO?8djyObH{TU3D2pN3v=6<4;E_nQqLSsN0Mts%hj8P`vFA!t^tN4NcwqN zljIxkP;eR=itG6=ISxh`EWsxCR689mYEv7cwQz1-$75v4m zdUDkvFsnkl@e`}3b>oRfRWB*EoC8kvG#l|yf2sCU@@lO-YYB6(i=+z3d5^D#{W_hu z6pB1EmVPb-#WSvOR>9b=jY&{{d4aCDvDR{NhJbsqFT-8-*mv@NPYx~Z?5`wfGnmX& zKW1~tuJZ%rIUuXIviEDQ{)qPd(&u|bEYhDnb>$~>#h*O=CAbPiUx+D`EDB)lSF zQOvQrV|-5`>H?^}eR^T&#yP*_V9NFP3QO4`CViz8DNww$_&!;+ZyvPWmg!7L2Muao zd@(F*FT8A8SpSJp%r>9b1+z6h*LXi^{w*)u!nSFZ9|qzL;HHJlCVnk1Ddlr`hZ+oJ zlpbM=O?0SF#hGk;(d`1=wTdDQ?y_?%BAhDaI-9B)UY1Ck!F>dg;?>IdXKZiE$>Gqh z%N2LR;aqvkS{mEdk$B>0RAYt41k5#NZ7uJAE)6ZtU?EdWArHUwX*Vcgi?Wt=e%v=$ zOP}KX75#jI$t<=@u*XbYnNtse&LJ3Q#E^tVm!czKk^>G2{fak%2#tS@rN_ezCf-+s z4@#X2A9&bep@harUh`5$@5JqI;Jjg$Pk77+QfLvRhDM|&C2+UFX&6HF$G)4Q<6R5e zTkaEBzs-R@|LNcyRs!hJ zoB7qobKU!Z9u5DBuK3K}fX(EkFSk5(h1h)U$3>&n&K|q{3gz75OWpu9cQM9ui;-l9 zJpUFziwN z^!XIZm|{>SHmw3WAS!#Gdn<8T{{hb7k$X!vTWe@9C-QK*mxET^=Yoc2SL+;5GYM?> z9=PM44SDD}Ta;+@@r2Odcfzs7z6;W=ZFyXq4dYmB*f$a zoKph+9> z{=9yq7C60Z?#u+}zWZAp4{JV(-vIZ zM303H{U4ccm_X*+z(sSC#-9%~2o89~wxeJ0-(Lj$J5d9;uDx`7Wcp9EA*cns5(*~< z^&bP12HpZmd3Jo(dB5<@zdvzJ7r2ps7xceN^MBjYxU8c}#d?3*|E?g* ze`C}D^skz{r~v96T&`CG!fwEn~*>|oKbH(Z; z=+y5e#?*)BI4r*t$?;vhpMETQUqDQwQp|V=OxKa6QY}p_TLETE%c_*=&;ix`vB0cV znbzwyxFlxdL6pO@%^`}nUohAX!NYSpD&m0O2R@Xwkbjkmi*`F~=u3C3&61ZOmrbQ4 z5f6{;`GPqFusuLx>rWta9=8Ed2)@c^35PG*@Id2UwX<|r!BY@=US|!b^J&TgHv`N} zbmOGpbqZ>iW@sTDil>Wt{t^oMR7wmeL%3mfKGrjz&X3XpMl4|?&=)+EX*a11CNNlI z(W;dTf@eCJk7s(HAFT*z+S~w*f;WJ1G4Zz-dnrylnxYG61HP}2k}EB?hLcXgJ!6aB zC9|U3-(DWj+?;K5Z2QCywYXhjxOWwQw?pd#S`4;Op&hU_X}5W{z~ga_1JUqOgMG>= zhOrq?xlC#e>dG+Kd$m1zXSKi5ru%re^2EI=wg8?c24sEFM90)?xdGkQA&xq!qAs2?J&GBHtALt8!Jo`YF zpk=Vsd^$*@U-r#Ok>&kPqG33UIV36HHzwUDASEZY`aA2}1%9AtG7DHsEP;pHi?fy^ zpo6Hvl35QatNA49`e84wwak@{Gh(3)_o{3nW5+d+MzWr2?XCqZ)TSe!e?Z zaz;|C!31l*Ida|S2o!dU*LMU1BR5v+UDkpr0M&1x3j(0jKdPCN46eptf4>7JlD%^_ zO>*xw z8klpXVkAZCnc znU(Ip6>>>RzrQ;IBogZ*|7#O}pd@RoTN0PNa?O$JkYIH%T2#)cd7an&+9oCtm=V(~ z^Uk$-9bejrWTwpkCc-nDq}`61TXv$6dkL>lH+47?*r!6(%w#}&2jmC6!9*rQ88~_k z|A`lxxe`&ItcwOint`>eA@ISYkN zUG26kxRrCx+93S+f5< z`xSgkN$hu+%)sY#k7fh8q)^_#!+lRKmre_mGrtRk?!o#3bUhgaCI^uN$z@?oemQ#x zEf)*rP=xH^P0eS!Nhv%jDHJ@-$8vw*`USAcARHs^$(Cu=KKDTx z90w-JO;HAb=c}1n52CE9UtwwNwP2PC*@~|t<7hh_E@3OL7b0wOzLEXA7r<0gkBuNt z_kvs4-+fIY)ghR*le(8unvPmEKlLYoE0fM;voCPZsIpP2&jE#Ta`>emvER*Sm(vZ& zIU0@Zr>nLnnAiBwu{77>a<~xozUf|%E=csF4NKb(Nz~TwCRM|OJ zq>|743`3*i6(pcBKarE)m5*nPK=-{X0D;BcD*zE6XQvfl&DddyUP}(MT_};;jsdeR zhDjk$Y-pm{J>;VaT{cjZB!wBsHI^o%tRd~=0XuBy%GQBtAIP|kiq0^c7WNG&Y?uF( zUzJ4Se^cwQH_L{AQO~eN(ExeIB#%A4N@ns%;TmY&dSfE=c7e{hH}MGODnH*~bOxBs zr+=E`5O}`Yn*aLexY3lR_op1ixe`qdv{EDXeZ zMCqVP+GI}AL0q$qj#MGWPF~ZEG>Zl4xh#=aLN8y(CQG~^gF_Jb5qK@+!+0JLCYA@7 zM{y_w9HY*+Hwa|#N2oYO%|}b=d~PxgVRlH5j2yVIM1yk@EuO%`;agn})Jrc^9bXJN zMKng9gfM1SsR%Qo?2|uSPwT$Jk<}0Vgp`Zm@@!Y^ej>=Z8p5~%5sjTh`*;LYZ5~7A z6={v!7rIeIAH0rn8cMyr8(hzXvOO70kg4e7{NDN(TDO5B*6eW zq5QIJj#!y7;cj$RzaX^(&o=fB%lHKFDkh( zE_)?)1hxni=l)2$;&aztrvnsWDK>_eHOv-EJMx3&tKVZZ%u=|@FTc0UAo;?)wDmEA z?7<665s8oDiqT;Dw3WD)WZ`Xih<2D{0m+jaCt#270(%zy1JMPXp(T5+Ea`NLcN&4i zz?%^L9<4wg zUbwm@B3q{ySNo!xtqV^43rF7D?5)NyOK&yB#Hb0YxA}5&n&2s7&n`6!lvIbgKJGYW zzoz48I~{}RugW2r6uzck*e*?n-3zW*SS%!eLAZY>((#5-s} z!MwZgSL9{PO1K&?1o~>D0FN3-WbBk{*Xzk(iQl({V(Ac~EFrGT>C&S!g%}+f{?jHJ z`M_;0AtUv3JzCH+*BEB)P}X+awu3*q~7-+h(`80l*a{ zMZogYE_4zIcR>0Ia5qoB-;uAl-Tjt<_oR~aS@E@`o)J_M=3!Qlg`Be4+1ALLn%Nzr zL!!6@Gio|^ehcsMB@s+=C^BdiwcND#hI! zDevLvAjXH#m@6m`C?D~s7vp7FslDFR(X?dw6b+^dF1Wu3!X-Kh$a5&FP*&(w} zoFaCTX_0l2_Y}#9r7-y94uFQ5YL1jSU-JHdHI{PI5Y8VqXGl9kT(}~Vz$4y7!1C#M zkXOk>LCogUA-7&@zD!NB_w>>+X4VMsT%8|$4oWf2@Lbi`Gnc_CrU!g|iI^qS$l0Y~FF^kAIMES|7VTQ4+)tY+P3%pV;wr-?@@L!ZoFF zsb^@dyRO}3g|lxWx*61zgj<_q7BWNu!E|Gd?WmNF7l8NBg&e`|;hptRH$ry&c%pJuz|W-wq^ncR0H%;qFqRo!wu0mQELKtpgt zx!^Rw;3>3*oVy?Xe)RhhB+k!qoA6PzX%92(9gYqtADn z1g#&{nAz@ir|t!H%(dG0cvAfM)$;(CxPhY5#=+O`xgidNK9>*&NPUYli<6{8y%yX> z24va!g@mrlAWlr;eNiRz3edz)LpQXOH=na}L~8aoSv8AfvcIB81wCY)n$UF!)lwCe1#zX(B$W1o}9_WS+#jfkxP++(!J2s%_2Qy>yE&VL7aX$_P%0`3Gl{3+@`1uYd+k%+-%Anwnh4 zmsUC3&?iFvsM#Vj!%S;Obc^y0RR|*aoOu*xwB2=`;j$eb`$&AmpsNA=^pPs7w-X-t zcRM8_&W-P*?P11Hwi%$3CWZ*%(VkGEY{Xdh)bG4I^_L@jNTKtT%}p$Xx2|nU{<-eMQ11k0^v~ z^94~Cez)Aw5QRsJ>u6Nf3Vh@in!Oo2dwBY<+9PUsJa-QQf7wh(mxTK@%#V0J@yni@ z@N4>QnB4o^@2WqIHVtItdo}d5rZ{#RL|%0>2sCtUd!9oudyM8{$lIcnU||{3Cw_Q2 zl(jI3@93FxDV%iYubBcp`>v+)$8ZijDpSdO?7hNc--?CX4$O}?n8OiOAA~!FbxokR zeA<5!Zj}i!K0(_D6T_?pWoTAEX zmLw2Rak%he^AcmKwYD8*7PrUQ4U4u@BksE6MX5@EDkD<@#9B>g5uvtWWEXe!nPmt5 z`q^?e-R2hZEYb3dE_th$lJx-%7X3wP323O&1U?nH5*RorR?Vlpvsa?Y%P&+C(JZEL z{oYkKN6ocEp^iDx{Mu7i>=TEEtrZ;B?K`lu3QBJWAkd`onq6LQMzL80Fb||SMMdaA z;@EpvPhu&b=NKpI=z-WipI8a*H)XY;Y+)T*&Kt_^5EhFYK32%aFdB2TK97R1Z`V^- zr5QG{Lf8u2GefOnr`f8u@b4LRQ~k=Q$f#eos{PV5mPYO6Sp0+Y6P+%v>hP-z*sWoW zjwM-TpJ6=BZe<#F6VK)}T+?O9`E1^cs^idWiz3hW9o`w5%+X~&*F7vMWSvVmXJw3S zYHp>W9i(akf#0oZok@_)$7+(s$`D$5CpouD4Xx7Rh_0^OC=94{b8ZN}bBa}k_0_$! zM|-m{Zr9E6Hi3vG;KWjEtz#r$6J)@jN?q6sok@*;D4mT^y%iW!j)Ghyn!<7486mE| zkLfsmR8SeUMbk-1fv0rFzTAL=e zz7Uz8wy68TF~YB+-w`Y{qkuO`SAe(MTMJrY(Ayq9oZxtUSACZiq@yPNvvOU3{`g8< zsEYA?Gh7UP1w1Hz`7D2Bb1WBV>e?uHs0O`qy3}^(P}L+q=2z?5I^Ikuto2#m?*iA7 zp_s~2%p&yZ7C$DEYIx~5oeZlAosqt_RJ#+)A%eG7t60Hs3#G$>{uCRmz&$bknJ`qW zLoY+Nh)FEb2eg9Ux?JZn74Lt^TkCl1(lR#TIn;s>5ai48@#F^v z{YRlznALl6H~Qq}Rm}KzZjncA2{pRkg~m)t2?4u7+(XmC`TdH-Y#u*2X|bGWE#MXx zLX3AAwbYw-$88NU;;sU%UuBRqx}b|Qt;Sn^;-r>7=Y@AX!-tu%FtNboBoRt%AxJ`s z4}7R4ndRX@7W5j3E}D-%OK>W0-pJn`pV3gtGx=|d;uBMGn@+1K zK+?RAR#5xVb%^dho%uO?@~eGbbAlmvfU%O=U8ntcmTRvfzN?2G7d$$b)||^5a!a+< z3)r;}xRAv>lv&QLtKHNuFO%u^_igJx(z-y~%E_(8Z7T>}hKvd@ecOLU293MN&IhWn zso?8Ayw0W=q!BuO8@YYZBA2^vb{b%ePKpR>*6(U}`)2Rxkpm&!Cq#-9ux z=%C;{0Q22^*oC7)lpu*leT`*B=&Se@L6d1>N3^vo#DA?raszS^9L%Cq`5cY zd38AZdTFnh^iQz)mbjIBsm@qVWxEwy^Ac8k`PbD3C64T?kFb7<>vRM`)P_1~25tU=UdSp%9=F&!$5ulon+ zP1vN_n_n(_p;5@P@{yR`blKoo`+i>h$a;sx54HI^P6vLd8;OvNl~>Q1F;-ejWUO{n zj*)I&&8~|sKc6TRD9lc|&J^}hVPM4rumpm1Rd;s2sR}`eYIJ^2!5&d`V+Z?o+eRgfjW?&dp46`ya5G+$%v_t2Xy zgu3-Ku@_+tkHb3g`E&2PVk%f;$PnYmyF2}G)tjG~o~+v+Z&?(d%EKfmryOLplY5cf zW0p~otPYR&TOY#p1~8kY51CoA+4?}x9ZX^2K47%3XvAm~S*Y!NZ8$Y}cxYw|mfes8Nq?UE$N0rT_A?PA{ zbI4_Haomv#H`i!Pk9XU}9fEBA0b|X36(Z7xk7rAm{o$nu^lL`=tV(zrL~}?v9tLTO zlJ#nAjF2}`X11y%0$Zt9NM}8k{unJW*y!EQMa-EZW?^ygEx#lkD8IFS0b&1aV$tF) z-RGo`R~nWx^(eYc9 zK@AJXez5WQw?`jkP7$UZ{tsDa85LL4tnCB{?gV#tcbA~SLV!VnyE_2_48dK3I|P@( zo!}ZgxCWQt5_GU{^StLd?>g)IH4E0vp54>6tE=n2s`_<%Hs)yi4Gyn{IotQpsa;#~ zCWd$4Z;DBR<1nd&&2xrKAeEmo1>9dOXyctnK2jFt>X!=AVbl zEoMy$Xg~A)CiGIZ(_Vq6$;FKcdRxV-yHvI{BP#eI71>Ylm)wjRhL9_v()Z&_{PfX~bk!Afs+jYpM9s2X#&rxiMFPgdmDk{j=WwjV z()*PIQ#{OZcCRS_1f;f&hN(gqq( zdNA%^V4bY>&$04E*nl~i!)98w)+QdPCHB1L%h4?#epw}WT67kC^+kTKkb9wnd>ZC| z*IW{_Id(1aY?iZ@@*x(BD6mh+3=@}`2_GJJGtnjIf9N09!I{^^`|NPAc&_V;*7FM| zQE+CGk}m7BHQ}MGcigB~Mg5XGr3n8$$+<{!6^&Hsjwj2kxWqt;`o|Mk7o;(n8D=>i1@l za1OEaNP@I&D-FaQo)-o^P(j2S=;Dx(efKS~0a2=O5VEp>P}MP_rQ}7@{CksnaD&>M z&fJ@k-gROW+h~T+4{Vgtp8VA-_*0edLj{ZTt)#T^kR9w7jVj=%DJNH-!=%ZDunJVL zw!POqI{(?baDBYXMUJV9ps=w5JYF{= z+f%I=xX@6gCTrEJh z3rTDgoX2Xjy9ML1)Vm`vU9(KdTffet5_`xXP?H%LL+i0(j6hd%?l1Ma@Lg9=4B)-Zq|7A2z3u*+2_9Q<;!>j~eC%*&SR2PvR#JpR;e0<`WV6 zn_cZQ5$z$e2)8m&3dsvhWXs!NmlIr#S5C^Ia6%~o+g^jy-$@&sta}0jV0R{Vxfx_X z6xh?wLnD*XR^)nx5%GfrEypwC9x41`vvaOLq|&~2g8VIBAC>XU{AM4C8M-V4^)*cz1qJuLE3a`Nll^CjFNX-{n9xUfpT`5#ZGV~HAB zPfrVnZfLqd)w|)9;&(R9BRU$S^WPB84NM>Btlk`Am-$nwi&3NAzqN7H^Hninp0FiZdWd7h-x7Rn$#+x-uTC8K4=9AL`WT8!^0mYH9B=!D^UZ7Q z6W^Jte8H}K!j1KLyRDCmKbY$r*7%a>x%FkA5sMhYD2Z%+v!=6+v-}NbTNFu4rKNWl z%mLG~u178#^A>fhi$kU&PQbOJhgRcLZPbtttM+u%2F4y<2n9!!6bcfzpPcyTjm({& zt{ej}>bL92%%4vLS;OOvP&Xzq!qb>>7{Nd^5JNxk@MF)aWjf#x5yN_rqfOqp^-*SN zVpPOzI>{hA_N_R9X%~mV=(`IdBA0uVo`C^o?9*I5H)SPm7VLMz-&WC2xY0l9&RjxP;uF=J=cMrgYD7;>} zX{}mLB>qo7J)m6|(rbd0N#kmZcCoBlhwq=x`^+kZeH4N3}wyjxL(< zR5B2L2++p2lRr5OagErm3iR;@r{U;|Y(>4P6Te-DwVs2d>3MDd|J!)?eSmv4jc8H{ zQ3P=h5PgOK5uP1*P0DcW5X3P_Xb&7c^5JpWmamh50`8pwXel!as(v|6tIp}Z)_epm zGOx*MQVJk?wo|9iHbTjVj~45I(o$7klwNPx0L?LfSOjDi``wWgRWd+Gt-EUdD-7NU z#y8s;PI6hcZ&Co1@W)K^jK67F{IT$1UVnFo0410i;D0!5MOOhZUkvu4a~x4@CcYn$v!VqFaAUb|Th4tT7(G*#`_>4I%f z(8EFi;<=8mdm&u)bhFK(j9S|3ESInwOWu*dCs1K7XT)7E`RY&j-m< zVBR20Z}C|0KRcc(tv?f&J&S`2PIz~Cq}>~ct(^|uWDagUcHE3-?Tp$c3tIwGGIfjq zmB`(8!iJ(D^kb@ZQ5rO65LP7*@#pJCm3PwXfKtd_P!icNZ{QtP1CpbSuJc@8UIoe1 z>wJmxk1b*+HQwhN&R`;wO*n zj{LR@fo^g|Nu*I$Kh~k+ZdVH4BH|eUt%T3HmN<8`47>`p9ow%G9ieBpO#qGqf=r+HCtfp3$Y65vXKh?MX<{ZXkTHit^0gCD9*C*vl4~1 zKJJ1Vg^gOVmpa=M@lwTGe$0gk^|eLFysm8pXPWzp$C_^-sw}*zXV(Q616v?KuIDPg{@ga>y30ADmidR%#SK;G5L@T9F$(+lV<8%M#=U( z@R->BQB@@Fc6hL*`2I=bvcpCQu>&G-G_jVzSr@Ekq*VlC5hB+<0lL`jx)Y$X!eg!W zwBM|jPo4r_X?!)Sb*d1dIe>5I!|8K3Vu%hrn|^l=>DEPzr`FR}j9C1g(<;KOKWRSZ ze;z0;&Mw=KK}BTmd~or+oRqs71=>Wm^VtEDyb-U+#<+F5XR&CWf(DGx*B&^EKu6!* z1rA=aD|krqS2^O3K5WGxfR}@8MhgqV#C)YbgG#Tr>}5~){<1gXS#=qbI7w7jQEODY zTl&0ge?_L*_Xba!!e;d~0kq}xYH)^i!U)%2QJI0eRv49rI*a)?spq@!KSPI6(+E&S|KnFovf z&-XUX2W90vW5An)fZ9#)c|U%YQocIP$s(4Oq>)mPg4=A`_m;~kMfbTkzSh@oPpW&- zC6hb6wSD#rQ{0O1^c~&iEYr;KvM84Tw&;t6N7!Egk^?sbjwG-IHK@gGz#8~Ml$`sO zy)SNSgal3k?A}PRV$eTM)5`qTrgB=@X>>uIsS8z-p{^66H$ec3B#&`b=xPi~Z|9ah zvaRuDx<9H@#dNQ%9v3?Na|Cb$WW-ioKaOf6y)a0yM^X9fOwR(zM9J|sk6VkweAA8) zya7w#1v_o88@o+L%f}Md5IeSUiabC3Eeo88kX%CA-LyJiYKRV%bS@wf{E+sAqO3P! znZ$JzOPW^c>Nu_6a*plfY$LoK`6zT9R*KNEZj4V-gEZ-wFPqhIKk4>XzH3DM`A)T> z?x2L> z2RC2GUK*nQ{IgaHJL)t&F@-Psca+<@dSFlTLUt`<&J-IKVTr`oY{lmn1sa;!Hf~PkU##^C0qyqDxB5O5jafif*=mnPIT7VpH%y{ z_Vh|eA{RfYp{z!2^XxV3cqXyDchac^ietG)8ZU3lxszn*j@u_dK!UBFyg_5$RJ%Pkz@YVFpNSS+8`Q4WtIHI3cg#%qtZ(T zx8NrQPm#B!8+yigC3RPHB#f6{QkP-K%w{VP9^rA_YeEyy=5|ECZ0F5=xQKHFJm-Ak z9q-e^G^`F-rcid8L+_0LxPBUMYCl=Qt-A*GvNMB@EX1FBDC~pbCfq5=(e8N&i9Yi~ zt@{9><=Ywh3r5(bS`zaQ>cG>%c~BL;$CbA&OUI0S$6(dg=jh$Nz5@V>pfyeJyMt?l zpX-ua@sbj0A3xn&ZT?UsoSR*Y|MthCv@rRjm`oU(zO@!8=X%MuYATEPZlTogj-vct zO^#GEjH1Y)o_jc`_H~ozsW$FsyqaS}9A0wwvI}O|q@HRzQQOWrkNV@Z#8?$dSd*RT zHnoW7qH#>GPECeiB=Px$mY>duB1q)ec)Pn&2K6$lvAnnApzsf}Lkt@;+@( zimhl`{Sq)gck+47_XcUTA00GM@7JNG&$znRM>YiTe}-Q1NFh>mMojsKAJ^E%_W$|-J;-;L4C zn~tI)liAXUGa9b<@@j#gwu)F@NWXm4oZJ~7|KW}2iN`1pVu;!3^{ZZ3U&J+|EsVA( zm&0#}BdzS;1QudR6A(YWAqXs2ni{P7a#F!=L2e=fe{eo?(X}e?85f@LKIf>V;P*Gf zj-(lS;)DV|7T`{Ot#Gs4=XA`|22Zy-Xg*i9Hi;&1oqxI#TCOO4a<}Hz^wm{aGm6@s zD_?Q^g1;IadMRX=J#{-c&0UT`O^X}_KkzjZV-Hv`K^$G{TPnQ;&cs7DVXc&yA1QNz z6|-GJyRQlfY-h8pV-YuuQ8>E#7LfVNT1QyoLUtyEe2E%H9dK)PH6AuF{1^z#utT-a znI0pcfvv{!!D!1|w%e$o)AzSv!@tN(P@~L}Ex87X#=Dir;w~jIP1J zpB6q_YxLC?2HxDVhsNAIpi^6h#cW6Baheh*+n+tFNey@6nyup_0%7X;_xL2E=oF|O z`SL92lXANjlAtCjeYU-kO^;d1wOYSN%8PS%&OSB(&DM8NP!J3mV7kNJYs)A2(jBNg zU>;{e2US6(Ze8!vJ{Tmv@%-5F0rxXh>InkL2vRs4m655AOX6Vl*fhgTxUfDS(Be)$ z+gJ6|y{BD@KgwYYHmo@+U3DG7nV5s$khEasZG%|h*OIGvQ5nkWKYZSoOCN46BO??) zpM__uMaB_6+(uo9Xw{1Ke)y%CN&;FnA#0Yq4b`GUB1j}sBR8j2URx}PYmcl#^y710 ztnz2=RReh{N@8bkDkKRgpZu8N$Du2A1fZ8j+2FX&VWx7W4{ITlhN+kmWVgEpzE`vT zoljR)QlPMU`z^MEfZ;(7=&oM&kITYgy^E9#^lr%S-6&>hU)>SO>y2c_&->K&92k{} zjI!y{Dy|K&EWR1{qTo?TvuRYxL$OK<9k)4ta? zk)H;$AFF#i7aAF))fMTxO?rhDsD^(#6huIpaE->UUHEb==I{}{A&&Rn76pN~~8o%{NpRWKHBMKlY! z4OV2?l$HiF7yZ<*n4C9E2M0BkNK+hmK=A3MnnG$g4AQLi3&5VL!PG?JJ#|6+U>~Z` zNuM!kkUKOl8{d0YQ}%(XSqhaWbqHsc0$0FvVlGwb)p{1%+%*6jFC4=4&~RTBz)m#U zn7+1BYBULqn@lQ$4^B1|icf`b%Y6<0v;Je9U=Vk$SOgVCPR(9pMLJkOrPAnwL!bl> z-OYk2#+7Z45{bl2_@%yxaLNVAeeCIuHY{2OdioGG^Aw^+qIHr);^#~}M<%7u*5r(9 z`Xkkq<3x_F+zpsQAET z73lK#`53T2p$a+9Sl~SQQbxXQQM!!O2(5~(n-vc%y3n+yM2u|vshCy^Ga?%0D_H+& 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%0D>T0#tJA_}MUckj_CIV>w)v22-j7PDXZ=Rb2> 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 aZm<^2Sb~hRU-?i0zbhI#>TlI79{mf9tP|b< literal 0 HcmV?d00001 diff --git a/site/content/docs/v1.17/img/gv_priority3-caseD.png b/site/content/docs/v1.17/img/gv_priority3-caseD.png new file mode 100644 index 0000000000000000000000000000000000000000..11c9a11ce8bfbf020cbf7ed3e1df4227fb28a04e GIT binary patch literal 69760 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�fu>MSxrxgi#n;Lqh=@0@!ay&F0yspK)28*_577-8-b z3r6UEwH0zS3Xzjm6e;P;>2Ie|SYWS8>Fo)f{91$2DxzRS)3~7HtG!~!V^TFhzAxdo zVe4~(oKLW?@9I<47Jel^E~=-XH&iL#vUkV2I>FNuA-soAyK5bE8LA%p$!*tpRn^k{ zJ&m&4t8UhP!-W1yDzf&&DuwCcl(}gz@tL&CEdD?lepJE(|MN5A92exXHDxTZd|B_# zgPb&+3<`?bfE>v4QXj>Pgg$aKDlK%Ga6c8s&~y}m7_>Go1ZVr+<6V2$($n(^AV zN+nh2qJ&=39O~ORx0K#o?E3w=;LiNFQxKx2T;9kC%i#UpZ>LCoIP)$G!JB5|`6vlvNh)KDhi%?D~SMf6{I-kqfCM_)0c)&!Z zbpgD=V1_aaQCp>)j#l8rv+%-nSN>9m1+nEi!X&PyTjYW=i*gQoEHbB+9pyze)2I5%Q;g_+Vy*ZrPoH$uaiwLyf&KP^J8nTN{iGMX)23X-V|O<+ zZB3i?&-~-b;yfJC8y?eaPkJ6`_L~8r*=WA&?H*`R>lRYuxuQ%>fc$W1`V_qA{Kb-O zV}grty%2zd8#c4h)CJK7NwAgG{s`oA7`Ui~Cuf`-=NDlP*6QjNstN@H{ap0K~T-O|sLc+B@K%tx1bU5?dOj6$lj)9i268bBQCv z-Xpu8HJa>YC(+S**yL5$y>=Bd?Db~8J36Q{%ojf9C5(b24!P!aG@$l0CV|xBKdT^y zB%KFqW7{=z{6d~eAJ3LFyR>djbEd8PeWR&bn4K6!FoNuED6^kQ^hqlj6jnJ)f$|jI_i+#f0j;5vVYn zN7q@@05|;Qd3P&+bnjJT!hqbI`2nFd=PtOWz2xti_fFvusVsu&m=gkm_h!NCD^E@` zUfP&bZ%`a7kf~0CR5oN;_!F6J)y3nzI9hLmMzACYB>KekV6HYdigYq$i&eOEp|po@ z1VXIvJ>)`~zfchm>h3dEbru@o1@_Fj$HxuJJFD2jOPGGY{Lny)A#8D;fQacCo6djW z8U7YoN8`sY!zryDC2sezC0JgQ=@tg*)z(O$*VE4|>gD!c=b3$geFzAyuUmMOX~BB( z0gYu;zYk~h{ggl1?riP2y;$c-VM#^rK0T4#jH(uus7MYftZl@$HX2r|zFwa%bv;gm zyMAmBw#N^qATpcH=GBOhspoG~z=Dt1%5zf>d8-f=?b^QAOj8U?p8RZ9PW;|iPK@H> zQX(KU-l;FV|#j1-TgjxpS5{7TONKOG+uJ3#iNM;M ze;^k)r%Lf(*4eQ~jXak$UIq zdg-7jFW%uVm3e!RAt^J10$Gj5J!{}ZMpMCw!_guM(8t{HvVaqxSycI495VYZUB)l( z&45+j3GO>KC}EDtZq;1^cai!tR?LYX^U=-PhKp*6o7wi138x zFJ+Si*ql&=%y=_IhpJQ%emS*L@_kBOtHwI^+{LxZ%~SGQ3F0B}sbYt^{P+4_xv;z2Mse3N8jK1u5h{38qnSh6MQz*A7 z8^7qQvzS%Z7(Z>>s3Um;TaDP_S75S|z1GxD9cu44Y2Nl>}`S*T^xFMJ}I@RMt!jHJoo~9GEVy{=#u9N>sH-Qp~Ut z5%*egC_3TB!Ag~v;abSyG<8qh^F64C*OMnmGmXa@ke4xzU1N1IDSy}x{>%=OGSn0F z=|}m;|I`5+YFAi5ChbhL{mc_{3_#MM=Y*zcqV!E<9YM?nGk<mcYCN2BI*Kl!e(i~@32)I7S=Z| zP2XpFoulAl0AHN2dBfl5l{N>HqWe{!#Snj&5*{-$=kE=g`F7(*<3-1D_(cnIz(~!4C z;C&xKWN(kp`D2_z@ljGCm+X>D(*t4*b-IoQT>(VUEX8uLVAo6|Xlv_L62(}G(i{Yw z0hraQ(I6CR*eD9(hH$Ycx0Fbt_(MFWJ_S15vnTdj<~>szr+8GXDRnPcH;n$lA1IWe z9F7GRrR&qJ9@>$7rq3&ba1?!|GEVcvROh33aIkNql*F$9&M9u^4Aiyv%e@qTFpjT! z3f_ppwK}`m2Uo0r=3s$4R#d?Zn~#U>uo&#!D3C#ywXKX( z=L2RiA7@r4u*g4U>0!#~s(m{k)4~0ksY~jBNfnftbDKsUNS(4kZCqhf2wU^s!P|L3 zI%qfggW(DaaZ}B<5QfSSI1gi1$zUZf=a1Rv9A^iq5q=-Z)+Qlic5@B;){d3slak^U z!7Ghl16dUsO(uL=3mPatG|ylRI?zK>su(&+6`9Sjlim9k zVwDWfrMPIP+QnI&FBDyo87$qr@Ui7MYDOzz00k^U}7;}c~M<-`zHKDMo<2Pq38;IZ|Yz!G+Vc@9h)v{6spE?ta;^6(T z^!A2Gfo26EX^|rGxDItlz#E4cd04^+GVE5o zx9bzGidN|yoNsjLb^ zO>A|uI(L+1}L3YqAA4(BrJ=v>!Rd8RsvsAt;{pS|;#zk?*6PH*LkDh#4Ln6)c4^(89R zz#7=<5;QqG8#*{4(uq$STPtGdNzm8!;^U9iqDlueoKLJS-J|t;atrbuTp8cOLXgs> z&1VUfmM{R{UCr`0L-5%J*bVYvGoYZh$oIjeiq14=@|%{g>rLZ~m)0#tPL}1l@+>10 zK%b2=GW=z1@0I7nxRCGj(^5NMq)D}|4Ja`lt(Jv9G;ES`qcv8MTdcsL&x40UlSI=w zRvF^bKqzm?3WEK4B!X;>k}StDEOkR>u66ai$S5(!kgq6}8N_NQHKJAu)GGRh`;Vw? zsUcedqt|{{wu{tG$ML&*HNP@MJ$^{Bp(lynO_qRq^65Pa5$ZCA;xPNYOokkeTc?fA zpqSogtU+>`UoD?Ht^|0L= zH_iQ+Z?yi-Qd#H*RFG6W4hWG(uDPX&>0M{bYzwN|6O1F#$Z9`4#6pGm)8*CarJ6zl z-^^20Hm||!TJ)u*NRHU+Fi$*wKh$+Cor8A9;pT8;L0sf?Fa#MdgUfs@Z$g&lZ;zXY z@qkYy*4=oXXyM;WNUHUOfg<#S21~V_;BZrkFb0GEQ+$(rq2hy$2uD-vPGDguEICe^ zsoQT)zyrY*s7mW?eJaQ2Aqe;M(vHKLd-Fu@n{R3n_}1^VGEwaL4;9iX_7GkVP>t&y z5(;pA59qzQfoF+u*014HX%!$W$6n@gLXTa)18jLgT9v>6?`H%Na5ZAl2kq0ooW-(U zg>Xh9VWi-ir`h@X_Wijo|8jiv%g(4Rf#}TSi6&~OYW5gt>u4Ody zMIGVzte;9$?+s8<$n~^9`+&@Kv_}ReAA*%L2R`PL=Q__NE9;6w4c?4_;*7(dI}RtPL%%lZ0c=sVPr5!=Zo@zkn-hpzA&o=xN{9 zovz-bTQwh#|Lt$BdygINkXs$Le9lSzrS>LB+%7@ zS}heu{%p~Ku|F64F-jY@B;aaub}lc?r765lf_aAQTj&(zxI|j3l_Y&otOYe;P7pO| zCQKcTp-pTZ7C!yh5^_{a=yO;p;VF>fn_J?Eog^J@`6$nT>ca)Ohh zVBi>;aeJleLU|Z$O7^m}mmF|;b@FlCjvkeAfcPN7nsi7%H_O;ampyR4ZZ~J%yuDt^2f+=lZ`s2Fv}YqbdjvcR~oG z*zEgu$Z;2g`io~UN?0UQhPwoJABz1>-|Kqrw8C&K*_Rc(KLz-jjXzf{@VRQvzJ88U zthL<$0tYl98cw2^7?3j|Vp{{jxS{5vp1KjbS60-@Z1gLqb5^mg z`%{4LVYhv~_f)-U?_?NoLKyQ`6;*{2{~0R$p3a-ITDlhgz#lX}YQ*(~C5<^+!JI#N z4A1Awl2{9hLuFxre}{s+yq}@E(F8_n;qmd6t{AL%Vbub;%a!RDC(%oc4*a zzgon`%i3?Moo`az(d7Nh7h6AE>NB^Mp2AiNVMk#;;ix=u4`o|+E2BU7W>|^$bNXr4 zcGXW&PpB;=ef2)z3@<&d1(^TPHCg{bL5PnxN8Qyi^eeuZ38UID59_#9;=MpBhMtLK zguZ2V%tQtLU&lud1z4IT-{c_6fjQ_;g6NFvt;y-P5EOBOg^5-xJT@7!n=7+wQ4{qn z{?cLZ8|Kgb>H2na1I3Rg{u3;P32K3vUl%1tuB%#GDI;>cmik3}4kk6V33rAb>L9@p zW^2ZDI(=n)+coJj!$tCf-@U&2Q6C?XBD3fr6$Of2;VMS}wVo6~G_oVtt4J63YkCk8 zr#v9Bq0n?L>-AV0*$piz5Jo#&DKQyESjaR5m__r8X#6C>KxINgSF zRwe1r?Ls(*;(1%*4C$p9R0<J_w55X!?!kTZpbhp?2?XNcbC#LI_D^o(`RYmFxRO6^^^{Y z#3Q*#u3xiS_ItOG{8Dq;-aDDRwlCD)Ip|?7-KP=pEtWTVI*0^W$eaALOfMx5cHp3d zhv9FpIW-wLH`l)s6@OuZYJ{5*3fC?=x($j?hOm@fv2SraRqm5Im>v6Nc2&9o4rpk< z{}5Ut!If7nV&^-h2df3_EE@zE{nj$MURKVpvccw!AJ2U*cWl9|CFJXruBu4Dd7*yac;^|9FmNAMe+R{O@3-3WV^S_mf|O3T?ID zYmx8Yhc=oG^JQ(ti#T{}wI3ydgdqonSGlkhbNBC|U(9hKjUTeB$Hk)lhU+uMk2>zj zG19-3lrL9t(Ttu=&>!i&LK0T9Y$VudDRN86LC*ji9@OQq)}b^5Gcbj0eJDCLDb10y zbQ+aY;BP-G%DU^UI?mIcbo%q@fRy6!Mt~-m+ew*CXV#4j6+NHBJwUY)Y1BFxM7KoS z_2p8(Nt7buv6uzPf(2Fo-6~Sd#hN}?hQI(IVcx)0R$$nC)_S>>a=2KjE_K}-e*uF_ z`Ia}eC?6gL5yC)0A|Ps7I_bojNk~xDKf^N##I??=CgNwh3SSPt3onYAqC$Z<@=V2} ziw=^FEXvHEeM4ZMFGSWSMidxwhSl3)u#Q zeZ^_O%P?+^>|BCny8ZlbqQeVFKF;C&=%~WR=Ay_U(J&x!jMiuSsEWyug$6gA&N(8+ z90F9ROjw50%xTBr9qDNc5qy;-q6|d)#h#4AD;}BQE^&E)?YX6=y zmXS3%oO+th3-+VsT~%m9nSsJQl5_O@Rbw`rEIlH9=9)Ask$z{KT#{uxu1Y!GkXmw-5BQ6sSa7C&yTZ;`AG2>bdU-H@XDnsc=LUWYyP< zP|TOp|C2na0~%U#T66N1EM3rg+MZgDRi5K^Po;*$pz_%bZKZHM9wR57)8~DnANh*-^9v{ir1@0E|SiF`R ziVlM?)9=saiD3{SNWtpE8rWxDQ=fYLC9%G?^O8^b~~~=T!gI9H-zO5QVNs z%r|kk6PD8HO{VJIrXp3p09%rL5QrdK%7 ziTPz!xj)!CIm$|D`b)@v*h>ipO@a2Lt+JlvosC88I#dhC*67K;!Z)I*4~oei)h&Mz zbz7%FctBOCeFE63W7LQ*mpsF2_(3WTA_vQ}`kUH-cBO8W|6LyrRGY+R4-V_1pEbu< zIHKDV7{5oO90a%tNarrdp~x_^Kp;gfv=#JOiWQK`eFU{C(ROnSi428@0EUTz@B15* zanKlMs^ar^YS+7yX!r?RGYyW$oa};sQiMLc82k<)Q76&~RoidBLi1`*xyTiCL-i;co!-W18ihhSPO9VE*5*pA=B)mAu+#&)-sgxomuzS~zp8>VpS^*qAs zJbz!Z`UioEh;J5B=wc90jL|923&x0eo@yK`2dZ4su&+ATnR0#{8Vx9naH!o$<#rj^ zryxvGLW>^B&6#El(kbS_!J#Lnr>q<>9#QZQth@|Ul2B~Ug&dveXDwmG$DLM@{Z}?{ zh@iMwhXhpo9UgX1d0OR4mSNnzVbJJAaNeb?5&j?sFaDP-H$+|9yf6I$`ay!A{9r^F zBrAY8p)Y45t(#~_Xy8Umfv|so3x~nORcd4uqo4z-U1SRSJkh0ykDaK21+Uj zD5Ovl5efU<%+O!rOoL2l(sy!&`A?{{erWhLQt)tX27VXCl4p} z(e-Q>SHS@azBrC5bRopnv+Laqt%q0BZP%3^rWh0Z;yU;-gs{k&EXKSP#c)$g51K1xFe0;exclaZ>--0EEuD6y=lf-zsDkjy@7Hv$ z1^+X}mk_Z~inE%ddx@?Y@GgymW6=^9J#*2l?E;P&IEa#12&Zp|0Rt))rX?2!O_Z1b ziJTdS(mWVVQChp7!rdlhvv*e-;fVaLc> ztK5Vaz$BTT0M;=URqqW`J{dkVK|Tr-4V43mSUG+iajSvEgZy*1eBw`}&8YF7;AR09 zP-_(dMFGLyX+U%SJG`PTWoV8nm|}E%wfrs7F3<5yndW&*AaCMt|1~VxH6-vq>Bc{c?<>RWy@E|3E=KJUpDJ=Qgsj12khZ{rko5G8B zB7?Ex{!BN7(G?Rm_p6Rq7ccE)c zf*1W7Sj@+lCH;dEBe7OzRZ%7N?rB7ROv{s!0D&xBotj{z*Uo_gnw2;s3w>2POWI=)bY+|8ufx cr?_~7RG)fuILZd?K)gS)Qc9B5;)a3$2S#KsC;$Ke literal 0 HcmV?d00001 diff --git a/site/content/docs/v1.17/locations.md b/site/content/docs/v1.17/locations.md new file mode 100644 index 000000000..db347801b --- /dev/null +++ b/site/content/docs/v1.17/locations.md @@ -0,0 +1,316 @@ +--- +title: "Backup Storage Locations and Volume Snapshot Locations" +layout: docs +--- + +## Overview + +Velero has two custom resources, `BackupStorageLocation` and `VolumeSnapshotLocation`, that are used to configure where Velero backups and their associated persistent volume snapshots are stored. + +A `BackupStorageLocation` is defined as a bucket or a prefix within a bucket under which all Velero data is stored and a set of additional provider-specific fields (AWS region, Azure storage account, etc.). Velero assumes it has control over the location you provide so you should use a dedicated bucket or prefix. If you provide a prefix, then the rest of the bucket is safe to use for multiple purposes. The [API documentation][1] captures the configurable parameters for each in-tree provider. + +A `VolumeSnapshotLocation` is defined entirely by provider-specific fields (AWS region, Azure resource group, Portworx snapshot type, etc.) The [API documentation][2] captures the configurable parameters for each in-tree provider. + +The user can pre-configure one or more possible `BackupStorageLocations` and one or more `VolumeSnapshotLocations`, and can select *at backup creation time* the location in which the backup and associated snapshots should be stored. + +This configuration design enables a number of different use cases, including: + +- Take snapshots of more than one kind of persistent volume in a single Velero backup. For example, in a cluster with both EBS volumes and Portworx volumes +- Have some Velero backups go to a bucket in an eastern USA region, and others go to a bucket in a western USA region, or to a different storage provider +- For volume providers that support it, like Portworx, you can have some snapshots stored locally on the cluster and have others stored in the cloud + +## Limitations / Caveats + +- Velero supports multiple credentials for `BackupStorageLocations`, allowing you to specify the credentials to use with any `BackupStorageLocation`. + However, use of this feature requires support within the plugin for the object storage provider you wish to use. + All [plugins maintained by the Velero team][5] support this feature. + If you are using a plugin from another provider, please check their documentation to determine if this feature is supported. + +- Velero supports multiple credentials for `VolumeSnapshotLocations`, allowing you to specify the credentials to use with any `VolumeSnapshotLocation`. + However, use of this feature requires support within the plugin for the object storage provider you wish to use. + All [plugins maintained by the Velero team][5] support this feature. + If you are using a plugin from another provider, please check their documentation to determine if this feature is supported. + +- Volume snapshots are still limited by where your provider allows you to create snapshots. For example, AWS and Azure do not allow you to create a volume snapshot in a different region than where the volume is. If you try to take a Velero backup using a volume snapshot location with a different region than where your cluster's volumes are, the backup will fail. + +- Each Velero backup has one `BackupStorageLocation`, and one `VolumeSnapshotLocation` per volume provider. It is not possible (yet) to send a single Velero backup to multiple backup storage locations simultaneously, or a single volume snapshot to multiple locations simultaneously. However, you can always set up multiple scheduled backups that differ only in the storage locations used if redundancy of backups across locations is important. + +- Cross-provider snapshots are not supported. If you have a cluster with more than one type of volume, like EBS and Portworx, but you only have a `VolumeSnapshotLocation` configured for EBS, then Velero will **only** snapshot the EBS volumes. + +- File System Backup data is stored under a prefix/subdirectory of the main Velero bucket, and will go into the bucket corresponding to the `BackupStorageLocation` selected by the user at backup creation time. + +- Velero's backups are split into 2 pieces - the metadata stored in object storage, and snapshots/backups of the persistent volume data. Right now, Velero *itself* does not encrypt either of them, instead it relies on the native mechanisms in the object and snapshot systems. A special case is File System Backup, which backs up the persistent volume data at the filesystem level and send it to Velero's object storage. + +- Velero's compression for object metadata is limited, using Golang's tar implementation. In most instances, Kubernetes objects are limited to 1.5MB in size, but many don't approach that, meaning that compression may not be necessary. Note that File System Backup has not yet implemented compression, but does have de-deduplication capabilities. + +- If you have [multiple](customize-installation.md/#configure-more-than-one-storage-location-for-backups-or-volume-snapshots) `VolumeSnapshotLocations` configured for a provider, you must always specify a valid `VolumeSnapshotLocation` when creating a backup, even if you are using [File System Backup](file-system-backup.md) for volume backups. You can optionally decide to set the [`--default-volume-snapshot-locations`](customize-locations.md#set-default-backup-storage-location-or-volume-snapshot-locations) flag using the `velero server`, which lists the default `VolumeSnapshotLocation` Velero should use if a `VolumeSnapshotLocation` is not specified when creating a backup. If you only have one `VolumeSnapshotLocation` for a provider, Velero will automatically use that location as the default. + +## Examples + +Let's look at some examples of how you can use this configuration mechanism to address some common use cases: + +### Take snapshots of more than one kind of persistent volume in a single Velero backup + +During server configuration: + +```shell +velero snapshot-location create ebs-us-east-1 \ + --provider aws \ + --config region=us-east-1 + +velero snapshot-location create portworx-cloud \ + --provider portworx \ + --config type=cloud +``` + +During backup creation: + +```shell +velero backup create full-cluster-backup \ + --volume-snapshot-locations ebs-us-east-1,portworx-cloud +``` + +Alternately, since in this example there's only one possible volume snapshot location configured for each of our two providers (`ebs-us-east-1` for `aws`, and `portworx-cloud` for `portworx`), Velero doesn't require them to be explicitly specified when creating the backup: + +```shell +velero backup create full-cluster-backup +``` + +### Have some Velero backups go to a bucket in an eastern USA region (default), and others go to a bucket in a western USA region + +In this example, two `BackupStorageLocations` will be created within the same account but in different regions. +They will both use the credentials provided at install time and stored in the `cloud-credentials` secret. +If you need to configure unique credentials for each `BackupStorageLocation`, please refer to the [later example][8]. + +During server configuration: + +```shell +velero backup-location create backups-primary \ + --provider aws \ + --bucket velero-backups \ + --config region=us-east-1 \ + --default + +velero backup-location create backups-secondary \ + --provider aws \ + --bucket velero-backups \ + --config region=us-west-1 +``` + +A "default" backup storage location (BSL) is where backups get saved to when no BSL is specified at backup creation time. + +You can change the default backup storage location at any time by setting the `--default` flag using the +`velero backup-location set` command and configure a different location to be the default. + +Examples: + +```shell +velero backup-location set backups-secondary --default +``` + + + +During backup creation: + +```shell +velero backup create full-cluster-backup +``` + +Or: + +```shell +velero backup create full-cluster-alternate-location-backup \ + --storage-location backups-secondary +``` + +### For volume providers that support it (like Portworx), have some snapshots be stored locally on the cluster and have others be stored in the cloud + +During server configuration: + +```shell +velero snapshot-location create portworx-local \ + --provider portworx \ + --config type=local + +velero snapshot-location create portworx-cloud \ + --provider portworx \ + --config type=cloud +``` + +During backup creation: + +```shell +# Note that since in this example you have two possible volume snapshot locations for the Portworx +# provider, you need to explicitly specify which one to use when creating a backup. Alternately, +# you can set the --default-volume-snapshot-locations flag on the `velero server` command (run by +# the Velero deployment) to specify which location should be used for each provider by default, in +# which case you don't need to specify it when creating a backup. +velero backup create local-snapshot-backup \ + --volume-snapshot-locations portworx-local +``` + +Or: + +```shell +velero backup create cloud-snapshot-backup \ + --volume-snapshot-locations portworx-cloud +``` + +### Use a single location + +If you don't have a use case for more than one location, it's still easy to use Velero. Let's assume you're running on AWS, in the `us-west-1` region: + +During server configuration: + +```shell +velero backup-location create backups-primary \ + --provider aws \ + --bucket velero-backups \ + --config region=us-west-1 \ + --default + +velero snapshot-location create ebs-us-west-1 \ + --provider aws \ + --config region=us-west-1 +``` + +During backup creation: + +```shell +# Velero will automatically use your configured backup storage location and volume snapshot location. +# Nothing needs to be specified when creating a backup. +velero backup create full-cluster-backup +``` + +### Create a storage location that uses unique credentials + +It is possible to create additional `BackupStorageLocations` that use their own credentials. +This enables you to save backups to another storage provider or to another account with the storage provider you are already using. + +If you create additional `BackupStorageLocations` without specifying the credentials to use, Velero will use the credentials provided at install time and stored in the `cloud-credentials` secret. +Please see the [earlier example][9] for details on how to create multiple `BackupStorageLocations` that use the same credentials. + +#### Prerequisites +- This feature requires support from the [object storage provider plugin][5] you wish to use. + All plugins maintained by the Velero team support this feature. + If you are using a plugin from another provider, please check their documentation to determine if this is supported. +- The [plugin for the object storage provider][5] you wish to use must be [installed][6]. +- You must create a file with the object storage credentials. Follow the instructions provided by your object storage provider plugin to create this file. + +Once you have installed the necessary plugin and created the credentials file, create a [Kubernetes Secret][7] in the Velero namespace that contains these credentials: + +```shell +kubectl create secret generic -n velero credentials --from-file=bsl= +``` + +This will create a secret named `credentials` with a single key (`bsl`) which contains the contents of your credentials file. +Next, create a `BackupStorageLocation` that uses this Secret by passing the Secret name and key in the `--credential` flag. +When interacting with this `BackupStorageLocation` in the future, Velero will fetch the data from the key within the Secret you provide. + +For example, a new `BackupStorageLocation` with a Secret would be configured as follows: + +```bash +velero backup-location create \ + --provider \ + --bucket \ + --config region= \ + --credential== +``` + +The `BackupStorageLocation` is ready to use when it has the phase `Available`. +You can check the status with the following command: + +```bash +velero backup-location get +``` + +To use this new `BackupStorageLocation` when performing a backup, use the flag `--storage-location ` when running `velero backup create`. +You may also set this new `BackupStorageLocation` as the default with the command `velero backup-location set --default `. + +### Modify the credentials used by an existing storage location + +By default, `BackupStorageLocations` will use the credentials provided at install time and stored in the `cloud-credentials` secret in the Velero namespace. +You can modify these existing credentials by [editing the `cloud-credentials` secret][10], however, these changes will apply to all locations using this secret. +This may be the desired outcome, for example, in the case where you wish to rotate the credentials used for a particular account. + +You can also opt to modify an existing `BackupStorageLocation` such that it uses its own credentials by using the `backup-location set` command. + +If you have a credentials file that you wish to use for a `BackupStorageLocation`, follow the instructions above to create the Secret with that file in the Velero namespace. + +Once you have created the Secret, or have an existing Secret which contains the credentials you wish to use for your `BackupStorageLocation`, set the credential to use as follows: + +```bash +velero backup-location set \ + --credential== +``` + +### Create a volume snapshot location that uses unique credentials + +It is possible to create additional `VolumeSnapshotLocations` that use their own credentials. +This may be necessary if you already have default credentials which don't match the account used by the cloud volumes being backed up. + +If you create additional `VolumeSnapshotLocations` without specifying the credentials to use, Velero will use the credentials provided at install time and stored in the `cloud-credentials` secret. + +#### Prerequisites +- This feature requires support from the [volume snapshotter plugin][5] you wish to use. + All plugins maintained by the Velero team support this feature. + If you are using a plugin from another provider, please check their documentation to determine if this is supported. +- The [plugin for the volume snapshotter provider][5] you wish to use must be [installed][6]. +- You must create a file with the object storage credentials. Follow the instructions provided by your object storage provider plugin to create this file. + +Once you have installed the necessary plugin and created the credentials file, create a [Kubernetes Secret][7] in the Velero namespace that contains these credentials: + +```shell +kubectl create secret generic -n velero credentials --from-file=vsl= +``` + +This will create a secret named `credentials` with a single key (`vsl`) which contains the contents of your credentials file. +Next, create a `VolumeSnapshotLocation` that uses this Secret by passing the Secret name and key in the `--credential` flag. +When interacting with this `VolumeSnapshotLocation` in the future, Velero will fetch the data from the key within the Secret you provide. + +For example, a new `VolumeSnapshotLocation` with a Secret would be configured as follows: + +```bash +velero snapshot-location create \ + --provider \ + --config region= \ + --credential== +``` + +To use this new `VolumeSnapshotLocation` when performing a backup, use the flag `--volume-snapshot-locations [, \ + --credential== +``` + +## Additional Use Cases + +1. If you're using Azure's AKS, you may want to store your volume snapshots outside of the "infrastructure" resource group that is automatically created when you create your AKS cluster. This is possible using a `VolumeSnapshotLocation`, by specifying a `resourceGroup` under the `config` section of the snapshot location. See the [Azure volume snapshot location documentation][3] for details. + +1. If you're using Azure, you may want to store your Velero backups across multiple storage accounts and/or resource groups/subscriptions. This is possible using a `BackupStorageLocation`, by specifying a `storageAccount`, `resourceGroup` and/or `subscriptionId`, respectively, under the `config` section of the backup location. See the [Azure backup storage location documentation][4] for details. + + + +[1]: api-types/backupstoragelocation.md +[2]: api-types/volumesnapshotlocation.md +[3]: https://github.com/vmware-tanzu/velero-plugin-for-microsoft-azure/blob/main/volumesnapshotlocation.md +[4]: https://github.com/vmware-tanzu/velero-plugin-for-microsoft-azure/blob/main/backupstoragelocation.md +[5]: /plugins +[6]: overview-plugins.md +[7]: https://kubernetes.io/docs/concepts/configuration/secret/ +[8]: #create-a-storage-location-that-uses-unique-credentials +[9]: #have-some-velero-backups-go-to-a-bucket-in-an-eastern-usa-region-default-and-others-go-to-a-bucket-in-a-western-usa-region +[10]: https://kubernetes.io/docs/concepts/configuration/secret/#editing-a-secret diff --git a/site/content/docs/v1.17/maintainers.md b/site/content/docs/v1.17/maintainers.md new file mode 100644 index 000000000..33b38260b --- /dev/null +++ b/site/content/docs/v1.17/maintainers.md @@ -0,0 +1,37 @@ +--- +title: "Instructions for Maintainers" +layout: docs +toc: "true" +--- + +There are some guidelines maintainers need to follow. We list them here for quick reference, especially for new maintainers. These guidelines apply to all projects in the Velero org, including the main project, the Velero Helm chart, and all other [related repositories](https://github.com/vmware-tanzu/velero/blob/v1.17.0/GOVERNANCE.md#code-repositories). + +Please be sure to also go through the guidance under the entire [Contribute](start-contributing/) section. + +## Reviewing PRs +- PRs require 2 approvals before it is mergeable. +- The second reviewer usually merges the PR (if you notice a PR open for a while and with 2 approvals, go ahead and merge it!) +- As you review a PR that is not yet ready to merge, please check if the "request review" needs to be refreshed for any reviewer (this is better than @mention at them) +- Refrain from @mention other maintainers to review the PR unless it is an immediate need. All maintainers already get notified through the automated add to the "request review". If it is an urgent need, please add a helpful message as to why it is so people can properly prioritize work. +- There is no need to manually request reviewers: after the PR is created, all maintainers will be automatically added to the list (note: feel free to remove people if they are on PTO, etc). +- Be familiar with the [lazy consensus](https://github.com/vmware-tanzu/velero/blob/v1.17.0/GOVERNANCE.md#lazy-consensus) policy for the project. + +Some tips for doing reviews: +- There are some [code standards and general guidelines](https://velero.io/docs/v1.17.0/code-standards) we aim for +- We have [guidelines for writing and reviewing documentation](https://velero.io/docs/v1.17.0/style-guide/) +- When reviewing a design document, ensure it follows [our format and guidelines]( https://github.com/vmware-tanzu/velero/blob/v1.17.0/design/_template.md). Also, when reviewing a PR that implements a previously accepted design, ensure the associated design doc is moved to the [design/implemented](https://github.com/vmware-tanzu/velero/tree/main/design/implemented) folder. + + +## Creating a release +Maintainers are expected to create releases for the project. We have parts of the process automated, and full [instructions](release-instructions). +We are working towards automating more the Velero testing, but there is still a need for manual testing as part of the release process. +The manual test cases for release testing are documented [here](./manual-testing). + +## Community support +Maintainers are expected to participate in the community support rotation. We have guidelines for how we handle the [support](support-process). + +## Community engagement +Maintainers for the Velero project are highly involved with the open source community. All the online community meetings for the project are listed in our [community](community) page. + +## How do I become a maintainer? +The Velero project welcomes contributors of all kinds. We are also always on the look out for a high level of engagement from contributors and opportunities to bring in new maintainers. If this is of interest, take a look at how [adding a maintainer](https://github.com/vmware-tanzu/velero/blob/v1.17.0/GOVERNANCE.md#maintainers) is decided. diff --git a/site/content/docs/v1.17/manual-testing.md b/site/content/docs/v1.17/manual-testing.md new file mode 100644 index 000000000..411508738 --- /dev/null +++ b/site/content/docs/v1.17/manual-testing.md @@ -0,0 +1,98 @@ +--- +title: "Manual Testing Requirements for Velero" +layout: docs +--- + +Although we have automated unit and end-to-end tests, there is still a need for Velero to undergo manual tests during a release. +This document outlines the manual test operations that Velero needs to correctly perform in order to be considered ready for release. + +## Current test cases + +The following are test cases that are currently performed as part of a Velero release. + +### Install + +- Verify that Velero CRDs are compatible with the earliest and latest versions of Kubernetes that we support: + - Kubernetes v1.12 + - Kubernetes v1.20 + +### Upgrade + +- Verify that Velero upgrade instructions work + +### Basic functionality + +The "Backup and Restore" test cases below describe general backup and restore functionality that needs to run successfully on all the following providers that we maintain plugins for: +- AWS +- GCP +- Microsoft Azure +- VMware vSphere + +#### Backup and Restore + +- Verify that a backup and restore using Volume Snapshots can be performed +- Verify that a backup and restore using File System Backup can be performed +- Verify that a backup of a cluster workload can be restored in a new cluster +- Verify that an installation using the latest version can be used to restore from backups created with the last 3 versions. + - e.g. Install Velero 1.6 and use it to restore backups from Velero v1.3, v1.4, v1.5. + +### Working with Multiple Providers + +The following are test cases that exercise Velero behaviour when interacting with multiple providers: + +- Verify that a backup and restore to multiple BackupStorageLocations using the same provider with unique credentials can be performed +- Verify that a backup and restore to multiple BackupStorageLocations using different providers with unique credentials can be performed +- Verify that a backup and restore that includes volume snapshots using different providers for the snapshots and object storage can be performed + - e.g. perform a backup and restore using AWS for the VolumeSnapshotLocation and Azure Blob Storage as the BackupStorageLocation + +## Future test cases + +The following are test cases that are not currently performed as part of a Velero release but cases that we will want to cover with future releases. + +### Schedules + +- Verify that schedules create a backup upon creation and create Backup resources at the correct frequency + +### Resource management + +- Verify that deleted backups are successfully removed from object storage +- Verify that backups that have been removed from object storage can still be deleted with `velero delete backup` +- Verify that Volume Snapshots associated with a deleted backup are removed +- Verify that backups that exceed their TTL are deleted +- Verify that existing backups in object storage are synced to Velero + +### Backup repository test cases + +- Verify that backup repository maintenance is performed as the specified interval + +### Backup Hooks + +- Verify that a pre backup hook provided via pod annotation is performed during backup +- Verify that a pre backup hook provided via Backup spec is performed during backup +- Verify that a post backup hook provided via pod annotation is performed during backup +- Verify that a post backup hook provided via Backup spec is performed during backup + +### Restore Hooks + +- Verify that an InitContainer restore hook provided via pod annotation is performed during restore +- Verify that an InitContainer restore hook provided via Restore spec is performed during restore +- Verify that an InitContainer restore hook provided via Restore spec is performed during restore that includes restoring File System Backup volumes +- Verify that an Exec restore hook provided via pod annotation is performed during restore +- Verify that an Exec restore hook provided via Restore spec is performed during restore + + +#### Resource filtering + +- Verify that backups and restores correctly apply the following resource filters: + - `--include-namespaces` + - `--include-resources` + - `--include-cluster-resources` + - `--exclude-namespaces` + - `--exclude-resources` + - `velero.io/exclude-from-backup=true` label + +- Since v1.11, new resource filters are added. The new filters only work for backup, and cannot work with old filters (`--include-resources`, `--exclude-resources` and `--include-cluster-resources`). Need to verify backups correctly apply the following new resource filters: + - `--exclude-cluster-scoped-resources` + - `--include-cluster-scoped-resources` + - `--exclude-namespace-scoped-resources` + - `--include-namespace-scoped-resources` diff --git a/site/content/docs/v1.17/migration-case.md b/site/content/docs/v1.17/migration-case.md new file mode 100644 index 000000000..5f51ac212 --- /dev/null +++ b/site/content/docs/v1.17/migration-case.md @@ -0,0 +1,108 @@ +--- +title: "Cluster migration" +layout: docs +--- + +Velero's backup and restore capabilities make it a valuable tool for migrating your data between clusters. Cluster migration with Velero is based on Velero's [object storage sync](how-velero-works.md#object-storage-sync) functionality, which is responsible for syncing Velero resources from your designated object storage to your cluster. This means that to perform cluster migration with Velero you must point each Velero instance running on clusters involved with the migration to the same cloud object storage location. + +This page outlines a cluster migration scenario and some common configurations you will need to start using Velero to begin migrating data. + +## Before migrating your cluster + +Before migrating you should consider the following, + +* Velero does not natively support the migration of persistent volumes snapshots across cloud providers. If you would like to migrate volume data between cloud platforms, enable [File System Backup](file-system-backup.md), which will backup volume contents at the filesystem level. +* Velero doesn't support restoring into a cluster with a lower Kubernetes version than where the backup was taken. +* Migrating workloads across clusters that are not running the same version of Kubernetes might be possible, but some factors need to be considered before migration, including the compatibility of API groups between clusters for each custom resource. If a Kubernetes version upgrade breaks the compatibility of core/native API groups, migrating with Velero will not be possible without first updating the impacted custom resources. For more information about API group versions, please see [EnableAPIGroupVersions](enable-api-group-versions-feature.md). +* The Velero plugin for AWS and Azure does not support migrating data between regions. If you need to do this, you must use [File System Backup](file-system-backup.md). + + +## Migration Scenario + +This scenario steps through the migration of resources from Cluster 1 to Cluster 2. In this scenario, both clusters are using the same cloud provider, AWS, and Velero's [AWS plugin](https://github.com/vmware-tanzu/velero-plugin-for-aws). + +1. On Cluster 1, make sure Velero is installed and points to an object storage location using the `--bucket` flag. + + ``` + velero install --provider aws --image velero/velero:v1.8.0 --plugins velero/velero-plugin-for-aws:v1.4.0 --bucket velero-migration-demo --secret-file xxxx/aws-credentials-cluster1 --backup-location-config region=us-east-2 --snapshot-location-config region=us-east-2 + ``` + + During installation, Velero creates a Backup Storage Location called `default` inside the `--bucket` your provided in the install command, in this case `velero-migration-demo`. This is the location that Velero will use to store backups. Running `velero backup-location get` will show the backup location of Cluster 1. + + + ``` + velero backup-location get + NAME PROVIDER BUCKET/PREFIX PHASE LAST VALIDATED ACCESS MODE DEFAULT + default aws velero-migration-demo Available 2022-05-13 13:41:30 +0800 CST ReadWrite true + ``` + +1. Still on Cluster 1, make sure you have a backup of your cluster. Replace `` with a name for your backup. + + ``` + velero backup create + ``` + + Alternatively, you can create a [scheduled backup](https://velero.io/docs/v1.17.0/backup-reference/#schedule-a-backup) of your data with the Velero `schedule` operation. This is the recommended way to make sure your data is automatically backed up according to the schedule you define. + + The default backup retention period, expressed as TTL (time to live), is 30 days (720 hours); you can use the `--ttl ` flag to change this as necessary. See [how velero works](how-velero-works.md#set-a-backup-to-expire) for more information about backup expiry. + +1. On Cluster 2, make sure that Velero is installed. Note that the install command below has the same `region` and `--bucket` location as the install command for Cluster 1. The Velero plugin for AWS does not support migrating data between regions. + + ``` + velero install --provider aws --image velero/velero:v1.8.0 --plugins velero/velero-plugin-for-aws:v1.4.0 --bucket velero-migration-demo --secret-file xxxx/aws-credentials-cluster2 --backup-location-config region=us-east-2 --snapshot-location-config region=us-east-2 + ``` + + Alternatively you could configure `BackupStorageLocations` and `VolumeSnapshotLocations` after installing Velero on Cluster 2, pointing to the `--bucket` location and `region` used by Cluster 1. To do this you can use to `velero backup-location create` and `velero snapshot-location create` commands. + + ``` + velero backup-location create bsl --provider aws --bucket velero-migration-demo --config region=us-east-2 --access-mode=ReadOnly + ``` + + Its recommended that you configure the `BackupStorageLocations` as read-only + by using the `--access-mode=ReadOnly` flag for `velero backup-location create`. This will make sure that the backup is not deleted from the object store by mistake during the restore. See `velero backup-location –help` for more information about the available flags for this command. + + ``` + velero snapshot-location create vsl --provider aws --config region=us-east-2 + ``` + See `velero snapshot-location –help` for more information about the available flags for this command. + + +1. Continuing on Cluster 2, make sure that the Velero Backup object created on Cluster 1 is available. `` should be the same name used to create your backup of Cluster 1. + + ``` + velero backup describe + ``` + + Velero resources are [synchronized](how-velero-works.md#object-storage-sync) with the backup files in object storage. This means that the Velero resources created by Cluster 1's backup will be synced to Cluster 2 through the shared Backup Storage Location. Once the sync occurs, you will be able to access the backup from Cluster 1 on Cluster 2 using Velero commands. The default sync interval is 1 minute, so you may need to wait before checking for the backup's availability on Cluster 2. You can configure this interval with the `--backup-sync-period` flag to the Velero server on Cluster 2. + +1. On Cluster 2, once you have confirmed that the right backup is available, you can restore everything to Cluster 2. + + ``` + velero restore create --from-backup + ``` + + Make sure `` is the same backup name from Cluster 1. + +## Verify Both Clusters + +Check that the Cluster 2 is behaving as expected: + +1. On Cluster 2, run: + + ``` + velero restore get + ``` + +1. Then run: + + ``` + velero restore describe + ``` + + Your data that was backed up from Cluster 1 should now be available on Cluster 2. + +If you encounter issues, make sure that Velero is running in the same namespace in both clusters. + + +## Notice +If the two clusters couldn't share the snapshots generated by backup, for example migration from EKS to AKS, then please consider using [the file system backup](file-system-backup.md) or [the snapshot data mover](csi-snapshot-data-movement.md). \ No newline at end of file diff --git a/site/content/docs/v1.17/namespace.md b/site/content/docs/v1.17/namespace.md new file mode 100644 index 000000000..68561e720 --- /dev/null +++ b/site/content/docs/v1.17/namespace.md @@ -0,0 +1,22 @@ +--- +title: "Run in a non-default namespace" +layout: docs +--- + +The Velero installation and backups by default are run in the `velero` namespace. However, it is possible to use a different namespace. + +## Customize the namespace during install + +Use the `--namespace` flag, in conjunction with the other flags in the `velero install` command (as shown in the [the Velero install instructions][0]). This will inform Velero where to install. + +## Customize the namespace for operational commands + +To have namespace consistency, specify the namespace for all Velero operational commands to be the same as the namespace used to install Velero: + +```bash +velero client config set namespace= +``` + +Alternatively, you may use the global `--namespace` flag with any operational command to tell Velero where to run. + +[0]: basic-install.md#install-the-cli diff --git a/site/content/docs/v1.17/node-agent-concurrency.md b/site/content/docs/v1.17/node-agent-concurrency.md new file mode 100644 index 000000000..1fbc52a19 --- /dev/null +++ b/site/content/docs/v1.17/node-agent-concurrency.md @@ -0,0 +1,81 @@ +--- +title: "Node-agent Concurrency" +layout: docs +--- + +Velero node-agent is a daemonset hosting modules to complete the concrete tasks of backups/restores, i.e., file system backup/restore, CSI snapshot data movement. +Varying from the data size, data complexity, resource availability, the tasks may take a long time and remarkable resources (CPU, memory, network bandwidth, etc.). These tasks make the loads of node-agent. + +Node-agent concurrency configurations allow you to configure the concurrent number of node-agent loads per node. When the resources are sufficient in nodes, you can set a large concurrent number, so as to reduce the backup/restore time; otherwise, the concurrency should be reduced, otherwise, the backup/restore may encounter problems, i.e., time lagging, hang or OOM kill. + +To set Node-agent concurrency configurations, a configMap should be created manually. The configMap should be in the same namespace where Velero is installed. If multiple Velero instances are installed in different namespaces, there should be one configMap in each namespace which applies to node-agent in that namespace only. The name of the configMap should be specified in the node-agent server parameter ```--node-agent-configmap```. +Node-agent server checks these configurations at startup time. Therefore, you could edit this configMap any time, but in order to make the changes effective, node-agent server needs to be restarted. + +The users can specify the ConfigMap name during velero installation by CLI: +`velero install --node-agent-configmap=` + +### Global concurrent number +You can specify a concurrent number that will be applied to all nodes if the per-node number is not specified. This number is set through ```globalConfig``` field in ```loadConcurrency```. +The number starts from 1 which means there is no concurrency, only one load is allowed. There is no roof limit. If this number is not specified or not valid, a hard-coded default value will be used, the value is set to 1. + +### Per-node concurrent number +You can specify different concurrent number per node, for example, you can set 3 concurrent instances in Node-1, 2 instances in Node-2 and 1 instance in Node-3. +The range of Per-node concurrent number is the same with Global concurrent number. Per-node concurrent number is preferable to Global concurrent number, so it will overwrite the Global concurrent number for that node. + +Per-node concurrent number is implemented through ```perNodeConfig``` field in ```loadConcurrency```. +```perNodeConfig``` is a list of ```RuledConfigs``` each item of which matches one or more nodes by label selectors and specify the concurrent number for the matched nodes. +Here is an example of the ```perNodeConfig``: +``` +"nodeSelector: kubernetes.io/hostname=node1; number: 3" +"nodeSelector: beta.kubernetes.io/instance-type=Standard_B4ms; number: 5" +``` +The first element means the node with host name ```node1``` gets the Per-node concurrent number of 3. +The second element means all the nodes with label ```beta.kubernetes.io/instance-type``` of value ```Standard_B4ms``` get the Per-node concurrent number of 5. +At least one node is expected to have a label with the specified ```RuledConfigs``` element (rule). If no node is with this label, the Per-node rule makes no effect. +If one node falls into more than one rules, e.g., if node1 also has the label ```beta.kubernetes.io/instance-type=Standard_B4ms```, the smallest number (3) will be used. + +### Sample +A sample of the complete ConfigMap is as below: +```json +{ + "loadConcurrency": { + "globalConfig": 2, + "perNodeConfig": [ + { + "nodeSelector": { + "matchLabels": { + "kubernetes.io/hostname": "node1" + } + }, + "number": 3 + }, + { + "nodeSelector": { + "matchLabels": { + "beta.kubernetes.io/instance-type": "Standard_B4ms" + } + }, + "number": 5 + } + ] + } +} +``` +To create the ConfigMap, save something like the above sample to a json file and then run below command: +``` +kubectl create cm -n velero --from-file= +``` +To provide the ConfigMap to node-agent, edit the node-agent daemonset and add the ```- --node-agent-configmap``` argument to the spec: +1. Open the node-agent daemonset spec +``` +kubectl edit ds node-agent -n velero +``` +2. Add ```- --node-agent-configmap``` to ```spec.template.spec.containers``` +``` +spec: + template: + spec: + containers: + - args: + - --node-agent-configmap= +``` diff --git a/site/content/docs/v1.17/node-agent-prepare-queue-length.md b/site/content/docs/v1.17/node-agent-prepare-queue-length.md new file mode 100644 index 000000000..aa2770175 --- /dev/null +++ b/site/content/docs/v1.17/node-agent-prepare-queue-length.md @@ -0,0 +1,48 @@ +--- +title: "Node-agent Prepare Queue Length" +layout: docs +--- + +During [CSI Snapshot Data Movement][1], Velero built-in data mover launches data mover pods to run the data transfer. +During [fs-backup][2], Velero also launches data mover pods to run the data transfer. +Other intermediate resources may also be created along with the data mover pods, i.e., PVCs, VolumeSnapshots, VolumeSnapshotContents, etc. + +Velero uses [node-agent Concurrency Configuration][3] to control the number of concurrent data transfer activities across the nodes, by default, the concurrency is 1 per node. + +when the parallelism across the available nodes are much lower than the total number of volumes to be backed up/restored, the intermediate objects may exist for much longer time unnecessarily, which takes unnecessary resources from the cluster. +The available nodes are decided by various factors, e.g., node OS type (linux or Windows), [Node Selection][4] (for CSI Snapshot Data Movement only), etc. + +Velero allows you to configure the `prepareQueueLength` in node-agent Configuration, which defines the maximum number of `DataUpload`/`DataDownload`/`PodVolumeBackup`/`PodVolumeRestore` CRs under the preparation statuses but are not yet processed by any node (e.g., in phases of `Accepted`, `Prepared`). In this way, the number of intermediate objects are constrained. + +### Sample +Here is a sample of the configMap with ```prepareQueueLength```: +```json +{ + "prepareQueueLength": 10 +} +``` + +To create the configMap, save something like the above sample to a json file and then run below command: +``` +kubectl create cm node-agent-config -n velero --from-file= +``` + +To provide the configMap to node-agent, edit the node-agent daemonset and add the ```- --node-agent-config``` argument to the spec: +1. Open the node-agent daemonset spec +``` +kubectl edit ds node-agent -n velero +``` +2. Add ```- --node-agent-config``` to ```spec.template.spec.containers``` +``` +spec: + template: + spec: + containers: + - args: + - --node-agent-config= +``` + +[1]: csi-snapshot-data-movement.md +[2]: file-system-backup.md +[3]: node-agent-concurrency.md +[4]: data-movement-node-selection.md \ No newline at end of file diff --git a/site/content/docs/v1.17/on-premises.md b/site/content/docs/v1.17/on-premises.md new file mode 100644 index 000000000..88e547973 --- /dev/null +++ b/site/content/docs/v1.17/on-premises.md @@ -0,0 +1,95 @@ +--- +title: "On-Premises Environments" +layout: docs +--- + +You can run Velero in an on-premises cluster in different ways depending on your requirements. + +### Selecting an object storage provider + +You must select an object storage backend that Velero can use to store backup data. [Supported providers][0] contains information on various +options that are supported or have been reported to work by users. + +If you do not already have an object storage system, [MinIO][2] is an open-source S3-compatible object storage system that can be installed on-premises and is compatible with Velero. The details of configuring it for production usage are out of scope for Velero's documentation, but an [evaluation install guide][3] using MinIO is provided for convenience. + +### (Optional) Selecting volume snapshot providers + +If you need to back up persistent volume data, you must select a volume backup solution. [Supported providers][0] contains information on the supported options. + +For example, if you use [Portworx][4] for persistent storage, you can install their Velero plugin to get native Portworx snapshots as part of your Velero backups. + +If there is no native snapshot plugin available for your storage platform, you can use Velero's [File System Backup][1], which provides a platform-agnostic file-level backup solution for volume data. + +### Air-gapped deployments + +In an air-gapped deployment, there is no access to the public internet, and therefore no access to public container registries. + +In these scenarios, you will need to make sure that you have an internal registry, such as [Harbor][5], installed and the Velero core and plugin images loaded into your internal registry. + +Below you will find instructions to downloading the Velero images to your local machine, tagging them, then uploading them to your custom registry. + +#### Preparing the Velero image + +First, download the Velero image, tag it for the your private registry, then upload it into the registry so that it can be pulled by your cluster. + +```bash +PRIVATE_REG= +VELERO_VERSION= + +docker pull velero/velero:$VELERO_VERSION +docker tag velero/velero:$VELERO_VERSION $PRIVATE_REG/velero:$VELERO_VERSION +docker push $PRIVATE_REG/velero:$VELERO_VERSION +``` + +#### Preparing plugin images + +Next, repeat these steps for any plugins you may need. This example will use the AWS plugin, but the plugin name should be replaced with the plugins you will need. + +```bash +PRIVATE_REG= +PLUGIN_VERSION= + +docker pull velero/velero-plugin-for-aws:$PLUGIN_VERSION +docker tag velero/velero-plugin-for-aws:$PLUGIN_VERSION $PRIVATE_REG/velero-plugin-for-aws:$PLUGIN_VERSION +docker push $PRIVATE_REG/velero-plugin-for-aws:$PLUGIN_VERSION +``` + +#### Preparing the restore helper image (optional) + +If you are using File System Backup, you will also need to upload the restore helper image. + +```bash +PRIVATE_REG= +VELERO_VERSION= + +docker pull velero/velero-restore-helper:$VELERO_VERSION +docker tag velero/velero-restore-helper:$VELERO_VERSION $PRIVATE_REG/velero-restore-helper:$VELERO_VERSION +docker push $PRIVATE_REG/velero-restore-helper:$VELERO_VERSION +``` + +#### Pulling specific architecture images (optional) + +Velero uses Docker manifests for its images, allowing Docker to pull the image needed based on your client machine's architecture. + +If you need to pull a specific image, you should replace the `velero/velero` image with the specific architecture image, such as `velero/velero-arm`. + +To see an up-to-date list of architectures, be sure to enable Docker experimental features and use `docker manifest inspect velero/velero` (or whichever image you're interested in), and join the architecture string to the end of the image name with `-`. + +#### Installing Velero + +By default, `velero install` will use the public `velero/velero` image. When using an air-gapped deployment, use your private registry's image for Velero and your private registry's images for any plugins. + +```bash +velero install \ + --image=$PRIVATE_REG/velero:$VELERO_VERSION \ + --plugins=$PRIVATE_REG/velero-plugin-for-aws:$PLUGIN_VERSION \ +<....> +``` + + +[0]: supported-providers.md +[1]: file-system-backup.md +[2]: https://min.io +[3]: contributions/minio.md +[4]: https://portworx.com +[5]: https://goharbor.io/ diff --git a/site/content/docs/v1.17/output-file-format.md b/site/content/docs/v1.17/output-file-format.md new file mode 100644 index 000000000..8d4823505 --- /dev/null +++ b/site/content/docs/v1.17/output-file-format.md @@ -0,0 +1,224 @@ +--- +title: "Output file format" +layout: docs +--- + +A backup is a gzip-compressed tar file whose name matches the Backup API resource's `metadata.name` (what is specified during `velero backup create `). + +In cloud object storage, each backup file is stored in its own subdirectory in the bucket specified in the Velero server configuration. This subdirectory includes an additional file called `velero-backup.json`. The JSON file lists all information about your associated Backup resource, including any default values. This gives you a complete historical record of the backup configuration. The JSON file also specifies `status.version`, which corresponds to the output file format. + +The directory structure in your cloud storage looks something like: + +``` +rootBucket/ + backup1234/ + velero-backup.json + backup1234.tar.gz +``` + +## Example backup JSON file + +```json +{ + "kind": "Backup", + "apiVersion": "velero.io/v1", + "metadata": { + "name": "test-backup", + "namespace": "velero", + "selfLink": "/apis/velero.io/v1/namespaces/velero/backups/test-backup", + "uid": "a12345cb-75f5-11e7-b4c2-abcdef123456", + "resourceVersion": "337075", + "creationTimestamp": "2017-07-31T13:39:15Z" + }, + "spec": { + "includedNamespaces": [ + "*" + ], + "excludedNamespaces": null, + "includedResources": [ + "*" + ], + "excludedResources": null, + "labelSelector": null, + "snapshotVolumes": true, + "ttl": "24h0m0s" + }, + "status": { + "version": 1, + "formatVersion": "1.1.0", + "expiration": "2017-08-01T13:39:15Z", + "phase": "Completed", + "volumeBackups": { + "pvc-e1e2d345-7583-11e7-b4c2-abcdef123456": { + "snapshotID": "snap-04b1a8e11dfb33ab0", + "type": "gp2", + "iops": 100 + } + }, + "validationErrors": null + } +} +``` +Note that this file includes detailed info about your volume snapshots in the `status.volumeBackups` field, which can be helpful if you want to manually check them in your cloud provider GUI. + +## Output File Format Versioning + +The Velero output file format is intended to be relatively stable, but may change over time to support new features. + +To accommodate this, Velero follows [Semantic Versioning](http://semver.org/) for the file format version. + +Minor and patch versions will indicate backwards-compatible changes that previous versions of Velero can restore, including new directories or files. + +A major version would indicate that a version of Velero older than the version that created the backup could not restore it, usually because of moved or renamed directories or files. + +Major versions of the file format will be incremented with major version releases of Velero. +However, a major version release of Velero does not necessarily mean that the backup format version changed - Velero 3.0 could still use backup file format 2.0, as an example. + +## Versions + +### File Format Version: 1.1 (Current) + +Version 1.1 added support of API groups versions as part of the backup. Previously, only the preferred version of each API groups was backed up. Each resource has one or more sub-directories: one sub-directory for each supported version of the API group. The preferred version API Group of each resource has the suffix "-preferredversion" as part of the sub-directory name. For backward compatibility, we kept the classic directory structure without the API group version, which sits on the same level as the API group sub-directory versions. + +By default, only the preferred API group of each resource is backed up. To take a backup of all API group versions, you need to run the Velero server with the `--features=EnableAPIGroupVersions` feature flag. This is an experimental flag and the restore logic to handle multiple API group versions is documented at [EnableAPIGroupVersions](enable-api-group-versions-feature.md). + +When unzipped, a typical backup directory (`backup1234.tar.gz`) taken with this file format version looks like the following (with the feature flag): + +``` +resources/ + persistentvolumes/ + cluster/ + pv01.json + ... + v1-preferredversion/ + cluster/ + pv01.json + ... + configmaps/ + namespaces/ + namespace1/ + myconfigmap.json + ... + namespace2/ + ... + v1-preferredversion/ + namespaces/ + namespace1/ + myconfigmap.json + ... + namespace2/ + ... + pods/ + namespaces/ + namespace1/ + mypod.json + ... + namespace2/ + ... + v1-preferredversion/ + namespaces/ + namespace1/ + mypod.json + ... + namespace2/ + ... + jobs.batch/ + namespaces/ + namespace1/ + awesome-job.json + ... + namespace2/ + ... + v1-preferredversion/ + namespaces/ + namespace1/ + awesome-job.json + ... + namespace2/ + ... + deployments/ + namespaces/ + namespace1/ + cool-deployment.json + ... + namespace2/ + ... + v1-preferredversion/ + namespaces/ + namespace1/ + cool-deployment.json + ... + namespace2/ + ... + horizontalpodautoscalers.autoscaling/ + namespaces/ + namespace1/ + hpa-to-the-rescue.json + ... + namespace2/ + ... + v1-preferredversion/ + namespaces/ + namespace1/ + hpa-to-the-rescue.json + ... + namespace2/ + ... + v2beta1/ + namespaces/ + namespace1/ + hpa-to-the-rescue.json + ... + namespace2/ + ... + v2beta2/ + namespaces/ + namespace1/ + hpa-to-the-rescue.json + ... + namespace2/ + ... + + ... +``` + +### File Format Version: 1 + +When unzipped, a typical backup directory (`backup1234.tar.gz`) looks like the following: + +``` +resources/ + persistentvolumes/ + cluster/ + pv01.json + ... + configmaps/ + namespaces/ + namespace1/ + myconfigmap.json + ... + namespace2/ + ... + pods/ + namespaces/ + namespace1/ + mypod.json + ... + namespace2/ + ... + jobs/ + namespaces/ + namespace1/ + awesome-job.json + ... + namespace2/ + ... + deployments/ + namespaces/ + namespace1/ + cool-deployment.json + ... + namespace2/ + ... + ... +``` diff --git a/site/content/docs/v1.17/overview-plugins.md b/site/content/docs/v1.17/overview-plugins.md new file mode 100644 index 000000000..037601d51 --- /dev/null +++ b/site/content/docs/v1.17/overview-plugins.md @@ -0,0 +1,29 @@ +--- +title: "Velero plugin system" +layout: docs +--- + +Velero uses storage provider plugins to integrate with a variety of storage systems to support backup and snapshot operations. + +For server installation, Velero requires that at least one plugin is added (with the `--plugins` flag). The plugin will be either of the type object store or volume snapshotter, or a plugin that contains both. An exception to this is that when the user is not configuring a backup storage location or a snapshot storage location at the time of install, this flag is optional. + +Any plugin can be added after Velero has been installed by using the command `velero plugin add `. + +Example with a dockerhub image: `velero plugin add velero/velero-plugin-for-aws:v1.0.0`. + +In the same way, any plugin can be removed by using the command `velero plugin remove `. + +## Creating a new plugin + +Anyone can add integrations for any platform to provide additional backup and volume storage without modifying the Velero codebase. To write a plugin for a new backup or volume storage platform, take a look at our [example repo][1] and at our documentation for [Custom plugins][2]. + +## Adding a new plugin + +After you publish your plugin on your own repository, open a PR that adds a link to it under the appropriate list of [supported providers][3] page in our documentation. + +You can also add the [`velero-plugin` GitHub Topic][4] to your repo, and it will be shown under the aggregated list of repositories automatically. + +[1]: https://github.com/vmware-tanzu/velero-plugin-example/ +[2]: custom-plugins.md +[3]: supported-providers.md +[4]: https://github.com/topics/velero-plugin diff --git a/site/content/docs/v1.17/performance-guidance.md b/site/content/docs/v1.17/performance-guidance.md new file mode 100644 index 000000000..8596b4a52 --- /dev/null +++ b/site/content/docs/v1.17/performance-guidance.md @@ -0,0 +1,163 @@ +--- +title: "Velero File System Backup Performance Guide" +layout: docs +--- + +When using Velero to do file system backup & restore, Restic uploader or Kopia uploader are both supported now. But the resources used and time consumption are a big difference between them. + +We've done series rounds of tests against Restic uploader and Kopia uploader through Velero, which may give you some guidance. But the test results will vary from different infrastructures, and our tests are limited and couldn't cover a variety of data scenarios, **the test results and analysis are for reference only**. + +## Infrastructure + +Minio is used as Velero backend storage, Network File System (NFS) is used to create the persistent volumes (PVs) and Persistent Volume Claims (PVC) based on the storage. The minio and NFS server are deployed independently in different virtual machines (VM), which with 300 MB/s write throughput and 175 MB/s read throughput representatively. + +The details of environmental information as below: + +``` +### KUBERNETES VERSION +root@velero-host-01:~# kubectl version +Client Version: version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.4" +Server Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.14" + +### DOCKER VERSION +root@velero-host-01:~# docker version +Client: + Version: 20.10.12 + API version: 1.41 + +Server: + Engine: + Version: 20.10.12 + API version: 1.41 (minimum version 1.12) + Go version: go1.16.2 + containerd: + Version: 1.5.9-0ubuntu1~20.04.4 + runc: + Version: 1.1.0-0ubuntu1~20.04.1 + docker-init: + Version: 0.19.0 + +### NODES +root@velero-host-01:~# kubectl get nodes |wc -l +6 // one master with 6 work nodes + +### DISK INFO +root@velero-host-01:~# smartctl -a /dev/sda +smartctl 7.1 2019-12-30 r5022 [x86_64-linux-5.4.0-126-generic] (local build) +Copyright (C) 2002-19, Bruce Allen, Christian Franke, www.smartmontools.org + +=== START OF INFORMATION SECTION === +Vendor: VMware +Product: Virtual disk +Revision: 1.0 +Logical block size: 512 bytes +Rotation Rate: Solid State Device +Device type: disk +### MEMORY INFO +root@velero-host-01:~# free -h + total used free shared buff/cache available +Mem: 3.8Gi 328Mi 3.1Gi 1.0Mi 469Mi 3.3Gi +Swap: 0B 0B 0B + +### CPU INFO +root@velero-host-01:~# cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c + 4 Intel(R) Xeon(R) Gold 6230R CPU @ 2.10GHz + +### SYSTEM INFO +root@velero-host-01:~# cat /proc/version +root@velero-host-01:~# cat /proc/version +Linux version 5.4.0-126-generic (build@lcy02-amd64-072) (gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.1)) #142-Ubuntu SMP Fri Aug 26 12:12:57 UTC 2022 + +### VELERO VERSION +root@velero-host-01:~# velero version +Client: + Version: main ###v1.10 pre-release version + Git commit: 9b22ca6100646523876b18a491d881561b4dbcf3-dirty +Server: + Version: main ###v1.10 pre-release version +``` + +## Test + +Below we've done 6 groups of tests, for each single group of test, we used limited resources (1 core CPU 2 GB memory or 4 cores CPU 4 GB memory) to do Velero file system backup under Restic path and Kopia path, and then compare the results. + +Recorded the metrics of time consumption, maximum CPU usage, maximum memory usage, and minio storage usage for node-agent daemonset, and the metrics of Velero deployment are not included since the differences are not obvious by whether using Restic uploader or Kopia uploader. + +Compression is either disabled or not unavailable for both uploader. + +### Case 1: 4194304(4M) files, 2396745(2M) directories, 0B per file total 0B content +#### result: +|Uploader| Resources|Times |Max CPU|Max Memory|Repo Usage| +|--------|----------|:----:|------:|:--------:|:--------:| +| Kopia | 1c2g |24m54s| 65% |1530 MB |80 MB | +| Restic | 1c2g |52m31s| 55% |1708 MB |3.3 GB | +| Kopia | 4c4g |24m52s| 63% |2216 MB |80 MB | +| Restic | 4c4g |52m28s| 54% |2329 MB |3.3 GB | +#### conclusion: +- The memory usage is larger than Velero's default memory limit (1GB) for both Kopia and Restic under massive empty files. +- For both using Kopia uploader and Restic uploader, there is no significant time reduction by increasing resources from 1c2g to 4c4g. +- Restic uploader is one more time slower than Kopia uploader under the same specification resources. +- Restic has an **irrational** repository size (3.3GB) + +### Case 2: Using the same size (100B) of file and default Velero's resource configuration, the testing quantity of files from 20 thousand to 2 million, these groups of cases mainly test the behavior with the increasing quantity of files. + +### Case 2.1: 235298(23K) files, 137257 (10k)directories, 100B per file total 22.440MB content +#### result: +| Uploader | Resources|Times |Max CPU|Max Memory|Repo Usage| +|-------|----------|:----:|------:|:--------:|:--------:| +| Kopia | 1c1g |2m34s | 70% |692 MB |108 MB | +| Restic| 1c1g |3m9s | 54% |714 MB |275 MB | + +### Case 2.2 470596(40k) files, 137257 (10k)directories, 100B per file total 44.880MB content +#### result: +| Uploader | Resources|Times |Max CPU|Max Memory|Repo Usage| +|-------|----------|:----:|------:|:--------:|:--------:| +| Kopia | 1c1g |3m45s | 68% |831 MB |108 MB | +| Restic| 1c1g |4m53s | 57% |788 MB |275 MB | + +### Case 2.3 705894(70k) files, 137257(10k) directories, 100B per file total 67.319MB content +#### result: +|Uploader| Resources|Times |Max CPU|Max Memory|Repo Usage| +|--------|----------|:----:|------:|:--------:|:--------:| +| Kopia | 1c1g |5m06s | 71% |861 MB |108 MB | +| Restic | 1c1g |6m23s | 56% |810 MB |275 MB | + +### Case 2.4 2097152(2M) files, 2396745(2M) directories, 100B per file total 200.000MB content +#### result: +|Uploader| Resources|Times |Max CPU|Max Memory|Repo Usage| +|--------|----------|:----:|------:|:--------:|:--------:| +| Kopia | 1c1g |OOM | 74% |N/A |N/A | +| Restic | 1c1g |41m47s| 52% |904 MB |3.2 GB | +#### conclusion: +- With the increasing number of files, there is no memory abnormal surge, the memory usage for both Kopia uploader and Restic uploader is linear increasing, until exceeds 1GB memory usage in Case 2.4 Kopia uploader OOM happened. +- Kopia uploader gets increasingly faster along with the increasing number of files. +- Restic uploader repository size is still much larger than Kopia uploader repository. + +### Case 3: 10625(10k) files, 781 directories, 1.000MB per file total 10.376GB content +#### result: +|Uploader| Resources|Times |Max CPU|Max Memory|Repo Usage| +|--------|----------|:----:|------:|:--------:|:--------:| +| Kopia | 1c2g |1m37s | 75% |251 MB |10 GB | +| Restic | 1c2g |5m25s | 100% |153 MB |10 GB | +| Kopia | 4c4g |1m35s | 75% |248 MB |10 GB | +| Restic | 4c4g |3m17s | 171% |126 MB |10 GB | +#### conclusion: +- This case involves a relatively large backup size, there is no significant time reduction by increasing resources from 1c2g to 4c4g for Kopia uploader, but for Restic uploader when increasing CPU from 1 core to 4, backup time-consuming was shortened by one-third, which means in this scenario should allocate more CPU resources for Restic uploader. +- For the large backup size case, Restic uploader's repository size comes to normal + +### Case 4: 900 files, 1 directory, 1.000GB per file total 900.000GB content +#### result: +|Uploader| Resources|Times |Max CPU|Max Memory|Repo Usage| +|--------|----------|:-----:|------:|:--------:|:--------:| +| Kopia | 1c2g |2h30m | 100% |714 MB |900 GB | +| Restic | 1c2g |Timeout| 100% |416 MB |N/A | +| Kopia | 4c4g |1h42m | 138% |786 MB |900 GB | +| Restic | 4c4g |2h15m | 351% |606 MB |900 GB | +#### conclusion: +- When the target backup data is relatively large, Restic uploader starts to Timeout under 1c2g. So it's better to allocate more memory for Restic uploader when backup large sizes of data. +- For backup large amounts of data, Kopia uploader is both less time-consuming and less resource usage. + +## Summary +- With the same specification resources, Kopia uploader is less time-consuming when backup. +- Performance would be better if choosing Kopia uploader for the scenario in backup large mounts of data or massive small files. +- It's better to set one reasonable resource configuration instead of the default depending on your scenario. For default resource configuration, it's easy to be timeout with Restic uploader in backup large amounts of data, and it's easy to be OOM for both Kopia uploader and Restic uploader in backup of massive small files. \ No newline at end of file diff --git a/site/content/docs/v1.17/plugin-release-instructions.md b/site/content/docs/v1.17/plugin-release-instructions.md new file mode 100644 index 000000000..4323d8c9a --- /dev/null +++ b/site/content/docs/v1.17/plugin-release-instructions.md @@ -0,0 +1,30 @@ +--- +title: Releasing Velero plugins +layout: docs +toc: "true" +--- + +Velero plugins maintained by the core maintainers do not have any shipped binaries, only container images, so there is no need to invoke a GoReleaser script. +Container images are built via a CI job on git push. + +Plugins the Velero core team is responsible include all those listed in [the Velero-supported providers list](supported-providers.md) _except_ the vSphere plugin. + + +## Steps +### Open a PR to prepare the repo +1. Update the README.md file to update the compatibility matrix and `velero install` instructions with the expected version number and open a PR. +1. Determining the version number is based on semantic versioning and whether the plugin uses any newly introduced, changed, or removed methods or variables from Velero. +2. Roll all unreleased changelogs into a new `CHANGELOG-v.md` file and delete the content of the `unreleased` folder. Edit the new changelog file as needed. +### Tag +1. Once the PR is merged, checkout the upstream `main` branch. Your local upstream might be named `upstream` or `origin`, so use this command: `git checkout /main`. +1. Tag the git version - `git tag v`. +1. Push the git tag - `git push --tags ` to trigger the image build. +2. Wait for the container images to build. You may check the progress of the GH action that triggers the image build at `https://github.com/vmware-tanzu//actions` +3. Verify that an image with the new tag is available at `https://hub.docker.com/repository/docker/velero//`. +4. Run the Velero [e2e tests][2] using the new image. Until it is made configurable, you will have to edit the [plugin version][1] in the test. +### Release +1. If all e2e tests pass, go to the GitHub release page of the plugin (`https://github.com/vmware-tanzu//releases`) and manually create a release for the new tag. +1. Copy and paste the content of the new changelog file into the release description field. + +[1]: https://github.com/vmware-tanzu/velero/blob/c8dfd648bbe85db0184ea53296de4220895497e6/test/e2e/velero_utils.go#L27 +[2]: https://github.com/vmware-tanzu/velero/tree/main/test/e2e diff --git a/site/content/docs/v1.17/proxy.md b/site/content/docs/v1.17/proxy.md new file mode 100644 index 000000000..047a4ac4c --- /dev/null +++ b/site/content/docs/v1.17/proxy.md @@ -0,0 +1,64 @@ +--- +title: "Behind Proxy" +layout: docs +toc: "true" +--- + +This document explains how to make Velero work behind proxy. +The procedures described in this document are concluded from the scenario that Velero is deployed behind proxy, and Velero needs to connect to a public MinIO server as storage location. Maybe other scenarios' configurations are not exactly the same, but basically they should share most parts. + +## Set the proxy server address +Specify the proxy server address by environment variables in Velero deployment and node-agent DaemonSet. +Take the following as an example: +``` yaml + ... + spec: + containers: + - args: + - server + - --features=EnableCSI + command: + - /velero + env: + ... + - name: HTTP_PROXY + value: + - name: HTTPS_PROXY + value: + # In case not all destinations that Velero connects to need go through proxy, users can specify the NO_PROXY to bypass proxy. + - name: NO_PROXY + value: +``` + +## Set the proxy required certificates +In some cases, the proxy requires certificate to connect. Set the certificate in the BSL's `Spec.ObjectStorage.CACert`. +It's possible that the object storage also requires certificate, and it's also set in `Spec.ObjectStorage.CACert`, then set both certificates in `Spec.ObjectStorage.CACert` field. + +The following is an example file contains two certificates, then encode its content with base64, and set the encode result in the BSL. + +``` bash +cat certs +-----BEGIN CERTIFICATE----- +certificates first content +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +certificates second content +-----END CERTIFICATE----- + +cat certs | base64 +LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCmNlcnRpZmljYXRlcyBmaXJzdCBjb250ZW50Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpjZXJ0aWZpY2F0ZXMgc2Vjb25kIGNvbnRlbnQKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= +``` + +``` yaml + apiVersion: velero.io/v1 + kind: BackupStorageLocation + ... + spec: + ... + default: true + objectStorage: + bucket: velero + caCert: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCmNlcnRpZmljYXRlcyBmaXJzdCBjb250ZW50Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpjZXJ0aWZpY2F0ZXMgc2Vjb25kIGNvbnRlbnQKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= + ... +``` diff --git a/site/content/docs/v1.17/rbac.md b/site/content/docs/v1.17/rbac.md new file mode 100644 index 000000000..a3e31be87 --- /dev/null +++ b/site/content/docs/v1.17/rbac.md @@ -0,0 +1,95 @@ +--- +title: "Run Velero more securely with restrictive RBAC settings" +layout: docs +--- + +By default Velero runs with an RBAC policy of ClusterRole `cluster-admin`. This is to make sure that Velero can back up or restore anything in your cluster. But `cluster-admin` access is wide open -- it gives Velero components access to everything in your cluster. Depending on your environment and your security needs, you should consider whether to configure additional RBAC policies with more restrictive access. + +**Note:** Roles and RoleBindings are associated with a single namespaces, not with an entire cluster. PersistentVolume backups are associated only with an entire cluster. This means that any backups or restores that use a restrictive Role and RoleBinding pair can manage only the resources that belong to the namespace. You do not need a wide open RBAC policy to manage PersistentVolumes, however. You can configure a ClusterRole and ClusterRoleBinding that allow backups and restores only of PersistentVolumes, not of all objects in the cluster. + +For more information about RBAC and access control generally in Kubernetes, see the Kubernetes documentation about [access control][1], [managing service accounts][2], and [RBAC authorization][3]. + +## Set up with restricted RBAC permissions + +Here's a sample of restricted permission setting. + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + namespace: YOUR_NAMESPACE_HERE + name: ROLE_NAME_HERE + labels: + component: velero +rules: + - apiGroups: + - velero.io + verbs: + - "*" + resources: + - "*" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ROLEBINDING_NAME_HERE + namespace: YOUR_NAMESPACE_HERE +subjects: + - kind: ServiceAccount + name: YOUR_SERVICEACCOUNT_HERE +roleRef: + kind: Role + name: ROLE_NAME_HERE + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: velero-clusterrole +rules: +- apiGroups: + - "" + resources: + - persistentvolumes + - namespaces + verbs: + - '*' +- apiGroups: + - '*' + resources: + - '*' + verbs: + - list +- apiGroups: + - 'apiextensions.k8s.io' + resources: + - 'customresourcedefinitions' + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: velero-clusterrolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: velero-clusterrole +subjects: + - kind: ServiceAccount + name: YOUR_SERVICEACCOUNT_HERE + namespace: YOUR_NAMESPACE_HERE +``` + +You can add more permissions into the `Role` setting according to the need. +`velero-clusterrole` ClusterRole is verified to work in most cases. +`Namespaces` resource permission is needed to create namespace during restore. If you don't need that, the `create` permission can be removed, but `list` and `get` permissions of `Namespaces` resource is still needed, because Velero needs to know whether the namespace it's assigned exists in the cluster. +`PersistentVolumes` resource permission is needed for back up and restore volumes. If that is not needed, it can be removed too. +`CustomResourceDefinitions` resource permission is needed to backup CR instances' CRD. It's better to keep them. +It's better to have the `list` permission for all resources, because Velero needs to read some resources during backup, for example, `ClusterRoles` is listed for backing `ServiceAccount` up, and `VolumeSnapshotContent` for CSI `PersistentVolumeClaim`. If you just enable `list` permissions for the resources you want to back up and restore, it's possible that backup or restore end with failure. + +[1]: https://kubernetes.io/docs/reference/access-authn-authz/controlling-access/ +[2]: https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/ +[3]: https://kubernetes.io/docs/reference/access-authn-authz/rbac/ +[4]: namespace.md + diff --git a/site/content/docs/v1.17/release-instructions.md b/site/content/docs/v1.17/release-instructions.md new file mode 100644 index 000000000..755205aec --- /dev/null +++ b/site/content/docs/v1.17/release-instructions.md @@ -0,0 +1,179 @@ +--- +title: "Release Instructions" +layout: docs +toc: "true" +--- +This page covers the steps to perform when releasing a new version of Velero. + +## General notes +- Please read the documented variables in each script to understand what they are for and how to properly format their values. +- You will need to have an upstream remote configured to use to the [vmware-tanzu/velero](https://github.com/vmware-tanzu/velero) repository. + You can check this using `git remote -v`. + The release script ([`tag-release.sh`](https://github.com/vmware-tanzu/velero/blob/v1.17.0/hack/release-tools/tag-release.sh)) will use `upstream` as the default remote name if it is not specified using the environment variable `REMOTE`. +- GA release: major and minor releases only. Example: 1.0 (major), 1.5 (minor). +- Pre-releases: Any release leading up to a GA. Example: 1.4.0-beta.1, 1.5.0-rc.1 +- RC releases: Release Candidate, contains everything that is supposed to ship with the GA release. This is still a pre-release. + +## Velero Release Requirements + +Velero is on a "train leaves the station" model for releases. We will generate a release candidate (RC) +at the scheduled time. Multiple release candidates may be generated, depending on if bugs are found during testing. +When testing has passed a release build will be generated. + +### Release Candidate criteria +The release candidate commit must meet the following criteria: + +* No major bugs outstanding +* Unit tests pass +* E2E tests against latest Kubernetes on AWS, vSphere and kind pass + +Once the release has moved to RC, a code freeze is in effect. Only changes needed to release are allowable. + +### Release criteria +In order for a release candidate to be released, it must meet the following criteria: + +* Unit tests pass +* E2E tests against latest K8S and earliest supported K8S on Azure, vSphere, Kind, AWS, GCP +* Manual tests pass (manual tests will be converted to automated testing) + +When bugs are identified by any of these methods, we will determine whether the bug is a release blocker or not and +a fix generated if it is. When release blocker bugs identifies in an release candidate are fixed, another RC will +be generated and the test cycle will restart. + +## Preparing + +### Create release blog post (GA only) +For each major or minor release, create and publish a blog post to let folks know what's new. Please follow these [instructions](how-to-write-and-release-a-blog-post). + +### Changelog and Docs PR +#### Troubleshooting +- If you encounter the error `You don't have enough free space in /var/cache/apt/archives/` when running `make serve-docs`: run `docker system prune`. + +#### Steps +1. If it doesn't already exist: in a branch, create the file `changelogs/CHANGELOG-..md` by copying the most recent one. +1. Update the file `changelogs/CHANGELOG-..md` + - Run `make changelog` to generate a list of all unreleased changes. + - Copy/paste the output into `CHANGELOG-..md`, under the "All Changes" section for the release. + - You *may* choose to tweak formatting on the list of changes by adding code blocks, etc. + - Update links at the top of the file to point to the new release version +1. Update the main `CHANGELOG.md` file to properly reference the release-specific changelog file + - Under "Current release": + - Should contain only the current GA release. + - Under "Development release": + - Should contain only the latest pre-release + - Move any prior pre-release into "Older releases" +1. GA Only: Remove all changelog files from `changelogs/unreleased`. +1. Generate new docs + - Run `make gen-docs`, passing the appropriate variables. Examples: + a) `VELERO_VERSION=v1.5.0-rc.1 NEW_DOCS_VERSION=v1.5.0-rc.1 make gen-docs`. + b) `VELERO_VERSION=v1.5.0 NEW_DOCS_VERSION=v1.5 make gen-docs`). + - Note: + - `PREVIOUS_DOCS_VERSION=` is optional; when not set, it will default to the latest doc version. + - `VELERO_VERSION` and `NEW_DOCS_VERSION` are slightly different, the `VELERO_VERSION` may have lots of small release versions for one specific $major.minor, such as 'v1.5.0' and 'v1.5.1', but `NEW_DOCS_VERSION` may still be 'v1.5' for not document update. +1. Clean up when there is an existing set of pre-release versioned docs for the version you are releasing + - Example: `site/content/docs/v1.5.0-beta.1` exists, and you're releasing `v1.5.0-rc.1` or `v1.5` + - Remove the directory containing the pre-release docs, i.e. `site/content/docs/`. + - Delete the pre-release docs table of contents file, i.e. `site/data/docs/-toc.yml`. + - Remove the pre-release docs table of contents mapping entry from `site/data/toc-mapping.yml`. + - Remove all references to the pre-release docs from `site/config.yml`. +1. Create the "Upgrade to $major.minor" page if it does not already exist ([example](https://velero.io/docs/v1.5/upgrade-to-1.5/)). + If it already exists, update any usage of the previous version string within this file to use the new version string instead ([example](https://github.com/vmware-tanzu/velero/pull/2941/files#diff-d594f8fd0901fed79c39aab4b348193d)). + This needs to be done in both the versioned and the `main` folders. +1. Review and submit PR + - Follow the additional instructions at `site/README-HUGO.md` to complete the docs generation process. + - Do a review of the diffs, and/or run `make serve-docs` and review the site. + - Submit a PR containing the changelog and the version-tagged docs. + +### Pin the base image +The image of velero is built based on [Distroless docker image](https://github.com/GoogleContainerTools/distroless). +For the reproducibility of the release, before the release candidate is tagged, we need to make sure the in the Dockerfile +on the release branch, the base image is referenced by digest, such as +https://github.com/vmware-tanzu/velero/blob/release-1.7/Dockerfile#L53-L54 + +## Velero release +### Notes +- Pre-requisite: PR with the changelog and docs is merged, so that it's included in the release tag. +- This process is the same for both pre-release and GA. +- Refer to the [General notes](general-notes) above for instructions. + +#### Troubleshooting +- If the dry-run fails with random errors, try running it again. + +#### Steps +1. Manually create the release branch on Github, in the form like `release-$major.$minor` +1. Create a tagged release in dry-run mode + - This won't push anything to GitHub. + - Run `VELERO_VERSION=v1.9.0-rc.1 REMOTE= GITHUB_TOKEN=REDACTED ON_RELEASE_BRANCH=TRUE ./hack/release-tools/tag-release.sh`. + - Fix any issue. +1. Create a tagged release and push it to GitHub + - Run `VELERO_VERSION=v1.9.0-rc.1 REMOTE= GITHUB_TOKEN=REDACTED ON_RELEASE_BRANCH=TRUE ./hack/release-tools/tag-release.sh publish`. +1. Publish the release + - Navigate to the draft GitHub release at https://github.com/vmware-tanzu/velero/releases and edit the release. + - If this is a patch release (e.g. `v1.9.1`), note that the full `CHANGELOG-1.9.md` contents will be included in the body of the GitHub release. You need to delete the previous releases' content (e.g. `v1.9.0`'s changelog) so that only the latest patch release's changelog shows. + - Do a quick review for formatting. + - **Note:** the `goreleaser` process should have detected if it's a pre-release version and, if so, checked the box at the bottom of the GitHub release page appropriately, but it's always worth double-checking. + - Verify that GitHub has built and pushed all the images (it takes a while): https://github.com/vmware-tanzu/velero/actions + - Verify that the images are on Docker Hub: https://hub.docker.com/r/velero/velero/tags + - Verify that the assets were published to the GitHub release + - Publish the release. +1. Test the release + - By now, the Docker images should have been published. + - Perform a smoke-test - for example: + - Download the CLI from the GitHub release + - Use it to install Velero into a cluster (or manually update an existing deployment to use the new images) + - Verify that `velero version` shows the expected output + - Run a backup/restore and ensure it works + +## Homebrew release (GA only) +These are the steps to update the Velero Homebrew version. + +### Steps +- If you don't already have one, create a [GitHub access token for Homebrew](https://github.com/settings/tokens/new?scopes=gist,public_repo&description=Homebrew) +- Run `export HOMEBREW_GITHUB_API_TOKEN=your_token_here` on your command line to make sure that `brew` can work on GitHub on your behalf. +- Run `hack/release-tools/brew-update.sh`. This script will download the necessary files, do the checks, and invoke the brew helper to submit the PR, which will open in your browser. +- Update Windows Chocolatey version. From a Windows computer, follow the step-by-step instructions to [create the Windows Chocolatey package for Velero CLI](https://github.com/adamrushuk/velero-choco/blob/main/README.md). Please update the `tools\chocolateyinstall.ps1` file content according to [the existing Velero chocolatey package install script file](https://community.chocolatey.org/packages/velero#files). The current Velero chocolatey package maintainer is [Adam Rush](https://github.com/adamrushuk). It's possible others don't have permission to upload the new version. If so, please contact [Adam Rush](https://github.com/adamrushuk) for help. + +## Plugins + +To release plugins maintained by the Velero team, follow the [plugin release instructions](plugin-release-instructions.md). + +After the plugin images are built, be sure to update any [e2e tests][3] that use these plugins. + +## Helm Chart (GA only) + +### Steps +- Update the CRDs under helm chart folder `crds` according to the current Velero GA version, and add the labels for the helm chart CRDs. For example: https://github.com/vmware-tanzu/helm-charts/pull/248. +- Bump the Chart version `version` on the `Chart.yaml`. +- Bump the Velero version `appVersion` on the `Chart.yaml` file and `tag` on the `values.yaml` file. +- Bump the plugin version on the `values.yaml` if needed. +- Update the _upgrade_ instruction and related tag on the `README.md` file. + +## How to write and release a blog post +What to include in a release blog: +* Thank all contributors for their involvement in the release. + * Where possible shoutout folks by name or consider spotlighting new maintainers. +* Highlight the themes, or areas of focus, for the release. Some examples of themes are security, bug fixes, feature improvements. See past Velero [release blog posts][1] for more examples. +* Include summaries of new features or workflows introduced in a release. + * This can also include new project initiatives, like a code-of-conduct update. + * Consider creating additional blog posts that go through new features in more detail. Plan to publish additional blogs after the release blog (all blogs don’t have to be publish all at once). + +Release blog post PR: +* Prepare a PR containing the release blog post. Read the [website guidelines][2] for more information on creating a blog post. It's usually easiest to make a copy of the most recent existing post, then replace the content as appropriate. +* You also need to update `site/content/_index.md` to have "Latest Release Information" contain a link to the new post. +* Plan to publish the blog post the same day as the release. + +## Announce a release +Once you are finished doing the release, let the rest of the world know it's available by posting messages in the following places. +1. GA Only: Merge the blog post PR. +1. Velero's Twitter account. Maintainers are encouraged to help spread the word by posting or reposting on social media. +1. Community Slack channel. +1. Google group message. + +What to include: +* Thank all contributors +* A brief list of highlights in the release +* Link to the release blog post, release notes, and/or github release page + +[1]: https://velero.io/blog +[2]: website-guidelines.md +[3]: https://github.com/vmware-tanzu/velero/tree/main/test/e2e diff --git a/site/content/docs/v1.17/release-schedule.md b/site/content/docs/v1.17/release-schedule.md new file mode 100644 index 000000000..7c7ce83b8 --- /dev/null +++ b/site/content/docs/v1.17/release-schedule.md @@ -0,0 +1,15 @@ +--- +title: "Release Schedule" +layout: docs +toc: "true" +--- + +Definitions borrowed from [the Kubernetes release process document](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-release/release.md#definitions) + +General phases for a Velero release +- Enhancement/Design freeze +- Implementation phase +- Feature freeze & pruning +- Code freeze & prerelease +- Release +- Velero plugin repositories would be bumped up one minor version when new Velero is released diff --git a/site/content/docs/v1.17/repository-maintenance.md b/site/content/docs/v1.17/repository-maintenance.md new file mode 100644 index 000000000..c9c76a677 --- /dev/null +++ b/site/content/docs/v1.17/repository-maintenance.md @@ -0,0 +1,213 @@ +--- +title: "Repository Maintenance" +layout: docs +--- + +From v1.14 on, Velero decouples repository maintenance from the Velero server by launching a k8s job to do maintenance when needed, to mitigate the impact on the Velero server during backups. + +Before v1.14.0, Velero performs periodic maintenance on the repository within Velero server pod, this operation may consume significant CPU and memory resources in some cases, leading to Velero server being killed by OOM. Now Velero will launch independent k8s jobs to do the maintenance in Velero installation namespace. + +For repository maintenance jobs, there's no limit on resources by default. You could configure the job resource limitation based on target data to be backed up. + +From v1.15 and on, Velero introduces a new ConfigMap, specified by `velero server --repo-maintenance-job-configmap` parameter, to set repository maintenance Job configuration, including Node Affinity and resources. The old `velero server` parameters ( `--maintenance-job-cpu-request`, `--maintenance-job-mem-request`, `--maintenance-job-cpu-limit`, `--maintenance-job-mem-limit`, and `--keep-latest-maintenance-jobs`) introduced in v1.14 are deprecated, and will be deleted in v1.17. + +The users can specify the ConfigMap name during velero installation by CLI: +`velero install --repo-maintenance-job-configmap=` + +## Settings +### Resource Limitation and Node Affinity +Those are specified by the ConfigMap specified by `velero server --repo-maintenance-job-configmap` parameter. + +This ConfigMap content is a Map. +If there is a key value as `global` in the map, the key's value is applied to all BackupRepositories maintenance jobs that cannot find their own specific configuration in the ConfigMap. +The other keys in the map is the combination of three elements of a BackupRepository, because those three keys can identify a unique BackupRepository: +* The namespace in which BackupRepository backs up volume data. +* The BackupRepository referenced BackupStorageLocation's name. +* The BackupRepository's type. Possible values are `kopia` and `restic`. + +If there is a key match with BackupRepository, the key's value is applied to the BackupRepository's maintenance jobs. +By this way, it's possible to let user configure before the BackupRepository is created. +This is especially convenient for administrator configuring during the Velero installation. +For example, the following BackupRepository's key should be `test-default-kopia`. + +``` yaml +- apiVersion: velero.io/v1 + kind: BackupRepository + metadata: + generateName: test-default-kopia- + labels: + velero.io/repository-type: kopia + velero.io/storage-location: default + velero.io/volume-namespace: test + name: test-default-kopia-kgt6n + namespace: velero + spec: + backupStorageLocation: default + maintenanceFrequency: 1h0m0s + repositoryType: kopia + resticIdentifier: gs:jxun:/restic/test + volumeNamespace: test +``` + +You can still customize the maintenance job resource requests and limit when using the [velero install][1] CLI command. + +The `LoadAffinity` structure is reused from design [node-agent affinity configuration][2]. + +### Affinity Example +It's possible that the users want to choose nodes that match condition A or condition B to run the job. +For example, the user want to let the nodes is in a specified machine type or the nodes locate in the us-central1-x zones to run the job. +This can be done by adding multiple entries in the `LoadAffinity` array. + +The sample of the ```repo-maintenance-job-configmap``` ConfigMap for the above scenario is as below: +``` bash +cat < repo-maintenance-job-config.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: repo-maintenance-job-config + namespace: velero +data: + global: | + { + "podResources": { + "cpuRequest": "100m", + "cpuLimit": "200m", + "memoryRequest": "100Mi", + "memoryLimit": "200Mi" + }, + "keepLatestMaintenanceJobs": 1, + "loadAffinity": [ + { + "nodeSelector": { + "matchExpressions": [ + { + "key": "cloud.google.com/machine-family", + "operator": "In", + "values": [ + "e2" + ] + } + ] + } + }, + { + "nodeSelector": { + "matchExpressions": [ + { + "key": "topology.kubernetes.io/zone", + "operator": "In", + "values": [ + "us-central1-a", + "us-central1-b", + "us-central1-c" + ] + } + ] + } + } + ] + } + kibishii-default-kopia: | + { + "podResources": { + "cpuRequest": "200m", + "cpuLimit": "400m", + "memoryRequest": "200Mi", + "memoryLimit": "400Mi" + }, + "keepLatestMaintenanceJobs": 2 + } +EOF +``` +This sample showcases two affinity configurations: +- matchLabels: maintenance job runs on nodes with label key `cloud.google.com/machine-family` and value `e2`. +- matchLabels: maintenance job runs on nodes located in `us-central1-a`, `us-central1-b` and `us-central1-c`. +The nodes matching one of the two conditions are selected. + +To create the configMap, users need to save something like the above sample to a json file and then run below command: +``` +kubectl apply -f repo-maintenance-job-config.yaml +``` + +### Log +Maintenance job inherits the log level and log format settings from the Velero server, so if the Velero server enabled the debug log, the maintenance job will also open the debug level log. + +### Num of Keeping Latest Maintenance Jobs +Velero will keep one specific number of the latest maintenance jobs for each repository. By default, we only keep 3 latest maintenance jobs for each repository, and Velero support configures this setting by the below command when Velero installs: + +```bash +velero install --keep-latest-maintenance-jobs +``` + +### Default Repository Maintenance Frequency +The frequency of running maintenance jobs could be set by the below command when Velero is installed: +```bash +velero install --default-repo-maintain-frequency +``` +For Kopia the default maintenance frequency is 1 hour, and Restic is 7 * 24 hours. + +### Full Maintenance Interval customization +See [backup repository configuration][3] + +### Maintenance History +You can view the maintenance history by describing the corresponding backupRepository CR: + +``` +Status: + Last Maintenance Time: + Recent Maintenance: + Complete Timestamp: + Result: Succeeded + Start Timestamp: + Complete Timestamp: + Result: Succeeded + Start Timestamp: + Message: + Result: Failed + Start Timestamp: +``` + +- `Last Maintenance Time` indicates the time of the latest successful maintenance job +- `Recent Maintenance` keeps the status of the recent 3 maintenance jobs, including its start time, result (succeeded/failed), completion time (if the maintenance job succeeded), or error message (if the maintenance failed) + +### Others +Maintenance jobs will inherit toleration, nodeSelector, service account, image, environment variables, cloud-credentials, priorityClassName etc. from Velero deployment. + +For labels and annotations, maintenance jobs do NOT inherit all labels and annotations from the Velero deployment. Instead, they include: + +**Labels:** + +* `velero.io/repo-name: ` - automatically added to identify which repository they are maintaining +* Only specific [third-party labels][4] from the Velero server deployment that are in the predefined list, currently limited to: + * `azure.workload.identity/use` + +**Annotations:** + +* Only specific [third-party annotations][5] from the Velero server deployment that are in the predefined list, currently limited to: + * `iam.amazonaws.com/role` + +**Important:** Other labels and annotations from the Velero deployment are NOT inherited by maintenance jobs. This is by design to ensure only specific labels and annotations required for cloud provider identity systems are propagated. +Maintenance jobs will not run for backup repositories whose backup storage location is set as readOnly. + +#### Priority Class Configuration +Maintenance jobs can be configured with a specific priority class through the repository maintenance job ConfigMap. The priority class name should be specified in the global configuration section: + +```json +{ + "global": { + "priorityClassName": "low-priority", + "podResources": { + "cpuRequest": "100m", + "memoryRequest": "128Mi" + } + } +} +``` + +Note that priority class configuration is only read from the global configuration section, ensuring all maintenance jobs use the same priority class regardless of which repository they are maintaining. + +[1]: velero-install.md#usage +[2]: node-agent-concurrency.md +[3]: backup-repository-configuration.md#full-maintenance-interval-customization +[4]: https://github.com/vmware-tanzu/velero/blob/d5a2e7e6b9512e8ba52ec269ed5ce9a0fa23548c/pkg/util/third_party.go#L19-L21 +[5]: https://github.com/vmware-tanzu/velero/blob/d5a2e7e6b9512e8ba52ec269ed5ce9a0fa23548c/pkg/util/third_party.go#L23-L25 diff --git a/site/content/docs/v1.17/resource-filtering.md b/site/content/docs/v1.17/resource-filtering.md new file mode 100644 index 000000000..710564789 --- /dev/null +++ b/site/content/docs/v1.17/resource-filtering.md @@ -0,0 +1,572 @@ +--- +title: "Resource filtering" +layout: docs +--- + +*Filter objects by namespace, type, labels or resource policies.* + +This page describes how to filter resource for backup and restore. +User could use the include and exclude flags with the `velero backup` and `velero restore` commands. And user could also use resource policies to handle backup. +By default, Velero includes all objects in a backup or restore when no filtering options are used. + +## Includes + +Only specific resources are included, all others are excluded. + +Wildcard takes precedence when both a wildcard and specific resource are included. + +### --include-namespaces + +Namespaces to include. Default is `*`, all namespaces. + +* Backup a namespace and it's objects. + + ```bash + velero backup create --include-namespaces + ``` + +* Restore two namespaces and their objects. + + ```bash + velero restore create --include-namespaces , + ``` + +### --include-resources + +Kubernetes resources to include in the backup, formatted as resource.group, such as storageclasses.storage.k8s.io (use `*` for all resources). Cannot work with `--include-cluster-scoped-resources`, `--exclude-cluster-scoped-resources`, `--include-namespace-scoped-resources` and `--exclude-namespace-scoped-resources`. + +* Backup all deployments in the cluster. + + ```bash + velero backup create --include-resources deployments + ``` + +* Restore all deployments and configmaps in the cluster. + + ```bash + velero restore create --include-resources deployments,configmaps + ``` + +* Backup the deployments in a namespace. + + ```bash + velero backup create --include-resources deployments --include-namespaces + ``` + +### --include-cluster-resources + +Includes cluster-scoped resources. Cannot work with `--include-cluster-scoped-resources`, `--exclude-cluster-scoped-resources`, `--include-namespace-scoped-resources` and `--exclude-namespace-scoped-resources`. This option can have three possible values: + +* `true`: all cluster-scoped resources are included. + +* `false`: no cluster-scoped resources are included. + +* `nil` ("auto" or not supplied): + + - Cluster-scoped resources are included when backing up or restoring all namespaces. Default: `true`. + + - Cluster-scoped resources are not included when namespace filtering is used. Default: `false`. + + * Some related cluster-scoped resources may still be backed/restored up if triggered by a custom action (for example, PVC->PV) unless `--include-cluster-resources=false`. + +* Backup entire cluster including cluster-scoped resources. + + ```bash + velero backup create + ``` + +* Restore only namespaced resources in the cluster. + + ```bash + velero restore create --include-cluster-resources=false + ``` + +* Backup a namespace and include cluster-scoped resources. + + ```bash + velero backup create --include-namespaces --include-cluster-resources=true + ``` + +### --selector + +* Include resources matching the label selector. + + ```bash + velero backup create --selector = + ``` +* Include resources that are not matching the selector + ```bash + velero backup create --selector " notin ()" + ``` + +For more information read the [Kubernetes label selector documentation](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors) + +### --or-selector + +To include the resources that match at least one of the label selectors from the list. Separate the selectors with ` or `. The ` or ` is used as a separator to split label selectors, and it is not an operator. + +This option cannot be used together with `--selector`. + +* Include resources matching any one of the label selector, `foo=bar` or `baz=qux` + + ```bash + velero backup create backup1 --or-selector "foo=bar or baz=qux" + ``` + +* Include resources that are labeled `environment=production` or `env=prod` or `env=production` or `environment=prod`. + + ```bash + velero restore create restore-prod --from-backup=prod-backup --or-selector "env in (prod,production) or environment in (prod, production)" + ``` + +### --include-cluster-scoped-resources +Kubernetes cluster-scoped resources to include in the backup, formatted as resource.group, such as `storageclasses.storage.k8s.io`(use '*' for all resources). Cannot work with `--include-resources`, `--exclude-resources` and `--include-cluster-resources`. This parameter only works for backup, not for restore. + +* Backup all StorageClasses and ClusterRoles in the cluster. + + ```bash + velero backup create --include-cluster-scoped-resources="storageclasses,clusterroles" + ``` + +* Backup all cluster-scoped resources in the cluster. + + ```bash + velero backup create --include-cluster-scoped-resources="*" + ``` + + +### --include-namespace-scoped-resources +Kubernetes namespace resources to include in the backup, formatted as resource.group, such as `deployments.apps`(use '*' for all resources). Cannot work with `--include-resources`, `--exclude-resources` and `--include-cluster-resources`. This parameter only works for backup, not for restore. + +* Backup all Deployments and ConfigMaps in the cluster. + + ```bash + velero backup create --include-namespace-scoped-resources="deployments.apps,configmaps" + ``` + +* Backup all namespace resources in the cluster. + + ```bash + velero backup create --include-namespace-scoped-resources="*" + ``` + +## Excludes + +Exclude specific resources from the backup. + +Wildcard excludes are ignored. + +### --exclude-namespaces + +Namespaces to exclude. + +* Exclude kube-system from the cluster backup. + + ```bash + velero backup create --exclude-namespaces kube-system + ``` + +* Exclude two namespaces during a restore. + + ```bash + velero restore create --exclude-namespaces , + ``` + +### --exclude-resources + +Kubernetes resources to exclude, formatted as resource.group, such as storageclasses.storage.k8s.io. Cannot work with `--include-cluster-scoped-resources`, `--exclude-cluster-scoped-resources`, `--include-namespace-scoped-resources` and `--exclude-namespace-scoped-resources`. + +* Exclude secrets from the backup. + + ```bash + velero backup create --exclude-resources secrets + ``` + +* Exclude secrets and rolebindings. + + ```bash + velero backup create --exclude-resources secrets,rolebindings + ``` + +### velero.io/exclude-from-backup=true + +* Resources with the label `velero.io/exclude-from-backup=true` are not included in backup, even if it contains a matching selector label. + +### --exclude-cluster-scoped-resources +Kubernetes cluster-scoped resources to exclude from the backup, formatted as resource.group, such as `storageclasses.storage.k8s.io`(use '*' for all resources). Cannot work with `--include-resources`, `--exclude-resources` and `--include-cluster-resources`. This parameter only works for backup, not for restore. + +* Exclude StorageClasses and ClusterRoles from the backup. + + ```bash + velero backup create --exclude-cluster-scoped-resources="storageclasses,clusterroles" + ``` + +* Exclude all cluster-scoped resources from the backup. + + ```bash + velero backup create --exclude-cluster-scoped-resources="*" + ``` + +### --exclude-namespace-scoped-resources +Kubernetes namespace resources to exclude from the backup, formatted as resource.group, such as `deployments.apps`(use '*' for all resources). Cannot work with `--include-resources`, `--exclude-resources` and `--include-cluster-resources`. This parameter only works for backup, not for restore. + +* Exclude all Deployments and ConfigMaps from the backup. + + ```bash + velero backup create --exclude-namespace-scoped-resources="deployments.apps,configmaps" + ``` + +* Exclude all namespace resources from the backup. + + ```bash + velero backup create --exclude-namespace-scoped-resources="*" + ``` + +## Resource policies +Velero provides resource policies to filter resources to do backup, which may contain `includeExcludePolicy` and `volumePolicies`. + +### Creating resource policies + +Below is the two-step of using resource policies in backup: +1. Creating resource policies configmap + + Users need to create one configmap in Velero install namespace from a YAML file that defined resource policies. The creating command would be like the below: + ```bash + kubectl create cm --from-file -n velero + ``` +2. Creating a backup reference to the defined resource policies + + Users create a backup with the flag `--resource-policies-configmap`, which will reference the current backup to the defined resource policies. The creating command would be like the below: + ```bash + velero backup create --resource-policies-configmap + ``` + This flag could also be combined with the other include and exclude filters above + +### YAML template +The policies YAML config file would look like this: +- Yaml template: + ```yaml + # currently only supports v1 version + version: v1 + # The filters in includeExcludePolicy work the same as the scoped resources filters in the Spec of a Backup + # NOTE: similar to scoped filters in Backup Spec, the includeExcludePolicy does not work with --include-resources, --exclude-resources and --include-cluster-resources filters in Backup. + includeExcludePolicy: + includedClusterScopedResources: + - "crd" + - "pv" + excludedClusterScopedResources: [] + includedNamespaceScopedResources: + - "pod" + - "service" + - "deployment" + - "pvc" + excludedNamespaceScopedResources: + - "configmap" + - "secret" + volumePolicies: + # each policy consists of a list of conditions and an action + # we could have lots of policies, but if the resource matched the first policy, the latter will be ignored + # each key in the object is one condition, and one policy will apply to resources that meet ALL conditions + # NOTE: capacity or storageClass is suited for [Persistent Volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes), and pod [Volume](https://kubernetes.io/docs/concepts/storage/volumes) not support it. + - conditions: + # capacity condition matches the volumes whose capacity falls into the range + capacity: "10,100Gi" + # pv matches specific csi driver + csi: + driver: ebs.csi.aws.com + # pv matches one of the storage class list + storageClass: + - gp2 + - standard + action: + type: skip + - conditions: + capacity: "0,100Gi" + # nfs volume source with specific server and path (nfs could be empty or only config server or path) + nfs: + server: 192.168.200.90 + path: /mnt/data + action: + type: skip + - conditions: + nfs: + server: 192.168.200.90 + action: + type: fs-backup + - conditions: + # nfs could be empty which matches any nfs volume source + nfs: {} + action: + type: skip + - conditions: + # csi could be empty which matches any csi volume source + csi: {} + action: + type: snapshot + - conditions: + volumeTypes: + - emptyDir + - downwardAPI + - configmap + - cinder + action: + type: skip + ``` +### IncludeExcludePolicy +The `includeExcludePolicy` is used to filter resources based on the namespace-scoped and cluster-scoped resources. User can use it +to define a group of filters and reuse them across different backups. + +For example, user can configmap `my-policy` of resource policies with following content: +```yaml +version: v1 +includeExcludePolicy: + includedClusterScopedResources: + - "crd" + excludedClusterScopedResources: [] + includedNamespaceScopedResources: [] + excludedNamespaceScopedResources: + - "configmap" + - "event" +``` +If the user creates a backup via command like +```bash +velero backup create --resource-policies-configmap my-policy --include-namespaces my-workload-ns +``` +The backup will include all resources in namespace `my-workload-ns` except for `configmap` and `event`, and all CRDs in the cluster. + +#### Limitations +The `includeExcludePolicy` does not work with `--include-resources`, `--exclude-resources` and `--include-cluster-resources` filters in Backup. +If the user create the backup with command like `velero backup create my-backup --include-cluster-resources --include-namespaces workload-ns --resource-policies-configmap my-policy` +the backup will fail with status `FailedValidation` + +The filters in `includeExcludePolicy` cannot include `*`. Only specific resources can be set in the filters. + +#### "includeExcludePolicy" .vs. filters in Backup Spec +User can use the includeExcludePolicy with other _scoped filters_ when creating a backup. velero will combine the filters +when it's collecting the resources during the backup. During this process the filters in the Backup Spec have higher priority. +For example, if the user use this command to create a backup, reusing the resource policies created in the previous example: +```bash +velero backup create --resource-policies-configmap my-policy --include-namespace-scoped-resources * --include-cluster-scoped-resources -apiservices --include-namespaces my-workload-ns +``` +The backup will include all resources in namespace `my-workload-ns`, including `configmap` and `event`, and all CRDs and +`apiservices` in the cluster. + +### VolumePolicy +VolumePolicy is a data structure to control how velero handle the volumes matching certain conditions. + +#### Supported VolumePolicy actions +There are three actions supported via the VolumePolicy feature: +* skip: don't back up the action matching volume's data. +* snapshot: back up the action matching volume's data by the snapshot way. +* fs-backup: back up the action matching volumes' data by the fs-backup way. + +#### Supported conditions + +Currently, Velero supports the volume attributes listed below: +- capacity: matching volumes have the capacity that falls within this `capacity` range. The capacity value should include the lower value and upper value concatenated by commas, the unit of each value in capacity could be `Ti`, `Gi`, `Mi`, `Ki` etc, which is a standard storage unit in Kubernetes. And it has several combinations below: + - "0,5Gi" or "0Gi,5Gi" which means capacity or size matches from 0 to 5Gi, including value 0 and value 5Gi + - ",5Gi" which is equal to "0,5Gi" + - "5Gi," which means capacity or size matches larger than 5Gi, including value 5Gi + - "5Gi" which is not supported and will be failed in validating the configuration +- storageClass: matching volumes those with specified `storageClass`, such as `gp2`, `ebs-sc` in eks +- volume sources: matching volumes that used specified volume sources. Currently we support nfs or csi backend volume source + +Velero supported conditions and format listed below: +- capacity + ```yaml + # match volume has the size between 10Gi and 100Gi + capacity: "10Gi,100Gi" + ``` +- storageClass + ```yaml + # match volume has the storage class gp2 or ebs-sc + storageClass: + - gp2 + - ebs-sc + ``` +- volume sources (currently only support below format and attributes) +1. Specify the volume source name, the name could be `nfs`, `rbd`, `iscsi`, `csi` etc, but Velero only support `nfs` and `csi` currently. + ```yaml + # match any volume has nfs volume source + nfs : {} + # match any volume has csi volume source + csi : {} + ``` + +2. Specify details for the related volume source (currently we only support csi driver filter and nfs server or path filter) + ```yaml + # match volume has csi volume source and using `aws.efs.csi.driver` + csi: + driver: aws.efs.csi.driver + # match volume has nfs volume source and using below server and path + nfs: + server: 192.168.200.90 + path: /mnt/nfs + ``` + For volume provisioned by [Persistent Volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes) support all above attributes, but for pod [Volume](https://kubernetes.io/docs/concepts/storage/volumes) only support filtered by volume source. + +- volume types + + Support filter volumes by types + ```yaml + volumeTypes: + # matches volumes listed below + - emptyDir + - downwardAPI + - configmap + - cinder + ``` + Volume types could be found in [Persistent Volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes) and pod [Volume](https://kubernetes.io/docs/concepts/storage/volumes) + +- pvc Labels + + This condition filters volumes based on the labels on their associated PVCs. The condition is specified as a simple key/value mapping. The volume matches this condition if all the key/value pairs defined in the policy are present on the PVC. + ```yaml + pvcLabels: + environment: production + ``` + + Some examples: + - Environment specific labels: Snapshot volumes whose associated PVC has the label `environment: production`. + ```yaml + volumePolicies: + - conditions: + pvcLabels: + environment: production + action: + type: snapshot + ``` + - Subset Matching: Even if the PVC contains extra labels, it will match as long as the required key/value pair is present. For example, if the PVC has: + ```yaml + labels: + environment: production + team: backend + ``` + the following policy will match because it only requires `environment: production`: + ```yaml + volumePolicies: + - conditions: + pvcLabels: + environment: production + action: + type: skip + ``` + - Mismatched PVC Labels: If the policy requires both `environment: production` and `app: frontend`, but the PVC only has `environment: production`, the volume will not match. + ```yaml + volumePolicies: + - conditions: + pvcLabels: + environment: production + app: frontend + action: + type: skip + ``` + +#### VolumePolicies rules +- Velero already has lots of include or exclude filters. the volume policies are the final filters after others include or exclude filters in one backup processing workflow. So if use a defined similar filter like the opt-in approach to backup one pod volume but skip backup of the same pod volume in volume policies, as volume policies are the final filters that are applied, the volume will not be backed up. +- If volume policies conflict with themselves the first matched policy will be respected when many policies are defined. + +#### VolumePolicy priority with existing filters +* [Includes filters](#includes) and [Excludes filters](#excludes) have the highest priority. The filtered-out resources by them cannot reach to the VolumePolicy. +* The VolumePolicy has the second priority. It supersedes all the other filters. +* The filesystem volume backup opt-in/opt-out way has the third priority. +* The `backup.Spec.SnapshotVolumes` has the fourth priority. + +#### Support for `fs-backup` and `snapshot` actions via volume policy feature +- Starting from velero 1.14, the volume policy feature has been extended to support more actions like `fs-backup` and `snapshot`. +- This feature only extends the action aspect of volume policy and not criteria aspect, the criteria components as described above remain the same. +- When we are using the volume policy approach for backing up the volumes then the volume policy criteria and action need to be specific and explicit, +there is no default behaviour, if a volume matches fs-backup action then fs-backup method will be used for that volume and similarly if the volume matches +the criteria for snapshot action then the snapshot workflow will be used for the volume backup. +- Another thing to note is that the volume policy workflow uses the legacy opt-in/opt-out approach as a fallback option. For instance, the user specifies +a volume policy but for a particular volume included in the backup there are no actions(fs-backup/snapshot) matching in the volume policy for that volume, +in such a scenario the legacy approach will be used for backing up the particular volume. Considering everything, the recommendation would be to use only one +of the approaches to backup volumes - volume policy approach or the opt-in/opt-out legacy approach, and not mix them for clarity. +- Snapshot action can either be a native snapshot or a csi snapshot or csi snapshot datamover, as is the case with the current flow where velero itself makes the decision based on the backup CR's existing options. +- The `snapshot` action via Volume Policy has higher priority if there is a `snapshot` action matching for a particular volume, this volume would be backed up via snapshot irrespective of the value of `backup.Spec.SnapshotVolumes`. +- If for a particular volume there is no `snapshot` matching action then the volume will be backed up via snapshot given that `backup.Spec.SnapshotVolumes` is not explicitly set to false. +- Let's see some examples on how to use the volume policy feature for `fs-backup` and `snapshot` action purposes: + +We will use a simple application example in which there is an application pod which has 2 volumes: +- Volume 1 has associated Persistent Volume Claim 1 and Persistent Volume 1 which uses storage class `gp2-csi` +- Volume 2 has associated Persistent Volume Claim 2 and Persistent Volume 2 which uses storage class `gp3-csi` + +Now lets go through some example uses-cases and their outcomes: + +***Example 1: User wants to use `fs-backup` action for backing up the volumes having storage class as `gp2-csi`*** +1. User specifies the volume policy as follows: +```yaml +version: v1 +volumePolicies: +- conditions: + storageClass: + - gp2-csi + action: + type: fs-backup +``` + +2. User creates a backup using this volume policy +3. The outcome would be that velero would perform `fs-backup` operation ***only*** on `Volume 1` as ***only*** `Volume 1` satisfies the criteria for `fs-backup` action. + +***Example 2: User wants to use `snapshot` action for backing up the volumes having storage class as `gp2-csi`*** +1. User specifies the volume policy as follows: +```yaml +version: v1 +volumePolicies: +- conditions: + storageClass: + - gp2-csi + action: + type: snapshot +``` +2. User creates a backup using this volume policy +3. The outcome would be that velero would perform `snapshot` operation ***only*** on `Volume 1` as ***only*** `Volume 1` satisfies the criteria for `snapshot` action. + +***Example 3: User wants to use `snapshot` action for backing up the volumes having storage class as `gp2-csi` and wants to use `fs-backup` action for backing up the volumes having storage class as `gp3-csi`*** +1. User specifies the volume policy as follows: +```yaml +version: v1 +volumePolicies: +- conditions: + storageClass: + - gp2-csi + action: + type: snapshot +- conditions: + storageClass: + - gp3-csi + action: + type: fs-backup +``` +2. User creates a backup using this volume policy +3. The outcome would be that velero would perform `snapshot` operation ***only*** on `Volume 1` as ***only*** `Volume 1` satisfies the criteria for `snapshot` action. Also, velero would perform `fs-backup` operation ***only*** on `Volume 2` as ***only*** `Volume 2` satisfies the criteria for `fs-backup` action. + +***Example 4: User wants to use `snapshot` action for backing up the volumes having storage class as `gp3-csi` and at the same time also annotates the pod to use opt-in fs-backup legacy approach for Volume 1*** +1. User specifies the volume policy as follows and also annotates the pod with `backup.velero.io/backup-volumes=Volume 1` +```yaml +version: v1 +volumePolicies: +- conditions: + storageClass: + - gp3-csi + action: + type: snapshot +``` +2. User creates a backup using this volume policy +3. The outcome would be that velero would perform `snapshot` operation for `Volume 2` as it matches the action criteria and velero would also perform the `fs-backup` operation for `Volume-1` via the legacy annotations based fallback approach as there is no matching action for `Volume-1` + +***Example 5: User wants to use `fs-backup` action for backing up the volumes having storage class as `gp2-csi` and at the same time also specifies `defaultVolumesToFSBackup: true` (fallback option for no action matching volumes)*** +1. User specifies the volume policy as follows and specifies `defaultVolumesToFSBackup: true`: +```yaml +version: v1 +volumePolicies: +- conditions: + storageClass: + - gp2-csi + action: + type: fs-backup +``` +2. User creates a backup using this volume policy +3. The outcome would be that velero would perform `fs-backup` operation on both the volumes + - `fs-backup` on `Volume 1` because `Volume 1` satisfies the criteria for `fs-backup` action. + - Also, for Volume 2 as no matching action was found so legacy approach will be used as a fallback option for this volume (`fs-backup` operation will be done as `defaultVolumesToFSBackup: true` is specified by the user). diff --git a/site/content/docs/v1.17/restore-hooks.md b/site/content/docs/v1.17/restore-hooks.md new file mode 100644 index 000000000..b5681733e --- /dev/null +++ b/site/content/docs/v1.17/restore-hooks.md @@ -0,0 +1,300 @@ +--- +title: "Restore Hooks" +layout: docs +--- + +Velero supports Restore Hooks, custom actions that can be executed during or after the restore process. There are two kinds of Restore Hooks: + +1. InitContainer Restore Hooks: These will add init containers into restored pods to perform any necessary setup before the application containers of the restored pod can start. +1. Exec Restore Hooks: These can be used to execute custom commands or scripts in containers of a restored Kubernetes pod. + +## InitContainer Restore Hooks + +Use an `InitContainer` hook to add init containers into a pod before it's restored. You can use these init containers to run any setup needed for the pod to resume running from its backed-up state. +The InitContainer added by the restore hook will be the first init container in the `podSpec` of the restored pod. +In the case where the pod had volumes backed up using File System Backup, then, the restore hook InitContainer will be added after the `restore-wait` InitContainer. + +NOTE: This ordering can be altered by any mutating webhooks that may be installed in the cluster. + +There are two ways to specify `InitContainer` restore hooks: +1. Specifying restore hooks in annotations +1. Specifying restore hooks in the restore spec + +### Specifying Restore Hooks As Pod Annotations + +Below are the annotations that can be added to a pod to specify restore hooks: +* `init.hook.restore.velero.io/container-image` + * The container image for the init container to be added. Optional. +* `init.hook.restore.velero.io/container-name` + * The name for the init container that is being added. Optional. +* `init.hook.restore.velero.io/command` + * This is the `ENTRYPOINT` for the init container being added. This command is not executed within a shell and the container image's `ENTRYPOINT` is used if this is not provided. If a shell is needed to run your command, include a shell command, like `/bin/sh`, that is supported by the container at the beginning of your command. If you need multiple arguments, specify the command as a JSON array, such as `["/usr/bin/uname", "-a"]`. See [InitContainer As Pod Annotation Example](#initcontainer-restore-hooks-as-pod-annotation-example). Optional. + +#### InitContainer Restore Hooks As Pod Annotation Example + +Use the below commands to add annotations to the pods before taking a backup. + +```bash +$ kubectl annotate pod -n \ + init.hook.restore.velero.io/container-name=restore-hook \ + init.hook.restore.velero.io/container-image=alpine:latest \ + init.hook.restore.velero.io/command='["/bin/ash", "-c", "date"]' +``` + +With the annotation above, Velero will add the following init container to the pod when it's restored. + +```json +{ + "command": [ + "/bin/ash", + "-c", + "date" + ], + "image": "alpine:latest", + "imagePullPolicy": "Always", + "name": "restore-hook" + ... +} +``` + +### Specifying Restore Hooks In Restore Spec + +Init container restore hooks can also be specified using the `RestoreSpec`. +Please refer to the documentation on the [Restore API Type][1] for how to specify hooks in the Restore spec. +Init container restore hook command is not executed within a shell by default. If a shell is needed to run your command, include a shell command, like /bin/sh, that is supported by the container at the beginning of your command. + +#### Example + +Below is an example of specifying restore hooks in `RestoreSpec` + +```yaml +apiVersion: velero.io/v1 +kind: Restore +metadata: + name: r2 + namespace: velero +spec: + backupName: b2 + excludedResources: + ... + includedNamespaces: + - '*' + hooks: + resources: + - name: restore-hook-1 + includedNamespaces: + - app + postHooks: + - init: + initContainers: + - name: restore-hook-init1 + image: alpine:latest + volumeMounts: + - mountPath: /restores/pvc1-vm + name: pvc1-vm + command: + - /bin/ash + - -c + - echo -n "FOOBARBAZ" >> /restores/pvc1-vm/foobarbaz + - name: restore-hook-init2 + image: alpine:latest + volumeMounts: + - mountPath: /restores/pvc2-vm + name: pvc2-vm + command: + - /bin/ash + - -c + - echo -n "DEADFEED" >> /restores/pvc2-vm/deadfeed +``` + +The `hooks` in the above `RestoreSpec`, when restored, will add two init containers to every pod in the `app` namespace + +```json +{ + "command": [ + "/bin/ash", + "-c", + "echo -n \"FOOBARBAZ\" >> /restores/pvc1-vm/foobarbaz" + ], + "image": "alpine:latest", + "imagePullPolicy": "Always", + "name": "restore-hook-init1", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/restores/pvc1-vm", + "name": "pvc1-vm" + } + ] + ... +} +``` + +and + +```json +{ + "command": [ + "/bin/ash", + "-c", + "echo -n \"DEADFEED\" >> /restores/pvc2-vm/deadfeed" + ], + "image": "alpine:latest", + "imagePullPolicy": "Always", + "name": "restore-hook-init2", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/restores/pvc2-vm", + "name": "pvc2-vm" + } + ] + ... +} +``` + +## Exec Restore Hooks + +Use an Exec Restore hook to execute commands in a restored pod's containers after they start. + +There are two ways to specify `Exec` restore hooks: +1. Specifying exec restore hooks in annotations +1. Specifying exec restore hooks in the restore spec + +If a pod has the annotation `post.hook.restore.velero.io/command` then that is the only hook that will be executed in the pod. +No hooks from the restore spec will be executed in that pod. + +### Specifying Exec Restore Hooks As Pod Annotations + +Below are the annotations that can be added to a pod to specify exec restore hooks: +* `post.hook.restore.velero.io/container` + * The container name where the hook will be executed. Defaults to the first container. Optional. +* `post.hook.restore.velero.io/command` + * The command that will be executed in the container. This command is not executed within a shell by default. If a shell is needed to run your command, include a shell command, like `/bin/sh`, that is supported by the container at the beginning of your command. If you need multiple arguments, specify the command as a JSON array, such as `["/usr/bin/uname", "-a"]`. See [Exec Restore Hooks As Pod Annotation Example](#exec-restore-hooks-as-pod-annotation-example). Optional. +* `post.hook.restore.velero.io/on-error` + * How to handle execution failures. Valid values are `Fail` and `Continue`. Defaults to `Continue`. With `Continue` mode, execution failures are logged only. With `Fail` mode, no more restore hooks will be executed in any container in any pod and the status of the Restore will be `PartiallyFailed`. Optional. +* `post.hook.restore.velero.io/exec-timeout` + * How long to wait once execution begins. Defaults is 30 seconds. Optional. +* `post.hook.restore.velero.io/wait-timeout` + * How long to wait for a container to become ready. This should be long enough for the container to start plus any preceding hooks in the same container to complete. The wait timeout begins when the container is restored and may require time for the image to pull and volumes to mount. If not set the restore will wait indefinitely. Optional. +* `post.hook.restore.velero.io/wait-for-ready` + * String representation of a boolean that ensure command will be launched when underlying container is fully [Ready](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-readiness-probes). Use with caution because if only one restore hook for a pod consists of `WaitForReady` flag as "true", all the other hook executions for that pod, whatever their origin (`Backup` or `Restore` CRD), will wait for `Ready` state too. Any value except "true" will be considered as "false". Defaults is false. Optional. + +#### Exec Restore Hooks As Pod Annotation Example + +Use the below commands to add annotations to the pods before taking a backup. + +```bash +$ kubectl annotate pod -n \ + post.hook.restore.velero.io/container=postgres \ + post.hook.restore.velero.io/command='["/bin/bash", "-c", "psql < /backup/backup.sql"]' \ + post.hook.restore.velero.io/wait-timeout=5m \ + post.hook.restore.velero.io/exec-timeout=45s \ + post.hook.restore.velero.io/on-error=Continue +``` + +### Specifying Exec Restore Hooks in Restore Spec + +Exec restore hooks can also be specified using the `RestoreSpec`. +Please refer to the documentation on the [Restore API Type][1] for how to specify hooks in the Restore spec. +Exec restore hook command is not executed within a shell by default. If a shell is needed to run your command, include a shell command, like /bin/sh, that is supported by the container at the beginning of your command. + +#### Multiple Exec Restore Hooks Example + +Below is an example of specifying restore hooks in a `RestoreSpec`. +When using the restore spec it is possible to specify multiple hooks for a single pod, as this example demonstrates. + +All hooks applicable to a single container will be executed sequentially in that container once it starts. +The ordering of hooks executed in a single container follows the order of the restore spec. +In this example, the `pg_isready` hook is guaranteed to run before the `psql` hook because they both apply to the same container and the `pg_isready` hook is defined first. + +If a pod has multiple containers with applicable hooks, all hooks for a single container will be executed before executing hooks in another container. +In this example, if the postgres container starts before the sidecar container, both postgres hooks will run before the hook in the sidecar. +This means the sidecar container may be running for several minutes before its hook is executed. + +Velero guarantees that no two hooks for a single pod are executed in parallel, but hooks executing in different pods may run in parallel. + + +```yaml +apiVersion: velero.io/v1 +kind: Restore +metadata: + name: r2 + namespace: velero +spec: + backupName: b2 + excludedResources: + ... + includedNamespaces: + - '*' + hooks: + resources: + - name: restore-hook-1 + includedNamespaces: + - app + postHooks: + - exec: + execTimeout: 1m + waitTimeout: 5m + onError: Fail + container: postgres + command: + - /bin/bash + - '-c' + - 'while ! pg_isready; do sleep 1; done' + - exec: + container: postgres + waitTimeout: 6m + execTimeout: 1m + command: + - /bin/bash + - '-c' + - 'psql < /backup/backup.sql' + - exec: + container: sidecar + command: + - /bin/bash + - '-c' + - 'date > /start' +``` + +## Restore hook commands using scenarios +### Using environment variables + +You are able to use environment variables from your pods in your pre and post hook commands by including a shell command before using the environment variable. For example, `MYSQL_ROOT_PASSWORD` is an environment variable defined in pod called `mysql`. To use `MYSQL_ROOT_PASSWORD` in your pre-hook, you'd include a shell, like `/bin/sh`, before calling your environment variable: + +``` +postHooks: +- exec: + container: mysql + command: + - /bin/sh + - -c + - mysql --password=$MYSQL_ROOT_PASSWORD -e "FLUSH TABLES WITH READ LOCK" + onError: Fail +``` + +Note that the container must support the shell command you use. + +## Restore Hook Execution Results +### Viewing Results + +Velero records the execution results of hooks, allowing users to obtain this information by running the following command: + +```bash +$ velero restore describe +``` + +The displayed results include the number of hooks that were attempted to be executed and the number of hooks that failed execution. Any detailed failure reasons will be present in `Errors` section if applicable. + +```bash +HooksAttempted: 1 +HooksFailed: 0 +``` + + +[1]: api-types/restore.md diff --git a/site/content/docs/v1.17/restore-reference.md b/site/content/docs/v1.17/restore-reference.md new file mode 100644 index 000000000..cf5418f7b --- /dev/null +++ b/site/content/docs/v1.17/restore-reference.md @@ -0,0 +1,403 @@ +--- +title: "Restore Reference" +layout: docs +--- + +The page outlines how to use the `velero restore` command, configuration options for restores, and describes the main process Velero uses to perform restores. + +## Restore command-line options +To see all commands for restores, run `velero restore --help`. + +To see all options associated with a specific command, provide the `--help` flag to that command. For example, `velero restore create --help` shows all options associated with the `create` command. + +```Usage: + velero restore [command] + +Available Commands: + create Create a restore + delete Delete restores + describe Describe restores + get Get restores + logs Get restore logs +``` + +## Detailed Restore workflow + +The following is an overview of Velero's restore process that starts after you run `velero restore create`. + +1. The Velero client makes a call to the Kubernetes API server to create a [`Restore`](api-types/restore.md) object. + +1. The `RestoreController` notices the new Restore object and performs validation. + +1. The `RestoreController` fetches basic information about the backup being restored, like the [BackupStorageLocation](locations.md) (BSL). It also fetches a tarball of the cluster resources in the backup, any volumes that will be restored using File System Backup, and any volume snapshots to be restored. + +1. The `RestoreController` then extracts the tarball of backup cluster resources to the /tmp folder and performs some pre-processing on the resources, including: + + * Sorting the resources to help Velero decide the [restore order](#resource-restore-order) to use. + + * Attempting to discover the resources by their Kubernetes [Group Version Resource (GVR)](https://kubernetes.io/docs/reference/using-api/api-concepts/). If a resource is not discoverable, Velero will exclude it from the restore. See more about how [Velero backs up API versions](#backed-up-api-versions). + + * Applying any configured [resource filters](resource-filtering.md). + + * Verify the target namespace, if you have configured [`--namespace-mappings`](#restoring-into-a-different-namespace) restore option. + + +1. The `RestoreController` begins restoring the eligible resources one at a time. Velero extracts the current resource into a Kubernetes resource object. Depending on the type of resource and restore options you specified, Velero will make the following modifications to the resource or preparations to the target cluster before attempting to create the resource: + + * The `RestoreController` makes sure the target namespace exists. If the target namespace does not exist, then the `RestoreController` will create a new one on the cluster. + + * If the resource is a Persistent Volume (PV), the `RestoreController` will [rename](#persistent-volume-rename) the PV and [remap](#restoring-into-a-different-namespace) its namespace. + + * If the resource is a Persistent Volume Claim (PVC), the `RestoreController` will modify the [PVC metadata](#pvc-restore). + + * Execute the resource’s `RestoreItemAction` [custom plugins](custom-plugins/), if you have configured one. + + * Update the resource object’s namespace if you've configured [namespace remapping](#restoring-into-a-different-namespace). + + * The `RestoreController` adds a `velero.io/backup-name` label with the backup name and a `velero.io/restore-name` with the restore name to the resource. This can help you easily identify restored resources and which backup they were restored from. + +1. The `RestoreController` creates the resource object on the target cluster. If the resource is a PV then the `RestoreController` will restore the PV data from the [durable snapshot](#durable-snapshot-pv-restore), [File System Backup](#file-system-backup-pv-restore), or [CSI snapshot](#csi-pv-restore) depending on how the PV was backed up. + + If the resource already exists in the target cluster, which is determined by the Kubernetes API during resource creation, the `RestoreController` will skip the resource. The only [exception](#restore-existing-resource-policy) are Service Accounts, which Velero will attempt to merge differences between the backed up ServiceAccount into the ServiceAccount on the target cluster. You can [change the default existing resource restore policy](#restore-existing-resource-policy) to update resources instead of skipping them using the `--existing-resource-policy`. + +1. Once the resource is created on the target cluster, Velero may take some additional steps or wait for additional processes to complete before moving onto the next resource to restore. + + * If the resource is a Pod, the `RestoreController` will execute any [Restore Hooks](restore-hooks.md) and wait for the hook to finish. + * If the resource is a PV restored by File System Backup, the `RestoreController` waits for File System Backup’s restore to complete. The `RestoreController` sets a timeout for any resources restored with File System Backup during a restore. The default timeout is 4 hours, but you can configure this be setting using `--fs-backup-timeout` restore option. + * If the resource is a Custom Resource Definition, the `RestoreController` waits for its availability in the cluster. The timeout is 1 minute. + + If any failures happen finishing these steps, the `RestoreController` will log an error in the restore result and will continue restoring. + +## Restore order + +By default, Velero will restore resources in the following order: + +* Custom Resource Definitions +* Namespaces +* StorageClasses +* VolumeSnapshotClass +* VolumeSnapshotContents +* VolumeSnapshots +* PersistentVolumes +* PersistentVolumeClaims +* Secrets +* ConfigMaps +* ServiceAccounts +* LimitRanges +* Pods +* ReplicaSets +* Clusters +* ClusterResourceSets + +It's recommended that you use the default order for your restores. You are able to customize this order if you need to by setting the `--restore-resource-priorities` flag on the Velero server and specifying a different resource order. This customized order will apply to all future restores. You don't have to specify all resources in the `--restore-resource-priorities` flag. Velero will append resources not listed to the end of your customized list in alphabetical order. + +```shell +velero server \ +--restore-resource-priorities=customresourcedefinitions,namespaces,storageclasses,\ +volumesnapshotclass.snapshot.storage.k8s.io,volumesnapshotcontents.snapshot.storage.k8s.io,\ +volumesnapshots.snapshot.storage.k8s.io,persistentvolumes,persistentvolumeclaims,secrets,\ +configmaps,serviceaccounts,limitranges,pods,replicasets.apps,clusters.cluster.x-k8s.io,\ +clusterresourcesets.addons.cluster.x-k8s.io +``` + + +## Restoring Persistent Volumes and Persistent Volume Claims + +Velero has three approaches when restoring a PV, depending on how the backup was taken. + +1. When restoring a snapshot, Velero statically creates the PV and then binds it to a restored PVC. Velero's PV rename and remap process is used only in this case because this is the only case where Velero creates the PV resource directly. +1. When restoring with File System Backup, Velero uses Kubernetes’ [dynamic provision process](https://kubernetes.io/docs/concepts/storage/dynamic-provisioning/) to provision the PV after creating the PVC. In this case, the PV object is not actually created by Velero. +1. When restoring with the [CSI plugin](csi.md), the PV is created from a CSI snapshot by the CSI driver. Velero doesn’t create the PV directly. Instead Velero creates a PVC with its DataSource referring to the CSI VolumeSnapshot object. + +### Snapshot PV Restore + +PV data backed up by durable snapshots is restored by VolumeSnapshot plugins. Velero calls the plugins’ interface to create a volume from a snapshot. The plugin returns the volume’s `volumeID`. This ID is created by storage vendors and will be updated in the PV object created by Velero, so that the PV object is connected to the volume restored from a snapshot. + +### File System Backup PV Restore + +For more information on File System Backup restores, see the [File System Backup](file-system-backup.md#restore) page. + +### CSI PV Restore + +A PV backed up by CSI snapshots is restored by the [CSI plugin](csi). This happens when restoring the PVC object that has been snapshotted by CSI. The CSI VolumeSnapshot object name is specified with the PVC during backup as the annotation `velero.io/volume-snapshot-name`. After validating the VolumeSnapshot object, Velero updates the PVC by adding a `DataSource` field and setting its value to the VolumeSnapshot name. + +### Persistent Volume Rename + +When restoring PVs, if the PV being restored does not exist on the target cluster, Velero will create the PV using the name from the backup. Velero will rename a PV before restoring if both of the following conditions are met: + +1. The PV already exists on the target cluster. +1. The PV’s claim namespace has been [remapped](#restoring-into-a-different-namespace). + +If both conditions are met, Velero will create the PV with a new name. The new name is the prefix `velero-clone-` and a random UUID. Velero also preserves the original name of the PV by adding an annotation `velero.io/original-pv-name` to the restored PV object. + +If you attempt to restore the PV's referenced PVC into its original namespace without remapping the namespace, Velero will not rename the PV. If a PV's referenced PVC exists already for that namespace, the restored PV creation attempt will fail, with an `Already Exist` error from the Kubernetes API Server. + +### PVC Restore + +PVC objects are created the same way as other Kubernetes resources during a restore, with some specific changes: +* For a dynamic binding PVCs, Velero removes the fields related to bindings from the PVC object. This enables the default Kubernetes [dynamic binding process](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#binding) to be used for this PVC. The fields include: + * volumeName + * pv.kubernetes.io/bind-completed annotation + * pv.kubernetes.io/bound-by-controller annotation +* For a PVC that is bound by Velero Restore, if the target PV has been renamed by the [PV restore process](#persistent-volume-rename), the RestoreController renames the `volumeName` field of the PVC object. + +### Changing PV/PVC Storage Classes + +Velero can change the storage class of persistent volumes and persistent volume claims during restores. To configure a storage class mapping, create a config map in the Velero namespace like the following: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + # any name can be used; Velero uses the labels (below) + # to identify it rather than the name + name: change-storage-class-config + # must be in the velero namespace + namespace: velero + # the below labels should be used verbatim in your + # ConfigMap. + labels: + # this value-less label identifies the ConfigMap as + # config for a plugin (i.e. the built-in restore item action plugin) + velero.io/plugin-config: "" + # this label identifies the name and kind of plugin + # that this ConfigMap is for. + velero.io/change-storage-class: RestoreItemAction +data: + # add 1+ key-value pairs here, where the key is the old + # storage class name and the value is the new storage + # class name. + : +``` +### Changing Image Repositories +Velero can change the image name of pod/deployment/statefulsets/daemonset/replicaset/replicationcontroller/job/cronjob during restores. To configure a image name mapping, create a config map in the Velero namespace like the following: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + # any name can be used; Velero uses the labels (below) + # to identify it rather than the name + name: change-image-name-config + # must be in the velero namespace + namespace: velero + # the below labels should be used verbatim in your + # ConfigMap. + labels: + # this value-less label identifies the ConfigMap as + # config for a plugin (i.e. the built-in restore item action plugin) + velero.io/plugin-config: "" + # this label identifies the name and kind of plugin + # that this ConfigMap is for. + velero.io/change-image-name: RestoreItemAction +data: + # add 1+ key-value pairs here, where the key can be any + # words that ConfigMap accepts. + # the value should be: + # "" + # for current implementation the can only be "," + # e.x: in case your old image name is 1.1.1.1:5000/abc:test + "case1":"1.1.1.1:5000,2.2.2.2:3000" + "case2":"5000,3000" + "case3":"abc:test,edf:test" + "case5":"test,latest" + "case4":"1.1.1.1:5000/abc:test,2.2.2.2:3000/edf:test" + # Please note that image name may contain more than one part that + # matching the replacing words. + # e.x:in case your old image names are: + # dev/image1:dev and dev/image2:dev + # you want change to: + # test/image1:dev and test/image2:dev + # the suggested replacing rule is: + "case5":"dev/,test/" + # this will avoid unexpected replacement to the second "dev". +``` + +### PVC selected-node + +Velero by default removes PVC's `volume.kubernetes.io/selected-node` annotation during restore, so that the restored PVC could be provisioned appropriately according to ```WaitForFirstConsumer``` rules, storage topologies and the restored pod's schedule result, etc. + +For more information of how this selected-node annotation matters to PVC restore, see issue https://github.com/vmware-tanzu/velero/issues/9053. + +As an expectation, when you provide the selected-node configuration, Velero sets the annotation to the node in the configuration, if the node doesn't exist in the cluster then the annotation will also be removed. +Note: This feature is under deprecation as of Velero 1.15, following Velero deprecation policy. This feature is primarily used to remedy some problems in old Kubernetes versions as described [here](https://github.com/vmware-tanzu/velero/pull/2377). It may not work with the new features of Kubernetes and Velero. For more information, see issue https://github.com/vmware-tanzu/velero/issues/9053 for more information. +To configure a selected-node, create a config map in the Velero namespace like the following: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + # any name can be used; Velero uses the labels (below) + # to identify it rather than the name + name: change-pvc-node-selector-config + # must be in the velero namespace + namespace: velero + # the below labels should be used verbatim in your + # ConfigMap. + labels: + # this value-less label identifies the ConfigMap as + # config for a plugin (i.e. the built-in restore item action plugin) + velero.io/plugin-config: "" + # this label identifies the name and kind of plugin + # that this ConfigMap is for. + velero.io/change-pvc-node-selector: RestoreItemAction +data: + # add 1+ key-value pairs here, where the key is the old + # node name and the value is the new node name. + : +``` + +## Restoring into a different namespace + +Velero can restore resources into a different namespace than the one they were backed up from. To do this, use the `--namespace-mappings` flag: + +```bash +velero restore create \ + --from-backup \ + --namespace-mappings old-ns-1:new-ns-1,old-ns-2:new-ns-2 +``` + +For example, A Persistent Volume object has a reference to the Persistent Volume Claim’s namespace in the field `Spec.ClaimRef.Namespace`. If you specify that Velero should remap the target namespace during the restore, Velero will change the `Spec.ClaimRef.Namespace` field on the PV object from `old-ns-1` to `new-ns-1`. + +## Restore existing resource policy + +By default, Velero is configured to be non-destructive during a restore. This means that it will never overwrite data that already exists in your cluster. When Velero attempts to create a resource during a restore, the resource being restored is compared to the existing resources on the target cluster. If the resource already exists in the target cluster, Velero skips restoring the current resource and moves onto the next resource to restore, without making any changes to the target cluster. + +An exception to the default restore policy is ServiceAccounts. When restoring a ServiceAccount that already exists on the target cluster, Velero will attempt to merge the fields of the ServiceAccount from the backup into the existing ServiceAccount. Secrets and ImagePullSecrets are appended from the backed-up ServiceAccount. Velero adds any non-existing labels and annotations from the backed-up ServiceAccount to the existing resource, leaving the existing labels and annotations in place. + +You can change this policy for a restore by using the `--existing-resource-policy` restore flag. The available options +are `none` (default) and `update`. If you choose to update existing resources during a restore +(`--existing-resource-policy=update`), Velero will attempt to update an existing resource to match the resource from the backup: + +* If the existing resource in the target cluster is the same as the resource Velero is attempting to restore, Velero will add a `velero.io/backup-name` label with the backup name and a `velero.io/restore-name` label with the restore name to the existing resource. If patching the labels fails, Velero adds a restore error and continues restoring the next resource. + +* If the existing resource in the target cluster is different from the backup, Velero will first try to patch the existing resource to match the backup resource. If the patch is successful, Velero will add a `velero.io/backup-name` label with the backup name and a `velero.io/restore-name` label with the restore name to the existing resource. If the patch fails, Velero adds a restore warning and tries to add the `velero.io/backup-name` and `velero.io/restore-name` labels on the resource. If the labels patch also fails, then Velero logs a restore error and continues restoring the next resource. + +You can also configure the existing resource policy in a [Restore](api-types/restore.md) object. + +**NOTE:** +* Update of a resource only applies to the Kubernetes resource data such as its spec. It may not work as expected for certain resource types such as PVCs and Pods. In case of PVCs for example, data in the PV is not restored or overwritten in any way. +* `update` existing resource policy works in a best-effort way, which means when restore's `--existing-resource-policy` is set to `update`, Velero will try to update the resource if the resource already exists, if the update fails, Velero will fall back to the default non-destructive way in the restore, and just logs a warning without failing the restore. + +## Restore "status" field of objects + +By default, Velero will remove the `status` field of an object before it's restored. This is because the value `status` field is typically set by the controller during reconciliation. However, some custom resources are designed to store environment specific information in the `status` field, and it is important to preserve such information during restore. + +You can use `--status-include-resources` and `--status-exclude-resources` flags to select the resources whose `status` field will be restored by Velero. If there are resources selected via these flags, velero will trigger another API call to update the restored object to restore `status` field after it's created. + +## Object-Level Resource Status Restoration + +Starting from Velero 1.16, Velero now supports object-level control over status restoration during restores. Previously, status restoration could only be configured at the resource type level using the `restoreStatus` field in the Restore CR. With this enhancement, users and controllers can now specify status restoration at the individual resource instance level using the annotation: +```yaml +metadata: + annotations: + velero.io/restore-status: "true" +``` +This feature provides fine-grained control over status restoration, allowing users and controllers to mark specific objects for status restore while keeping others unaffected. + +Velero determines whether to restore the status of an object based on the following precedence: +1. Object-Level Annotation (`velero.io/restore-status`) +- If the annotation is present with a valid value ("true" or "false"), it overrides the global `restoreStatus` setting. +- "true" → Status will be restored for this object, even if the resource type is not included in `restoreStatus.includedResources`. +- "false" → Status will not be restored for this object, even if the resource type is included in `restoreStatus.includedResources`. +2. Restore CR (`restoreStatus` Field) +• If the annotation is missing or invalid, Velero falls back to the `restoreStatus` configuration in the Restore CR. +• Objects of resource types listed in `restoreStatus.includedResources` will have their status restored. +• Objects of resource types excluded from `restoreStatus.excludedResources` will not have their status restored. +3. Default Behavior +• If an object has no annotation and its resource type is not included in `restoreStatus.includedResources`, status restoration is skipped. + +Let's go over some examples: + +1. Restore Status for a Specific Object: If you want Velero to restore the status for a specific resource instance regardless of global restore settings, add the annotation: +```yaml +metadata: + annotations: + velero.io/restore-status: "true" +``` +Even if the resource type is not listed in `restoreStatus.includedResources`, this object’s status will be restored. + +2. Prevent Status Restore for a Specific Object: If you want to exclude a specific object from status restoration, even if its resource type is included in `restoreStatus.includedResources`, use: +```yaml +metadata: + annotations: + velero.io/restore-status: "false" +``` +This ensures that this specific object will not have its status restored. + +3. Restore Status Based on Resource Type: If you want to restore the status for all objects of a resource type, use the `restoreStatus` field in the Restore CR: +```yaml +apiVersion: velero.io/v1 +kind: Restore +metadata: + name: restore-with-status + namespace: velero +spec: + restoreStatus: + includedResources: + - foo.bar.io +``` +All `foo.bar.io` objects will have their status restored, except those that have `velero.io/restore-status`: "false" annotation. + +4. Default Behavior (No Annotations & No Restore Spec): If no `velero.io/restore-status` annotation is set and the resource type is not listed in `restoreStatus.includedResources`, Velero skips restoring status for that object. This maintains the existing default behavior. + +## Write Sparse files +If using fs-restore or CSI snapshot data movements, it's supported to write sparse files during restore by the below command: +```bash +velero restore create --from-backup --write-sparse-files --wait +``` + +## Parallel Files Download +If using fs-restore or CSI snapshot data movements, it's possible to configure one option for parallel file downloads during the restore by Kopia uploader using the command below: +```bash +velero restore create --from-backup --parallel-files-download --wait +``` + +## Removing a Restore object + +There are two ways to delete a Restore object: + +1. Deleting with `velero restore delete` will delete the Custom Resource representing the restore, along with its individual log and results files. It will not delete any objects that were created by the restore in your cluster. +2. Deleting with `kubectl -n velero delete restore` will delete the Custom Resource representing the restore. It will not delete restore log or results files from object storage, or any objects that were created during the restore in your cluster. + +## What happens to NodePorts and HealthCheckNodePort when restoring Services + +During a restore, Velero deletes **Auto assigned** NodePorts and HealthCheckNodePort by default and Services get new **auto assigned** nodePorts and healthCheckNodePort after restore. + +Velero auto detects **explicitly specified** NodePorts using **`last-applied-config`** annotation and **`managedFields`**. They are **preserved** after restore. NodePorts can be explicitly specified as `.spec.ports[*].nodePort` field on Service definition. + +Velero will do the same to the `HealthCheckNodePort` as `NodePorts`. + +### Always Preserve NodePorts and HealthCheckNodePort + +It is not always possible to set nodePorts and healthCheckNodePort explicitly on some big clusters because of operational complexity. As the Kubernetes [NodePort documentation](https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport) states, "if you want a specific port number, you can specify a value in the `nodePort` field. The control plane will either allocate you that port or report that the API transaction failed. This means that you need to take care of possible port collisions yourself. You also have to use a valid port number, one that's inside the range configured for NodePort use."" + +The clusters which are not explicitly specifying nodePorts may still need to restore original NodePorts in the event of a disaster. Auto assigned nodePorts are typically defined on Load Balancers located in front of cluster. Changing all these nodePorts on Load Balancers is another operation complexity you are responsible for updating after disaster if nodePorts are changed. + +Use the `velero restore create ` command's `--preserve-nodeports` flag to preserve Service nodePorts and healthCheckNodePort always, regardless of whether nodePorts are explicitly specified or not. This flag is used for preserving the original nodePorts and healthCheckNodePort from a backup and can be used as `--preserve-nodeports` or `--preserve-nodeports=true`. If this flag is present, Velero will not remove the nodePorts and healthCheckNodePort when restoring a Service, but will try to use the nodePorts from the backup. + +Trying to preserve nodePorts and healthCheckNodePort may cause port conflicts when restoring on situations below: + +- If the nodePort from the backup is already allocated on the target cluster then Velero prints error log as shown below and continues the restore operation. + + ``` + time="2020-11-23T12:58:31+03:00" level=info msg="Executing item action for services" logSource="pkg/restore/restore.go:1002" restore=velero/test-with-3-svc-20201123125825 + + time="2020-11-23T12:58:31+03:00" level=info msg="Restoring Services with original NodePort(s)" cmd=_output/bin/linux/amd64/velero logSource="pkg/restore/service_action.go:61" pluginName=velero restore=velero/test-with-3-svc-20201123125825 + + time="2020-11-23T12:58:31+03:00" level=info msg="Attempting to restore Service: hello-service" logSource="pkg/restore/restore.go:1107" restore=velero/test-with-3-svc-20201123125825 + + time="2020-11-23T12:58:31+03:00" level=error msg="error restoring hello-service: Service \"hello-service\" is invalid: spec.ports[0].nodePort: Invalid value: 31536: provided port is already allocated" logSource="pkg/restore/restore.go:1170" restore=velero/test-with-3-svc-20201123125825 + ``` + +- If the nodePort from the backup is not in the nodePort range of target cluster then Velero prints error log as below and continues with the restore operation. Kubernetes default nodePort range is 30000-32767 but on the example cluster nodePort range is 20000-22767 and tried to restore Service with nodePort 31536. + + ``` + time="2020-11-23T13:09:17+03:00" level=info msg="Executing item action for services" logSource="pkg/restore/restore.go:1002" restore=velero/test-with-3-svc-20201123130915 + + time="2020-11-23T13:09:17+03:00" level=info msg="Restoring Services with original NodePort(s)" cmd=_output/bin/linux/amd64/velero logSource="pkg/restore/service_action.go:61" pluginName=velero restore=velero/test-with-3-svc-20201123130915 + + time="2020-11-23T13:09:17+03:00" level=info msg="Attempting to restore Service: hello-service" logSource="pkg/restore/restore.go:1107" restore=velero/test-with-3-svc-20201123130915 + + time="2020-11-23T13:09:17+03:00" level=error msg="error restoring hello-service: Service \"hello-service\" is invalid: spec.ports[0].nodePort: Invalid value: 31536: provided port is not in the valid range. The range of valid ports is 20000-22767" logSource="pkg/restore/restore.go:1170" restore=velero/test-with-3-svc-20201123130915 + ``` diff --git a/site/content/docs/v1.17/restore-resource-modifiers.md b/site/content/docs/v1.17/restore-resource-modifiers.md new file mode 100644 index 000000000..0c1f2f217 --- /dev/null +++ b/site/content/docs/v1.17/restore-resource-modifiers.md @@ -0,0 +1,187 @@ +--- +title: "Restore Resource Modifiers" +layout: docs +--- + +## Resource Modifiers +Velero provides a generic ability to modify the resources during restore by specifying json patches. The json patches are applied to the resources before they are restored. The json patches are specified in a configmap and the configmap is referenced in the restore command. + +**Creating resource Modifiers** + +Below is the two-step of using resource modifiers to modify the resources during restore. +1. Creating resource modifiers configmap + + You need to create one configmap in Velero install namespace from a YAML file that defined resource modifiers. The creating command would be like the below: + ```bash + kubectl create cm --from-file -n velero + ``` +2. Creating a restore reference to the defined resource policies + + You can create a restore with the flag `--resource-modifier-configmap`, which will apply the defined resource modifiers to the current restore. The creating command would be like the below: + ```bash + velero restore create --resource-modifier-configmap + ``` + +**YAML template** + +- Yaml template: +```yaml +version: v1 +resourceModifierRules: +- conditions: + groupResource: persistentvolumeclaims + resourceNameRegex: "^mysql.*$" + namespaces: + - bar + - foo + labelSelector: + matchLabels: + foo: bar + patches: + - operation: replace + path: "/spec/storageClassName" + value: "premium" + - operation: remove + path: "/metadata/labels/test" + ``` + +- The above configmap will apply the JSON Patch to all the PVCs in the namespaces bar and foo with name starting with mysql and match label `foo: bar`. The JSON Patch will replace the storageClassName with "premium" and remove the label "test" from the PVCs. +- Note that the Namespace here is the original namespace of the backed up resource, not the new namespace where the resource is going to be restored. +- You can specify multiple JSON Patches for a particular resource. The patches will be applied in the order specified in the configmap. A subsequent patch is applied in order and if multiple patches are specified for the same path, the last patch will override the previous patches. +- You can specify multiple resourceModifierRules in the configmap. The rules will be applied in the order specified in the configmap. + +### Operations supported by the JSON Patch RFC: +- add +- remove +- replace +- move +- copy +- test (covered below) + +### Advanced scenarios +#### **Conditional patches using test operation** + The `test` operation can be used to check if a particular value is present in the resource. If the value is present, the patch will be applied. If the value is not present, the patch will not be applied. This can be used to apply a patch only if a particular value is present in the resource. For example, if you wish to change the storage class of a PVC only if the PVC is using a particular storage class, you can use the following configmap. +```yaml +version: v1 +resourceModifierRules: +- conditions: + groupResource: persistentvolumeclaims + resourceNameRegex: ".*" + namespaces: + - bar + - foo + patches: + - operation: test + path: "/spec/storageClassName" + value: "premium" + - operation: replace + path: "/spec/storageClassName" + value: "standard" +``` + +#### **Other examples** +```yaml +version: v1 +resourceModifierRules: +- conditions: + groupResource: deployments.apps + resourceNameRegex: "^test-.*$" + namespaces: + - bar + - foo + patches: + # Dealing with complex values by escaping the yaml + - operation: add + path: "/spec/template/spec/containers/0" + value: "{\"name\": \"nginx\", \"image\": \"nginx:1.14.2\", \"ports\": [{\"containerPort\": 80}]}" + # Copy Operator + - operation: copy + from: "/spec/template/spec/containers/0" + path: "/spec/template/spec/containers/1" +``` + +**Note:** +- The design and approach is inspired from [kubectl patch command](https://github.com/kubernetes/kubectl/blob/0a61782351a027411b8b45b1443ec3dceddef421/pkg/cmd/patch/patch.go#L102C2-L104C1) +- Update a container's image using a json patch with positional arrays +kubectl patch pod valid-pod -type='json' -p='[{"op": "replace", "path": "/spec/containers/0/image", "value":"new image"}]' +- Before creating the resource modifier yaml, you can try it out using kubectl patch command. The same commands should work as it is. + +#### JSON Merge Patch +You can modify a resource using JSON Merge Patch +```yaml +version: v1 +resourceModifierRules: +- conditions: + groupResource: pods + namespaces: + - ns1 + mergePatches: + - patchData: | + { + "metadata": { + "annotations": { + "foo": null + } + } + } +``` +- The above configmap will apply the Merge Patch to all the pods in namespace ns1 and remove the annotation `foo` from the pods. +- Both json and yaml format are supported for the patchData. +- For more details, please refer to [this doc](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/) + +#### Strategic Merge Patch +You can modify a resource using Strategic Merge Patch +```yaml +version: v1 +resourceModifierRules: +- conditions: + groupResource: pods + resourceNameRegex: "^my-pod$" + namespaces: + - ns1 + strategicPatches: + - patchData: | + { + "spec": { + "containers": [ + { + "name": "nginx", + "image": "repo2/nginx" + } + ] + } + } +``` +- The above configmap will apply the Strategic Merge Patch to the pod with name my-pod in namespace ns1 and update the image of container nginx to `repo2/nginx`. +- Both json and yaml format are supported for the patchData. +- For more details, please refer to [this doc](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/) + + +### Conditional Patches in ALL Patch Types +A new field `matches` is added in conditions to support conditional patches. + +Example of matches in conditions +```yaml +version: v1 +resourceModifierRules: +- conditions: + groupResource: persistentvolumeclaims.storage.k8s.io + matches: + - path: "/spec/storageClassName" + value: "premium" + mergePatches: + - patchData: | + { + "metadata": { + "annotations": { + "foo": null + } + } + } +``` +- The above configmap will apply the Merge Patch to all the PVCs in all namespaces with storageClassName premium and remove the annotation `foo` from the PVCs. +- You can specify multiple rules in the `matches` list. The patch will be applied only if all the matches are satisfied. + +### Wildcard Support for GroupResource +The user can specify a wildcard for groupResource in the conditions' struct. This will allow the user to apply the patches for all the resources of a particular group or all resources in all groups. For example, `*.apps` will apply to all the resources in the `apps` group, `*` will apply to all the resources in core group, `*.*` will apply to all the resources in all groups. +- If both `*.groupName` and `namespaces` are specified, the patches will be applied to all the namespaced resources in this group in the specified namespaces and all the cluster resources in this group. \ No newline at end of file diff --git a/site/content/docs/v1.17/run-locally.md b/site/content/docs/v1.17/run-locally.md new file mode 100644 index 000000000..897ee1893 --- /dev/null +++ b/site/content/docs/v1.17/run-locally.md @@ -0,0 +1,53 @@ +--- +title: "Run Velero locally in development" +layout: docs +--- + +Running the Velero server locally can speed up iterative development. This eliminates the need to rebuild the Velero server +image and redeploy it to the cluster with each change. + +## Run Velero locally with a remote cluster + +Velero runs against the Kubernetes API server as the endpoint (as per the `kubeconfig` configuration), so both the Velero server and client use the same `client-go` to communicate with Kubernetes. This means the Velero server can be run locally just as functionally as if it was running in the remote cluster. + +### Prerequisites + +When running Velero, you will need to ensure that you set up all of the following: + +* Appropriate RBAC permissions in the cluster + * Read access for all data from the source cluster and namespaces + * Write access to the target cluster and namespaces +* Cloud provider credentials + * Read/write access to volumes + * Read/write access to object storage for backup data +* A [BackupStorageLocation][20] object definition for the Velero server +* (Optional) A [VolumeSnapshotLocation][21] object definition for the Velero server, to take PV snapshots + +### 1. Install Velero + +See documentation on how to install Velero in some specific providers: [Install overview][22] + +### 2. Scale deployment down to zero + +After you use the `velero install` command to install Velero into your cluster, you scale the Velero deployment down to 0 so it is not simultaneously being run on the remote cluster and potentially causing things to get out of sync: + +`kubectl scale --replicas=0 deployment velero -n velero` + +#### 3. Start the Velero server locally + +* To run the server locally, use the full path according to the binary you need. Example, if you are on a Mac, and using `AWS` as a provider, this is how to run the binary you built from source using the full path: `AWS_SHARED_CREDENTIALS_FILE= ./_output/bin/darwin/amd64/velero`. Alternatively, you may add the `velero` binary to your `PATH`. + +* Start the server: `velero server [CLI flags]`. The following CLI flags may be useful to customize, but see `velero server --help` for full details: + * `--log-level`: set the Velero server's log level (default `info`, use `debug` for the most logging) + * `--kubeconfig`: set the path to the kubeconfig file the Velero server uses to talk to the Kubernetes apiserver (default `$KUBECONFIG`) + * `--namespace`: the set namespace where the Velero server should look for backups, schedules, restores (default `velero`) + * `--plugin-dir`: set the directory where the Velero server looks for plugins (default `/plugins`) + * The `--plugin-dir` flag requires the plugin binary to be present locally, and should be set to the directory containing this built binary. + * `--metrics-address`: set the bind address and port where Prometheus metrics are exposed (default `:8085`) + +[15]: https://docs.aws.amazon.com/cli/latest/topic/config-vars.html#the-shared-credentials-file +[16]: https://cloud.google.com/docs/authentication/getting-started#setting_the_environment_variable +[18]: https://eksctl.io/ +[20]: api-types/backupstoragelocation.md +[21]: api-types/volumesnapshotlocation.md +[22]: basic-install.md diff --git a/site/content/docs/v1.17/self-signed-certificates.md b/site/content/docs/v1.17/self-signed-certificates.md new file mode 100644 index 000000000..ac088b694 --- /dev/null +++ b/site/content/docs/v1.17/self-signed-certificates.md @@ -0,0 +1,84 @@ +--- +title: "Use Velero with a storage provider secured by a self-signed certificate" +layout: docs +--- + +If you are using an S3-Compatible storage provider that is secured with a self-signed certificate, connections to the object store may fail with a `certificate signed by unknown authority` message. +To proceed, provide a certificate bundle when adding the storage provider. + +## Trusting a self-signed certificate during installation + +When using the `velero install` command, you can use the `--cacert` flag to provide a path +to a PEM-encoded certificate bundle to trust. + +```bash +velero install \ + --plugins + --provider \ + --bucket \ + --secret-file \ + --cacert +``` + +Velero will then automatically use the provided CA bundle to verify TLS connections to +that storage provider when backing up and restoring. + +## Trusting a self-signed certificate with the Velero client + +When using Velero client commands like describe, download, or logs to access backups or restores +in storage secured by a self-signed certificate, the CA certificate can be configured in two ways: + +1. **Using the `--cacert` flag** (legacy method): + + ```bash + velero backup describe my-backup --cacert + ``` + +2. **Configuring the CA certificate in the BackupStorageLocation**: + + ```yaml + apiVersion: velero.io/v1 + kind: BackupStorageLocation + metadata: + name: default + namespace: velero + spec: + provider: aws + objectStorage: + bucket: velero-backups + caCert: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi4uLiAoYmFzZTY0IGVuY29kZWQgY2VydGlmaWNhdGUgY29udGVudCkgLi4uCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + config: + region: us-east-1 + ``` + +When the CA certificate is configured in the BackupStorageLocation, Velero client commands will automatically use it without requiring the `--cacert` flag. + +## Error with client certificate with custom S3 server + +In case you are using a custom S3-compatible server, you may encounter that the backup fails with an error similar to one below. + +```text +rpc error: code = Unknown desc = RequestError: send request failed caused by: +Get https://minio.com:3000/k8s-backup-bucket?delimiter=%2F&list-type=2&prefix=: remote error: tls: alert(116) +``` + +Error 116 represents certificate required as seen here in [error codes](https://datatracker.ietf.org/doc/html/rfc8446#appendix-B.2). +Velero as a client does not include its certificate while performing SSL handshake with the server. +From [TLS 1.3 spec](https://tools.ietf.org/html/rfc8446), verifying client certificate is optional on the server. +You will need to change this setting on the server to make it work. + +## Skipping TLS verification + +**Note:** The `--insecure-skip-tls-verify` flag is insecure and susceptible to man-in-the-middle attacks and meant to help your testing and developing scenarios in an on-premises environment. Using this flag in production is not recommended. + +Velero provides a way for you to skip TLS verification on the object store when using the [AWS provider plugin](https://github.com/vmware-tanzu/velero-plugin-for-aws) or [File System Backup](file-system-backup.md) by passing the `--insecure-skip-tls-verify` flag with the following Velero commands, + +* velero backup describe +* velero backup download +* velero backup logs +* velero restore describe +* velero restore log + +If true, the object store's TLS certificate will not be checked for validity before Velero or backup repository connects to the object storage. You can permanently skip TLS verification for an object store by setting `Spec.Config.InsecureSkipTLSVerify` to true in the [BackupStorageLocation](api-types/backupstoragelocation.md) CRD. + +Note that Velero's File System Backup uses Restic or Kopia to do data transfer between object store and Kubernetes cluster disks. This means that when you specify `--insecure-skip-tls-verify` in Velero operations that involve File System Backup, Velero will convey this information to Restic or Kopia. For example, for Restic, Velero will add the Restic global command parameter `--insecure-tls` to Restic commands. diff --git a/site/content/docs/v1.17/start-contributing.md b/site/content/docs/v1.17/start-contributing.md new file mode 100644 index 000000000..ae443e287 --- /dev/null +++ b/site/content/docs/v1.17/start-contributing.md @@ -0,0 +1,34 @@ +--- +title: "Start contributing" +layout: docs +--- + +## Before you start + +* Please familiarize yourself with the [Code of Conduct][1] before contributing. +* Also, see [CONTRIBUTING.md][2] for instructions on the developer certificate of origin that we require. + +## Creating a design doc + +Having a high level design document with the proposed change and the impacts helps the maintainers evaluate if a major change should be incorporated. + +To make a design pull request, you can copy the template found in the `design/_template.md` file into a new Markdown file. + +## Finding your way around + +You may join the Velero community and contribute in many different ways, including helping us design or test new features. For any significant feature we consider adding, we start with a design document. You may find a list of in progress new designs here: https://github.com/vmware-tanzu/velero/pulls?q=is%3Aopen+is%3Apr+label%3ADesign. Feel free to review and help us with your input. + +You can also vote on issues using :+1: and :-1:, as explained in our [Feature enhancement request][3] and [Bug issue][4] templates. This will help us quantify importance and prioritize issues. + +For information on how to connect with our maintainers and community, join our online meetings, or find good first issues, start on our [Velero community](https://velero.io/community/) page. + +Please browse our list of resources, including a playlist of past online community meetings, blog posts, and other resources to help you get familiar with our project: [Velero resources](https://velero.io/resources/). + +## Contributing + +If you are ready to jump in and test, add code, or help with documentation, please use the navigation on the left under `Contribute`. + +[1]: https://github.com/vmware-tanzu/velero/blob/v1.17.0/CODE_OF_CONDUCT.md +[2]: https://github.com/vmware-tanzu/velero/blob/v1.17.0/CONTRIBUTING.md +[3]: https://github.com/vmware-tanzu/velero/blob/v1.17.0/.github/ISSUE_TEMPLATE/feature-enhancement-request.md +[4]: https://github.com/vmware-tanzu/velero/blob/v1.17.0/.github/ISSUE_TEMPLATE/bug_report.md diff --git a/site/content/docs/v1.17/style-guide.md b/site/content/docs/v1.17/style-guide.md new file mode 100644 index 000000000..5fb5e55dd --- /dev/null +++ b/site/content/docs/v1.17/style-guide.md @@ -0,0 +1,345 @@ +--- +title: "Documentation Style Guide" +layout: docs +--- + +_This style guide is adapted from the [Kubernetes style guide](https://kubernetes.io/docs/contribute/style/style-guide/)._ + +This page outlines writing style guidelines for the Velero documentation and you should use this page as a reference you write or edit content. Note that these are guidelines, not rules. Use your best judgment as you write documentation, and feel free to propose changes to these guidelines. Changes to the style guide are made by the Velero maintainers as a group. To propose a change or addition create an issue/PR, or add a suggestion to the [community meeting agenda](https://hackmd.io/Jq6F5zqZR7S80CeDWUklkA) and attend the meeting to participate in the discussion. + +The Velero documentation uses the [kramdown](https://kramdown.gettalong.org/) Markdown renderer. + +## Content best practices +### Use present tense + +{{< table caption="Do and Don't - Use present tense" >}} +|Do|Don't| +|--- |--- | +|This `command` starts a proxy.|This command will start a proxy.| +{{< /table >}} + +Exception: Use future or past tense if it is required to convey the correct meaning. + +### Use active voice + +{{< table caption="Do and Don't - Use active voice" >}} +|Do|Don't| +|--- |--- | +|You can explore the API using a browser.|The API can be explored using a browser.| +|The YAML file specifies the replica count.|The replica count is specified in the YAML file.| +{{< /table >}} + +Exception: Use passive voice if active voice leads to an awkward sentence construction. + +### Use simple and direct language + +Use simple and direct language. Avoid using unnecessary phrases, such as saying "please." + +{{< table caption="Do and Don't - Use simple and direct language" >}} +|Do|Don't| +|--- |--- | +|To create a ReplicaSet, ...|In order to create a ReplicaSet, ...| +|See the configuration file.|Please see the configuration file.| +|View the Pods.|With this next command, we'll view the Pods.| +{{< /table >}} + +### Address the reader as "you" + +{{< table caption="Do and Don't - Addressing the reader" >}} +|Do|Don't| +|--- |--- | +|You can create a Deployment by ...|We'll create a Deployment by ...| +|In the preceding output, you can see...|In the preceding output, we can see ...| +{{< /table >}} + +### Avoid Latin phrases + +Prefer English terms over Latin abbreviations. + +{{< table caption="Do and Don't - Avoid Latin phrases" >}} +|Do|Don't| +|--- |--- | +|For example, ...|e.g., ...| +|That is, ...|i.e., ...| +{{< /table >}} + +Exception: Use "etc." for et cetera. + +## Patterns to avoid + + +### Avoid using "we" + +Using "we" in a sentence can be confusing, because the reader might not know +whether they're part of the "we" you're describing. + +{{< table caption="Do and Don't - Avoid using we" >}} +|Do|Don't| +|--- |--- | +|Version 1.4 includes ...|In version 1.4, we have added ...| +|Kubernetes provides a new feature for ...|We provide a new feature ...| +|This page teaches you how to use Pods.|In this page, we are going to learn about Pods.| +{{< /table >}} + +### Avoid jargon and idioms + +Many readers speak English as a second language. Avoid jargon and idioms to help them understand better. + +{{< table caption="Do and Don't - Avoid jargon and idioms" >}} +|Do|Don't| +|--- |--- | +|Internally, ...|Under the hood, ...| +|Create a new cluster.|Turn up a new cluster.| +{{< /table >}} + +### Avoid statements about the future or that will soon be out of date + +Avoid making promises or giving hints about the future. If you need to talk about +a beta feature, put the text under a heading that identifies it as beta +information. + +Also avoid words like “recently”, "currently" and "new." A feature that is new today might not be +considered new in a few months. + +{{< table caption="Do and Don't - Avoid statements that will soon be out of date" >}} +|Do|Don't| +|--- |--- | +|In version 1.4, ...|In the current version, ...| +|The Federation feature provides ...|The new Federation feature provides ...| +{{< /table >}} + +### Language + +This documentation uses U.S. English spelling and grammar. + +## Documentation formatting standards + +### Use camel case for API objects + +When you refer to an API object, use the same uppercase and lowercase letters +that are used in the actual object name. Typically, the names of API +objects use +[camel case](https://en.wikipedia.org/wiki/Camel_case). + +Don't split the API object name into separate words. For example, use +PodTemplateList, not Pod Template List. + +Refer to API objects without saying "object," unless omitting "object" +leads to an awkward sentence construction. + +{{< table caption="Do and Don't - Do and Don't - API objects" >}} +|Do|Don't| +|--- |--- | +|The Pod has two containers.|The pod has two containers.| +|The Deployment is responsible for ...|The Deployment object is responsible for ...| +|A PodList is a list of Pods.|A Pod List is a list of pods.| +|The two ContainerPorts ...|The two ContainerPort objects ...| +|The two ContainerStateTerminated objects ...|The two ContainerStateTerminateds ...| +{{< /table >}} + +### Use angle brackets for placeholders + +Use angle brackets for placeholders. Tell the reader what a placeholder represents. + +1. Display information about a Pod: + + kubectl describe pod -n + + If the pod is in the default namespace, you can omit the '-n' parameter. + +### Use bold for user interface elements + +{{< table caption="Do and Don't - Bold interface elements" >}} +|Do|Don't| +|--- |--- | +|Click **Fork**.|Click "Fork".| +|Select **Other**.|Select "Other".| +{{< /table >}} + +### Use italics to define or introduce new terms + +{{< table caption="Do and Don't - Use italics for new terms" >}} +|Do|Don't| +|--- |--- | +|A _cluster_ is a set of nodes ...|A "cluster" is a set of nodes ...| +|These components form the _control plane_.|These components form the **control plane**.| +{{< /table >}} + +### Use code style for filenames, directories, paths, object field names and namespaces +{{< table caption="Do and Don't - Use code style for filenames, directories, paths, object field names and namespaces" >}} +|Do|Don't| +|--- |--- | +|Open the `envars.yaml` file.|Open the envars.yaml file.| +|Go to the `/docs/tutorials` directory.|Go to the /docs/tutorials directory.| +|Open the `/_data/concepts.yaml` file.|Open the /\_data/concepts.yaml file.| +{{< /table >}} + + +### Use punctuation inside quotes +{{< table caption="Do and Don't - Use code style for filenames, directories, paths, object field names and namespaces" >}} +|Do|Don't| +|--- |--- | +|events are recorded with an associated "stage."|events are recorded with an associated "stage".| +|The copy is called a "fork."|The copy is called a "fork".| +{{< /table >}} + +Exception: When the quoted word is a user input. + +Example: +* My user ID is “IM47g”. +* Did you try the password “mycatisawesome”? + +## Inline code formatting + + +### Use code style for inline code and commands + +For inline code in an HTML document, use the `` tag. In a Markdown +document, use the backtick (`` ` ``). + +{{< table caption="Do and Don't - Use code style for filenames, directories, paths, object field names and namespaces" >}} +|Do|Don't| +|--- |--- | +|The `kubectl run` command creates a Deployment.|The "kubectl run" command creates a Deployment.| +|For declarative management, use `kubectl apply`.|For declarative management, use "kubectl apply".| +|Use single backticks to enclose inline code. For example, `var example = true`.|Use two asterisks (`**`) or an underscore (`_`) to enclose inline code. For example, **var example = true**.| +|Use triple backticks (\`\`\`) before and after a multi-line block of code for fenced code blocks.|Use multi-line blocks of code to create diagrams, flowcharts, or other illustrations.| +|Use meaningful variable names that have a context.|Use variable names such as 'foo','bar', and 'baz' that are not meaningful and lack context.| +|Remove trailing spaces in the code.|Add trailing spaces in the code, where these are important, because a screen reader will read out the spaces as well.| +{{< /table >}} + +### Starting a sentence with a component tool or component name + +{{< table caption="Do and Don't - Starting a sentence with a component tool or component name" >}} +|Do|Don't| +|--- |--- | +|The `kubeadm` tool bootstraps and provisions machines in a cluster.|`kubeadm` tool bootstraps and provisions machines in a cluster.| +|The kube-scheduler is the default scheduler for Kubernetes.|kube-scheduler is the default scheduler for Kubernetes.| +{{< /table >}} + +### Use normal style for string and integer field values + +For field values of type string or integer, use normal style without quotation marks. + +{{< table caption="Do and Don't - Use normal style for string and integer field values" >}} +|Do|Don't| +|--- |--- | +|Set the value of `imagePullPolicy` to `Always`.|Set the value of `imagePullPolicy` to "Always".| +|Set the value of `image` to `nginx:1.16`.|Set the value of `image` to nginx:1.16.| +|Set the value of the `replicas` field to `2`.|Set the value of the `replicas` field to 2.| +{{< /table >}} + +## Code snippet formatting + + +### Don't include the command prompt + +{{< table caption="Do and Don't - Don't include the command prompt" >}} +|Do|Don't| +|--- |--- | +|kubectl get pods|$ kubectl get pods| +{{< /table >}} + +### Separate commands from output + +Verify that the Pod is running on your chosen node: + +``` +kubectl get pods --output=wide +``` + +The output is similar to this: + +``` +NAME READY STATUS RESTARTS AGE IP NODE +nginx 1/1 Running 0 13s 10.200.0.4 worker0 +``` + +## Velero.io word list + + +A list of Velero-specific terms and words to be used consistently across the site. + +{{< table caption="Velero.io word list" >}} +|Term|Usage| +|--- |--- | +|Kubernetes|Kubernetes should always be capitalized.| +|Docker|Docker should always be capitalized.| +|Velero|Velero should always be capitalized.| +|VMware|VMware should always be correctly capitalized.| +|On-premises|On-premises or on-prem rather than on-premise or other variations.| +|Backup|Backup for noun or adjective, rather than back-up, back up or other variations.| +|Back up|Back up for verb, rather than other variations.| +|Plugin|Plugin rather than plug-in or other variations.| +|Allowlist|Use allowlist instead of whitelist.| +|Denylist|Use denylist instead of blacklist.| +{{< /table >}} + +## Markdown elements + +### Headings +People accessing this documentation may use a screen reader or other assistive technology (AT). [Screen readers](https://en.wikipedia.org/wiki/Screen_reader) are linear output devices, they output items on a page one at a time. If there is a lot of content on a page, you can use headings to give the page an internal structure. A good page structure helps all readers to easily navigate the page or filter topics of interest. + +{{< table caption="Do and Don't - Headings" >}} +|Do|Don't| +|--- |--- | +|Include a title on each page or blog post.|Include more than one title headings (#) in a page.| +|Use ordered headings to provide a meaningful high-level outline of your content.|Use headings level 4 through 6, unless it is absolutely necessary. If your content is that detailed, it may need to be broken into separate articles.| +|Use sentence case for headings. For example, **Extend kubectl with plugins**|Use title case for headings. For example, **Extend Kubectl With Plugins**| +{{< /table >}} + +### Paragraphs + +{{< table caption="Do and Don't - Paragraphs" >}} + +|Do|Don't| +|--- |--- | +|Try to keep paragraphs under 6 sentences.|Write long-winded paragraphs.| +|Use three hyphens (`---`) to create a horizontal rule for breaks in paragraph content.|Use horizontal rules for decoration.| +{{< /table >}} + +### Links + +{{< table caption="Do and Don't - Links" >}} +|Do|Don't| +|--- |--- | +|Write hyperlinks that give you context for the content they link to. For example: Certain ports are open on your machines. See [check required ports](#check-required-ports) for more details.|Use ambiguous terms such as “click here”. For example: Certain ports are open on your machines. See [here](#check-required-ports) for more details.| +|Write Markdown-style links: `[link text](URL)`. For example: `[community meeting agenda](https://hackmd.io/Jq6F5zqZR7S80CeDWUklkA)` and the output is [community meeting agenda](https://hackmd.io/Jq6F5zqZR7S80CeDWUklkA).|Write HTML-style links: `Visit our tutorial!`| +{{< /table >}} + + +### Lists + +Group items in a list that are related to each other and need to appear in a specific order or to indicate a correlation between multiple items. When a screen reader comes across a list—whether it is an ordered or unordered list—it will be announced to the user that there is a group of list items. The user can then use the arrow keys to move up and down between the various items in the list. +Website navigation links can also be marked up as list items; after all they are nothing but a group of related links. + + - End each item in a list with a period if one or more items in the list are complete sentences. For the sake of consistency, normally either all items or none should be complete sentences. + + - Ordered lists that are part of an incomplete introductory sentence can be in lowercase and punctuated as if each item was a part of the introductory sentence. + + - Use the number one (`1.`) for ordered lists. + + - Use (`+`), (`*`), or (`-`) for unordered lists - be consistent within the same document. + + - Leave a blank line after each list. + + - Indent nested lists with four spaces (for example, ⋅⋅⋅⋅). + + - List items may consist of multiple paragraphs. Each subsequent paragraph in a list item must be indented by either four spaces or one tab. + +### Tables + +The semantic purpose of a data table is to present tabular data. Sighted users can quickly scan the table but a screen reader goes through line by line. A table [caption](https://www.w3schools.com/tags/tag_caption.asp) is used to create a descriptive title for a data table. Assistive technologies (AT) use the HTML table caption element to identify the table contents to the user within the page structure. + +If you need to create a table, create the table in markdown and use the table [Hugo shortcode](https://gohugo.io/content-management/shortcodes/) to include a caption. + +``` +{{}} +Parameter | Description | Default +:---------|:------------|:------- +`timeout` | The timeout for requests | `30s` +`logLevel` | The log level for log output | `INFO` +{{< /table */>}} + +``` +**Note:** This shortcode does not support markdown reference-style links. Use inline-style links in tables. See more information about [markdown link styles](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#links). diff --git a/site/content/docs/v1.17/support-process.md b/site/content/docs/v1.17/support-process.md new file mode 100644 index 000000000..096ae6a63 --- /dev/null +++ b/site/content/docs/v1.17/support-process.md @@ -0,0 +1,43 @@ +--- +title: "Support Process" +layout: docs +--- + + +Velero provides best effort support through the process on this page for the current version of Velero and n-1 Velero version, including all patch releases in the supported minor releases. For example, if the current version is 1.9, the Velero maintainers would offer best effort support for v1.9 and v1.8. If you have a question about a previous Velero version (for example, 1.7), please note that maintainers may ask you to upgrade to a supported version before doing any investigation into your issue. + +For more information about Velero testing and supported Kubernetes versions, see Velero's [compatibility matrix](https://github.com/vmware-tanzu/velero/blob/v1.17.0/README.md#velero-compatibility-matrix). + + +## Weekly Rotation + +The Velero maintainers use a weekly rotation to manage community support. Each week, a different maintainer is the point person for responding to incoming support issues via Slack, GitHub, and the Google group. The point person is *not* expected to be on-call 24x7. Instead, they choose one or more hour(s) per day to be available/responding to incoming issues. They will communicate to the community what that time slot will be each week. + +## Start of Week + +We will update the public Slack channel's topic to indicate that you are the point person for the week, and what hours you'll be available. + +## During the Week + +### Where we will monitor +- `#velero-users` and `#velero-dev` public Slack channels in Kubernetes org +- [all Velero-related repos][0] in GitHub (`velero`, `velero-plugin-for-[aws|gcp|microsoft-azure|csi]`, `helm-charts`) + +### GitHub issue flow + +Generally speaking, new GitHub issues will fall into one of several categories. We use the following process for each: + +1. **Feature request** + - Label the issue with `kind/requirement` +1. **Bug** + - Label the issue with `Bug` +1. **User question/problem** that does not clearly fall into one of the previous categories + - Add comments as you go, so both the user and future support people have as much context as possible + - Use the `Needs investigation` label to indicate additional work needed to truly understand the problem or the root cause. + - Use the `Needs Info` label to indicate an issue is waiting for information from the user. Remove/re-add the label as needed. + - For the issues that require reproduction, add label `Needs reproduction` or `status/not-reproducible` to indicate the status. + - If you resolve the issue with the user, close it out + - If the issue ends up being a feature request or a bug, update the title and follow the appropriate process for it + - If the reporter becomes unresponsive after multiple pings, close out the issue due to inactivity and comment that the user can always reach out again as needed + +[0]: https://github.com/vmware-tanzu?q=velero&type=&language= diff --git a/site/content/docs/v1.17/supported-providers.md b/site/content/docs/v1.17/supported-providers.md new file mode 100644 index 000000000..11ea60a15 --- /dev/null +++ b/site/content/docs/v1.17/supported-providers.md @@ -0,0 +1,70 @@ +--- +title: "Providers" +layout: docs +--- + +Velero supports a variety of storage providers for different backup and snapshot operations. Velero has a plugin system which allows anyone to add compatibility for additional backup and volume storage platforms without modifying the Velero codebase. + +## Provider plugins maintained by the Velero maintainers + +{{< table caption="Velero supported providers" >}} + +| Provider | Object Store | Volume Snapshotter | Plugin Provider Repo | Setup Instructions | Parameters | +|-----------------------------------|--------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------|-----------------------------------------|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [Amazon Web Services (AWS)](https://aws.amazon.com) | AWS S3 | AWS EBS | [Velero plugin for AWS](https://github.com/vmware-tanzu/velero-plugin-for-aws) | [AWS Plugin Setup](https://github.com/vmware-tanzu/velero-plugin-for-aws#setup) | [BackupStorageLocation](https://github.com/vmware-tanzu/velero-plugin-for-aws/blob/main/backupstoragelocation.md)
    [VolumeSnapshotLocation](https://github.com/vmware-tanzu/velero-plugin-for-aws/blob/main/volumesnapshotlocation.md) | +| [Google Cloud Platform (GCP)](https://cloud.google.com) | [Google Cloud Storage](https://github.com/vmware-tanzu/velero-plugin-for-gcp/blob/main/backupstoragelocation.md) | [Google Compute Engine Disks](https://github.com/vmware-tanzu/velero-plugin-for-gcp/blob/main/volumesnapshotlocation.md) | [Velero plugin for GCP](https://github.com/vmware-tanzu/velero-plugin-for-gcp) | [GCP Plugin Setup](https://github.com/vmware-tanzu/velero-plugin-for-gcp#setup) | [BackupStorageLocation](https://github.com/vmware-tanzu/velero-plugin-for-gcp/blob/main/backupstoragelocation.md)
    [VolumeSnapshotLocation](https://github.com/vmware-tanzu/velero-plugin-for-gcp/blob/main/volumesnapshotlocation.md) | +| [Microsoft Azure](https://azure.com) | Azure Blob Storage | Azure Managed Disks | [Velero plugin for Microsoft Azure](https://github.com/vmware-tanzu/velero-plugin-for-microsoft-azure) | [Azure Plugin Setup](https://github.com/vmware-tanzu/velero-plugin-for-microsoft-azure#setup) | [BackupStorageLocation](https://github.com/vmware-tanzu/velero-plugin-for-microsoft-azure/blob/main/backupstoragelocation.md)
    [VolumeSnapshotLocation](https://github.com/vmware-tanzu/velero-plugin-for-microsoft-azure/blob/main/volumesnapshotlocation.md) | +| [VMware vSphere](https://www.vmware.com/ca/products/vsphere.html) | 🚫 | vSphere Volumes | [VMware vSphere](https://github.com/vmware-tanzu/velero-plugin-for-vsphere) | [vSphere Plugin Setup](https://github.com/vmware-tanzu/velero-plugin-for-vsphere#velero-plugin-for-vsphere-installation-and-configuration-details) | 🚫 | +{{< /table >}} + +Contact: [#Velero Slack](https://kubernetes.slack.com/messages/velero), [GitHub Issues](https://github.com/vmware-tanzu/velero/issues) + +## Provider plugins maintained by the Velero community +{{< table caption="Community supported providers" >}} + +| Provider | Object Store | Volume Snapshotter | Plugin Documentation | Contact | +|---------------------------|------------------------------|------------------------------------|------------------------|---------------------------------| +| [AlibabaCloud](https://www.alibabacloud.com/) | Alibaba Cloud OSS | Alibaba Cloud | [AlibabaCloud](https://github.com/AliyunContainerService/velero-plugin) | [GitHub Issue](https://github.com/AliyunContainerService/velero-plugin/issues) | +| [DigitalOcean](https://www.digitalocean.com/) | DigitalOcean Object Storage | DigitalOcean Volumes Block Storage | [StackPointCloud](https://github.com/StackPointCloud/ark-plugin-digitalocean) | | +| [Hewlett Packard](https://www.hpe.com/us/en/storage.html) | 🚫 | HPE Storage | [Hewlett Packard](https://github.com/hpe-storage/velero-plugin) | [Slack](https://slack.hpedev.io/), [GitHub Issue](https://github.com/hpe-storage/velero-plugin/issues) | +| [HuaweiCloud](https://www.huaweicloud.com) | HuaweiCloud OBS | 🚫 | [HuaweiCloud](https://github.com/setoru/velero-plugin-for-huaweicloud) | [GitHub Issue](https://github.com/setoru/velero-plugin-for-huaweicloud/issues) | +| [OpenEBS](https://openebs.io/) | 🚫 | OpenEBS CStor Volume | [OpenEBS](https://github.com/openebs/velero-plugin) | [Slack](https://openebs-community.slack.com/), [GitHub Issue](https://github.com/openebs/velero-plugin/issues) | +| [OpenStack](https://www.openstack.org/) | Swift | Cinder | [OpenStack](https://github.com/Lirt/velero-plugin-for-openstack) | [GitHub Issue](https://github.com/Lirt/velero-plugin-for-openstack/issues) | +| [Portworx](https://portworx.com/) | 🚫 | Portworx Volume | [Portworx](https://docs.portworx.com/scheduler/kubernetes/ark.html) | [Slack](https://portworx.slack.com/messages/px-k8s), [GitHub Issue](https://github.com/portworx/ark-plugin/issues) | +| [Storj](https://storj.io) | Storj Object Storage | 🚫 | [Storj](https://github.com/storj-thirdparty/velero-plugin) | [GitHub Issue](https://github.com/storj-thirdparty/velero-plugin/issues) | +{{< /table >}} + +## S3-Compatible object store providers + +Velero's AWS Object Store plugin uses [Amazon's Go SDK][0] to connect to the AWS S3 API. Some third-party storage providers also support the S3 API, and users have reported the following providers work with Velero: + +_Note that these storage providers are not regularly tested by the Velero team._ + + * [IBM Cloud][1] + * [Oracle Cloud][2] + * [Minio][3] + * [DigitalOcean][4] + * [NooBaa][5] + * [Tencent Cloud][7] + * Ceph RADOS v12.2.7 + * Quobyte + * [Cloudian HyperStore][38] + +_Some storage providers, like Quobyte, may need a different [signature algorithm version][6]._ + +## Non-supported volume snapshots + +In the case you want to take volume snapshots but didn't find a plugin for your provider, Velero has support for snapshotting using File System Backup. Please see the [File System Backup][30] documentation. + +[0]: https://github.com/aws/aws-sdk-go-v2 +[1]: contributions/ibm-config.md +[2]: contributions/oracle-config.md +[3]: contributions/minio.md +[4]: https://github.com/StackPointCloud/ark-plugin-digitalocean +[5]: http://www.noobaa.com/ +[6]: https://github.com/vmware-tanzu/velero-plugin-for-aws/blob/main/backupstoragelocation.md +[7]: contributions/tencent-config.md +[25]: https://github.com/hpe-storage/velero-plugin +[30]: file-system-backup.md +[36]: https://github.com/vmware-tanzu/velero-plugin-for-gcp#setup +[38]: https://www.cloudian.com/ diff --git a/site/content/docs/v1.17/tilt.md b/site/content/docs/v1.17/tilt.md new file mode 100644 index 000000000..6d802220c --- /dev/null +++ b/site/content/docs/v1.17/tilt.md @@ -0,0 +1,209 @@ +--- +title: "Rapid iterative Velero development with Tilt " +layout: docs +--- + +## Overview +This document describes how to use [Tilt](https://tilt.dev) with any cluster for a simplified +workflow that offers easy deployments and rapid iterative builds. + +This setup allows for continuing deployment of the Velero server and, if specified, any provider plugin or the node-agent daemonset. +It does this work by: + +1. Deploying the necessary Kubernetes resources, such as the Velero CRDs and Velero deployment +1. Building a local binary for Velero and (if specified) provider plugins as a `local_resource` +1. Invoking `docker_build` to live update any binary into the container/init container and trigger a re-start + +Tilt will look for configuration files under `velero/tilt-resources`. Most of the +files in this directory are gitignored so you may configure your setup according to your needs. + +## Prerequisites +1. [Docker](https://docs.docker.com/install/) v19.03 or newer +1. A Kubernetes cluster v1.16 or greater (does not have to be Kind) +1. [Tilt](https://docs.tilt.dev/install.html) v0.12.0 or newer +1. Clone the [Velero project](https://github.com/vmware-tanzu/velero) repository + locally +1. Access to an S3 object storage +1. Clone any [provider plugin(s)](https://velero.io/plugins/) you want to make changes to and deploy (optional, must be configured to be deployed by the Velero Tilt's setup, [more info below](#provider-plugins)) + +Note: To properly configure any plugin you use, please follow the plugin's documentation. + +## Getting started + +### tl;dr +- Copy all sample files under `velero/tilt-resources/examples` into `velero/tilt-resources`. +- Configure the `velero_v1_backupstoragelocation.yaml` file, and the `cloud` file for the storage credentials/secret. + +- Run `tilt up`. + +### Create a Tilt settings file +Create a configuration file named `tilt-settings.json` and place it in your local copy of `velero/tilt-resources`. Alternatively, +you may copy and paste the sample file found in `velero/tilt-resources/examples`. + +Here is an example: + +```json +{ + "default_registry": "", + "enable_providers": [ + "aws", + "gcp", + "azure", + "csi" + ], + "providers": { + "aws": "../velero-plugin-for-aws", + "gcp": "../velero-plugin-for-gcp", + "azure": "../velero-plugin-for-microsoft-azure", + }, + "allowed_contexts": [ + "development" + ], + "use_node_agent": false, + "create_backup_locations": true, + "setup-minio": true, + "enable_debug": false, + "debug_continue_on_start": true +} +``` + +#### tilt-settings.json fields +**default_registry** (String, default=""): The image registry to use if you need to push images. See the [Tilt +*documentation](https://docs.tilt.dev/api.html#api.default_registry) for more details. + +**provider_repos** (Array[]String, default=[]): A list of paths to all the provider plugins you want to make changes to. Each provider must have a +`tilt-provider.json` file describing how to build the provider. + +**enable_providers** (Array[]String, default=[]): A list of the provider plugins to enable. See [provider plugins](provider-plugins) +for more details. Note: when not making changes to a plugin, it is not necessary to load them into +Tilt: an existing image and version might be specified in the Velero deployment instead, and Tilt will load that. + +**allowed_contexts** (Array, default=[]): A list of kubeconfig contexts Tilt is allowed to use. See the Tilt documentation on +*[allow_k8s_contexts](https://docs.tilt.dev/api.html#api.allow_k8s_contexts) for more details. Note: Kind is automatically allowed. + +**use_node_agent** (Bool, default=false): Indicate whether to deploy the node-agent Daemonset. If set to `true`, Tilt will look for a `velero/tilt-resources/node-agent.yaml` file +containing the configuration of the Velero node-agent DaemonSet. + +**create_backup_locations** (Bool, default=false): Indicate whether to create one or more backup storage locations. If set to `true`, Tilt will look for a `velero/tilt-resources/velero_v1_backupstoragelocation.yaml` file +containing at least one configuration for a Velero backup storage location. + +**setup-minio** (Bool, default=false): Configure this to `true` if you want to configure backup storage locations in a Minio instance running inside your cluster. + +**enable_debug** (Bool, default=false): Configure this to `true` if you want to debug the velero process using [Delve](https://github.com/go-delve/delve). + +**debug_continue_on_start** (Bool, default=true): Configure this to `true` if you want the velero process to continue on start when in debug mode. See [Delve CLI documentation](https://github.com/go-delve/delve/blob/master/Documentation/usage/dlv.md). + +### Create Kubernetes resource files to deploy +All needed Kubernetes resource files are provided as ready to use samples in the `velero/tilt-resources/examples` directory. You only have to move them to the `velero/tilt-resources` level. + +Because the Velero Kubernetes deployment as well as the node-agent DaemonSet contain the configuration +for any plugin to be used, files for these resources are expected to be provided by the user so you may choose +which provider plugin to load as a init container. Currently, the sample files provided are configured with all the +plugins supported by Velero, feel free to remove any of them as needed. + +For Velero to operate fully, it also needs at least one backup +storage location. A sample file is provided that needs to be modified with the specific +configuration for your object storage. See the next sub-section for more details on this. + +### Configure a backup storage location +You will have to configure the `velero/tilt-resources/velero_v1_backupstoragelocation.yaml` with the proper values according to your storage provider. Read the [plugin documentation](https://velero.io/plugins/) +to learn what field/value pairs are required for your particular provider's backup storage location configuration. + +Below are some ways to configure a backup storage location for Velero. +#### As a storage with a service provider +Follow the provider documentation to provision the storage. We have a [list of all known object storage providers](supported-providers/) with corresponding plugins for Velero. + +#### Using MinIO as an object storage +Note: to use MinIO as an object storage, you will need to use the [`AWS` plugin](https://github.com/vmware-tanzu/velero-plugin-for-aws), and configure the storage location with the `spec.provider` set to `aws` and the `spec.config.region` set to `minio`. Example: +``` +spec: + config: + region: minio + s3ForcePathStyle: "true" + s3Url: http://minio.velero.svc:9000 + objectStorage: + bucket: velero + provider: aws +``` + +Here are two ways to use MinIO as the storage: + +1) As a MinIO instance running inside your cluster (don't do this for production!) + + In the `tilt-settings.json` file, set `"setup-minio": true`. This will configure a Kubernetes deployment containing a running +instance of MinIO inside your cluster. There are [extra steps](contributions/minio/#expose-minio-outside-your-cluster-with-a-service) +necessary to expose MinIO outside the cluster. + + To access this storage, you will need to expose MinIO outside the cluster by forwarding the MinIO port to the local machine using kubectl port-forward -n svc/minio 9000. Update the BSL configuration to use that as its "public URL" by adding `publicUrl: http://localhost:9000` to the BSL config. This is necessary to do things like download a backup file. + + Note: with this setup, when your cluster is terminated so is the storage and any backup/restore in it. + +1) As a standalone MinIO instance running locally in a Docker container + + See [these instructions](https://github.com/vmware-tanzu/velero/discussions/3381) to run MinIO locally on your computer, as a standalone as opposed to running it on a Pod. + +Please see our [locations documentation](locations/) to learn more how backup locations work. + +### Configure the provider credentials (secret) +Whatever object storage provider you use, configure the credentials for in the `velero/tilt-resources/cloud` file. Read the [plugin documentation](https://velero.io/plugins/) +to learn what field/value pairs are required for your provider's credentials. The Tilt file will invoke Kustomize to create the secret under the hard-coded key `secret.cloud-credentials.data.cloud` in the Velero namespace. + +There is a sample credentials file properly formatted for a MinIO storage credentials in `velero/tilt-resources/examples/cloud`. + +### Configure debugging with Delve +If you would like to debug the Velero process, you can enable debug mode by setting the field `enable_debug` to `true` in your `tilt-resources/tile-settings.json` file. +This will enable you to debug the process using [Delve](https://github.com/go-delve/delve). +By enabling debug mode, the Velero executable will be built in debug mode (using the flags `-gcflags="-N -l"` which disables optimizations and inlining), and the process will be started in the Velero deployment using [`dlv exec`](https://github.com/go-delve/delve/blob/master/Documentation/usage/dlv_exec.md). + +The debug server will accept connections on port 2345 and Tilt is configured to forward this port to the local machine. +Once Tilt is [running](#run-tilt) and the Velero resource is ready, you can connect to the debug server to begin debugging. +To connect to the session, you can use the Delve CLI locally by running `dlv connect 127.0.0.1:2345`. See the [Delve CLI documentation](https://github.com/go-delve/delve/tree/master/Documentation/cli) for more guidance on how to use Delve. +Delve can also be used within a number of [editors and IDEs](https://github.com/go-delve/delve/blob/master/Documentation/EditorIntegration.md). + +By default, the Velero process will continue on start when in debug mode. +This means that the process will run until a breakpoint is set. +You can disable this by setting the field `debug_continue_on_start` to `false` in your `tilt-resources/tile-settings.json` file. +When this setting is disabled, the Velero process will not continue to run until a `continue` instruction is issued through your Delve session. + +When exiting your debug session, the CLI and editor integrations will typically ask if the remote process should be stopped. +It is important to leave the remote process running and just disconnect from the debugging session. +By stopping the remote process, that will cause the Velero container to stop and the pod to restart. +If backups are in progress, these will be left in a stale state as they are not resumed when the Velero pod restarts. + +### Run Tilt! +To launch your development environment, run: + +``` bash +tilt up +``` + +This will output the address to a web browser interface where you can monitor Tilt's status and the logs for each Tilt resource. After a brief amount of time, you should have a running development environment, and you should now be able to +create backups/restores and fully operate Velero. + +Note: Running `tilt down` after exiting out of Tilt [will delete all resources](https://docs.tilt.dev/cli/tilt_down.html) specified in the Tiltfile. + +Tip: Create an alias to `velero/_tuiltbuild/local/velero` and you won't have to run `make local` to get a refreshed version of the Velero CLI, just use the alias. + +Please see the documentation for [how Velero works](how-velero-works/). + +## Provider plugins +A provider must supply a `tilt-provider.json` file describing how to build it. Here is an example: + +```json +{ + "plugin_name": "velero-plugin-for-aws", + "context": ".", + "image": "velero/velero-plugin-for-aws", + "live_reload_deps": [ + "velero-plugin-for-aws" + ], + "go_main": "./velero-plugin-for-aws" +} +``` + +## Live updates +Each provider plugin configured to be deployed by Velero's Tilt setup has a `live_reload_deps` list. This defines the files and/or directories that Tilt +should monitor for changes. When a dependency is modified, Tilt rebuilds the provider's binary **on your local +machine**, copies the binary to the init container, and triggers a restart of the Velero container. This is significantly faster +than rebuilding the container image for each change. It also helps keep the size of each development image as small as +possible (the container images do not need the entire go toolchain, source code, module dependencies, etc.). diff --git a/site/content/docs/v1.17/troubleshooting.md b/site/content/docs/v1.17/troubleshooting.md new file mode 100644 index 000000000..e61eb0d7e --- /dev/null +++ b/site/content/docs/v1.17/troubleshooting.md @@ -0,0 +1,252 @@ +--- +title: "Troubleshooting" +layout: docs +--- + +These tips can help you troubleshoot known issues. If they don't help, you can [file an issue][4], or talk to us on the [#velero channel][25] on the Kubernetes Slack server. + +## Debug installation/ setup issues + +- [Debug installation/setup issues][2] + +## Debug restores + +- [Debug restores][1] + +## General troubleshooting information + +You can use the `velero bug` command to open a [Github issue][4] by launching a browser window with some prepopulated values. Values included are OS, CPU architecture, `kubectl` client and server versions (if available) and the `velero` client version. This information isn't submitted to Github until you click the `Submit new issue` button in the Github UI, so feel free to add, remove or update whatever information you like. + +You can use the `velero debug` command to generate a debug bundle, which is a tarball +that contains: +* Version information +* Logs of velero server and plugins +* Resources managed by velero server such as backup, restore, podvolumebackup, podvolumerestore, etc. +* Logs of the backup and restore, if specified in the parameters + +Please use command `velero debug --help` to see more usage details. + +### Getting velero debug logs + +You can increase the verbosity of the Velero server by editing your Velero deployment to look like this: + + +``` +kubectl edit deployment/velero -n velero +... + containers: + - name: velero + image: velero/velero:latest + command: + - /velero + args: + - server + - --log-level # Add this line + - debug # Add this line +... +``` + +**Note:** Velero plugins are started as separate processes and once the Velero operation is done (either successfully or not), they exit. So, if you see **received EOF, stopping recv loop** messages in debug logs, that does not mean an error occurred, just that a plugin finished executing. + +## Known issue with restoring LoadBalancer Service + +Because of how Kubernetes handles Service objects of `type=LoadBalancer`, when you restore these objects you might encounter an issue with changed values for Service UIDs. Kubernetes automatically generates the name of the cloud resource based on the Service UID, which is different when restored, resulting in a different name for the cloud load balancer. If the DNS CNAME for your application points to the DNS name of your cloud load balancer, you'll need to update the CNAME pointer when you perform a Velero restore. + +Alternatively, you might be able to use the Service's `spec.loadBalancerIP` field to keep connections valid, if your cloud provider supports this value. See [the Kubernetes documentation about Services of Type LoadBalancer](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer). + +## Known issue with restoring resources when Admission webhooks are enabled + +The [Admission webhooks](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/) may forbid a resource to be created based on the input, it may optionally mutate the input as well. +Because velero calls the API server to restore resources, it is possible that the admission webhooks are invoked and cause unexpected failures, depending on the implementation and the configuration of the webhooks. +To work around such issue, you may disable the webhooks or create a restore item action plugin to modify the resources before they are restored. + +## Miscellaneous issues + +### Velero reports `custom resource not found` errors when starting up. + +Velero's server will not start if the required Custom Resource Definitions are not found in Kubernetes. Run `velero install` again to install any missing custom resource definitions. + +### `velero backup logs` returns a `SignatureDoesNotMatch` error + +Downloading artifacts from object storage utilizes temporary, signed URLs. In the case of S3-compatible +providers, such as Ceph, there may be differences between their implementation and the official S3 +API that cause errors. + +Here are some things to verify if you receive `SignatureDoesNotMatch` errors: + + * Make sure your S3-compatible layer is using [signature version 4][5] (such as Ceph RADOS v12.2.7) + * For Ceph, try using a native Ceph account for credentials instead of external providers such as OpenStack Keystone + +## Velero (or a pod it was backing up) restarted during a backup and the backup is stuck InProgress + +Velero cannot resume backups that were interrupted. Backups stuck in the `InProgress` phase can be deleted with `kubectl delete backup -n `. +Backups in the `InProgress` phase have not uploaded any files to object storage. + +## Velero is not publishing prometheus metrics + +Steps to troubleshoot: + +- Confirm that your velero deployment has metrics publishing enabled. The [latest Velero helm charts][6] have been setup with [metrics enabled by default][7]. +- Confirm that the Velero server pod exposes the port on which the metrics server listens on. By default, this value is 8085. + +```yaml + ports: + - containerPort: 8085 + name: metrics + protocol: TCP +``` + +- Confirm that the metric server is listening for and responding to connections on this port. This can be done using [port-forwarding][9] as shown below + +```bash +$ kubectl -n port-forward 8085:8085 +Forwarding from 127.0.0.1:8085 -> 8085 +Forwarding from [::1]:8085 -> 8085 +. +. +. +``` + +Now, visiting http://localhost:8085/metrics on a browser should show the metrics that are being scraped from Velero. + +- Confirm that the Velero server pod has the necessary [annotations][8] for prometheus to scrape metrics. +- Confirm, from the Prometheus UI, that the Velero pod is one of the targets being scraped from Prometheus. + + +## Is Velero using the correct cloud credentials? + +Cloud provider credentials are given to Velero to store and retrieve backups from the object store and to perform volume snapshotting operations. + +These credentials are either passed to Velero at install time using: +1. `--secret-file` flag to the `velero install` command. OR +1. `--set-file credentials.secretContents.cloud` flag to the `helm install` command. + +Or, they are specified when creating a `BackupStorageLocation` using the `--credential` flag. + +### Troubleshooting credentials provided during install + +If using the credentials provided at install time, they are stored in the cluster as a Kubernetes secret named `cloud-credentials` in the same namespace in which Velero is installed. + +Follow the below troubleshooting steps to confirm that Velero is using the correct credentials: +1. Confirm that the `cloud-credentials` secret exists and has the correct content. + ```bash + $ kubectl -n velero get secrets cloud-credentials + NAME TYPE DATA AGE + cloud-credentials Opaque 1 11h + $ kubectl -n velero get secrets cloud-credentials -ojsonpath={.data.cloud} | base64 --decode + + ``` + +1. Confirm that velero deployment is mounting the `cloud-credentials` secret. + ```bash + $ kubectl -n velero get deploy velero -ojson | jq .spec.template.spec.containers[0].volumeMounts + [ + { + "mountPath": "/plugins", + "name": "plugins" + }, + { + "mountPath": "/scratch", + "name": "scratch" + }, + { + "mountPath": "/credentials", + "name": "cloud-credentials" + } + ] + ``` + + If [File System Backup][3] is enabled, then, confirm that the node-agent daemonset is also mounting the `cloud-credentials` secret. + ```bash + $ kubectl -n velero get ds node-agent -ojson |jq .spec.template.spec.containers[0].volumeMounts + [ + { + "mountPath": "/host_pods", + "mountPropagation": "HostToContainer", + "name": "host-pods" + }, + { + "mountPath": "/scratch", + "name": "scratch" + }, + { + "mountPath": "/credentials", + "name": "cloud-credentials" + } + ] + ``` + +1. Confirm if the correct credentials are mounted into the Velero pod. + ```bash + $ kubectl -n velero exec -ti deploy/velero -- bash + nobody@velero-69f9c874c-l8mqp:/$ cat /credentials/cloud + + ``` + +### Troubleshooting `BackupStorageLocation` and `VolumeSnapshotLocation` credentials + +Follow the below troubleshooting steps to confirm that Velero is using the correct credentials if using credentials specific to a [`BackupStorageLocation` or `VolumeSnapshotLocation`][10]: +1. Confirm that the object storage provider plugin being used supports multiple credentials. + + If the logs from the Velero deployment contain the error message `"config has invalid keys credentialsFile"`, the version of your object storage plugin does not yet support multiple credentials. + + The object storage plugins [maintained by the Velero team][11] support this feature, so please update your plugin to the latest version if you see the above error message. + + If you are using a plugin from a different provider, please contact them for further advice. + +1. Confirm that the secret and key referenced by the `BackupStorageLocation` or `VolumeSnapshotLocation` exists in the Velero namespace and has the correct content: + ```bash + # Determine which secret and key the BackupStorageLocation is using + BSL_SECRET=$(kubectl get backupstoragelocations.velero.io -n velero -o yaml -o jsonpath={.spec.credential.name}) + BSL_SECRET_KEY=$(kubectl get backupstoragelocations.velero.io -n velero -o yaml -o jsonpath={.spec.credential.key}) + + # Confirm that the secret exists + kubectl -n velero get secret $BSL_SECRET + + # Print the content of the secret and ensure it is correct + kubectl -n velero get secret $BSL_SECRET -ojsonpath={.data.$BSL_SECRET_KEY} | base64 --decode + + # Determine which secret and key the VolumeSnapshotLocation is using + VSL_SECRET=$(kubectl get volumesnapshotlocations.velero.io -n velero -o yaml -o jsonpath={.spec.credential.name}) + VSL_SECRET_KEY=$(kubectl get volumesnapshotlocations.velero.io -n velero -o yaml -o jsonpath={.spec.credential.key}) + + # Confirm that the secret exists + kubectl -n velero get secret $VSL_SECRET + + # Print the content of the secret and ensure it is correct + kubectl -n velero get secret $VSL_SECRET -ojsonpath={.data.$VSL_SECRET_KEY} | base64 --decode + ``` + If the secret can't be found, the secret does not exist within the Velero namespace and must be created. + + If no output is produced when printing the contents of the secret, the key within the secret may not exist or may have no content. + Ensure that the key exists within the secret's data by checking the output from `kubectl -n velero describe secret $BSL_SECRET` or `kubectl -n velero describe secret $VSL_SECRET`. + If it does not exist, follow the instructions for [editing a Kubernetes secret][12] to add the base64 encoded credentials data. + +## Kopia repository files' ownership mismatch + +Velero sets the files' ownership created in the Kopia repository to `default@default`. + +If users need to use Kopia CLI to connect to the Velero created Kopia repositories, please use the following CLI as an example to avoid overwriting the ownership by accident. +``` bash +kopia repository connect <--read-only> --bucket= --override-username=default --override-hostname=default +``` + +If the ownership conflict error(`maintenance must be run by designated user`) already happens, +Velero doesn't handle the conflict by design. +To resolve it, please use Kopia maintenance CLI to set the ownership correctly, e.g. `kopia maintenance set --owner=default@default`. + +Please refer to [Issue 9007](https://github.com/vmware-tanzu/velero/issues/9007) for more information. + +[1]: debugging-restores.md +[2]: debugging-install.md +[3]: file-system-backup.md +[4]: https://github.com/vmware-tanzu/velero/issues +[5]: https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html +[6]: https://github.com/vmware-tanzu/helm-charts/blob/main/charts/velero +[7]: https://github.com/vmware-tanzu/helm-charts/blob/main/charts/velero/values.yaml#L44 +[8]: https://github.com/vmware-tanzu/helm-charts/blob/main/charts/velero/values.yaml#L49-L52 +[9]: https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#port-forward +[10]: locations.md +[11]: /plugins +[12]: https://kubernetes.io/docs/concepts/configuration/secret/#editing-a-secret +[25]: https://kubernetes.slack.com/messages/velero diff --git a/site/content/docs/v1.17/uninstalling.md b/site/content/docs/v1.17/uninstalling.md new file mode 100644 index 000000000..a20d95e7a --- /dev/null +++ b/site/content/docs/v1.17/uninstalling.md @@ -0,0 +1,10 @@ +--- +title: "Uninstalling Velero" +layout: docs +--- + +If you would like to completely uninstall Velero from your cluster, the following commands will remove all resources created by `velero install`: + +```bash +velero uninstall +``` diff --git a/site/content/docs/v1.17/upgrade-to-1.17.md b/site/content/docs/v1.17/upgrade-to-1.17.md new file mode 100644 index 000000000..f6738d55c --- /dev/null +++ b/site/content/docs/v1.17/upgrade-to-1.17.md @@ -0,0 +1,96 @@ +--- +title: "Upgrading to Velero 1.17" +layout: docs +--- + +## Prerequisites + +- Velero [v1.16.x][9] installed. + +If you're not yet running at least Velero v1.16, see the following: + +- [Upgrading to v1.8][1] +- [Upgrading to v1.9][2] +- [Upgrading to v1.10][3] +- [Upgrading to v1.11][4] +- [Upgrading to v1.12][5] +- [Upgrading to v1.13][6] +- [Upgrading to v1.14][7] +- [Upgrading to v1.15][8] +- [Upgrading to v1.16][9] + +Before upgrading, check the [Velero compatibility matrix](https://github.com/vmware-tanzu/velero#velero-compatibility-matrix) to make sure your version of Kubernetes is supported by the new version of Velero. + +## Instructions + +### Upgrade from v1.16 +1. Install the Velero v1.17 command-line interface (CLI) by following the [instructions here][0]. + + Verify that you've properly installed it by running: + + ```bash + velero version --client-only + ``` + + You should see the following output: + + ```bash + Client: + Version: v1.17.0 + Git commit: + ``` + +2. Update the Velero custom resource definitions (CRDs) to include schema changes across all CRDs that are at the core of the new features in this release: + + ```bash + velero install --crds-only --dry-run -o yaml | kubectl apply -f - + ``` + +3. (optional) Update the `uploader-type` to `kopia` if you are using `restic`: + ```bash + kubectl get deploy -n velero -ojson \ + | sed "s/\"--uploader-type=restic\"/\"--uploader-type=kopia\"/g" \ + | kubectl apply -f - + ``` + +4. Update the container image used by the Velero deployment, plugin and (optionally) the node agent daemon set: + ```bash + # set the container and image of the init container for plugin accordingly, + # if you are using other plugin + kubectl set image deployment/velero \ + velero=velero/velero:v1.17.0 \ + velero-plugin-for-aws=velero/velero-plugin-for-aws:v1.13.0 \ + --namespace velero + + # optional, if using the node agent daemonset + kubectl set image daemonset/node-agent \ + node-agent=velero/velero:v1.17.0 \ + --namespace velero + ``` +5. Confirm that the deployment is up and running with the correct version by running: + + ```bash + velero version + ``` + + You should see the following output: + + ```bash + Client: + Version: v1.17.0 + Git commit: + + Server: + Version: v1.17.0 + ``` + +[0]: basic-install.md#install-the-cli +[1]: https://velero.io/docs/v1.8/upgrade-to-1.8 +[2]: https://velero.io/docs/v1.9/upgrade-to-1.9 +[3]: https://velero.io/docs/v1.10/upgrade-to-1.10 +[4]: https://velero.io/docs/v1.11/upgrade-to-1.11 +[5]: https://velero.io/docs/v1.12/upgrade-to-1.12 +[6]: https://velero.io/docs/v1.13/upgrade-to-1.13 +[7]: https://velero.io/docs/v1.14/upgrade-to-1.14 +[8]: https://velero.io/docs/v1.15/upgrade-to-1.15 +[9]: https://velero.io/docs/v1.16/upgrade-to-1.16 \ No newline at end of file diff --git a/site/content/docs/v1.17/velero-install.md b/site/content/docs/v1.17/velero-install.md new file mode 100644 index 000000000..a4925278c --- /dev/null +++ b/site/content/docs/v1.17/velero-install.md @@ -0,0 +1,58 @@ +--- +title: "Velero Install CLI" +layout: docs +--- + +This document serves as a guide to using the `velero install` CLI command to install `velero` server components into your Kubernetes cluster. + +_NOTE_: `velero install` will, by default, use the CLI's version information to determine the version of the server components to deploy. This behavior may be overridden by using the `--image` flag. Refer to [Building Server Component Container Images][1]. + +## Usage + +This section explains some of the basic flags supported by the `velero install` CLI command. For a complete explanation of the flags, please run `velero install --help` + +```bash +velero install \ + --plugins + --provider \ + --bucket \ + --secret-file \ + --velero-pod-cpu-request \ + --velero-pod-mem-request \ + --velero-pod-cpu-limit \ + --velero-pod-mem-limit \ + --kubelet-root-dir \ + [--use-node-agent] \ + [--default-volumes-to-fs-backup] \ + [--node-agent-pod-cpu-request ] \ + [--node-agent-pod-mem-request ] \ + [--node-agent-pod-cpu-limit ] \ + [--node-agent-pod-mem-limit ] \ + [--maintenance-job-cpu-request ] \ + [--maintenance-job-mem-request ] \ + [--maintenance-job-cpu-limit ] \ + [--maintenance-job-mem-limit ] \ + [--server-priority-class-name ] \ + [--node-agent-priority-class-name ] +``` + +The values for the resource requests and limits flags follow the same format as [Kubernetes resource requirements][3] +For plugin container images, please refer to our [supported providers][2] page. + +The `--server-priority-class-name` and `--node-agent-priority-class-name` flags allow you to set priority classes for the Velero server deployment and node agent daemonset respectively. This can help ensure proper scheduling and eviction behavior in resource-constrained environments. Note that you must create the priority class before installing Velero. + +## Examples + +This section provides examples that serve as a starting point for more customized installations. + +```bash +velero install --provider gcp --plugins velero/velero-plugin-for-gcp:v1.0.0 --bucket mybucket --secret-file ./gcp-service-account.json + +velero install --provider aws --plugins velero/velero-plugin-for-aws:v1.0.0 --bucket backups --secret-file ./aws-iam-creds --backup-location-config region=us-east-2 --snapshot-location-config region=us-east-2 --use-node-agent + +velero install --provider azure --plugins velero/velero-plugin-for-microsoft-azure:v1.0.0 --bucket $BLOB_CONTAINER --secret-file ./credentials-velero --backup-location-config resourceGroup=$AZURE_BACKUP_RESOURCE_GROUP,storageAccount=$AZURE_STORAGE_ACCOUNT_ID[,subscriptionId=$AZURE_BACKUP_SUBSCRIPTION_ID] --snapshot-location-config apiTimeout=[,resourceGroup=$AZURE_BACKUP_RESOURCE_GROUP,subscriptionId=$AZURE_BACKUP_SUBSCRIPTION_ID] +``` + +[1]: build-from-source.md#making-images-and-updating-velero +[2]: supported-providers.md +[3]: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ diff --git a/site/content/docs/v1.17/volume-group-snapshots.md b/site/content/docs/v1.17/volume-group-snapshots.md new file mode 100644 index 000000000..cb2e545d2 --- /dev/null +++ b/site/content/docs/v1.17/volume-group-snapshots.md @@ -0,0 +1,379 @@ +--- +title: "Volume Group Snapshots" +description: "A guide to using Volume Group Snapshots with Velero for consistent backups of multi-volume applications." +layout: docs +--- + +Velero provides robust support for **Volume Group Snapshots (VGS)**, a powerful Kubernetes feature for creating atomic, crash-consistent snapshots of multiple volumes simultaneously. This capability is essential for stateful applications that distribute data across several PersistentVolumeClaims (PVCs) and require that all data be captured at the exact same moment to ensure data integrity. + +> **Who is this for?** This guide is for application owners and backup administrators who need to ensure data consistency for multi-volume stateful applications, such as distributed databases (e.g., Cassandra, Zookeeper) or complex stateful services. + +## When to Use Volume Group Snapshots + +You should consider using Volume Group Snapshots when: + +- Your application uses multiple PVCs that are logically related. +- You need to ensure write-order consistency across all volumes. +- Your storage provider's CSI driver supports the Volume Group Snapshot feature. + +## Key Concepts + +Before diving in, let's clarify the Kubernetes resources involved in this process: + +- **VolumeGroupSnapshot (VGS):** A request to your storage provider to create a snapshot of a group of volumes. +- **VolumeGroupSnapshotContent (VGSC):** Represents the actual snapshot of the volume group, provisioned by the CSI driver. +- **VolumeGroupSnapshotClass (VGSClass):** A cluster-level resource that defines the configuration for a VGS, including the CSI driver and other parameters. +- **VolumeSnapshot (VS) & VolumeSnapshotContent (VSC):** The individual volume snapshots that are created as part of the VGS process. + +## Velero's VGS Backup and Restore Workflow + +Velero's integration with VGS is designed to be as seamless as possible, automating the complexities of group snapshots. Velero supports three distinct workflows depending on your configuration: + +### Three VGS Workflow Branches + +Velero automatically selects the appropriate workflow based on your backup configuration: + +#### 1. VGS + Data Mover +**When**: PVCs have VGS labels AND `--snapshot-move-data=true` flag is used + +**Use case**: Need atomic consistency + long-term storage/cross-cloud portability + +- Creates `VolumeGroupSnapshot` for write-order consistency across all labeled PVCs +- Extracts individual `VolumeSnapshot` objects from the VGS +- Creates `DataUpload` CRs that move each volume's data to object storage +- Cleans up temporary VGS and VGS Content resources +- **Result**: Volume data stored in object storage, no local snapshots retained + +#### 2. VGS without Data Mover +**When**: PVCs have VGS labels BUT `--snapshot-move-data=false` (or flag omitted) + +**Use case**: Need atomic consistency with local snapshot storage + +- Creates `VolumeGroupSnapshot` for write-order consistency across all labeled PVCs +- Extracts individual `VolumeSnapshot` objects from the VGS +- Backup depends only on `VolumeSnapshots`, no `DataUpload` or data mover involved +- Cleans up temporary VGS and VGS Content resources +- **Result**: Individual `VolumeSnapshots` stored on your storage system + +#### 3. Individual Volume Snapshots +**When**: PVCs have NO VGS labels (standard CSI snapshot behavior) + +**Use case**: Independent volume backups, no consistency requirements + +- Creates individual `VolumeSnapshot` per PVC independently +- No atomic consistency guarantees across volumes +- Optionally uses data movement if `--snapshot-move-data=true` flag is set +- **Result**: Independent volume snapshots (local or in object storage) + +### Choosing the Right Workflow + +Select your workflow based on your application's requirements: + +| Scenario | VGS Labels | Data Movement Flag | Workflow | Best For | +|----------|------------|-------------------|----------|----------| +| Multi-volume app + cross-cloud backup | ✅ | `--snapshot-move-data=true` | **VGS + Data Movement** | Distributed databases with portability needs | +| Multi-volume app + local snapshots | ✅ | `--snapshot-move-data=false` (or omitted) | **VGS Only** | Applications requiring consistency with fast local snapshots | +| Single volumes or independent backups | ❌ | `--snapshot-move-data=true` (optional) | **Individual Snapshots** | Simple applications, testing, or independent services | + +**Example Commands:** +```bash +# VGS + Data Movement (cross-cloud, long-term storage) +velero backup create db-backup --include-namespaces my-database --snapshot-move-data=true + +# VGS Only (atomic consistency, local storage) +velero backup create db-backup --include-namespaces my-database --snapshot-move-data=false + +# Individual Snapshots (standard CSI behavior) +velero backup create app-backup --include-namespaces my-app +``` + +### The Backup Process + +The VGS backup workflow is triggered by a simple label on your PVCs. + +1. **Grouping PVCs:** When a backup is initiated, Velero's `PVCAction` plugin scans for PVCs with the VGS label (the default is `velero.io/volume-group`). All PVCs within the same namespace that share the same label value are collected into a single `ItemBlock`. This ensures they are processed as a single, atomic unit. + +2. **Orchestrating the Snapshot:** The CSI plugin takes over to manage the snapshot creation: + * **Driver Verification:** It first confirms that all PVCs in the group are managed by the same CSI driver. + * **Class Selection:** It then determines the correct `VolumeGroupSnapshotClass` to use based on your configuration. + * **VGS Creation:** A `VolumeGroupSnapshot` resource is created, signaling the CSI driver to begin the snapshot process for the entire group. + +3. **Snapshot Finalization:** Velero monitors the process, and once the `VolumeGroupSnapshot` is ready, it performs these final steps: + * Waits for the CSI driver to create the individual `VolumeSnapshot` objects. + * Applies the backup's labels to each `VolumeSnapshot` for tracking. + +4. **Resource Cleanup:** To keep your cluster tidy, Velero deletes the temporary `VolumeGroupSnapshot` and `VolumeGroupSnapshotContent` resources after the individual `VolumeSnapshots` have been created and secured. + +Here is a visual representation of the backup workflow: + +![VGS Backup Workflow](/img/vgs-flow.svg) + +### The Restore Process + +Restoring from a VGS backup is simple and flexible. During backup, Velero creates individual `VolumeSnapshots` from the `VolumeGroupSnapshot`, so the restore process works with standard volume snapshot restoration. + +> **Good to know:** No special VGS-related logic is needed during the restore. This means you can restore your data to a cluster that doesn't have VGS support enabled, providing excellent portability. + +## Prerequisites + +Before using Volume Group Snapshots with Velero, ensure your environment meets these requirements: + +### 1. Kubernetes Version +- Kubernetes 1.20+ (when VolumeGroupSnapshot API was introduced) +- Check your version: `kubectl version --short` + +### 2. VolumeGroupSnapshot CRDs +Check the Volume Group Snapshot CRDs on your cluster: + +```bash +# Check if VGS CRDs are installed +kubectl get crd | grep volumegroup +``` + +### 3. CSI Driver Support +Verify your CSI driver supports Volume Group Snapshots: + +```bash +# Check if your CSI driver has VolumeGroupSnapshotClass resources +kubectl get volumegroupsnapshotclass + +# Verify CSI driver capabilities (example for AWS EBS) +kubectl describe csidriver ebs.csi.aws.com +``` + +### 4. VolumeGroupSnapshotClass Configuration +Ensure a VolumeGroupSnapshotClass exists for your storage and is properly labeled for Velero discovery: + +```bash +# List available VolumeGroupSnapshotClasses +kubectl get volumegroupsnapshotclass -o wide +``` + +**Important:** The VolumeGroupSnapshotClass must have the label `velero.io/csi-volumegroupsnapshot-class: "true"` for Velero to automatically discover and use it: + +```yaml +apiVersion: groupsnapshot.storage.k8s.io/v1alpha1 +kind: VolumeGroupSnapshotClass +metadata: + name: csi-vgs-class + labels: + velero.io/csi-volumegroupsnapshot-class: "true" +spec: + driver: ebs.csi.aws.com + deletionPolicy: Delete +``` + +Verify your VolumeGroupSnapshotClass has the correct label: +```bash +# Check if VolumeGroupSnapshotClass has the required label +kubectl get volumegroupsnapshotclass --show-labels +``` + +## Step-by-Step: Using VGS with Velero + +Here's how to get started with VGS backups: + +1. **Verify Prerequisites:** Ensure all prerequisites above are met. + +2. **Label Your PVCs:** The key to grouping volumes is to apply a consistent label to all PVCs that should be snapshotted together. **Important:** All PVCs in a group must use the same CSI driver and exist in the same namespace. + +### Complete Workflow Example + +Here's a complete end-to-end example of using VGS with a database application that has multiple volumes: + +#### 1. Set Up the Application + +Deploy a database application with multiple PVCs: + +**PVC for Primary Data:** +```yaml +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: db-data-pvc + namespace: my-database + labels: + velero.io/volume-group: db-cluster-1 +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi + storageClassName: my-csi-storage-class +``` + +**PVC for Transaction Logs:** +```yaml +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: db-logs-pvc + namespace: my-database + labels: + velero.io/volume-group: db-cluster-1 +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi + storageClassName: my-csi-storage-class +``` + +When you next back up the `my-database` namespace, Velero will see the `velero.io/volume-group: db-cluster-1` label on both PVCs and will trigger a `VolumeGroupSnapshot` for the `db-cluster-1` group. + +#### 2. Create the Backup + +```bash +# Create backup that will use VGS for labeled PVCs +velero backup create my-app-backup --include-namespaces my-database + +# Monitor backup progress +velero backup describe my-app-backup +velero backup logs my-app-backup +``` + +#### 3. Verify VGS Processing + +```bash +# Verify VolumeSnapshots were created from the VGS +kubectl get volumesnapshot -n my-database -o wide + +# Check that snapshots have the correct labels +kubectl get volumesnapshot -n my-database --show-labels + +# Confirm backup completed successfully +velero backup describe my-app-backup | grep Phase +``` + +#### 4. Test Restore + +```bash +# Create a test namespace for restore +kubectl create namespace my-database-restore + +# Restore to the new namespace +velero restore create test-restore \ + --from-backup my-app-backup \ + --namespace-mappings my-database:my-database-restore + +# Monitor restore progress +velero restore describe test-restore +velero restore logs test-restore + +# Verify PVCs were restored correctly +kubectl get pvc -n my-database-restore --show-labels +``` + +#### 5. Cleanup Test Resources + +```bash +# Remove test namespace after verification +kubectl delete namespace my-database-restore + +# List backups and restores +velero backup get +velero restore get +``` + +## Advanced Configuration + +You can customize the label key that Velero uses to identify VGS groups. This is useful if you have pre-existing labels or want to use a different convention. The configuration is applied with the following order of precedence: + +1. **Backup Resource Spec (Highest Priority):** For the most granular control, you can specify the label key directly in your `Backup` resource definition. + ```yaml + apiVersion: velero.io/v1 + kind: Backup + metadata: + name: my-app-backup + namespace: velero + spec: + volumeGroupSnapshotLabelKey: "my-organization.io/snapshot-group" + includedNamespaces: [ "my-database" ] + # ... other backup spec details + ``` + +2. **Velero Server Argument:** You can set a cluster-wide default by providing the `--volume-group-snapshot-label-key` command-line argument when you install or start the Velero server. + +3. **Default Value (Lowest Priority):** If you don't provide any custom configuration, Velero defaults to using `velero.io/volume-group`. + +## Troubleshooting + +### Common Issues and Solutions + +#### VGS Not Created During Backup + +**Symptoms:** Backup completes but individual VolumeSnapshots are created instead of VGS +```bash +# Check if PVCs have the correct label +kubectl get pvc -n my-database --show-labels + +# Verify all PVCs use the same CSI driver +kubectl get pv $(kubectl get pvc -n my-database -o jsonpath='{.items[*].spec.volumeName}') -o jsonpath='{range .items[*]}{.metadata.name}: {.spec.csi.driver}{"\n"}{end}' +``` + +**Solutions:** +- Ensure all PVCs have the same volume group label value +- Verify all PVCs use the same CSI driver +- Check that VolumeGroupSnapshotClass exists for your CSI driver + +#### VGS Creation Fails + +**Symptoms:** Backup fails with VGS-related errors +```bash +# Check Velero logs for VGS errors +velero backup logs my-app-backup | grep -i "VolumeGroup" + +# Check CSI driver logs +kubectl logs -n kube-system -l app=ebs-csi-controller --tail=100 +``` + +**Solutions:** +- Verify CSI driver supports VolumeGroupSnapshots +- Check VolumeGroupSnapshotClass configuration +- Ensure storage backend supports group snapshots + +#### VolumeGroupSnapshot Setup: Default VolumeSnapshotClass Required + +**Issue** + +When creating VolumeGroupSnapshot backups, you may encounter this error: + +``` +VolumeSnapshot has a temporary error Failed to set default snapshot class with error cannot find default snapshot class. Snapshot controller will retry later. +``` + +**Cause** + +The Kubernetes snapshot controller requires a default VolumeSnapshotClass to be configured in the cluster, but none is currently set. + +**Solution** + +Set a default VolumeSnapshotClass that uses the same CSI driver as your VolumeGroupSnapshotClass: + +```bash +# List available VolumeSnapshotClasses +kubectl get volumesnapshotclasses + +# Set the appropriate class as default for your CSI driver +kubectl patch volumesnapshotclass \ + -p '{"metadata":{"annotations":{"snapshot.storage.kubernetes.io/is-default-class":"true"}}}' + +# Example for Ceph RBD: +kubectl patch volumesnapshotclass ocs-storagecluster-rbdplugin-snapclass \ + -p '{"metadata":{"annotations":{"snapshot.storage.kubernetes.io/is-default-class":"true"}}}' +``` + +**Important:** Ensure the default VolumeSnapshotClass uses the same CSI driver as your VolumeGroupSnapshotClass. For example, if your VolumeGroupSnapshotClass uses `ebs.csi.aws.com`, the default VolumeSnapshotClass should also use `ebs.csi.aws.com`. + +**Note:** Only one VolumeSnapshotClass should be marked as default per CSI driver to avoid conflicts. The default VolumeSnapshotClass driver must match the CSI driver used by your VolumeGroupSnapshotClass. + +### Best Practices + +1. **Test VGS Support:** Always test VGS functionality in a non-production environment first +2. **Monitor Resource Usage:** VGS operations may consume more resources than individual snapshots +3. **Label Consistency:** Use consistent labeling across your organization +4. **Backup Validation:** Always verify backup success before relying on it for disaster recovery +5. **Storage Quotas:** Ensure sufficient storage quota for group snapshots + diff --git a/site/content/docs/v1.17/website-guidelines.md b/site/content/docs/v1.17/website-guidelines.md new file mode 100644 index 000000000..c5373f4d8 --- /dev/null +++ b/site/content/docs/v1.17/website-guidelines.md @@ -0,0 +1,45 @@ +--- +title: "Website Guidelines" +layout: docs +--- + +## Running the website locally + +When making changes to the website, please run the site locally before submitting a PR and manually verify your changes. + +At the root of the project, run: + +```bash +make serve-docs +``` + +This runs all the Hugo dependencies in a container. + +Alternatively, for quickly loading the website, under the `velero/site/` directory run: + +```bash +hugo serve +``` + +For more information on how to run the website locally, please see our [Hugo documentation](https://gohugo.io/getting-started/). + +## Adding a blog post + +To add a blog post, create a new markdown (.MD) file in the `/site/content/posts/` folder. A blog post requires the following front matter. + +```yaml +title: "Title of the blog" +excerpt: Brief summary of thee blog post that appears as a preview on velero.io/blogs +author_name: Jane Smith +slug: URL-For-Blog +# Use different categories that apply to your blog. This is used to connect related blogs on the site +categories: ['velero','release'] +# Image to use for blog. The path is relative to the site/static/ folder +image: /img/posts/example-image.jpg +# Tag should match author to drive author pages. Tags can have multiple values. +tags: ['Velero Team', 'Nolan Brubaker'] +``` + +Include the `author_name` value in tags field so the page that lists the author's posts will work properly, for example https://velero.io/tags/carlisia-thompson/. + +Ideally each blog will have a unique image to use on the blog home page, but if you do not include an image, the default Velero logo will be used instead. Use an image that is less than 70KB and add it to the `/site/static/img/posts` folder. diff --git a/site/data/docs/toc-mapping.yml b/site/data/docs/toc-mapping.yml index 0e6bb5ae3..f08001a91 100644 --- a/site/data/docs/toc-mapping.yml +++ b/site/data/docs/toc-mapping.yml @@ -3,6 +3,7 @@ # that the navigation for older versions still work. main: main-toc +v1.17: v1-17-toc v1.16: v1-16-toc v1.15: v1-15-toc v1.14: v1-14-toc diff --git a/site/data/docs/v1-17-toc.yml b/site/data/docs/v1-17-toc.yml new file mode 100644 index 000000000..8b93bc400 --- /dev/null +++ b/site/data/docs/v1-17-toc.yml @@ -0,0 +1,123 @@ +toc: + - title: Introduction + subfolderitems: + - page: About Velero + url: /index.html + - page: How Velero works + url: /how-velero-works + - page: About locations + url: /locations + - title: Install + subfolderitems: + - page: Basic Install + url: /basic-install + - page: Customize Installation + url: /customize-installation + - page: Upgrade to 1.17 + url: /upgrade-to-1.17 + - page: Supported providers + url: /supported-providers + - page: Evaluation install + url: /contributions/minio + - page: Examples + url: /examples + - page: Uninstalling + url: /uninstalling + - title: Use + subfolderitems: + - page: Disaster recovery + url: /disaster-case + - page: Cluster migration + url: /migration-case + - page: Enable API group versions + url: /enable-api-group-versions-feature + - page: Resource filtering + url: /resource-filtering + - page: Backup reference + url: /backup-reference + - page: Backup hooks + url: /backup-hooks + - page: Restore reference + url: /restore-reference + - page: Restore hooks + url: /restore-hooks + - page: Restore Resource Modifiers + url: /restore-resource-modifiers + - page: Run in any namespace + url: /namespace + - page: File system backup + url: /file-system-backup + - page: CSI Support + url: /csi + - page: Volume Group Snapshots + url: /volume-group-snapshots + - page: Backup Repository Configuration + url: /backup-repository-configuration + - page: Verifying Self-signed Certificates + url: /self-signed-certificates + - page: Changing RBAC permissions + url: /rbac + - page: Behind proxy + url: /proxy + - page: Repository Maintenance + url: /repository-maintenance + - page: Backup Restore Windows Workloads + url: /backup-restore-windows + - title: Data Mover + subfolderitems: + - page: CSI Snapshot Data Mover + url: /csi-snapshot-data-movement + - page: Data Movement Backup PVC Configuration + url: /data-movement-backup-pvc-configuration + - page: Data Movement Restore PVC Configuration + url: /data-movement-restore-pvc-configuration + - page: Data Movement Pod Resource Configuration + url: /data-movement-pod-resource-configuration + - page: Data Movement Node Selection Configuration + url: /data-movement-node-selection + - page: Node-agent Concurrency + url: /node-agent-concurrency + - title: Plugins + subfolderitems: + - page: Overview + url: /overview-plugins + - page: Custom plugins + url: /custom-plugins + - title: Troubleshoot + subfolderitems: + - page: Troubleshooting + url: /troubleshooting + - page: Troubleshoot an install or setup + url: /debugging-install + - page: Troubleshoot a restore + url: /debugging-restores + - page: Troubleshoot file system backup + url: /file-system-backup#troubleshooting + - title: Contribute + subfolderitems: + - page: Start Contributing + url: /start-contributing + - page: Development + url: /development + - page: Rapid development with Tilt + url: /tilt + - page: Build from source + url: /build-from-source + - page: Run locally + url: /run-locally + - page: Code standards + url: /code-standards + - page: Website guidelines + url: /website-guidelines + - page: Documentation style guide + url: /style-guide + - title: More information + subfolderitems: + - page: Backup file format + url: /output-file-format + - page: API types + url: /api-types + - page: Support process + url: /support-process + - page: For maintainers + url: /maintainers From d952cfbb2577374344cc5139d6ebf3596994b71d Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Wed, 27 Aug 2025 15:29:11 +0800 Subject: [PATCH 019/104] add 1.17 chagnelog Signed-off-by: Lyndon-Li --- changelogs/CHANGELOG-1.17.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/changelogs/CHANGELOG-1.17.md b/changelogs/CHANGELOG-1.17.md index aaeecf20d..54e1c22dc 100644 --- a/changelogs/CHANGELOG-1.17.md +++ b/changelogs/CHANGELOG-1.17.md @@ -26,11 +26,11 @@ In v1.17, Velero fs-backup supports to backup/restore Windows workloads. By leve Check design https://github.com/vmware-tanzu/velero/blob/main/design/vgdp-micro-service-for-fs-backup/vgdp-micro-service-for-fs-backup.md for more details. #### Volume group snapshot support -In v1.17, Velero supports volume group snapshots which is a beta feature in Kubernetes upstream (https://kubernetes.io/blog/2024/12/18/kubernetes-1-32-volume-group-snapshot-beta/), for both CSI snapshot backup and CSI snapshot data movement. This allows a snapshot to be taken from multiple volumes at the same point-in-time to achieve write order consistency, which is helpful to achieve better data consistency when multiple volumes being backed up are correlated. +In v1.17, Velero supports [volume group snapshots](https://kubernetes.io/blog/2024/12/18/kubernetes-1-32-volume-group-snapshot-beta/) which is a beta feature in Kubernetes upstream, for both CSI snapshot backup and CSI snapshot data movement. This allows a snapshot to be taken from multiple volumes at the same point-in-time to achieve write order consistency, which is helpful to achieve better data consistency when multiple volumes being backed up are correlated. Check the document https://velero.io/docs/main/volume-group-snapshots/ for more details. #### Priority class support -In v1.17, Kubernete priority class (https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#priorityclass) is supported for all modules across Velero. Specifically, users are allowed to configure priority class to Velero server, node-agent, data mover pods, backup repository maintenance jobs separately. +In v1.17, [Kubernetes priority class](https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#priorityclass) is supported for all modules across Velero. Specifically, users are allowed to configure priority class to Velero server, node-agent, data mover pods, backup repository maintenance jobs separately. Check design https://github.com/vmware-tanzu/velero/blob/main/design/Implemented/priority-class-name-support_design.md for more details. #### Scalability and Resiliency improvements of data movers @@ -46,6 +46,10 @@ Check issue https://github.com/vmware-tanzu/velero/issues/8534 for more details. In v1.17, CSI snapshot data movement restore acquires the same node-selection capability as backup, that is, users could specify which nodes can/cannot run data mover pods for both backup and restore now. And users are also allowed to configure the node-selection per storage class, which is particularly helpful to the environments where a storage class are not usable by all cluster nodes. Check issue https://github.com/vmware-tanzu/velero/issues/8186 and https://github.com/vmware-tanzu/velero/issues/8223 for more details. +#### Include/exclude policy support for resource policy +In v1.17, Velero resource policy supports `includeExcludePolicy` besides the existing `volumePolicy`. This allows users to set include/exclude filters for resources in a resource policy configmap, so that these filters are reusable among multiple backups. +Check the document https://velero.io/docs/main/resource-filtering/#creating-resource-policies:~:text=resources%3D%22*%22-,Resource%20policies,-Velero%20provides%20resource for more details. + ### Runtime and dependencies Golang runtime: 1.24.6 kopia: 0.21.1 @@ -54,7 +58,7 @@ kopia: 0.21.1 ### Breaking changes #### Deprecation of Restic -According to [Velero deprecation policy][https://github.com/vmware-tanzu/velero/blob/main/GOVERNANCE.md#deprecation-policy], backup of fs-backup under Restic path is removed in v1.17, so `--uploader-type=restic` is not a valid installation configuration anymore. This means you cannot create a backup under Restic path, but you can still restore from the previous backups under Restic path until v1.19. +According to [Velero deprecation policy](https://github.com/vmware-tanzu/velero/blob/main/GOVERNANCE.md#deprecation-policy), backup of fs-backup under Restic path is removed in v1.17, so `--uploader-type=restic` is not a valid installation configuration anymore. This means you cannot create a backup under Restic path, but you can still restore from the previous backups under Restic path until v1.19. #### Repository maintenance job configurations are removed from Velero server parameter Since the repository maintenance job configurations are moved to repository maintenance job configMap, in v1.17 below Velero sever parameters are removed: From 996d2a025fa33b31cba4eec57ad48fa7193a6d13 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Thu, 28 Aug 2025 14:05:56 +0800 Subject: [PATCH 020/104] Add E2E test cases for repository maintenance job configuration. Signed-off-by: Xun Jiang --- pkg/builder/priority_class_builder.go | 52 ++++ test/e2e/e2e_suite_test.go | 24 ++ test/e2e/migration/migration.go | 6 + .../repo_maintenance_config.go | 247 ++++++++++++++++++ test/e2e/test/test.go | 8 +- test/types.go | 5 + test/util/velero/install.go | 25 +- test/util/velero/velero_utils.go | 47 ++++ 8 files changed, 410 insertions(+), 4 deletions(-) create mode 100644 pkg/builder/priority_class_builder.go create mode 100644 test/e2e/repomaintenance/repo_maintenance_config.go diff --git a/pkg/builder/priority_class_builder.go b/pkg/builder/priority_class_builder.go new file mode 100644 index 000000000..b197e6d74 --- /dev/null +++ b/pkg/builder/priority_class_builder.go @@ -0,0 +1,52 @@ +/* +Copyright 2019 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 builder + +import ( + corev1api "k8s.io/api/core/v1" + schedulingv1api "k8s.io/api/scheduling/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type PriorityClassBuilder struct { + object *schedulingv1api.PriorityClass +} + +func ForPriorityClass(name string) *PriorityClassBuilder { + return &PriorityClassBuilder{ + object: &schedulingv1api.PriorityClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + }, + } +} + +func (p *PriorityClassBuilder) Value(value int) *PriorityClassBuilder { + p.object.Value = int32(value) + return p +} + +func (p *PriorityClassBuilder) PreemptionPolicy(policy string) *PriorityClassBuilder { + preemptionPolicy := corev1api.PreemptionPolicy(policy) + p.object.PreemptionPolicy = &preemptionPolicy + return p +} + +func (p *PriorityClassBuilder) Result() *schedulingv1api.PriorityClass { + return p.object +} diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go index 0159af8af..0e632dcc4 100644 --- a/test/e2e/e2e_suite_test.go +++ b/test/e2e/e2e_suite_test.go @@ -43,6 +43,7 @@ import ( . "github.com/vmware-tanzu/velero/test/e2e/parallelfilesupload" . "github.com/vmware-tanzu/velero/test/e2e/privilegesmgmt" . "github.com/vmware-tanzu/velero/test/e2e/pv-backup" + . "github.com/vmware-tanzu/velero/test/e2e/repomaintenance" . "github.com/vmware-tanzu/velero/test/e2e/resource-filtering" . "github.com/vmware-tanzu/velero/test/e2e/resourcemodifiers" . "github.com/vmware-tanzu/velero/test/e2e/resourcepolicies" @@ -660,6 +661,18 @@ var _ = Describe( ParallelFilesDownloadTest, ) +var _ = Describe( + "Test Repository Maintenance Job Configuration's global part", + Label("RepoMaintenance", "LongTime"), + GlobalRepoMaintenanceTest, +) + +var _ = Describe( + "Test Repository Maintenance Job Configuration's specific part", + Label("RepoMaintenance", "LongTime"), + SpecificRepoMaintenanceTest, +) + func GetKubeConfigContext() error { var err error var tcDefault, tcStandby k8s.TestClient @@ -740,6 +753,12 @@ var _ = BeforeSuite(func() { ).To(Succeed()) } + // Create the needed PriorityClasses + Expect(veleroutil.CreatePriorityClasses( + context.Background(), + test.VeleroCfg.ClientToInstallVelero.Kubebuilder, + )).To(Succeed()) + if test.InstallVelero { By("Install test resources before testing") Expect( @@ -783,6 +802,11 @@ var _ = AfterSuite(func() { ).To(Succeed()) } + Expect(veleroutil.DeletePriorityClasses( + ctx, + test.VeleroCfg.ClientToInstallVelero.Kubebuilder, + )).To(Succeed()) + // If the Velero is installed during test, and the FailFast is not enabled, // uninstall Velero. If not, either Velero is not installed, or kept it for debug on failure. if test.InstallVelero && (testSuitePassed || !test.VeleroCfg.FailFast) { diff --git a/test/e2e/migration/migration.go b/test/e2e/migration/migration.go index 1c896aa9f..b26f87f38 100644 --- a/test/e2e/migration/migration.go +++ b/test/e2e/migration/migration.go @@ -342,6 +342,12 @@ func (m *migrationE2E) Restore() error { Expect(veleroutil.InstallStorageClasses( m.VeleroCfg.StandbyClusterCloudProvider)).To(Succeed()) + // Create the needed PriorityClasses + Expect(veleroutil.CreatePriorityClasses( + context.Background(), + test.VeleroCfg.StandbyClient.Kubebuilder, + )).To(Succeed()) + if strings.EqualFold(m.VeleroCfg.Features, test.FeatureCSI) && m.VeleroCfg.UseVolumeSnapshots { By("Install VolumeSnapshotClass for E2E.") diff --git a/test/e2e/repomaintenance/repo_maintenance_config.go b/test/e2e/repomaintenance/repo_maintenance_config.go new file mode 100644 index 000000000..711d9bb89 --- /dev/null +++ b/test/e2e/repomaintenance/repo_maintenance_config.go @@ -0,0 +1,247 @@ +/* +Copyright 2021 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 repomaintenance + +import ( + "encoding/json" + "fmt" + "strings" + "time" + + . "github.com/onsi/gomega" + "github.com/pkg/errors" + batchv1api "k8s.io/api/batch/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "sigs.k8s.io/controller-runtime/pkg/client" + + velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + "github.com/vmware-tanzu/velero/pkg/builder" + velerotypes "github.com/vmware-tanzu/velero/pkg/types" + "github.com/vmware-tanzu/velero/pkg/util/kube" + velerokubeutil "github.com/vmware-tanzu/velero/pkg/util/kube" + "github.com/vmware-tanzu/velero/test" + . "github.com/vmware-tanzu/velero/test/e2e/test" + k8sutil "github.com/vmware-tanzu/velero/test/util/k8s" + veleroutil "github.com/vmware-tanzu/velero/test/util/velero" +) + +type RepoMaintenanceTestCase struct { + TestCase + repoMaintenanceConfigMapName string + repoMaintenanceConfigKey string + jobConfigs velerotypes.JobConfigs +} + +var keepJobNum = 1 + +var GlobalRepoMaintenanceTest func() = TestFunc(&RepoMaintenanceTestCase{ + repoMaintenanceConfigKey: "global", + repoMaintenanceConfigMapName: "global", + jobConfigs: velerotypes.JobConfigs{ + KeepLatestMaintenanceJobs: &keepJobNum, + PodResources: &velerokubeutil.PodResources{ + CPURequest: "100m", + MemoryRequest: "100Mi", + CPULimit: "200m", + MemoryLimit: "200Mi", + }, + PriorityClassName: test.PriorityClassNameForRepoMaintenance, + }, +}) + +var SpecificRepoMaintenanceTest func() = TestFunc(&RepoMaintenanceTestCase{ + repoMaintenanceConfigKey: "", + repoMaintenanceConfigMapName: "specific", + jobConfigs: velerotypes.JobConfigs{ + KeepLatestMaintenanceJobs: &keepJobNum, + PodResources: &velerokubeutil.PodResources{ + CPURequest: "100m", + MemoryRequest: "100Mi", + CPULimit: "200m", + MemoryLimit: "200Mi", + }, + PriorityClassName: test.PriorityClassNameForRepoMaintenance, + }, +}) + +func (r *RepoMaintenanceTestCase) Init() error { + // generate random number as UUIDgen and set one default timeout duration + r.TestCase.Init() + + // generate variable names based on CaseBaseName + UUIDgen + r.CaseBaseName = "repo-maintenance-" + r.UUIDgen + r.BackupName = "backup-" + r.CaseBaseName + r.RestoreName = "restore-" + r.CaseBaseName + + // generate namespaces by NamespacesTotal + r.NamespacesTotal = 1 + r.NSIncluded = &[]string{} + for nsNum := 0; nsNum < r.NamespacesTotal; nsNum++ { + createNSName := fmt.Sprintf("%s-%00000d", r.CaseBaseName, nsNum) + *r.NSIncluded = append(*r.NSIncluded, createNSName) + } + + // If repoMaintenanceConfigKey is not set, it means testing the specific repo case. + // Need to assemble the BackupRepository name. The format is "volumeNamespace-bslName-uploaderName" + if r.repoMaintenanceConfigKey == "" { + r.repoMaintenanceConfigKey = (*r.NSIncluded)[0] + "-" + "default" + "-" + test.UploaderTypeKopia + } + + // assign values to the inner variable for specific case + r.VeleroCfg.UseNodeAgent = true + r.VeleroCfg.UseNodeAgentWindows = true + + r.BackupArgs = []string{ + "create", "--namespace", r.VeleroCfg.VeleroNamespace, "backup", r.BackupName, + "--include-namespaces", strings.Join(*r.NSIncluded, ","), + "--snapshot-volumes=true", "--snapshot-move-data", "--wait", + } + + // Message output by ginkgo + r.TestMsg = &TestMSG{ + Desc: "Validate Repository Maintenance Job configuration", + FailedMSG: "Failed to apply and / or validate configuration in repository maintenance jobs.", + Text: "Should be able to apply and validate configuration in repository maintenance jobs.", + } + return nil +} + +func (r *RepoMaintenanceTestCase) InstallVelero() error { + // Because this test needs to use customized repository maintenance ConfigMap, + // need to uninstall and reinstall Velero. + + fmt.Println("Start to uninstall Velero") + if err := veleroutil.VeleroUninstall(r.Ctx, r.VeleroCfg); err != nil { + fmt.Printf("Fail to uninstall Velero: %s\n", err.Error()) + return err + } + + result, err := json.Marshal(r.jobConfigs) + if err != nil { + return err + } + + repoMaintenanceConfig := builder.ForConfigMap(r.VeleroCfg.VeleroNamespace, r.repoMaintenanceConfigMapName). + Data(r.repoMaintenanceConfigKey, string(result)).Result() + + r.VeleroCfg.RepoMaintenanceJobConfigMap = r.repoMaintenanceConfigMapName + + return veleroutil.PrepareVelero( + r.Ctx, + r.CaseBaseName, + r.VeleroCfg, + repoMaintenanceConfig, + ) +} + +func (r *RepoMaintenanceTestCase) CreateResources() error { + for _, ns := range *r.NSIncluded { + if err := k8sutil.CreateNamespace(r.Ctx, r.Client, ns); err != nil { + fmt.Printf("Fail to create ns %s: %s\n", ns, err.Error()) + return err + } + + pvc, err := k8sutil.CreatePVC(r.Client, ns, "volume-1", test.StorageClassName, nil) + if err != nil { + fmt.Printf("Fail to create PVC %s: %s\n", "volume-1", err.Error()) + return err + } + + vols := k8sutil.CreateVolumes(pvc.Name, []string{"volume-1"}) + + deployment := k8sutil.NewDeployment( + r.CaseBaseName, + (*r.NSIncluded)[0], + 1, + map[string]string{"app": "test"}, + r.VeleroCfg.ImageRegistryProxy, + r.VeleroCfg.WorkerOS, + ).WithVolume(vols).Result() + + deployment, err = k8sutil.CreateDeployment(r.Client.ClientGo, ns, deployment) + if err != nil { + fmt.Printf("Fail to create deployment %s: %s \n", deployment.Name, err.Error()) + return errors.Wrap(err, fmt.Sprintf("failed to create deployment: %s", err.Error())) + } + + if err := k8sutil.WaitForReadyDeployment(r.Client.ClientGo, deployment.Namespace, deployment.Name); err != nil { + fmt.Printf("Fail to create deployment %s: %s\n", r.CaseBaseName, err.Error()) + return err + } + } + + return nil +} + +func (r *RepoMaintenanceTestCase) Verify() error { + // Reduce the MaintenanceFrequency to 1 minute. + backupRepositoryList := new(velerov1api.BackupRepositoryList) + if err := r.VeleroCfg.ClientToInstallVelero.Kubebuilder.List( + r.Ctx, + backupRepositoryList, + &client.ListOptions{ + Namespace: r.VeleroCfg.Namespace, + LabelSelector: labels.SelectorFromSet(map[string]string{velerov1api.VolumeNamespaceLabel: (*r.NSIncluded)[0]}), + }, + ); err != nil { + return err + } + + if len(backupRepositoryList.Items) <= 0 { + return fmt.Errorf("fail list BackupRepository. no item is returned") + } + + backupRepository := backupRepositoryList.Items[0] + + updated := backupRepository.DeepCopy() + updated.Spec.MaintenanceFrequency = metav1.Duration{Duration: time.Minute} + if err := r.VeleroCfg.ClientToInstallVelero.Kubebuilder.Patch(r.Ctx, updated, client.MergeFrom(&backupRepository)); err != nil { + fmt.Printf("failed to patch BackupRepository %q: %s", backupRepository.GetName(), err.Error()) + return err + } + + // The minimal time unit of Repository Maintenance is 5 minutes. + // Wait for more than one cycles to make sure the result is valid. + time.Sleep(6 * time.Minute) + + jobList := new(batchv1api.JobList) + if err := r.VeleroCfg.ClientToInstallVelero.Kubebuilder.List(r.Ctx, jobList, &client.ListOptions{ + Namespace: r.VeleroCfg.Namespace, + LabelSelector: labels.SelectorFromSet(map[string]string{"velero.io/repo-name": backupRepository.Name}), + }); err != nil { + return nil + } + + resources, err := kube.ParseResourceRequirements( + r.jobConfigs.PodResources.CPURequest, + r.jobConfigs.PodResources.MemoryRequest, + r.jobConfigs.PodResources.CPULimit, + r.jobConfigs.PodResources.MemoryLimit, + ) + if err != nil { + return errors.Wrap(err, "failed to parse resource requirements for maintenance job") + } + + Expect(jobList.Items[0].Spec.Template.Spec.Containers[0].Resources).To(Equal(resources)) + + Expect(jobList.Items).To(HaveLen(*r.jobConfigs.KeepLatestMaintenanceJobs)) + + Expect(jobList.Items[0].Spec.Template.Spec.PriorityClassName).To(Equal(r.jobConfigs.PriorityClassName)) + + return nil +} diff --git a/test/e2e/test/test.go b/test/e2e/test/test.go index 78704a4bb..1a91c115f 100644 --- a/test/e2e/test/test.go +++ b/test/e2e/test/test.go @@ -41,6 +41,7 @@ depends on your test patterns. */ type VeleroBackupRestoreTest interface { Init() error + InstallVelero() error CreateResources() error Backup() error Destroy() error @@ -109,6 +110,10 @@ func (t *TestCase) GenerateUUID() string { return fmt.Sprintf("%08d", rand.IntN(100000000)) } +func (t *TestCase) InstallVelero() error { + return PrepareVelero(context.Background(), t.GetTestCase().CaseBaseName, t.GetTestCase().VeleroCfg) +} + func (t *TestCase) CreateResources() error { return nil } @@ -221,7 +226,8 @@ func RunTestCase(test VeleroBackupRestoreTest) error { fmt.Printf("Running test case %s %s\n", test.GetTestMsg().Desc, time.Now().Format("2006-01-02 15:04:05")) if InstallVelero { - Expect(PrepareVelero(context.Background(), test.GetTestCase().CaseBaseName, test.GetTestCase().VeleroCfg)).To(Succeed()) + fmt.Printf("Install Velero for test case %s: %s", test.GetTestCase().CaseBaseName, time.Now().Format("2006-01-02 15:04:05")) + Expect(test.InstallVelero()).To(Succeed()) } defer test.Clean() diff --git a/test/types.go b/test/types.go index 01ea91c35..ef9582ce3 100644 --- a/test/types.go +++ b/test/types.go @@ -57,6 +57,11 @@ const ( BackupRepositoryConfigName = "backup-repository-config" ) +const ( + PriorityClassNameForDataMover = "data-mover" + PriorityClassNameForRepoMaintenance = "repo-maintenance" +) + var PublicCloudProviders = []string{AWS, Azure, GCP, Vsphere} var LocalCloudProviders = []string{Kind, VanillaZFS} var CloudProviders = append(PublicCloudProviders, LocalCloudProviders...) diff --git a/test/util/velero/install.go b/test/util/velero/install.go index 2f4eb43de..ca6e207d1 100644 --- a/test/util/velero/install.go +++ b/test/util/velero/install.go @@ -36,6 +36,7 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/util/wait" clientset "k8s.io/client-go/kubernetes" + "sigs.k8s.io/controller-runtime/pkg/client" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" "github.com/vmware-tanzu/velero/pkg/cmd/cli/install" @@ -56,7 +57,17 @@ type installOptions struct { WorkerOS string } -func VeleroInstall(ctx context.Context, veleroCfg *test.VeleroConfig, isStandbyCluster bool) error { +/* +VeleroInstall is used to install Velero for E2E test + +params: + + ctx: The context + veleroCfg: Velero E2E case configuration + isStandbyCluster: Whether Velero is installed on standby cluster + objects: The objects are installed in Velero installed namespace, e.g. the ConfigMaps. +*/ +func VeleroInstall(ctx context.Context, veleroCfg *test.VeleroConfig, isStandbyCluster bool, objects ...client.Object) error { fmt.Printf("Velero install %s\n", time.Now().Format("2006-01-02 15:04:05")) // veleroCfg struct including a set of BSL params and a set of additional BSL params, @@ -153,6 +164,14 @@ func VeleroInstall(ctx context.Context, veleroCfg *test.VeleroConfig, isStandbyC ) } + // Install the passed-in objects in Velero installed namespace + for _, obj := range objects { + if err := veleroCfg.ClientToInstallVelero.Kubebuilder.Create(ctx, obj); err != nil { + fmt.Printf("fail to create object %s in namespace %s: %s\n", obj.GetName(), obj.GetNamespace(), err.Error()) + return fmt.Errorf("fail to create object %s in namespace %s: %w", obj.GetName(), obj.GetNamespace(), err) + } + } + // For AWS IRSA credential test, AWS IAM service account is required, so if ServiceAccountName and EKSPolicyARN // are both provided, we assume IRSA test is running, otherwise skip this IAM service account creation part. if veleroCfg.CloudProvider == test.AWS && veleroInstallOptions.ServiceAccountName != "" { @@ -790,7 +809,7 @@ func CheckBSL(ctx context.Context, ns string, bslName string) error { return err } -func PrepareVelero(ctx context.Context, caseName string, veleroCfg test.VeleroConfig) error { +func PrepareVelero(ctx context.Context, caseName string, veleroCfg test.VeleroConfig, objects ...client.Object) error { ready, err := IsVeleroReady(context.Background(), &veleroCfg) if err != nil { fmt.Printf("error in checking velero status with %v", err) @@ -804,7 +823,7 @@ func PrepareVelero(ctx context.Context, caseName string, veleroCfg test.VeleroCo return nil } fmt.Printf("need to install velero for case %s \n", caseName) - return VeleroInstall(context.Background(), &veleroCfg, false) + return VeleroInstall(context.Background(), &veleroCfg, false, objects...) } func VeleroUninstall(ctx context.Context, veleroCfg test.VeleroConfig) error { diff --git a/test/util/velero/velero_utils.go b/test/util/velero/velero_utils.go index 5985dd509..65f56bf03 100644 --- a/test/util/velero/velero_utils.go +++ b/test/util/velero/velero_utils.go @@ -38,6 +38,8 @@ import ( "github.com/pkg/errors" "golang.org/x/mod/semver" + schedulingv1api "k8s.io/api/scheduling/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" ver "k8s.io/apimachinery/pkg/util/version" "k8s.io/apimachinery/pkg/util/wait" @@ -45,9 +47,11 @@ import ( "github.com/vmware-tanzu/velero/internal/volume" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + "github.com/vmware-tanzu/velero/pkg/builder" cliinstall "github.com/vmware-tanzu/velero/pkg/cmd/cli/install" "github.com/vmware-tanzu/velero/pkg/cmd/util/flag" veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec" + "github.com/vmware-tanzu/velero/test" . "github.com/vmware-tanzu/velero/test" common "github.com/vmware-tanzu/velero/test/util/common" . "github.com/vmware-tanzu/velero/test/util/k8s" @@ -274,6 +278,9 @@ func getProviderVeleroInstallOptions(veleroCfg *VeleroConfig, io.ItemBlockWorkerCount = veleroCfg.ItemBlockWorkerCount io.ServerPriorityClassName = veleroCfg.ServerPriorityClassName io.NodeAgentPriorityClassName = veleroCfg.NodeAgentPriorityClassName + io.RepoMaintenanceJobConfigMap = veleroCfg.RepoMaintenanceJobConfigMap + io.BackupRepoConfigMap = veleroCfg.BackupRepoConfigMap + io.NodeAgentConfigMap = veleroCfg.NodeAgentConfigMap return io, nil } @@ -1812,3 +1819,43 @@ func KubectlGetAllDeleteBackupRequest(ctx context.Context, backupName, veleroNam return common.GetListByCmdPipes(ctx, cmds) } + +func CreatePriorityClasses(ctx context.Context, client kbclient.Client) error { + dataMoverPriorityClass := builder.ForPriorityClass(test.PriorityClassNameForDataMover). + Value(90000).PreemptionPolicy("Never").Result() + if err := client.Create(ctx, dataMoverPriorityClass); err != nil { + fmt.Printf("Fail to create PriorityClass %s: %s\n", test.PriorityClassNameForDataMover, err.Error()) + return fmt.Errorf("fail to create PriorityClass %s: %w", test.PriorityClassNameForDataMover, err) + } + + repoMaintenancePriorityClass := builder.ForPriorityClass(test.PriorityClassNameForRepoMaintenance). + Value(80000).PreemptionPolicy("Never").Result() + if err := client.Create(ctx, repoMaintenancePriorityClass); err != nil { + fmt.Printf("Fail to create PriorityClass %s: %s\n", test.PriorityClassNameForRepoMaintenance, err.Error()) + return fmt.Errorf("fail to create PriorityClass %s: %w", test.PriorityClassNameForRepoMaintenance, err) + } + + return nil +} + +func DeletePriorityClasses(ctx context.Context, client kbclient.Client) error { + priorityClassDataMover := &schedulingv1api.PriorityClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: test.PriorityClassNameForDataMover, + }, + } + if err := client.Delete(ctx, priorityClassDataMover); err != nil { + return err + } + + priorityClassRepoMaintenance := &schedulingv1api.PriorityClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: test.PriorityClassNameForRepoMaintenance, + }, + } + if err := client.Delete(ctx, priorityClassRepoMaintenance); err != nil { + return err + } + + return nil +} From 248a8409182b20a5ac51be15b9280017aea135b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Nussbaumer?= Date: Tue, 5 Aug 2025 16:26:16 +0200 Subject: [PATCH 021/104] feat: Permit specifying annotations for the BackupPVC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Clément Nussbaumer --- changelogs/unreleased/9173-clementnuss | 1 + pkg/exposer/csi_snapshot.go | 14 ++++++++++---- pkg/exposer/csi_snapshot_test.go | 2 +- pkg/types/node_agent.go | 3 +++ .../main/data-movement-backup-pvc-configuration.md | 10 ++++++++-- 5 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 changelogs/unreleased/9173-clementnuss diff --git a/changelogs/unreleased/9173-clementnuss b/changelogs/unreleased/9173-clementnuss new file mode 100644 index 000000000..c7dece117 --- /dev/null +++ b/changelogs/unreleased/9173-clementnuss @@ -0,0 +1 @@ +feat: Permit specifying annotations for the BackupPVC diff --git a/pkg/exposer/csi_snapshot.go b/pkg/exposer/csi_snapshot.go index a886c60c3..531330f62 100644 --- a/pkg/exposer/csi_snapshot.go +++ b/pkg/exposer/csi_snapshot.go @@ -188,6 +188,7 @@ func (e *csiSnapshotExposer) Expose(ctx context.Context, ownerObject corev1api.O backupPVCStorageClass := csiExposeParam.StorageClass backupPVCReadOnly := false spcNoRelabeling := false + backupPVCAnnotations := map[string]string{} if value, exists := csiExposeParam.BackupPVCConfig[csiExposeParam.StorageClass]; exists { if value.StorageClass != "" { backupPVCStorageClass = value.StorageClass @@ -201,9 +202,13 @@ func (e *csiSnapshotExposer) Expose(ctx context.Context, ownerObject corev1api.O curLog.WithField("vs name", volumeSnapshot.Name).Warn("Ignoring spcNoRelabling for read-write volume") } } + + if len(value.Annotations) > 0 { + backupPVCAnnotations = value.Annotations + } } - backupPVC, err := e.createBackupPVC(ctx, ownerObject, backupVS.Name, backupPVCStorageClass, csiExposeParam.AccessMode, volumeSize, backupPVCReadOnly) + backupPVC, err := e.createBackupPVC(ctx, ownerObject, backupVS.Name, backupPVCStorageClass, csiExposeParam.AccessMode, volumeSize, backupPVCReadOnly, backupPVCAnnotations) if err != nil { return errors.Wrap(err, "error to create backup pvc") } @@ -485,7 +490,7 @@ func (e *csiSnapshotExposer) createBackupVSC(ctx context.Context, ownerObject co return e.csiSnapshotClient.VolumeSnapshotContents().Create(ctx, vsc, metav1.CreateOptions{}) } -func (e *csiSnapshotExposer) createBackupPVC(ctx context.Context, ownerObject corev1api.ObjectReference, backupVS, storageClass, accessMode string, resource resource.Quantity, readOnly bool) (*corev1api.PersistentVolumeClaim, error) { +func (e *csiSnapshotExposer) createBackupPVC(ctx context.Context, ownerObject corev1api.ObjectReference, backupVS, storageClass, accessMode string, resource resource.Quantity, readOnly bool, annotations map[string]string) (*corev1api.PersistentVolumeClaim, error) { backupPVCName := ownerObject.Name volumeMode, err := getVolumeModeByAccessMode(accessMode) @@ -507,8 +512,9 @@ func (e *csiSnapshotExposer) createBackupPVC(ctx context.Context, ownerObject co pvc := &corev1api.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ - Namespace: ownerObject.Namespace, - Name: backupPVCName, + Namespace: ownerObject.Namespace, + Name: backupPVCName, + Annotations: annotations, OwnerReferences: []metav1.OwnerReference{ { APIVersion: ownerObject.APIVersion, diff --git a/pkg/exposer/csi_snapshot_test.go b/pkg/exposer/csi_snapshot_test.go index 5dd745065..a6d74d9fe 100644 --- a/pkg/exposer/csi_snapshot_test.go +++ b/pkg/exposer/csi_snapshot_test.go @@ -1114,7 +1114,7 @@ func Test_csiSnapshotExposer_createBackupPVC(t *testing.T) { APIVersion: tt.ownerBackup.APIVersion, } } - got, err := e.createBackupPVC(t.Context(), ownerObject, tt.backupVS, tt.storageClass, tt.accessMode, tt.resource, tt.readOnly) + got, err := e.createBackupPVC(t.Context(), ownerObject, tt.backupVS, tt.storageClass, tt.accessMode, tt.resource, tt.readOnly, map[string]string{}) if !tt.wantErr(t, err, fmt.Sprintf("createBackupPVC(%v, %v, %v, %v, %v, %v)", ownerObject, tt.backupVS, tt.storageClass, tt.accessMode, tt.resource, tt.readOnly)) { return } diff --git a/pkg/types/node_agent.go b/pkg/types/node_agent.go index d0696dc95..778aefcf1 100644 --- a/pkg/types/node_agent.go +++ b/pkg/types/node_agent.go @@ -56,6 +56,9 @@ type BackupPVC struct { // SPCNoRelabeling sets Spec.SecurityContext.SELinux.Type to "spc_t" for the pod mounting the backupPVC // ignored if ReadOnly is false SPCNoRelabeling bool `json:"spcNoRelabeling,omitempty"` + + // Annotations permits setting annotations for the backupPVC + Annotations map[string]string `json:"annotations,omitempty"` } type RestorePVC struct { diff --git a/site/content/docs/main/data-movement-backup-pvc-configuration.md b/site/content/docs/main/data-movement-backup-pvc-configuration.md index 11f6d6bc7..1dc290820 100644 --- a/site/content/docs/main/data-movement-backup-pvc-configuration.md +++ b/site/content/docs/main/data-movement-backup-pvc-configuration.md @@ -37,6 +37,9 @@ default the source PVC's storage class will be used. The users can specify the ConfigMap name during velero installation by CLI: `velero install --node-agent-configmap=` +- `annotations`: permits to set annotations on the backupPVC itself. typically useful for some CSI provider which cannot mount + a VolumeSnapshot without a custom annotation. + A sample of `backupPVC` config as part of the ConfigMap would look like: ```json { @@ -49,8 +52,11 @@ A sample of `backupPVC` config as part of the ConfigMap would look like: "storageClass": "backupPVC-storage-class" }, "storage-class-3": { - "readOnly": true - } + "readOnly": true, + "annotations": { + "some-csi.provider.io/readOnlyClone": true + } + }, "storage-class-4": { "readOnly": true, "spcNoRelabeling": true From c5b70b4a0d46b8d333777056147fa4f87b270b94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Nussbaumer?= Date: Tue, 12 Aug 2025 16:36:21 +0200 Subject: [PATCH 022/104] test: fix backuppvc annotations test case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Clément Nussbaumer --- pkg/exposer/csi_snapshot_test.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/exposer/csi_snapshot_test.go b/pkg/exposer/csi_snapshot_test.go index a6d74d9fe..9bb4b95b8 100644 --- a/pkg/exposer/csi_snapshot_test.go +++ b/pkg/exposer/csi_snapshot_test.go @@ -1001,8 +1001,9 @@ func Test_csiSnapshotExposer_createBackupPVC(t *testing.T) { backupPVC := corev1api.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ - Namespace: velerov1.DefaultNamespace, - Name: "fake-backup", + Namespace: velerov1.DefaultNamespace, + Name: "fake-backup", + Annotations: map[string]string{}, OwnerReferences: []metav1.OwnerReference{ { APIVersion: backup.APIVersion, @@ -1031,8 +1032,9 @@ func Test_csiSnapshotExposer_createBackupPVC(t *testing.T) { backupPVCReadOnly := corev1api.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ - Namespace: velerov1.DefaultNamespace, - Name: "fake-backup", + Namespace: velerov1.DefaultNamespace, + Name: "fake-backup", + Annotations: map[string]string{}, OwnerReferences: []metav1.OwnerReference{ { APIVersion: backup.APIVersion, From 8e1c4a7dc55806fe4806d34d83279f09bdeb375b Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 29 Aug 2025 11:33:28 +0800 Subject: [PATCH 023/104] Add E2E cases for node-agent-configmap. Fix the default BackupRepoConfig setting issue. Delete PriorityClass in migration case clean stage. Signed-off-by: Xun Jiang --- test/e2e/e2e_suite_test.go | 11 +- test/e2e/migration/migration.go | 10 +- test/e2e/nodeagentconfig/node-agent-config.go | 347 ++++++++++++++++++ test/util/velero/install.go | 5 +- 4 files changed, 368 insertions(+), 5 deletions(-) create mode 100644 test/e2e/nodeagentconfig/node-agent-config.go diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go index 0e632dcc4..71d501e60 100644 --- a/test/e2e/e2e_suite_test.go +++ b/test/e2e/e2e_suite_test.go @@ -39,6 +39,7 @@ import ( . "github.com/vmware-tanzu/velero/test/e2e/basic/resources-check" . "github.com/vmware-tanzu/velero/test/e2e/bsl-mgmt" . "github.com/vmware-tanzu/velero/test/e2e/migration" + . "github.com/vmware-tanzu/velero/test/e2e/nodeagentconfig" . "github.com/vmware-tanzu/velero/test/e2e/parallelfilesdownload" . "github.com/vmware-tanzu/velero/test/e2e/parallelfilesupload" . "github.com/vmware-tanzu/velero/test/e2e/privilegesmgmt" @@ -673,6 +674,12 @@ var _ = Describe( SpecificRepoMaintenanceTest, ) +var _ = Describe( + "Test node agent config's LoadAffinity part", + Label("NodeAgentConfig", "LoadAffinity"), + LoadAffinities, +) + func GetKubeConfigContext() error { var err error var tcDefault, tcStandby k8s.TestClient @@ -753,7 +760,7 @@ var _ = BeforeSuite(func() { ).To(Succeed()) } - // Create the needed PriorityClasses + By("Install PriorityClasses for E2E.") Expect(veleroutil.CreatePriorityClasses( context.Background(), test.VeleroCfg.ClientToInstallVelero.Kubebuilder, @@ -783,6 +790,8 @@ var _ = AfterSuite(func() { test.StorageClassName, ), ).To(Succeed()) + + By("Delete PriorityClasses created by E2E") Expect( k8s.DeleteStorageClass( ctx, diff --git a/test/e2e/migration/migration.go b/test/e2e/migration/migration.go index b26f87f38..f91bcffff 100644 --- a/test/e2e/migration/migration.go +++ b/test/e2e/migration/migration.go @@ -342,7 +342,7 @@ func (m *migrationE2E) Restore() error { Expect(veleroutil.InstallStorageClasses( m.VeleroCfg.StandbyClusterCloudProvider)).To(Succeed()) - // Create the needed PriorityClasses + By("Install PriorityClass for E2E.") Expect(veleroutil.CreatePriorityClasses( context.Background(), test.VeleroCfg.StandbyClient.Kubebuilder, @@ -453,6 +453,7 @@ func (m *migrationE2E) Clean() error { Expect(k8sutil.KubectlConfigUseContext( m.Ctx, m.VeleroCfg.StandbyClusterContext)).To(Succeed()) + m.VeleroCfg.ClientToInstallVelero = m.VeleroCfg.StandbyClient m.VeleroCfg.ClusterToInstallVelero = m.VeleroCfg.StandbyClusterName @@ -465,7 +466,6 @@ func (m *migrationE2E) Clean() error { fmt.Println("Fail to delete StorageClass1: ", err) return } - if err := k8sutil.DeleteStorageClass( m.Ctx, *m.VeleroCfg.ClientToInstallVelero, @@ -475,6 +475,12 @@ func (m *migrationE2E) Clean() error { return } + By("Delete PriorityClasses created by E2E") + Expect(veleroutil.DeletePriorityClasses( + m.Ctx, + m.VeleroCfg.ClientToInstallVelero.Kubebuilder, + )).To(Succeed()) + if strings.EqualFold(m.VeleroCfg.Features, test.FeatureCSI) && m.VeleroCfg.UseVolumeSnapshots { By("Delete VolumeSnapshotClass created by E2E") diff --git a/test/e2e/nodeagentconfig/node-agent-config.go b/test/e2e/nodeagentconfig/node-agent-config.go new file mode 100644 index 000000000..1b46eed65 --- /dev/null +++ b/test/e2e/nodeagentconfig/node-agent-config.go @@ -0,0 +1,347 @@ +/* +Copyright 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 nodeagentconfig + +import ( + "context" + "encoding/json" + "fmt" + "strings" + "time" + + . "github.com/onsi/gomega" + "github.com/pkg/errors" + corev1api "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/util/wait" + "sigs.k8s.io/controller-runtime/pkg/client" + + velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + velerov2alpha1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1" + "github.com/vmware-tanzu/velero/pkg/builder" + velerotypes "github.com/vmware-tanzu/velero/pkg/types" + "github.com/vmware-tanzu/velero/pkg/util/kube" + velerokubeutil "github.com/vmware-tanzu/velero/pkg/util/kube" + "github.com/vmware-tanzu/velero/test" + . "github.com/vmware-tanzu/velero/test/e2e/test" + k8sutil "github.com/vmware-tanzu/velero/test/util/k8s" + veleroutil "github.com/vmware-tanzu/velero/test/util/velero" +) + +type NodeAgentConfigTestCase struct { + TestCase + nodeAgentConfigs velerotypes.NodeAgentConfigs + nodeAgentConfigMapName string +} + +var LoadAffinities func() = TestFunc(&NodeAgentConfigTestCase{ + nodeAgentConfigs: velerotypes.NodeAgentConfigs{ + LoadAffinity: []*kube.LoadAffinity{ + { + NodeSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "beta.kubernetes.io/arch": "amd64", + }, + }, + StorageClass: test.StorageClassName, + }, + { + NodeSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "kubernetes.io/arch": "amd64", + }, + }, + StorageClass: test.StorageClassName2, + }, + }, + BackupPVCConfig: map[string]velerotypes.BackupPVC{ + test.StorageClassName: { + StorageClass: test.StorageClassName2, + }, + }, + RestorePVCConfig: &velerotypes.RestorePVC{ + IgnoreDelayBinding: true, + }, + PriorityClassName: test.PriorityClassNameForDataMover, + }, + nodeAgentConfigMapName: "node-agent-config", +}) + +func (n *NodeAgentConfigTestCase) Init() error { + // generate random number as UUIDgen and set one default timeout duration + n.TestCase.Init() + + // generate variable names based on CaseBaseName + UUIDgen + n.CaseBaseName = "node-agent-config-" + n.UUIDgen + n.BackupName = "backup-" + n.CaseBaseName + n.RestoreName = "restore-" + n.CaseBaseName + + // generate namespaces by NamespacesTotal + n.NamespacesTotal = 1 + n.NSIncluded = &[]string{} + for nsNum := 0; nsNum < n.NamespacesTotal; nsNum++ { + createNSName := fmt.Sprintf("%s-%00000d", n.CaseBaseName, nsNum) + *n.NSIncluded = append(*n.NSIncluded, createNSName) + } + + // assign values to the inner variable for specific case + n.VeleroCfg.UseNodeAgent = true + n.VeleroCfg.UseNodeAgentWindows = true + + // Need to verify the data mover pod content, so don't wait until backup completion. + n.BackupArgs = []string{ + "create", "--namespace", n.VeleroCfg.VeleroNamespace, "backup", n.BackupName, + "--include-namespaces", strings.Join(*n.NSIncluded, ","), + "--snapshot-volumes=true", "--snapshot-move-data", + } + + // Need to verify the data mover pod content, so don't wait until restore completion. + n.RestoreArgs = []string{ + "create", "--namespace", n.VeleroCfg.VeleroNamespace, "restore", n.RestoreName, + "--from-backup", n.BackupName, + } + + // Message output by ginkgo + n.TestMsg = &TestMSG{ + Desc: "Validate Node Agent ConfigMap configuration", + FailedMSG: "Failed to apply and / or validate configuration in VGDP pod.", + Text: "Should be able to apply and validate configuration in VGDP pod.", + } + return nil +} + +func (n *NodeAgentConfigTestCase) InstallVelero() error { + // Because this test needs to use customized Node Agent ConfigMap, + // need to uninstall and reinstall Velero. + + fmt.Println("Start to uninstall Velero") + if err := veleroutil.VeleroUninstall(n.Ctx, n.VeleroCfg); err != nil { + fmt.Printf("Fail to uninstall Velero: %s\n", err.Error()) + return err + } + + result, err := json.Marshal(n.nodeAgentConfigs) + if err != nil { + return err + } + + repoMaintenanceConfig := builder.ForConfigMap(n.VeleroCfg.VeleroNamespace, n.nodeAgentConfigMapName). + Data("node-agent-config", string(result)).Result() + + n.VeleroCfg.NodeAgentConfigMap = n.nodeAgentConfigMapName + + return veleroutil.PrepareVelero( + n.Ctx, + n.CaseBaseName, + n.VeleroCfg, + repoMaintenanceConfig, + ) +} + +func (n *NodeAgentConfigTestCase) CreateResources() error { + for _, ns := range *n.NSIncluded { + if err := k8sutil.CreateNamespace(n.Ctx, n.Client, ns); err != nil { + fmt.Printf("Fail to create ns %s: %s\n", ns, err.Error()) + return err + } + + pvc, err := k8sutil.CreatePVC(n.Client, ns, "volume-1", test.StorageClassName, nil) + if err != nil { + fmt.Printf("Fail to create PVC %s: %s\n", "volume-1", err.Error()) + return err + } + + vols := k8sutil.CreateVolumes(pvc.Name, []string{"volume-1"}) + + deployment := k8sutil.NewDeployment( + n.CaseBaseName, + (*n.NSIncluded)[0], + 1, + map[string]string{"app": "test"}, + n.VeleroCfg.ImageRegistryProxy, + n.VeleroCfg.WorkerOS, + ).WithVolume(vols).Result() + + deployment, err = k8sutil.CreateDeployment(n.Client.ClientGo, ns, deployment) + if err != nil { + fmt.Printf("Fail to create deployment %s: %s \n", deployment.Name, err.Error()) + return errors.Wrap(err, fmt.Sprintf("failed to create deployment: %s", err.Error())) + } + + if err := k8sutil.WaitForReadyDeployment(n.Client.ClientGo, deployment.Namespace, deployment.Name); err != nil { + fmt.Printf("Fail to create deployment %s: %s\n", n.CaseBaseName, err.Error()) + return err + } + } + + return nil +} + +func (n *NodeAgentConfigTestCase) Backup() error { + if err := veleroutil.VeleroCmdExec(n.Ctx, n.VeleroCfg.VeleroCLI, n.BackupArgs); err != nil { + return err + } + + backupPodList := new(corev1api.PodList) + + wait.PollUntilContextTimeout(n.Ctx, 5*time.Second, 5*time.Minute, true, func(ctx context.Context) (bool, error) { + duList := new(velerov2alpha1api.DataUploadList) + if err := n.VeleroCfg.ClientToInstallVelero.Kubebuilder.List( + n.Ctx, + duList, + &client.ListOptions{Namespace: n.VeleroCfg.VeleroNamespace}, + ); err != nil { + fmt.Printf("Fail to list DataUpload: %s\n", err.Error()) + return false, fmt.Errorf("Fail to list DataUpload: %w", err) + } else { + if len(duList.Items) <= 0 { + fmt.Println("No DataUpload found yet. Continue polling.") + return false, nil + } + } + + if err := n.VeleroCfg.ClientToInstallVelero.Kubebuilder.List( + n.Ctx, + backupPodList, + &client.ListOptions{ + LabelSelector: labels.SelectorFromSet(map[string]string{ + velerov1api.DataUploadLabel: duList.Items[0].Name, + }), + }); err != nil { + fmt.Printf("Fail to list backupPod %s\n", err.Error()) + return false, errors.Wrapf(err, "error to list backup pods") + } else { + if len(backupPodList.Items) <= 0 { + fmt.Println("No backupPod found yet. Continue polling.") + return false, nil + } + } + + return true, nil + }) + + fmt.Println("Start to verify backupPod content.") + + Expect(backupPodList.Items[0].Spec.PriorityClassName).To(Equal(n.nodeAgentConfigs.PriorityClassName)) + + // In backup, only the second element of LoadAffinity array should be used. + expectedAffinity := velerokubeutil.ToSystemAffinity(n.nodeAgentConfigs.LoadAffinity[1:]) + + Expect(backupPodList.Items[0].Spec.Affinity).To(Equal(expectedAffinity)) + + fmt.Println("backupPod content verification completed successfully.") + + wait.PollUntilContextTimeout(n.Ctx, 5*time.Second, 5*time.Minute, true, func(ctx context.Context) (bool, error) { + backup := new(velerov1api.Backup) + if err := n.VeleroCfg.ClientToInstallVelero.Kubebuilder.Get( + n.Ctx, + client.ObjectKey{Namespace: n.VeleroCfg.VeleroNamespace, Name: n.BackupName}, + backup, + ); err != nil { + return false, err + } + + if backup.Status.Phase != velerov1api.BackupPhaseCompleted && + backup.Status.Phase != velerov1api.BackupPhaseFailed && + backup.Status.Phase != velerov1api.BackupPhasePartiallyFailed { + fmt.Printf("backup status is %s. Continue polling until backup reach to a final state.\n", backup.Status.Phase) + return false, nil + } + + return true, nil + }) + + return nil +} + +func (n *NodeAgentConfigTestCase) Restore() error { + if err := veleroutil.VeleroCmdExec(n.Ctx, n.VeleroCfg.VeleroCLI, n.RestoreArgs); err != nil { + return err + } + + restorePodList := new(corev1api.PodList) + + wait.PollUntilContextTimeout(n.Ctx, 5*time.Second, 5*time.Minute, true, func(ctx context.Context) (bool, error) { + ddList := new(velerov2alpha1api.DataDownloadList) + if err := n.VeleroCfg.ClientToInstallVelero.Kubebuilder.List( + n.Ctx, + ddList, + &client.ListOptions{Namespace: n.VeleroCfg.VeleroNamespace}, + ); err != nil { + fmt.Printf("Fail to list DataDownload: %s\n", err.Error()) + return false, fmt.Errorf("Fail to list DataDownload %w", err) + } else { + if len(ddList.Items) <= 0 { + fmt.Println("No DataDownload found yet. Continue polling.") + return false, nil + } + } + + if err := n.VeleroCfg.ClientToInstallVelero.Kubebuilder.List( + n.Ctx, + restorePodList, + &client.ListOptions{ + LabelSelector: labels.SelectorFromSet(map[string]string{ + velerov1api.DataDownloadLabel: ddList.Items[0].Name, + }), + }); err != nil { + fmt.Printf("Fail to list restorePod %s\n", err.Error()) + return false, errors.Wrapf(err, "error to list restore pods") + } else { + if len(restorePodList.Items) <= 0 { + fmt.Println("No restorePod found yet. Continue polling.") + return false, nil + } + } + + return true, nil + }) + + fmt.Println("Start to verify restorePod content.") + + Expect(restorePodList.Items[0].Spec.PriorityClassName).To(Equal(n.nodeAgentConfigs.PriorityClassName)) + + // In restore, only the first element of LoadAffinity array should be used. + expectedAffinity := velerokubeutil.ToSystemAffinity(n.nodeAgentConfigs.LoadAffinity[:1]) + + Expect(restorePodList.Items[0].Spec.Affinity).To(Equal(expectedAffinity)) + + fmt.Println("restorePod content verification completed successfully.") + + wait.PollUntilContextTimeout(n.Ctx, 5*time.Second, 5*time.Minute, true, func(ctx context.Context) (bool, error) { + restore := new(velerov1api.Restore) + if err := n.VeleroCfg.ClientToInstallVelero.Kubebuilder.Get( + n.Ctx, + client.ObjectKey{Namespace: n.VeleroCfg.VeleroNamespace, Name: n.RestoreName}, + restore, + ); err != nil { + return false, err + } + + if restore.Status.Phase != velerov1api.RestorePhaseCompleted && + restore.Status.Phase != velerov1api.RestorePhaseFailed && + restore.Status.Phase != velerov1api.RestorePhasePartiallyFailed { + fmt.Printf("restore status is %s. Continue polling until restore reach to a final state.\n", restore.Status.Phase) + return false, nil + } + + return true, nil + }) + + return nil +} diff --git a/test/util/velero/install.go b/test/util/velero/install.go index ca6e207d1..6ffa8812d 100644 --- a/test/util/velero/install.go +++ b/test/util/velero/install.go @@ -163,6 +163,7 @@ func VeleroInstall(ctx context.Context, veleroCfg *test.VeleroConfig, isStandbyC veleroCfg.VeleroNamespace, ) } + veleroCfg.BackupRepoConfigMap = test.BackupRepositoryConfigName // Install the passed-in objects in Velero installed namespace for _, obj := range objects { @@ -654,7 +655,7 @@ func patchResources(resources *unstructured.UnstructuredList, namespace string, APIVersion: corev1api.SchemeGroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ - Name: "restic-restore-action-config", + Name: "fs-restore-action-config", Namespace: namespace, Labels: map[string]string{ "velero.io/plugin-config": "", @@ -671,7 +672,7 @@ func patchResources(resources *unstructured.UnstructuredList, namespace string, return errors.Wrapf(err, "failed to convert restore action config to unstructure") } resources.Items = append(resources.Items, un) - fmt.Printf("the restic restore helper image is set by the configmap %q \n", "restic-restore-action-config") + fmt.Printf("the restic restore helper image is set by the configmap %q \n", "fs-restore-action-config") } return nil From 80da461458b729241346600a1021bcf41b208ff5 Mon Sep 17 00:00:00 2001 From: weeix Date: Thu, 28 Aug 2025 12:33:16 +0700 Subject: [PATCH 024/104] clarify VolumeSnapshotClass error for mismatched driver/provisioner Signed-off-by: weeix --- pkg/util/csi/volume_snapshot.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pkg/util/csi/volume_snapshot.go b/pkg/util/csi/volume_snapshot.go index 7d00664cd..8e59dd69f 100644 --- a/pkg/util/csi/volume_snapshot.go +++ b/pkg/util/csi/volume_snapshot.go @@ -447,8 +447,13 @@ func GetVolumeSnapshotClassForStorageClass( return &vsClass, nil } return nil, fmt.Errorf( - "failed to get VolumeSnapshotClass for provisioner %s, ensure that the desired VolumeSnapshot class has the %s label or %s annotation", - provisioner, velerov1api.VolumeSnapshotClassSelectorLabel, velerov1api.VolumeSnapshotClassKubernetesAnnotation) + "failed to get VolumeSnapshotClass for provisioner %s: "+ + "ensure that the desired VolumeSnapshotClass has the %s label or %s annotation, "+ + "and that its driver matches the StorageClass provisioner", + provisioner, + velerov1api.VolumeSnapshotClassSelectorLabel, + velerov1api.VolumeSnapshotClassKubernetesAnnotation, + ) } // IsVolumeSnapshotClassHasListerSecret returns whether a volumesnapshotclass has a snapshotlister secret From 7132720a496f56e7d65b25f4e3b2fc799566d96e Mon Sep 17 00:00:00 2001 From: Scott Seago Date: Thu, 29 May 2025 15:05:23 -0400 Subject: [PATCH 025/104] Concurrent backup design doc Signed-off-by: Scott Seago --- design/concurrent-backup-processing.md | 257 +++++++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 design/concurrent-backup-processing.md diff --git a/design/concurrent-backup-processing.md b/design/concurrent-backup-processing.md new file mode 100644 index 000000000..76c22c3c0 --- /dev/null +++ b/design/concurrent-backup-processing.md @@ -0,0 +1,257 @@ +# Concurrent Backup Processing + +This enhancement will enable Velero to process multiple backups at the same time. This is largely a usability enhancement rather than a performance enhancement, since the overall backup throughput may not be significantly improved over the current implementation, since we are already processing individual backup items in parallel. It is a significant usability improvement, though, as with the current design, a user who submits a small backup may have to wait significantly longer than expected if the backup is submitted immediately after a large backup. + +## Background + +With the current implementation, only one backup may be `InProgress` at a time. A second backup created will not start processing until the first backup moves on to `WaitingForPluginOperations` or `Finalizing`. This is a usability concern, especially in clusters when multiple users are initiating backups. With this enhancement, we intend to allow multiple backups to be processed concurrently. This will allow backups to start processing immediately, even if a large backup was just submitted by another user. This enhancement will build on top of the prior parallel item processing feature by creating a dedicatede ItemBlock worker pool for each running backup. The pool will be created at the beginning of the backup reconcile, and the input channel will be passed to the Kubernetes backupper just like it is in the current release. + +The primary challenge is to make sure that the same workload in multiple backups is not backed up concurrently. If that were to happen, we would risk data corruption, especially around the processing of pod hooks and volume backup. For this first release we will take a conservative, high-level approach to overlap detection. Two backups will not run concurrently if there is any overlap in included namespaces. For example, if a backup that includes `ns1` and `ns2` is running, then a second backup for `ns2` and `ns3` will not be started. If a backup which does not filter namespaces is running (either a whole cluster backup or a non-namespace-limited backup with a label selector) then no other backups will be started, since a backup across all namespaces overlaps with any other backup. Calculating item-level overlap for queued backups is problematic since we don't know which items are included in a backup until backup processing has begun. A future release may add ItemBlock overlap detection, where at the item block worker level, the same item will not be processed by two different workers at the same time. This works together with workload conflict detection to further detect conflicts in a more granular level for shared resources between backups. Eventually, with a more complete understanding of individual workloads (either via ItemBlocks or some higher level model), the namespace level overlap detection may be relaxed in future versions. + +## Goals +- Process multiple backups concurrently +- Detect namespace overlap to avoid conflicts +- For queued backups (not yet runnable due to concurrency limits or overlap), indicate the queue position in status + +## Non Goals +- Handling NFS PVs when more than one PV point to the same underlying NFS share +- Handling VGDP cancellation for failed backups on restart +- Mounting a PVC for scenarios in which /tmp is too small for the number of concurrent backups +- Providing a mechanism to identify high priority backups which get preferential treatment in terms of ItemBlock worker availability +- Item-level overlap detection (future feature) +- Providing the ability to disable namespace-level overlap detection once Item-level overlap detection is in place (although this may be supported in a future version). + +## High-Level Design + +### Backup CRD changes + +Two new backup phases will be added: `Queued` and `ReadyToStart`. In the Backup workflow, new backups will be moved to the Queued phase when they are added to the backup queue. When a backup is removed from the queue because it is now able to run, it will be moved to the `ReadyToStart` phase, which will allow the backup controller to start processing it. + +In addition, a new Status field, `QueuePosition`, will be added to track the backup's current position in the queue. + +### New Controller: `backupQueueReconciler` + +A new reconciler will be added, `backupQueueReconciler` which will use the current `backupReconciler` logic for reconciling `New` backups but instead of running the backup, it will move the Backup to the `Queued` phase and set `QueuePosition`. + +In addition, this reconciler will periodically reconcile all queued backups (on some configurable time interval) and if there is a runnable backup, remove it from the queue, update `QueuePosition` for any queued backups behind it, and update its phase to `ReadyToStart`. + +Queued backups will be reconciled in order based on `QueuePosition`, so the first runnable backup found will be processed. A backup is runnable if both of the following conditions are true: +1) The total number of backups either `InProgress` or `ReadyToStart` is less than the configured number of concurrent backups. +2) The backup has no overlap with any backups currently `InProgress` or `ReadyToStart` or with any `Queued` backups with a higher (i.e. closer to 1) queue position than this backup. + +### Updates to Backup controller + +The current `backupReconciler` will change its reconciling rules. Instead of watching and reconciling New backups, it will reconcile `ReadyToStart` backups. In addition, it will be configured to run in parallel by setting `MaxConcurrentReconciles` based on the `concurrent-backups` server arg. + +The startup (and shutdown) of the ItemBlock worker pool will be moved from reconciler startup to the backup reconcile, which will give each running backup its own dedicated worker pool. The per-backup worker pool will will use the existing `--item-block-worker-count` installer/server arg. This means that the maximum number of ItemBlock workers for the entire Velero pod will be the ItemBlock worker count multiplied by concurrentBackups. For example, if concurrentBackups is 5, and itemBlockWorkerCount is 6, then there will be, at most, 30 worker threads active, 5 dedicated to each InProgress backup, but this maximum will only be achieved when the maximum number of backups are InProgress. This also means that each InProgress backup will have a dedicated ItemBlock input channel with the same fixed buffer size. + +## Detailed Design + +### New Install/Server configuration args + +A new install/server arg, `concurrent-backups` will be added. This will be an int-valued field specifying the number of backups which may be processed concurrently (with phase `InProgress`). If not specified, the default value of 1 will be used. + +### Consideration of backup overlap and concurrent backup processing + +The primary consideration for running additional backups concurrently is the configured `concurrent-backups` parameter. If the total number of `InProgress` and `ReadyToStart` backups is equal to `concurrent-backups` then any `Queued` backups will remain in the queue. + +The second consideration is backup overlap. In order to prevent interaction between running backups (particularly around volume backup and pod hooks), we cannot allow two overlapping backups to run at the same time. For now, we will define overlap broadly -- requiring that two concurrent backups don't include any of the same namespaces. A backup for `ns1` can run concurrently with a backup for `ns2`, but a backup for `[ns1,ns2]` cannot run concurrently with a backup for `ns1`. One consequence of this approach is that a backup which includes all namespaces (even if further filtered by resource or label) cannot run concurrently with *any other backup*. + +When determining which queued backup to run next, velero will look for the next queued backup which has no overlap with any InProgress backup or any Queued backup ahead of it. The reason we need to consider queued as well as running backups for overlap detection is as follows. + +Consider the following scenario. These are the current not-completed backups (ordered from oldest to newest) +1. backup1, includedNamespaces: [ns1, ns2], phase: InProgress +2. backup2, includedNamespaces: [ns2, ns3, ns5], phase: Queued, QueuePosition: 1 +3. backup3, includedNamespaces: [ns4, ns3], phase: Queued, QueuePosition: 2 +4. backup4, includedNamespaces: [ns5, ns6], phase: Queued, QueuePosition: 2 +5. backup5, includedNamespaces: [ns8, ns9], phase: Queued, QueuePosition: 3 + +Assuming `concurrent-backups` is 2, on the next reconcile, Velero will be able to start a second backup if there is one with no overlap. `backup2` cannot run, since `ns2` overlaps between it and the running `backup1`. If we only considered running overlap (and not queued overlap), then `backup3` could run now. It conflicts with the queued `backup2` on `ns3` but it does not conflict with the running backup. However, if it runs now, then when `backup1` completes, then `backup2` still can't run (since it now overlaps with running `backup3`on `ns3`), so `backup4` starts instead. Now when `backup3` completes, `backup2` still can't run (since it now conflicts with `backup4` on `ns5`). This means that even though it was the second backup created, it's the fourth to run -- providing worse time to completion than without parallel backups. If a queued backup has a large number of namespaces (a full-cluster backup for example), it would never run as long as new single-namespace backups keep being added to the queue. + +To resolve this problem we consider both running backups as well as backups ahead in the queue when resolving overlap conflicts. In the above scenario, `backup2` can't run yet since it overlaps with the running backup on `ns2`. In addition, `backup3` and `backup4` also can't run yet since they overlap with queued `backup2`. Therefore, `backup5` will run now. Once `backup1` completes, `backup2` will be free to run. + +### Backup CRD changes + +New Backup phases: +```go +const ( + // BackupPhaseQueued means the backup has been added to the + // queue by the BackupQueueReconciler. + BackupPhaseQueued BackupPhase = "Queued" + + // BackupPhaseReadyToStart means the backup has been removed from the + // queue by the BackupQueueReconciler and is ready to start. + BackupPhaseReadyToStart BackupPhase = "ReadyToStart" +) +``` + +In addition, a new Status field, `queuePosition`, will be added to track the backup's current position in the queue. +```go + // QueuePosition is the position held by the backup in the queue. + // QueuePosition=1 means this backup is the next to be considered. + // Only relevant when Phase is "Queued" + // +optional + QueuePosition int `json:"queuePosition,omitempty"` +``` + +### New Controller: `backupQueueReconciler` + +A new reconciler will be added, `backupQueueReconciler` which will reconcile backups under these conditions: +1) Watching Create/Update for backups in `New` (or empty) phase +2) Watching for Backup phase transition from `InProgress` to something else to reconcile all `Queued` backups +2) Watching for Backup phase transition from `New` (or empty) to `Queued` to reconcile all `Queued` backups +2) Periodic reconcile of `Queued` backups to handle backups queued at server startup as well as to make sure we never have a situation where backups are queued indefinitely because of a race condition or was otherwise missed in the reconcile on prior backup completion. + +The reconciler will be set up as follows -- note that New backups are reconciled on Create/Update, while Queued backups are reconciled when an InProgress backup moves on to another state or when a new backup moves to the Queued state. We also reconcile Queued backups periodically to handle the case of a Velero pod restart with Queued backups, as well as to handle possible edge cases where a queued backup doesn't get moved out of the queue at the point of backup completion or an error occurs during a prior Queued backup reconcile. + +```go +func (c *backupOperationsReconciler) SetupWithManager(mgr ctrl.Manager) error { + // only consider Queued backups, order by QueuePosition + gp := kube.NewGenericEventPredicate(func(object client.Object) bool { + backup := object.(*velerov1api.Backup) + return (backup.Status.Phase == velerov1api.BackupPhaseQueued) + }) + s := kube.NewPeriodicalEnqueueSource(c.logger.WithField("controller", constant.ControllerBackupOperations), mgr.GetClient(), &velerov1api.BackupList{}, c.frequency, kube.PeriodicalEnqueueSourceOption{ + Predicates: []predicate.Predicate{gp}, + OrderFunc: queuePositionOrderFunc, + }) + + return ctrl.NewControllerManagedBy(mgr). + For(&velerov1api.Backup{}, builder.WithPredicates(predicate.Funcs{ + UpdateFunc: func(ue event.UpdateEvent) bool { + backup := ue.ObjectNew.(*velerov1api.Backup) + return backup.Status.Phase == "" || backup.status.Phase == velerov1api.BackupPhaseNew + }, + CreateFunc: func(event.CreateEvent) bool { + return backup.Status.Phase == "" || backup.status.Phase == velerov1api.BackupPhaseNew + }, + DeleteFunc: func(de event.DeleteEvent) bool { + return false + }, + GenericFunc: func(ge event.GenericEvent) bool { + return false + }, + })). + Watch( + &source.Kind{Type: &velerov1api.Backup{}}, + &handler.EnqueueRequestsFromMapFunc{ + ToRequests: handler.ToRequestsFunc(func(a handler.MapObject) []reconcile.Request { + backupList := velerov1api.BackupList{} + if err := p.List(ctx, backupList); err != nil { + p.logger.WithError(err).Error("error listing backups") + return + } + requests = []reconcile.request{} + // filter backup list by Phase=queued + // sort backup list by queuePosition + return requests + }), + }, + builder.WithPredicates(predicate.Funcs{ + UpdateFunc: func(ue event.UpdateEvent) bool { + oldBackup := ue.ObjectOld.(*velerov1api.Backup) + newBackup := ue.ObjectNew.(*velerov1api.Backup) + return oldBackup.Status.Phase == velerov1api.BackupPhaseInProgress && + newBackup.Status.Phase != velerov1api.BackupPhaseInProgress || + oldBackup.Status.Phase != velerov1api.BackupPhaseQueued && + newBackup.Status.Phase == velerov1api.BackupPhaseQueued + }, + CreateFunc: func(event.CreateEvent) bool { + return false + }, + DeleteFunc: func(de event.DeleteEvent) bool { + return false + }, + GenericFunc: func(ge event.GenericEvent) bool { + return false + }, + }). + WatchesRawSource(s). + Named(constant.ControllerBackupQueue). + Complete(c) +} +``` + +New backups will be queued: Phase will be set to `Queued`, and `QueuePosition` will be set to a int value incremented from the highest current `QueuePosition` value among Queued backups. + +Queued backups will be removed from the queue if runnable: +1) If the total number of backups either InProgress or ReadyToStart is greater than or equal to the concurrency limit, then exit without removing from the queue. +2) If the current backup overlaps with any InProgress, ReadyToStart, or Queued backup with `QueuePosition < currentBackup.QueuePosition` then exit without removing from the queue. +3) If we get here, the backup is runnable. To resolve a potential race condition where an InProgress backup completes between reconciling the backup with QueuePosition `n-1` and reconciling the current backup with QueuePosition `n`, we also check to see whether there are any runnable backups in the queue ahead of this one. The only time this will happen is if a backup completes immediately before reconcile starts which either frees up a concurrency slot or removes a namespace conflict. In this case, we don't want to run the current backup since the one ahead of this one in the queue (which was recently passed over before the InProgress backup completed) must run first. In this case, exit without removing from the queue. +4) If we get here, remove the backup from the queue by setting Phase to `ReadyToStart` and `QueuePosition` to zero. Decrement the `QueuePosition` of any other Queued backups with a `QueuePosition` higher than the current backup's queue position prior to dequeuing. At this point, the backup reconciler will start the backup. + +`if len(inProgressBackups)+len(pendingStartBackups) >= concurrentBackups` + +``` + switch original.Status.Phase { + case "", velerov1api.BackupPhaseNew: + // enqueue backup -- set phase=Queued, set queuePosition=maxCurrentQueuePosition+1 + } + // We should only ever get these events when added in order by the periodical enqueue source + // so as long as the current backup has not conflicts ahead of it or running, we should be good to + // dequeue + case "", velerov1api.BackupPhaseQueued: + // list backups, filter on Queued, ReadyToStart, and InProgress + // if number of InProgress backups + number of ReadyToStart backups >= concurrency limit, exit + // generate list of all namespaces included in InProgress, ReadyToStart, and Queued backups with + // queuePosition < backup.Status.QueuePosition + // if overlap found, exit + // check backups ahead of this one in the queue for runnability. If any are runnable, exit + // dequeue backup: set Phase to ReadyToStart, QueuePosition to 0, and decrement QueuePosition + // for all QueuedBackups behind this one in the queue + } + +``` + +The queue controller will run as a single reconciler thread, so we will not need to deal with concurrency issues when moving backups from New to Queued or from Queued to ReadyToStart, and all of the updates to QueuePosition will be from a single thread. + +### Updates to Backup controller + +The Reconcile logic will be updated to respond to ReadyToStart backups instead of New backups: + +``` +@@ -234,8 +234,8 @@ func (b *backupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr + // InProgress, we still need this check so we can return nil to indicate we've finished processing + // this key (even though it was a no-op). + switch original.Status.Phase { +- case "", velerov1api.BackupPhaseNew: +- // only process new backups ++ case velerov1api.BackupPhaseReadyToStart: ++ // only process ReadyToStart backups + default: + b.logger.WithFields(logrus.Fields{ + "backup": kubeutil.NamespaceAndName(original), +``` + +In addition, it will be configured to run in parallel by setting `MaxConcurrentReconciles` based on the `concurrent-backups` server arg. + +``` +@@ -149,6 +149,9 @@ func NewBackupReconciler( + func (b *backupReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&velerov1api.Backup{}). ++ WithOptions(controller.Options{ ++ MaxConcurrentReconciles: concurrentBackups, ++ }). + Named(constant.ControllerBackup). + Complete(b) + } +``` + +The controller-runtime core reconciler logic already prevents the same resource from being reconciled by two different reconciler threads, so we don't need to worry about concurrency issues at the controller level. + +The workerPool reference will be moved from the backupReconciler to the backupRequest, since this will now be backup-specific, and the initialization code for the worker pool will be moved from the reconciler init into the backup reconcile. This worker pool will be shut down upon exiting the Reconcile method. + +### Resilience to restart of velero pod + +The new backup phases (`Queued` and `ReadyToStart`) will be resilient to velero pod restarts. If the velero pod crashes or is restarted, only backups in the `InProgress` phase will be failed, so there is no change to current behavior. Queued backups will retain their queue position on restart, and ReadyToStart backups will move to InProgress when reconciled. + +### Observability + +#### Logging + +When a backup is dequeued, an info log message will also include the wait time, calculated as `now - creationTimestamp`. When a backup is passed over due to overlap, an info log message will indicate which namespaces were in conflict. + +#### Velero CLI + +The `velero backup describe` output will include the current queue position for queued backups. From 2a9203f1b26105b43e9a030046043189f2f7431a Mon Sep 17 00:00:00 2001 From: Scott Seago Date: Thu, 4 Sep 2025 18:35:53 -0400 Subject: [PATCH 026/104] Get pod list once per namespace in pvc IBA Signed-off-by: Scott Seago --- changelogs/unreleased/9226-sseago | 1 + pkg/itemblock/actions/pvc_action.go | 62 +++++++++++++++++++---------- 2 files changed, 41 insertions(+), 22 deletions(-) create mode 100644 changelogs/unreleased/9226-sseago diff --git a/changelogs/unreleased/9226-sseago b/changelogs/unreleased/9226-sseago new file mode 100644 index 000000000..fe67d4cbf --- /dev/null +++ b/changelogs/unreleased/9226-sseago @@ -0,0 +1 @@ +Get pod list once per namespace in pvc IBA diff --git a/pkg/itemblock/actions/pvc_action.go b/pkg/itemblock/actions/pvc_action.go index b5d7074af..6777ef566 100644 --- a/pkg/itemblock/actions/pvc_action.go +++ b/pkg/itemblock/actions/pvc_action.go @@ -39,6 +39,8 @@ import ( type PVCAction struct { log logrus.FieldLogger crClient crclient.Client + // map[namespace]->[map[pvcVolumes]->[]podName] + nsPVCs map[string]map[string][]string } func NewPVCAction(f client.Factory) plugincommon.HandlerInitializer { @@ -78,31 +80,18 @@ func (a *PVCAction) GetRelatedItems(item runtime.Unstructured, backup *v1.Backup // Adds pods mounting this PVC to ensure that multiple pods mounting the same RWX // volume get backed up together. - pods := new(corev1api.PodList) - err := a.crClient.List(context.Background(), pods, crclient.InNamespace(pvc.Namespace)) + pvcs, err := a.getPVCList(pvc.Namespace) if err != nil { - return nil, errors.Wrap(err, "failed to list pods") + return nil, err } - for i := range pods.Items { - for _, volume := range pods.Items[i].Spec.Volumes { - if volume.VolumeSource.PersistentVolumeClaim == nil { - continue - } - if volume.PersistentVolumeClaim.ClaimName == pvc.Name { - if kube.IsPodRunning(&pods.Items[i]) != nil { - a.log.Infof("Related pod %s is not running, not adding to ItemBlock for PVC %s", pods.Items[i].Name, pvc.Name) - } else { - a.log.Infof("Adding related Pod %s to PVC %s", pods.Items[i].Name, pvc.Name) - relatedItems = append(relatedItems, velero.ResourceIdentifier{ - GroupResource: kuberesource.Pods, - Namespace: pods.Items[i].Namespace, - Name: pods.Items[i].Name, - }) - } - break - } - } + for _, pod := range pvcs[pvc.Name] { + a.log.Infof("Adding related Pod %s to PVC %s", pod, pvc.Name) + relatedItems = append(relatedItems, velero.ResourceIdentifier{ + GroupResource: kuberesource.Pods, + Namespace: pvc.Namespace, + Name: pod, + }) } // Gather groupedPVCs based on VGS label provided in the backup @@ -117,6 +106,35 @@ func (a *PVCAction) GetRelatedItems(item runtime.Unstructured, backup *v1.Backup return relatedItems, nil } +func (a *PVCAction) getPVCList(ns string) (map[string][]string, error) { + if a.nsPVCs == nil { + a.nsPVCs = make(map[string]map[string][]string) + } + pvcList, ok := a.nsPVCs[ns] + if ok { + return pvcList, nil + } + pvcList = make(map[string][]string) + pods := new(corev1api.PodList) + err := a.crClient.List(context.Background(), pods, crclient.InNamespace(ns)) + if err != nil { + return nil, errors.Wrap(err, "failed to list pods") + } + for i := range pods.Items { + if kube.IsPodRunning(&pods.Items[i]) != nil { + a.log.Debugf("Pod %s is not running, not adding to Pod list for PVC IBA plugin", pods.Items[i].Name) + continue + } + for _, volume := range pods.Items[i].Spec.Volumes { + if volume.VolumeSource.PersistentVolumeClaim != nil { + pvcList[volume.VolumeSource.PersistentVolumeClaim.ClaimName] = append(pvcList[volume.VolumeSource.PersistentVolumeClaim.ClaimName], pods.Items[i].Name) + } + } + } + a.nsPVCs[ns] = pvcList + return pvcList, nil +} + func (a *PVCAction) Name() string { return "PVCItemBlockAction" } From 4c30499340c38dce005181aa47fe33d6541a8b79 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Wed, 10 Sep 2025 17:28:23 +0800 Subject: [PATCH 027/104] Add v1.34.0 for v1.17 compatible k8s versions. Signed-off-by: Xun Jiang --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d5318873..046e55c91 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ The following is a list of the supported Kubernetes versions for each Velero ver | Velero version | Expected Kubernetes version compatibility | Tested on Kubernetes version | |----------------|-------------------------------------------|-------------------------------------| -| 1.17 | 1.18-latest | 1.31.7, 1.32.3, and 1.33.1 | +| 1.17 | 1.18-latest | 1.31.7, 1.32.3, 1.33.1, and 1.34.0 | | 1.16 | 1.18-latest | 1.31.4, 1.32.3, and 1.33.0 | | 1.15 | 1.18-latest | 1.28.8, 1.29.8, 1.30.4 and 1.31.1 | | 1.14 | 1.18-latest | 1.27.9, 1.28.9, and 1.29.4 | From e8208097ba68be79e5cbd92b9d6e5a1dee13d344 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Mon, 8 Sep 2025 11:18:32 +0800 Subject: [PATCH 028/104] Bump k8s library to v1.33. Replace deprecated EventExpansion method with WithContext methods. Modify UTs. Align the E2E ginkgo CLI version with go.mod Signed-off-by: Xun Jiang --- go.mod | 56 +++++----- go.sum | 102 +++++++++--------- .../backup_repository_controller_test.go | 4 +- pkg/repository/ensurer_test.go | 8 +- .../maintenance/maintenance_test.go | 4 +- pkg/util/kube/event.go | 7 +- test/Makefile | 2 +- 7 files changed, 94 insertions(+), 89 deletions(-) diff --git a/go.mod b/go.mod index 033773e82..9eeda4bfb 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/vmware-tanzu/velero -go 1.24 +go 1.24.0 require ( cloud.google.com/go/storage v1.55.0 @@ -17,7 +17,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/s3 v1.48.0 github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 github.com/bombsimon/logrusr/v3 v3.0.0 - github.com/evanphx/json-patch/v5 v5.9.0 + github.com/evanphx/json-patch/v5 v5.9.11 github.com/fatih/color v1.18.0 github.com/gobwas/glob v0.2.3 github.com/google/go-cmp v0.7.0 @@ -27,8 +27,8 @@ require ( github.com/joho/godotenv v1.3.0 github.com/kopia/kopia v0.16.0 github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0 - github.com/onsi/ginkgo/v2 v2.19.0 - github.com/onsi/gomega v1.33.1 + github.com/onsi/ginkgo/v2 v2.22.0 + github.com/onsi/gomega v1.36.1 github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.22.0 @@ -49,17 +49,17 @@ require ( google.golang.org/grpc v1.73.0 google.golang.org/protobuf v1.36.6 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.31.3 - k8s.io/apiextensions-apiserver v0.31.3 - k8s.io/apimachinery v0.31.3 - k8s.io/cli-runtime v0.31.3 - k8s.io/client-go v0.31.3 + k8s.io/api v0.33.3 + k8s.io/apiextensions-apiserver v0.33.3 + k8s.io/apimachinery v0.33.3 + k8s.io/cli-runtime v0.33.3 + k8s.io/client-go v0.33.3 k8s.io/klog/v2 v2.130.1 - k8s.io/kube-aggregator v0.31.3 - k8s.io/metrics v0.31.3 - k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 - sigs.k8s.io/controller-runtime v0.19.3 - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd + k8s.io/kube-aggregator v0.33.3 + k8s.io/metrics v0.33.3 + k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 + sigs.k8s.io/controller-runtime v0.21.0 + sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 sigs.k8s.io/yaml v1.4.0 ) @@ -72,7 +72,7 @@ require ( cloud.google.com/go/iam v1.5.2 // indirect cloud.google.com/go/monitoring v1.24.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 // indirect @@ -91,6 +91,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.6 // indirect github.com/aws/smithy-go v1.19.0 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chmduquesne/rollinghash v4.0.0+incompatible // indirect github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f // indirect @@ -101,32 +102,31 @@ require ( github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-ini/ini v1.67.0 // indirect github.com/go-jose/go-jose/v4 v4.0.5 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.4 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/gofrs/flock v0.12.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af // indirect + github.com/google/btree v1.1.3 // indirect + github.com/google/gnostic-models v0.6.9 // indirect + github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect github.com/googleapis/gax-go/v2 v2.14.2 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/hashicorp/cronexpr v1.1.2 // indirect github.com/hashicorp/yamux v0.1.1 // indirect - github.com/imdario/mergo v0.3.13 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -144,7 +144,7 @@ require ( github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/minio-go/v7 v7.0.94 // indirect github.com/mitchellh/go-testing-interface v1.0.0 // indirect - github.com/moby/spdystream v0.4.0 // indirect + github.com/moby/spdystream v0.5.0 // indirect github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -181,7 +181,7 @@ require ( go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.40.0 // indirect - golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/sync v0.16.0 // indirect golang.org/x/sys v0.34.0 // indirect golang.org/x/term v0.33.0 // indirect @@ -193,9 +193,9 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect ) replace github.com/kopia/kopia => github.com/project-velero/kopia v0.0.0-20250722052735-3ea24d208777 diff --git a/go.sum b/go.sum index 99f7a87ee..b9a742d4c 100644 --- a/go.sum +++ b/go.sum @@ -84,8 +84,8 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.0/go.mod h1:DWAciXemNf++PQJLeXUB4HHH5OpsAh12HZnu2wXE1jA= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1 h1:lhZdRq7TIx0GJQvSyX2Si406vrYsov2FXGp/RnSEtcs= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1/go.mod h1:8cl44BDmi+effbARHMQjgOKA2AYvcohNm7KEt42mSV8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= @@ -170,6 +170,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bombsimon/logrusr/v3 v3.0.0 h1:tcAoLfuAhKP9npBxWzSdpsvKPQt1XV02nSf2lZA82TQ= github.com/bombsimon/logrusr/v3 v3.0.0/go.mod h1:PksPPgSFEL2I52pla2glgCyyd2OqOHAnFF5E+g8Ixco= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= @@ -239,8 +241,8 @@ github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2T github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= -github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= +github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= @@ -282,8 +284,9 @@ github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= @@ -291,8 +294,8 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= @@ -318,7 +321,6 @@ github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -350,8 +352,10 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= +github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -389,8 +393,8 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= -github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= @@ -413,8 +417,8 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -455,8 +459,6 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= @@ -550,8 +552,8 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= -github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= +github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -584,13 +586,13 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= -github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= +github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= +github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= @@ -804,8 +806,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1206,7 +1208,6 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1217,47 +1218,50 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= -k8s.io/api v0.31.3 h1:umzm5o8lFbdN/hIXbrK9oRpOproJO62CV1zqxXrLgk8= -k8s.io/api v0.31.3/go.mod h1:UJrkIp9pnMOI9K2nlL6vwpxRzzEX5sWgn8kGQe92kCE= -k8s.io/apiextensions-apiserver v0.31.3 h1:+GFGj2qFiU7rGCsA5o+p/rul1OQIq6oYpQw4+u+nciE= -k8s.io/apiextensions-apiserver v0.31.3/go.mod h1:2DSpFhUZZJmn/cr/RweH1cEVVbzFw9YBu4T+U3mf1e4= +k8s.io/api v0.33.3 h1:SRd5t//hhkI1buzxb288fy2xvjubstenEKL9K51KBI8= +k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE= +k8s.io/apiextensions-apiserver v0.33.3 h1:qmOcAHN6DjfD0v9kxL5udB27SRP6SG/MTopmge3MwEs= +k8s.io/apiextensions-apiserver v0.33.3/go.mod h1:oROuctgo27mUsyp9+Obahos6CWcMISSAPzQ77CAQGz8= k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= -k8s.io/apimachinery v0.31.3 h1:6l0WhcYgasZ/wk9ktLq5vLaoXJJr5ts6lkaQzgeYPq4= -k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA= +k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= k8s.io/cli-runtime v0.22.2/go.mod h1:tkm2YeORFpbgQHEK/igqttvPTRIHFRz5kATlw53zlMI= -k8s.io/cli-runtime v0.31.3 h1:fEQD9Xokir78y7pVK/fCJN090/iYNrLHpFbGU4ul9TI= -k8s.io/cli-runtime v0.31.3/go.mod h1:Q2jkyTpl+f6AtodQvgDI8io3jrfr+Z0LyQBPJJ2Btq8= +k8s.io/cli-runtime v0.33.3 h1:Dgy4vPjNIu8LMJBSvs8W0LcdV0PX/8aGG1DA1W8lklA= +k8s.io/cli-runtime v0.33.3/go.mod h1:yklhLklD4vLS8HNGgC9wGiuHWze4g7x6XQZ+8edsKEo= k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= -k8s.io/client-go v0.31.3 h1:CAlZuM+PH2cm+86LOBemaJI/lQ5linJ6UFxKX/SoG+4= -k8s.io/client-go v0.31.3/go.mod h1:2CgjPUTpv3fE5dNygAr2NcM8nhHzXvxB8KL5gYc3kJs= +k8s.io/client-go v0.33.3 h1:M5AfDnKfYmVJif92ngN532gFqakcGi6RvaOF16efrpA= +k8s.io/client-go v0.33.3/go.mod h1:luqKBQggEf3shbxHY4uVENAxrDISLOarxpTKMiUuujg= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-aggregator v0.31.3 h1:DqHPdTglJHgOfB884AaroyxrML/aL82ASYOh65m7MSk= -k8s.io/kube-aggregator v0.31.3/go.mod h1:Kx59Xjnf0SnY47qf9Or++4y3XCHQ3kR0xk1Di6KFiFU= +k8s.io/kube-aggregator v0.33.3 h1:Pa6hQpKJMX0p0D2wwcxXJgu02++gYcGWXoW1z1ZJDfo= +k8s.io/kube-aggregator v0.33.3/go.mod h1:hwvkUoQ8q6gv0+SgNnlmQ3eUue1zHhJKTHsX7BwxwSE= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/metrics v0.31.3 h1:DkT9I3gFlb2/z+/4BMY7WrQ/PnbukuV4Yli82v/KBCM= -k8s.io/metrics v0.31.3/go.mod h1:2w9gpd8z+13oJmaPR6p3kDyrDqnxSyoKpnOw2qLIdhI= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= +k8s.io/metrics v0.33.3 h1:9CcqBz15JZfISqwca33gdHS8I6XfsK1vA8WUdEnG70g= +k8s.io/metrics v0.33.3/go.mod h1:Aw+cdg4AYHw0HvUY+lCyq40FOO84awrqvJRTw0cmXDs= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/controller-runtime v0.19.3 h1:XO2GvC9OPftRst6xWCpTgBZO04S2cbp0Qqkj8bX1sPw= -sigs.k8s.io/controller-runtime v0.19.3/go.mod h1:j4j87DqtsThvwTv5/Tc5NFRyyF/RF0ip4+62tbTSIUM= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8= +sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= sigs.k8s.io/kustomize/api v0.8.11/go.mod h1:a77Ls36JdfCWojpUqR6m60pdGY1AYFix4AH83nJtY1g= sigs.k8s.io/kustomize/kyaml v0.11.0/go.mod h1:GNMwjim4Ypgp/MueD3zXHLRJEjz7RvtPae0AwlvEMFM= +sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/pkg/controller/backup_repository_controller_test.go b/pkg/controller/backup_repository_controller_test.go index b8de27539..0a4a04610 100644 --- a/pkg/controller/backup_repository_controller_test.go +++ b/pkg/controller/backup_repository_controller_test.go @@ -1047,7 +1047,7 @@ func TestRecallMaintenance(t *testing.T) { { name: "wait completion error", runtimeScheme: schemeFail, - expectedErr: "error waiting incomplete repo maintenance job for repo repo: error listing maintenance job for repo repo: no kind is registered for the type v1.JobList in scheme \"pkg/runtime/scheme.go:100\"", + expectedErr: "error waiting incomplete repo maintenance job for repo repo: error listing maintenance job for repo repo: no kind is registered for the type v1.JobList in scheme", }, { name: "no consolidate result", @@ -1105,7 +1105,7 @@ func TestRecallMaintenance(t *testing.T) { err := r.recallMaintenance(t.Context(), backupRepo, velerotest.NewLogger()) if test.expectedErr != "" { - assert.EqualError(t, err, test.expectedErr) + assert.ErrorContains(t, err, test.expectedErr) } else { assert.NoError(t, err) diff --git a/pkg/repository/ensurer_test.go b/pkg/repository/ensurer_test.go index 4003aa369..b2d60eb21 100644 --- a/pkg/repository/ensurer_test.go +++ b/pkg/repository/ensurer_test.go @@ -81,7 +81,7 @@ func TestEnsureRepo(t *testing.T) { namespace: "fake-ns", bsl: "fake-bsl", repositoryType: "fake-repo-type", - err: "error getting backup repository list: no kind is registered for the type v1.BackupRepositoryList in scheme \"pkg/runtime/scheme.go:100\"", + err: "error getting backup repository list: no kind is registered for the type v1.BackupRepositoryList in scheme", }, { name: "success on existing repo", @@ -128,7 +128,7 @@ func TestEnsureRepo(t *testing.T) { repo, err := ensurer.EnsureRepo(t.Context(), velerov1.DefaultNamespace, test.namespace, test.bsl, test.repositoryType) if err != nil { - require.EqualError(t, err, test.err) + require.ErrorContains(t, err, test.err) } else { require.NoError(t, err) } @@ -190,7 +190,7 @@ func TestCreateBackupRepositoryAndWait(t *testing.T) { namespace: "fake-ns", bsl: "fake-bsl", repositoryType: "fake-repo-type", - err: "unable to create backup repository resource: no kind is registered for the type v1.BackupRepository in scheme \"pkg/runtime/scheme.go:100\"", + err: "unable to create backup repository resource: no kind is registered for the type v1.BackupRepository in scheme", }, { name: "get repo fail", @@ -252,7 +252,7 @@ func TestCreateBackupRepositoryAndWait(t *testing.T) { RepositoryType: test.repositoryType, }) if err != nil { - require.EqualError(t, err, test.err) + require.ErrorContains(t, err, test.err) } else { require.NoError(t, err) } diff --git a/pkg/repository/maintenance/maintenance_test.go b/pkg/repository/maintenance/maintenance_test.go index 3dd12e5fa..925a94043 100644 --- a/pkg/repository/maintenance/maintenance_test.go +++ b/pkg/repository/maintenance/maintenance_test.go @@ -698,7 +698,7 @@ func TestWaitAllJobsComplete(t *testing.T) { { name: "list job error", runtimeScheme: schemeFail, - expectedError: "error listing maintenance job for repo fake-repo: no kind is registered for the type v1.JobList in scheme \"pkg/runtime/scheme.go:100\"", + expectedError: "error listing maintenance job for repo fake-repo: no kind is registered for the type v1.JobList in scheme", }, { name: "job not exist", @@ -847,7 +847,7 @@ func TestWaitAllJobsComplete(t *testing.T) { history, err := WaitAllJobsComplete(test.ctx, fakeClient, repo, 3, velerotest.NewLogger()) if test.expectedError != "" { - require.EqualError(t, err, test.expectedError) + require.ErrorContains(t, err, test.expectedError) } else { require.NoError(t, err) } diff --git a/pkg/util/kube/event.go b/pkg/util/kube/event.go index a216853cd..ae514f4da 100644 --- a/pkg/util/kube/event.go +++ b/pkg/util/kube/event.go @@ -16,6 +16,7 @@ limitations under the License. package kube import ( + "context" "math" "sync" "time" @@ -182,13 +183,13 @@ func (es *eventSink) Create(event *corev1api.Event) (*corev1api.Event, error) { return event, nil } - return es.sink.CreateWithEventNamespace(event) + return es.sink.CreateWithEventNamespaceWithContext(context.Background(), event) } func (es *eventSink) Update(event *corev1api.Event) (*corev1api.Event, error) { - return es.sink.UpdateWithEventNamespace(event) + return es.sink.UpdateWithEventNamespaceWithContext(context.Background(), event) } func (es *eventSink) Patch(event *corev1api.Event, data []byte) (*corev1api.Event, error) { - return es.sink.PatchWithEventNamespace(event, data) + return es.sink.PatchWithEventNamespaceWithContext(context.Background(), event, data) } diff --git a/test/Makefile b/test/Makefile index 4eb6103e5..e24efce95 100644 --- a/test/Makefile +++ b/test/Makefile @@ -184,7 +184,7 @@ ginkgo: ${GOBIN}/ginkgo # This target does not run if ginkgo is already in $GOBIN ${GOBIN}/ginkgo: - GOBIN=${GOBIN} go install github.com/onsi/ginkgo/v2/ginkgo@v2.19.0 + GOBIN=${GOBIN} go install github.com/onsi/ginkgo/v2/ginkgo@v2.22.0 .PHONY: run-e2e run-e2e: ginkgo From 02edbc0c6535e08df54277d59fd7fd9b62d2fc5e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Sep 2025 16:44:18 -0500 Subject: [PATCH 029/104] Bump actions/stale from 9.1.0 to 10.0.0 (#9232) Bumps [actions/stale](https://github.com/actions/stale) from 9.1.0 to 10.0.0. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v9.1.0...v10.0.0) --- updated-dependencies: - dependency-name: actions/stale dependency-version: 10.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/stale-issues.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale-issues.yml b/.github/workflows/stale-issues.yml index 5fe397ba8..8f94ea65b 100644 --- a/.github/workflows/stale-issues.yml +++ b/.github/workflows/stale-issues.yml @@ -7,7 +7,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v9.1.0 + - uses: actions/stale@v10.0.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: "This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 14 days. If a Velero team member has requested log or more information, please provide the output of the shared commands." From 81c5b6692d13d000b7d78068fd711bc2d9f66cdd Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Tue, 9 Sep 2025 14:00:59 +0800 Subject: [PATCH 030/104] backupPVC to different node Signed-off-by: Lyndon-Li --- changelogs/unreleased/9233-Lyndon-Li | 1 + pkg/controller/data_upload_controller.go | 9 ++ pkg/exposer/csi_snapshot.go | 30 +++++ pkg/exposer/csi_snapshot_priority_test.go | 2 + pkg/exposer/csi_snapshot_test.go | 136 ++++++++++++++++++++++ pkg/util/kube/pvc_pv.go | 16 +++ pkg/util/third_party.go | 4 + 7 files changed, 198 insertions(+) create mode 100644 changelogs/unreleased/9233-Lyndon-Li diff --git a/changelogs/unreleased/9233-Lyndon-Li b/changelogs/unreleased/9233-Lyndon-Li new file mode 100644 index 000000000..492765e63 --- /dev/null +++ b/changelogs/unreleased/9233-Lyndon-Li @@ -0,0 +1 @@ +Fix issue #9229, add intolerateSourceNode backupPVC option \ No newline at end of file diff --git a/pkg/controller/data_upload_controller.go b/pkg/controller/data_upload_controller.go index d0467a843..46704e5b1 100644 --- a/pkg/controller/data_upload_controller.go +++ b/pkg/controller/data_upload_controller.go @@ -916,6 +916,13 @@ func (r *DataUploadReconciler) setupExposeParam(du *velerov2alpha1api.DataUpload return nil, errors.Wrapf(err, "failed to get PVC %s/%s", du.Spec.SourceNamespace, du.Spec.SourcePVC) } + pv := &corev1api.PersistentVolume{} + if err := r.client.Get(context.Background(), types.NamespacedName{ + Name: pvc.Spec.VolumeName, + }, pv); err != nil { + return nil, errors.Wrapf(err, "failed to get source PV %s", pvc.Spec.VolumeName) + } + nodeOS := kube.GetPVCAttachingNodeOS(pvc, r.kubeClient.CoreV1(), r.kubeClient.StorageV1(), log) if err := kube.HasNodeWithOS(context.Background(), nodeOS, r.kubeClient.CoreV1()); err != nil { @@ -963,6 +970,8 @@ func (r *DataUploadReconciler) setupExposeParam(du *velerov2alpha1api.DataUpload return &exposer.CSISnapshotExposeParam{ SnapshotName: du.Spec.CSISnapshot.VolumeSnapshot, SourceNamespace: du.Spec.SourceNamespace, + SourcePVCName: pvc.Name, + SourcePVName: pv.Name, StorageClass: du.Spec.CSISnapshot.StorageClass, HostingPodLabels: hostingPodLabels, HostingPodAnnotations: hostingPodAnnotation, diff --git a/pkg/exposer/csi_snapshot.go b/pkg/exposer/csi_snapshot.go index 531330f62..50b7c976f 100644 --- a/pkg/exposer/csi_snapshot.go +++ b/pkg/exposer/csi_snapshot.go @@ -35,6 +35,7 @@ import ( "github.com/vmware-tanzu/velero/pkg/nodeagent" velerotypes "github.com/vmware-tanzu/velero/pkg/types" + "github.com/vmware-tanzu/velero/pkg/util" "github.com/vmware-tanzu/velero/pkg/util/boolptr" "github.com/vmware-tanzu/velero/pkg/util/csi" "github.com/vmware-tanzu/velero/pkg/util/kube" @@ -48,6 +49,12 @@ type CSISnapshotExposeParam struct { // SourceNamespace is the original namespace of the volume that the snapshot is taken for SourceNamespace string + // SourcePVCName is the original name of the PVC that the snapshot is taken for + SourcePVCName string + + // SourcePVCName is the name of PV for SourcePVC + SourcePVName string + // AccessMode defines the mode to access the snapshot AccessMode string @@ -189,6 +196,7 @@ func (e *csiSnapshotExposer) Expose(ctx context.Context, ownerObject corev1api.O backupPVCReadOnly := false spcNoRelabeling := false backupPVCAnnotations := map[string]string{} + intoleratableNodes := []string{} if value, exists := csiExposeParam.BackupPVCConfig[csiExposeParam.StorageClass]; exists { if value.StorageClass != "" { backupPVCStorageClass = value.StorageClass @@ -206,6 +214,14 @@ func (e *csiSnapshotExposer) Expose(ctx context.Context, ownerObject corev1api.O if len(value.Annotations) > 0 { backupPVCAnnotations = value.Annotations } + + if _, found := backupPVCAnnotations[util.VSphereCNSFastCloneAnno]; found { + if n, err := kube.GetPVAttachedNodes(ctx, csiExposeParam.SourcePVName, e.kubeClient.StorageV1()); err != nil { + curLog.WithField("source PV", csiExposeParam.SourcePVName).WithError(err).Warn("Failed to get attached node for source PV, ignore intolerable nodes") + } else { + intoleratableNodes = n + } + } } backupPVC, err := e.createBackupPVC(ctx, ownerObject, backupVS.Name, backupPVCStorageClass, csiExposeParam.AccessMode, volumeSize, backupPVCReadOnly, backupPVCAnnotations) @@ -236,6 +252,7 @@ func (e *csiSnapshotExposer) Expose(ctx context.Context, ownerObject corev1api.O spcNoRelabeling, csiExposeParam.NodeOS, csiExposeParam.PriorityClassName, + intoleratableNodes, ) if err != nil { return errors.Wrap(err, "error to create backup pod") @@ -564,6 +581,7 @@ func (e *csiSnapshotExposer) createBackupPod( spcNoRelabeling bool, nodeOS string, priorityClassName string, + intoleratableNodes []string, ) (*corev1api.Pod, error) { podName := ownerObject.Name @@ -664,6 +682,18 @@ func (e *csiSnapshotExposer) createBackupPod( } var podAffinity *corev1api.Affinity + if len(intoleratableNodes) > 0 { + if affinity == nil { + affinity = &kube.LoadAffinity{} + } + + affinity.NodeSelector.MatchExpressions = append(affinity.NodeSelector.MatchExpressions, metav1.LabelSelectorRequirement{ + Key: "kubernetes.io/hostname", + Values: intoleratableNodes, + Operator: metav1.LabelSelectorOpNotIn, + }) + } + if affinity != nil { podAffinity = kube.ToSystemAffinity([]*kube.LoadAffinity{affinity}) } diff --git a/pkg/exposer/csi_snapshot_priority_test.go b/pkg/exposer/csi_snapshot_priority_test.go index 236d15acb..345d5b327 100644 --- a/pkg/exposer/csi_snapshot_priority_test.go +++ b/pkg/exposer/csi_snapshot_priority_test.go @@ -153,6 +153,7 @@ func TestCreateBackupPodWithPriorityClass(t *testing.T) { false, // spcNoRelabeling kube.NodeOSLinux, tc.expectedPriorityClass, + nil, ) require.NoError(t, err, tc.description) @@ -237,6 +238,7 @@ func TestCreateBackupPodWithMissingConfigMap(t *testing.T) { false, // spcNoRelabeling kube.NodeOSLinux, "", // empty priority class since config map is missing + nil, ) // Should succeed even when config map is missing diff --git a/pkg/exposer/csi_snapshot_test.go b/pkg/exposer/csi_snapshot_test.go index 9bb4b95b8..95e5789e7 100644 --- a/pkg/exposer/csi_snapshot_test.go +++ b/pkg/exposer/csi_snapshot_test.go @@ -39,8 +39,11 @@ import ( velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" velerotest "github.com/vmware-tanzu/velero/pkg/test" velerotypes "github.com/vmware-tanzu/velero/pkg/types" + "github.com/vmware-tanzu/velero/pkg/util" "github.com/vmware-tanzu/velero/pkg/util/boolptr" "github.com/vmware-tanzu/velero/pkg/util/kube" + + storagev1api "k8s.io/api/storage/v1" ) type reactor struct { @@ -156,6 +159,31 @@ func TestExpose(t *testing.T) { }, } + pvName := "pv-1" + volumeAttachement1 := &storagev1api.VolumeAttachment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "va1", + }, + Spec: storagev1api.VolumeAttachmentSpec{ + Source: storagev1api.VolumeAttachmentSource{ + PersistentVolumeName: &pvName, + }, + NodeName: "node-1", + }, + } + + volumeAttachement2 := &storagev1api.VolumeAttachment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "va2", + }, + Spec: storagev1api.VolumeAttachmentSpec{ + Source: storagev1api.VolumeAttachmentSource{ + PersistentVolumeName: &pvName, + }, + NodeName: "node-2", + }, + } + tests := []struct { name string snapshotClientObj []runtime.Object @@ -624,6 +652,114 @@ func TestExpose(t *testing.T) { expectedBackupPVCStorageClass: "fake-sc-read-only", expectedAffinity: nil, }, + { + name: "IntolerateSourceNode, get source node fail", + ownerBackup: backup, + exposeParam: CSISnapshotExposeParam{ + SnapshotName: "fake-vs", + SourceNamespace: "fake-ns", + SourcePVName: pvName, + StorageClass: "fake-sc", + AccessMode: AccessModeFileSystem, + OperationTimeout: time.Millisecond, + ExposeTimeout: time.Millisecond, + BackupPVCConfig: map[string]velerotypes.BackupPVC{ + "fake-sc": { + Annotations: map[string]string{util.VSphereCNSFastCloneAnno: "true"}, + }, + }, + Affinity: nil, + }, + snapshotClientObj: []runtime.Object{ + vsObject, + vscObj, + }, + kubeClientObj: []runtime.Object{ + daemonSet, + }, + kubeReactors: []reactor{ + { + verb: "list", + resource: "volumeattachments", + reactorFunc: func(action clientTesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, errors.New("fake-create-error") + }, + }, + }, + expectedAffinity: nil, + }, + { + name: "IntolerateSourceNode, get empty source node", + ownerBackup: backup, + exposeParam: CSISnapshotExposeParam{ + SnapshotName: "fake-vs", + SourceNamespace: "fake-ns", + SourcePVName: pvName, + StorageClass: "fake-sc", + AccessMode: AccessModeFileSystem, + OperationTimeout: time.Millisecond, + ExposeTimeout: time.Millisecond, + BackupPVCConfig: map[string]velerotypes.BackupPVC{ + "fake-sc": { + Annotations: map[string]string{util.VSphereCNSFastCloneAnno: "true"}, + }, + }, + Affinity: nil, + }, + snapshotClientObj: []runtime.Object{ + vsObject, + vscObj, + }, + kubeClientObj: []runtime.Object{ + daemonSet, + }, + expectedAffinity: nil, + }, + { + name: "IntolerateSourceNode, get source nodes", + ownerBackup: backup, + exposeParam: CSISnapshotExposeParam{ + SnapshotName: "fake-vs", + SourceNamespace: "fake-ns", + SourcePVName: pvName, + StorageClass: "fake-sc", + AccessMode: AccessModeFileSystem, + OperationTimeout: time.Millisecond, + ExposeTimeout: time.Millisecond, + BackupPVCConfig: map[string]velerotypes.BackupPVC{ + "fake-sc": { + Annotations: map[string]string{util.VSphereCNSFastCloneAnno: "true"}, + }, + }, + Affinity: nil, + }, + snapshotClientObj: []runtime.Object{ + vsObject, + vscObj, + }, + kubeClientObj: []runtime.Object{ + daemonSet, + volumeAttachement1, + volumeAttachement2, + }, + expectedAffinity: &corev1api.Affinity{ + NodeAffinity: &corev1api.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1api.NodeSelector{ + NodeSelectorTerms: []corev1api.NodeSelectorTerm{ + { + MatchExpressions: []corev1api.NodeSelectorRequirement{ + { + Key: "kubernetes.io/hostname", + Operator: corev1api.NodeSelectorOpNotIn, + Values: []string{"node-1", "node-2"}, + }, + }, + }, + }, + }, + }, + }, + }, } for _, test := range tests { diff --git a/pkg/util/kube/pvc_pv.go b/pkg/util/kube/pvc_pv.go index 634d79127..e18d33c77 100644 --- a/pkg/util/kube/pvc_pv.go +++ b/pkg/util/kube/pvc_pv.go @@ -554,3 +554,19 @@ func GetPVAttachedNode(ctx context.Context, pv string, storageClient storagev1.S return "", nil } + +func GetPVAttachedNodes(ctx context.Context, pv string, storageClient storagev1.StorageV1Interface) ([]string, error) { + vaList, err := storageClient.VolumeAttachments().List(ctx, metav1.ListOptions{}) + if err != nil { + return nil, errors.Wrapf(err, "error listing volumeattachment") + } + + nodes := []string{} + for _, va := range vaList.Items { + if va.Spec.Source.PersistentVolumeName != nil && *va.Spec.Source.PersistentVolumeName == pv { + nodes = append(nodes, va.Spec.NodeName) + } + } + + return nodes, nil +} diff --git a/pkg/util/third_party.go b/pkg/util/third_party.go index e85dc4a24..400c7a898 100644 --- a/pkg/util/third_party.go +++ b/pkg/util/third_party.go @@ -28,3 +28,7 @@ var ThirdPartyTolerations = []string{ "kubernetes.azure.com/scalesetpriority", "CriticalAddonsOnly", } + +const ( + VSphereCNSFastCloneAnno = "csi.vsphere.volume/fast-provisioning" +) From f1476defded0ffc91046e56ce37b1ca497e5d220 Mon Sep 17 00:00:00 2001 From: Priyansh Choudhary Date: Thu, 11 Sep 2025 23:37:46 +0530 Subject: [PATCH 031/104] Update AzureAD Microsoft Authentication Library to v1.5.0 (#9244) * Update AzureAD Microsoft Authentication Library to v1.5.0 Signed-off-by: Priyansh Choudhary * Added Changelog Signed-off-by: Priyansh Choudhary --------- Signed-off-by: Priyansh Choudhary --- changelogs/unreleased/9244-priyansh17 | 1 + go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/9244-priyansh17 diff --git a/changelogs/unreleased/9244-priyansh17 b/changelogs/unreleased/9244-priyansh17 new file mode 100644 index 000000000..931c43946 --- /dev/null +++ b/changelogs/unreleased/9244-priyansh17 @@ -0,0 +1 @@ +Update AzureAD Microsoft Authentication Library to v1.5.0 \ No newline at end of file diff --git a/go.mod b/go.mod index 9eeda4bfb..d32340b2b 100644 --- a/go.mod +++ b/go.mod @@ -73,7 +73,7 @@ require ( cloud.google.com/go/monitoring v1.24.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 // indirect diff --git a/go.sum b/go.sum index b9a742d4c..84a94ed32 100644 --- a/go.sum +++ b/go.sum @@ -95,8 +95,8 @@ github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= -github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs= -github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 h1:XkkQbfMyuH2jTSjQjSoihryI8GINRcs4xp8lNawg0FI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/GehirnInc/crypt v0.0.0-20230320061759-8cc1b52080c5 h1:IEjq88XO4PuBDcvmjQJcQGg+w+UaafSy8G5Kcb5tBhI= From 5ba00dfb097de68c6312d7497c2ef2675a64d1a9 Mon Sep 17 00:00:00 2001 From: Shubham Pampattiwar Date: Thu, 11 Sep 2025 15:51:46 -0700 Subject: [PATCH 032/104] Fix maintenance jobs toleration inheritance from Velero deployment Signed-off-by: Shubham Pampattiwar fix codespell and add changelog file Signed-off-by: Shubham Pampattiwar --- .../unreleased/9256-shubham-pampattiwar | 1 + pkg/repository/maintenance/maintenance.go | 40 ++- .../maintenance/maintenance_test.go | 288 ++++++++++++++++++ 3 files changed, 320 insertions(+), 9 deletions(-) create mode 100644 changelogs/unreleased/9256-shubham-pampattiwar diff --git a/changelogs/unreleased/9256-shubham-pampattiwar b/changelogs/unreleased/9256-shubham-pampattiwar new file mode 100644 index 000000000..2400fb6b6 --- /dev/null +++ b/changelogs/unreleased/9256-shubham-pampattiwar @@ -0,0 +1 @@ +Fix repository maintenance jobs to inherit allowlisted tolerations from Velero deployment diff --git a/pkg/repository/maintenance/maintenance.go b/pkg/repository/maintenance/maintenance.go index 16a94535f..e43918d4d 100644 --- a/pkg/repository/maintenance/maintenance.go +++ b/pkg/repository/maintenance/maintenance.go @@ -449,6 +449,35 @@ func StartNewJob( return maintenanceJob.Name, nil } +// buildTolerationsForMaintenanceJob builds the tolerations for maintenance jobs. +// It includes the required Windows toleration for backward compatibility and filters +// tolerations from the Velero deployment to only include those with keys that are +// in the ThirdPartyTolerations allowlist, following the same pattern as labels and annotations. +func buildTolerationsForMaintenanceJob(deployment *appsv1api.Deployment) []corev1api.Toleration { + // Start with the Windows toleration for backward compatibility + windowsToleration := corev1api.Toleration{ + Key: "os", + Operator: "Equal", + Effect: "NoSchedule", + Value: "windows", + } + result := []corev1api.Toleration{windowsToleration} + + // Filter tolerations from the Velero deployment to only include allowed ones + // Only tolerations that exist on the deployment AND have keys in the allowlist are inherited + deploymentTolerations := veleroutil.GetTolerationsFromVeleroServer(deployment) + for _, k := range util.ThirdPartyTolerations { + for _, toleration := range deploymentTolerations { + if toleration.Key == k { + result = append(result, toleration) + break // Only add the first matching toleration for each allowed key + } + } + } + + return result +} + func getPriorityClassName(ctx context.Context, cli client.Client, config *velerotypes.JobConfigs, logger logrus.FieldLogger) string { // Use the priority class name from the global job configuration if available // Note: Priority class is only read from global config, not per-repository @@ -593,15 +622,8 @@ func buildJob( SecurityContext: podSecurityContext, Volumes: volumes, ServiceAccountName: serviceAccount, - Tolerations: []corev1api.Toleration{ - { - Key: "os", - Operator: "Equal", - Effect: "NoSchedule", - Value: "windows", - }, - }, - ImagePullSecrets: imagePullSecrets, + Tolerations: buildTolerationsForMaintenanceJob(deployment), + ImagePullSecrets: imagePullSecrets, }, }, }, diff --git a/pkg/repository/maintenance/maintenance_test.go b/pkg/repository/maintenance/maintenance_test.go index 925a94043..93d8f9b2f 100644 --- a/pkg/repository/maintenance/maintenance_test.go +++ b/pkg/repository/maintenance/maintenance_test.go @@ -1481,3 +1481,291 @@ func TestBuildJobWithPriorityClassName(t *testing.T) { }) } } + +func TestBuildTolerationsForMaintenanceJob(t *testing.T) { + windowsToleration := corev1api.Toleration{ + Key: "os", + Operator: "Equal", + Effect: "NoSchedule", + Value: "windows", + } + + testCases := []struct { + name string + deploymentTolerations []corev1api.Toleration + expectedTolerations []corev1api.Toleration + }{ + { + name: "no tolerations should only include Windows toleration", + deploymentTolerations: nil, + expectedTolerations: []corev1api.Toleration{ + windowsToleration, + }, + }, + { + name: "empty tolerations should only include Windows toleration", + deploymentTolerations: []corev1api.Toleration{}, + expectedTolerations: []corev1api.Toleration{ + windowsToleration, + }, + }, + { + name: "non-allowed toleration should not be inherited", + deploymentTolerations: []corev1api.Toleration{ + { + Key: "vng-ondemand", + Operator: "Equal", + Effect: "NoSchedule", + Value: "amd64", + }, + }, + expectedTolerations: []corev1api.Toleration{ + windowsToleration, + }, + }, + { + name: "allowed toleration should be inherited", + deploymentTolerations: []corev1api.Toleration{ + { + Key: "kubernetes.azure.com/scalesetpriority", + Operator: "Equal", + Effect: "NoSchedule", + Value: "spot", + }, + }, + expectedTolerations: []corev1api.Toleration{ + windowsToleration, + { + Key: "kubernetes.azure.com/scalesetpriority", + Operator: "Equal", + Effect: "NoSchedule", + Value: "spot", + }, + }, + }, + { + name: "mixed allowed and non-allowed tolerations should only inherit allowed", + deploymentTolerations: []corev1api.Toleration{ + { + Key: "vng-ondemand", // not in allowlist + Operator: "Equal", + Effect: "NoSchedule", + Value: "amd64", + }, + { + Key: "CriticalAddonsOnly", // in allowlist + Operator: "Exists", + Effect: "NoSchedule", + }, + { + Key: "custom-key", // not in allowlist + Operator: "Equal", + Effect: "NoSchedule", + Value: "custom-value", + }, + }, + expectedTolerations: []corev1api.Toleration{ + windowsToleration, + { + Key: "CriticalAddonsOnly", + Operator: "Exists", + Effect: "NoSchedule", + }, + }, + }, + { + name: "multiple allowed tolerations should all be inherited", + deploymentTolerations: []corev1api.Toleration{ + { + Key: "kubernetes.azure.com/scalesetpriority", + Operator: "Equal", + Effect: "NoSchedule", + Value: "spot", + }, + { + Key: "CriticalAddonsOnly", + Operator: "Exists", + Effect: "NoSchedule", + }, + }, + expectedTolerations: []corev1api.Toleration{ + windowsToleration, + { + Key: "kubernetes.azure.com/scalesetpriority", + Operator: "Equal", + Effect: "NoSchedule", + Value: "spot", + }, + { + Key: "CriticalAddonsOnly", + Operator: "Exists", + Effect: "NoSchedule", + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Create a deployment with the specified tolerations + deployment := &appsv1api.Deployment{ + Spec: appsv1api.DeploymentSpec{ + Template: corev1api.PodTemplateSpec{ + Spec: corev1api.PodSpec{ + Tolerations: tc.deploymentTolerations, + }, + }, + }, + } + + result := buildTolerationsForMaintenanceJob(deployment) + assert.Equal(t, tc.expectedTolerations, result) + }) + } +} + +func TestBuildJobWithTolerationsInheritance(t *testing.T) { + // Define allowed tolerations that would be set on Velero deployment + allowedTolerations := []corev1api.Toleration{ + { + Key: "kubernetes.azure.com/scalesetpriority", + Operator: "Equal", + Effect: "NoSchedule", + Value: "spot", + }, + { + Key: "CriticalAddonsOnly", + Operator: "Exists", + Effect: "NoSchedule", + }, + } + + // Mixed tolerations (allowed and non-allowed) + mixedTolerations := []corev1api.Toleration{ + { + Key: "vng-ondemand", // not in allowlist + Operator: "Equal", + Effect: "NoSchedule", + Value: "amd64", + }, + { + Key: "CriticalAddonsOnly", // in allowlist + Operator: "Exists", + Effect: "NoSchedule", + }, + } + + // Windows toleration that should always be present + windowsToleration := corev1api.Toleration{ + Key: "os", + Operator: "Equal", + Effect: "NoSchedule", + Value: "windows", + } + + testCases := []struct { + name string + deploymentTolerations []corev1api.Toleration + expectedTolerations []corev1api.Toleration + }{ + { + name: "no tolerations on deployment should only have Windows toleration", + deploymentTolerations: nil, + expectedTolerations: []corev1api.Toleration{ + windowsToleration, + }, + }, + { + name: "allowed tolerations should be inherited along with Windows toleration", + deploymentTolerations: allowedTolerations, + expectedTolerations: []corev1api.Toleration{ + windowsToleration, + { + Key: "kubernetes.azure.com/scalesetpriority", + Operator: "Equal", + Effect: "NoSchedule", + Value: "spot", + }, + { + Key: "CriticalAddonsOnly", + Operator: "Exists", + Effect: "NoSchedule", + }, + }, + }, + { + name: "mixed tolerations should only inherit allowed ones", + deploymentTolerations: mixedTolerations, + expectedTolerations: []corev1api.Toleration{ + windowsToleration, + { + Key: "CriticalAddonsOnly", + Operator: "Exists", + Effect: "NoSchedule", + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Create a new scheme and add necessary API types + localScheme := runtime.NewScheme() + err := velerov1api.AddToScheme(localScheme) + require.NoError(t, err) + err = appsv1api.AddToScheme(localScheme) + require.NoError(t, err) + err = batchv1api.AddToScheme(localScheme) + require.NoError(t, err) + + // Create a deployment with the specified tolerations + deployment := &appsv1api.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "velero", + Namespace: "velero", + }, + Spec: appsv1api.DeploymentSpec{ + Template: corev1api.PodTemplateSpec{ + Spec: corev1api.PodSpec{ + Containers: []corev1api.Container{ + { + Name: "velero", + Image: "velero/velero:latest", + }, + }, + Tolerations: tc.deploymentTolerations, + }, + }, + }, + } + + // Create a backup repository + repo := &velerov1api.BackupRepository{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-repo", + Namespace: "velero", + }, + Spec: velerov1api.BackupRepositorySpec{ + VolumeNamespace: "velero", + BackupStorageLocation: "default", + }, + } + + // Create fake client and add the deployment + client := fake.NewClientBuilder().WithScheme(localScheme).WithObjects(deployment).Build() + + // Create minimal job configs and resources + jobConfig := &velerotypes.JobConfigs{} + logLevel := logrus.InfoLevel + logFormat := logging.NewFormatFlag() + logFormat.Set("text") + + // Call buildJob + job, err := buildJob(client, t.Context(), repo, "default", jobConfig, logLevel, logFormat, logrus.New()) + require.NoError(t, err) + + // Verify the tolerations are set correctly + assert.Equal(t, tc.expectedTolerations, job.Spec.Template.Spec.Tolerations) + }) + } +} From 25a7ef0e875ecca3d4a1ca86606b508f47f14580 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Thu, 11 Sep 2025 14:49:41 +0800 Subject: [PATCH 033/104] backupPVC to different node Signed-off-by: Lyndon-Li --- changelogs/unreleased/9233-Lyndon-Li | 2 +- pkg/exposer/csi_snapshot.go | 5 +++-- pkg/exposer/csi_snapshot_test.go | 14 ++++++++++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/changelogs/unreleased/9233-Lyndon-Li b/changelogs/unreleased/9233-Lyndon-Li index 492765e63..f6dd7213a 100644 --- a/changelogs/unreleased/9233-Lyndon-Li +++ b/changelogs/unreleased/9233-Lyndon-Li @@ -1 +1 @@ -Fix issue #9229, add intolerateSourceNode backupPVC option \ No newline at end of file +Fix issue #9229, don't attach backupPVC to the source node \ No newline at end of file diff --git a/pkg/exposer/csi_snapshot.go b/pkg/exposer/csi_snapshot.go index 50b7c976f..781739ff5 100644 --- a/pkg/exposer/csi_snapshot.go +++ b/pkg/exposer/csi_snapshot.go @@ -52,7 +52,7 @@ type CSISnapshotExposeParam struct { // SourcePVCName is the original name of the PVC that the snapshot is taken for SourcePVCName string - // SourcePVCName is the name of PV for SourcePVC + // SourcePVName is the name of PV for SourcePVC SourcePVName string // AccessMode defines the mode to access the snapshot @@ -217,7 +217,8 @@ func (e *csiSnapshotExposer) Expose(ctx context.Context, ownerObject corev1api.O if _, found := backupPVCAnnotations[util.VSphereCNSFastCloneAnno]; found { if n, err := kube.GetPVAttachedNodes(ctx, csiExposeParam.SourcePVName, e.kubeClient.StorageV1()); err != nil { - curLog.WithField("source PV", csiExposeParam.SourcePVName).WithError(err).Warn("Failed to get attached node for source PV, ignore intolerable nodes") + curLog.WithField("source PV", csiExposeParam.SourcePVName).WithError(err).Warnf("Failed to get attached node for source PV, ignore %s annotation", util.VSphereCNSFastCloneAnno) + delete(backupPVCAnnotations, util.VSphereCNSFastCloneAnno) } else { intoleratableNodes = n } diff --git a/pkg/exposer/csi_snapshot_test.go b/pkg/exposer/csi_snapshot_test.go index 95e5789e7..7e8e6d883 100644 --- a/pkg/exposer/csi_snapshot_test.go +++ b/pkg/exposer/csi_snapshot_test.go @@ -197,6 +197,7 @@ func TestExpose(t *testing.T) { expectedReadOnlyPVC bool expectedBackupPVCStorageClass string expectedAffinity *corev1api.Affinity + expectedPVCAnnotation map[string]string }{ { name: "wait vs ready fail", @@ -686,7 +687,8 @@ func TestExpose(t *testing.T) { }, }, }, - expectedAffinity: nil, + expectedAffinity: nil, + expectedPVCAnnotation: nil, }, { name: "IntolerateSourceNode, get empty source node", @@ -713,7 +715,8 @@ func TestExpose(t *testing.T) { kubeClientObj: []runtime.Object{ daemonSet, }, - expectedAffinity: nil, + expectedAffinity: nil, + expectedPVCAnnotation: map[string]string{util.VSphereCNSFastCloneAnno: "true"}, }, { name: "IntolerateSourceNode, get source nodes", @@ -759,6 +762,7 @@ func TestExpose(t *testing.T) { }, }, }, + expectedPVCAnnotation: map[string]string{util.VSphereCNSFastCloneAnno: "true"}, }, } @@ -841,6 +845,12 @@ func TestExpose(t *testing.T) { if test.expectedAffinity != nil { assert.Equal(t, test.expectedAffinity, backupPod.Spec.Affinity) } + + if test.expectedPVCAnnotation != nil { + assert.Equal(t, test.expectedPVCAnnotation, backupPVC.Annotations) + } else { + assert.Empty(t, backupPVC.Annotations) + } } else { assert.EqualError(t, err, test.err) } From 59289fba76ad39096543c79bf493ed551f795a10 Mon Sep 17 00:00:00 2001 From: Shubham Pampattiwar Date: Mon, 15 Sep 2025 16:01:33 -0700 Subject: [PATCH 034/104] Fix Schedule Backup Queue Accumulation During Extended Blocking Scenarios Signed-off-by: Shubham Pampattiwar --- pkg/controller/schedule_controller.go | 2 +- pkg/controller/schedule_controller_test.go | 26 ++++++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/pkg/controller/schedule_controller.go b/pkg/controller/schedule_controller.go index 799a8c77a..ec8894571 100644 --- a/pkg/controller/schedule_controller.go +++ b/pkg/controller/schedule_controller.go @@ -229,7 +229,7 @@ func (c *scheduleReconciler) checkIfBackupInNewOrProgress(schedule *velerov1.Sch } for _, backup := range backupList.Items { - if backup.Status.Phase == velerov1.BackupPhaseNew || backup.Status.Phase == velerov1.BackupPhaseInProgress { + if backup.Status.Phase == "" || backup.Status.Phase == velerov1.BackupPhaseNew || backup.Status.Phase == velerov1.BackupPhaseInProgress { log.Debugf("%s/%s still has backups that are in InProgress or New...", schedule.Namespace, schedule.Name) return true } diff --git a/pkg/controller/schedule_controller_test.go b/pkg/controller/schedule_controller_test.go index ab0a3f66d..f4585763c 100644 --- a/pkg/controller/schedule_controller_test.go +++ b/pkg/controller/schedule_controller_test.go @@ -149,6 +149,13 @@ func TestReconcileOfSchedule(t *testing.T) { expectedPhase: string(velerov1.SchedulePhaseEnabled), backup: builder.ForBackup("ns", "name-20220905120000").ObjectMeta(builder.WithLabels(velerov1.ScheduleNameLabel, "name")).Phase(velerov1.BackupPhaseNew).Result(), }, + { + name: "schedule already has backup with empty phase (not yet reconciled).", + schedule: newScheduleBuilder(velerov1.SchedulePhaseEnabled).CronSchedule("@every 5m").LastBackupTime("2000-01-01 00:00:00").Result(), + fakeClockTime: "2017-01-01 12:00:00", + expectedPhase: string(velerov1.SchedulePhaseEnabled), + backup: builder.ForBackup("ns", "name-20220905120000").ObjectMeta(builder.WithLabels(velerov1.ScheduleNameLabel, "name")).Phase("").Result(), + }, } for _, test := range tests { @@ -215,10 +222,10 @@ func TestReconcileOfSchedule(t *testing.T) { backups := &velerov1.BackupList{} require.NoError(t, client.List(ctx, backups)) - // If backup associated with schedule's status is in New or InProgress, + // If backup associated with schedule's status is in New or InProgress or empty phase, // new backup shouldn't be submitted. if test.backup != nil && - (test.backup.Status.Phase == velerov1.BackupPhaseNew || test.backup.Status.Phase == velerov1.BackupPhaseInProgress) { + (test.backup.Status.Phase == "" || test.backup.Status.Phase == velerov1.BackupPhaseNew || test.backup.Status.Phase == velerov1.BackupPhaseInProgress) { assert.Len(t, backups.Items, 1) require.NoError(t, client.Delete(ctx, test.backup)) } @@ -479,4 +486,19 @@ func TestCheckIfBackupInNewOrProgress(t *testing.T) { reconciler = NewScheduleReconciler("namespace", logger, client, metrics.NewServerMetrics(), false) result = reconciler.checkIfBackupInNewOrProgress(testSchedule) assert.True(t, result) + + // Clean backup in InProgress phase. + err = client.Delete(ctx, inProgressBackup) + require.NoError(t, err, "fail to delete backup in InProgress phase in TestCheckIfBackupInNewOrProgress: %v", err) + + // Create backup with empty phase (not yet reconciled). + emptyPhaseBackup := builder.ForBackup("ns", "backup-3"). + ObjectMeta(builder.WithLabels(velerov1.ScheduleNameLabel, "name")). + Phase("").Result() + err = client.Create(ctx, emptyPhaseBackup) + require.NoError(t, err, "fail to create backup with empty phase in TestCheckIfBackupInNewOrProgress: %v", err) + + reconciler = NewScheduleReconciler("namespace", logger, client, metrics.NewServerMetrics(), false) + result = reconciler.checkIfBackupInNewOrProgress(testSchedule) + assert.True(t, result) } From a7b2985c8396c5db9a259e62abcd47acc4da7343 Mon Sep 17 00:00:00 2001 From: Shubham Pampattiwar Date: Mon, 15 Sep 2025 16:07:40 -0700 Subject: [PATCH 035/104] add changelog file Signed-off-by: Shubham Pampattiwar --- changelogs/unreleased/9264-shubham-pampattiwar | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/unreleased/9264-shubham-pampattiwar diff --git a/changelogs/unreleased/9264-shubham-pampattiwar b/changelogs/unreleased/9264-shubham-pampattiwar new file mode 100644 index 000000000..711ea4b57 --- /dev/null +++ b/changelogs/unreleased/9264-shubham-pampattiwar @@ -0,0 +1 @@ +Fix schedule controller to prevent backup queue accumulation during extended blocking scenarios by properly handling empty backup phases \ No newline at end of file From 7e15e9ba056902fc0c58b42084a1bba9b86dca45 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Wed, 17 Sep 2025 15:09:54 +0800 Subject: [PATCH 036/104] deprecate pvc node selection Signed-off-by: Lyndon-Li --- pkg/restore/actions/pvc_action.go | 69 +----------- pkg/restore/actions/pvc_action_test.go | 112 +++++--------------- site/content/docs/main/restore-reference.md | 32 +----- 3 files changed, 33 insertions(+), 180 deletions(-) diff --git a/pkg/restore/actions/pvc_action.go b/pkg/restore/actions/pvc_action.go index fdc0c26ec..a4a63374d 100644 --- a/pkg/restore/actions/pvc_action.go +++ b/pkg/restore/actions/pvc_action.go @@ -17,20 +17,15 @@ limitations under the License. package actions import ( - "context" - "github.com/pkg/errors" "github.com/sirupsen/logrus" corev1api "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" corev1client "k8s.io/client-go/kubernetes/typed/core/v1" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" "github.com/vmware-tanzu/velero/pkg/kuberesource" - "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" "github.com/vmware-tanzu/velero/pkg/plugin/velero" "github.com/vmware-tanzu/velero/pkg/util" ) @@ -91,46 +86,13 @@ func (p *PVCAction) Execute(input *velero.RestoreItemActionExecuteInput) (*veler return nil, errors.WithStack(err) } - if pvc.Annotations == nil { - pvc.Annotations = make(map[string]string) - } - log := p.logger.WithFields(map[string]any{ "kind": pvc.Kind, "namespace": pvc.Namespace, "name": pvc.Name, }) - // Handle selected node annotation - node, ok := pvc.Annotations[AnnSelectedNode] - if ok { - // fetch node mapping from configMap - newNode, err := getNewNodeFromConfigMap(p.configMapClient, node) - if err != nil { - return nil, err - } - - if len(newNode) != 0 { - // Check whether the mapped node exists first. - exists, err := isNodeExist(p.nodeClient, newNode) - if err != nil { - return nil, errors.Wrapf(err, "error checking %s's mapped node %s existence", node, newNode) - } - if !exists { - log.Warnf("Selected-node's mapped node doesn't exist: source: %s, dest: %s. Please check the ConfigMap with label velero.io/change-pvc-node-selector.", node, newNode) - } - - // set node selector - // We assume that node exist for node-mapping - pvc.Annotations[AnnSelectedNode] = newNode - log.Infof("Updating selected-node to %s from %s", newNode, node) - } else { - log.Info("Clearing PVC selected-node annotation") - delete(pvc.Annotations, AnnSelectedNode) - } - } - - // Remove other annotations + // Remove PVC annotations removePVCAnnotations( &pvc, []string{ @@ -138,6 +100,7 @@ func (p *PVCAction) Execute(input *velero.RestoreItemActionExecuteInput) (*veler AnnBoundByController, AnnStorageProvisioner, AnnBetaStorageProvisioner, + AnnSelectedNode, velerov1api.VolumeSnapshotLabel, velerov1api.DataUploadNameAnnotation, }, @@ -167,34 +130,6 @@ func (p *PVCAction) Execute(input *velero.RestoreItemActionExecuteInput) (*veler return output, nil } -func getNewNodeFromConfigMap(client corev1client.ConfigMapInterface, node string) (string, error) { - // fetch node mapping from configMap - config, err := common.GetPluginConfig(common.PluginKindRestoreItemAction, "velero.io/change-pvc-node-selector", client) - if err != nil { - return "", err - } - - if config == nil { - // there is no node mapping defined for change-pvc-node - // so we will return empty new node - return "", nil - } - - return config.Data[node], nil -} - -// isNodeExist check if node resource exist or not -func isNodeExist(nodeClient corev1client.NodeInterface, name string) (bool, error) { - _, err := nodeClient.Get(context.TODO(), name, metav1.GetOptions{}) - if err != nil { - if apierrors.IsNotFound(err) { - return false, nil - } - return false, err - } - return true, nil -} - func removePVCAnnotations(pvc *corev1api.PersistentVolumeClaim, remove []string) { for k := range pvc.Annotations { if util.Contains(remove, k) { diff --git a/pkg/restore/actions/pvc_action_test.go b/pkg/restore/actions/pvc_action_test.go index f00ec9264..aa2ddeeef 100644 --- a/pkg/restore/actions/pvc_action_test.go +++ b/pkg/restore/actions/pvc_action_test.go @@ -17,11 +17,9 @@ limitations under the License. package actions import ( - "bytes" "fmt" "testing" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" corev1api "k8s.io/api/core/v1" @@ -42,105 +40,57 @@ import ( // desired result. func TestPVCActionExecute(t *testing.T) { tests := []struct { - name string - pvc *corev1api.PersistentVolumeClaim - configMap *corev1api.ConfigMap - node *corev1api.Node - newNode *corev1api.Node - want *corev1api.PersistentVolumeClaim - wantErr error + name string + pvc *corev1api.PersistentVolumeClaim + want *corev1api.PersistentVolumeClaim + wantErr error }{ { - name: "a valid mapping for a persistent volume claim is applied correctly", - pvc: builder.ForPersistentVolumeClaim("source-ns", "pvc-1"). - ObjectMeta( - builder.WithAnnotations("volume.kubernetes.io/selected-node", "source-node"), - ).Result(), - configMap: builder.ForConfigMap("velero", "change-pvc-node"). - ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-pvc-node-selector", "RestoreItemAction")). - Data("source-node", "dest-node"). - Result(), - newNode: builder.ForNode("dest-node").Result(), - want: builder.ForPersistentVolumeClaim("source-ns", "pvc-1"). - ObjectMeta( - builder.WithAnnotations("volume.kubernetes.io/selected-node", "dest-node"), - ).Result(), - }, - { - name: "when no config map exists for the plugin, the item is returned without node selector", - pvc: builder.ForPersistentVolumeClaim("source-ns", "pvc-1"). - ObjectMeta( - builder.WithAnnotations("volume.kubernetes.io/selected-node", "source-node"), - ).Result(), - configMap: builder.ForConfigMap("velero", "change-pvc-node"). - ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/some-other-plugin", "RestoreItemAction")). - Data("source-node", "dest-node"). - Result(), - node: builder.ForNode("source-node").Result(), - want: builder.ForPersistentVolumeClaim("source-ns", "pvc-1").Result(), - }, - { - name: "when no node-mappings exist in the plugin config map, the item is returned without node selector", - pvc: builder.ForPersistentVolumeClaim("source-ns", "pvc-1"). - ObjectMeta( - builder.WithAnnotations("volume.kubernetes.io/selected-node", "source-node"), - ).Result(), - configMap: builder.ForConfigMap("velero", "change-pvc-node"). - ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-pvc-node-selector", "RestoreItemAction")). - Result(), - node: builder.ForNode("source-node").Result(), - want: builder.ForPersistentVolumeClaim("source-ns", "pvc-1").Result(), - }, - { - name: "when persistent volume claim has no node selector, the item is returned as-is", + name: "a persistent volume claim with no annotation", pvc: builder.ForPersistentVolumeClaim("source-ns", "pvc-1").Result(), - configMap: builder.ForConfigMap("velero", "change-pvc-node"). - ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-pvc-node-selector", "RestoreItemAction")). - Data("source-node", "dest-node"). - Result(), want: builder.ForPersistentVolumeClaim("source-ns", "pvc-1").Result(), }, { - name: "when persistent volume claim's node-selector has no mapping in the config map, the item is returned without node selector", + name: "a persistent volume claim with selected-node annotation", pvc: builder.ForPersistentVolumeClaim("source-ns", "pvc-1"). ObjectMeta( builder.WithAnnotations("volume.kubernetes.io/selected-node", "source-node"), ).Result(), - configMap: builder.ForConfigMap("velero", "change-pvc-node"). - ObjectMeta(builder.WithLabels("velero.io/plugin-config", "", "velero.io/change-pvc-node-selector", "RestoreItemAction")). - Data("source-node-1", "dest-node"). - Result(), - node: builder.ForNode("source-node").Result(), - want: builder.ForPersistentVolumeClaim("source-ns", "pvc-1").Result(), + want: builder.ForPersistentVolumeClaim("source-ns", "pvc-1").ObjectMeta(builder.WithAnnotationsMap(map[string]string{})).Result(), + }, + { + name: "a persistent volume claim with other annotation", + pvc: builder.ForPersistentVolumeClaim("source-ns", "pvc-1"). + ObjectMeta( + builder.WithAnnotations("other-anno-1", "other-value-1", "other-anno-2", "other-value-2"), + ).Result(), + want: builder.ForPersistentVolumeClaim("source-ns", "pvc-1").ObjectMeta( + builder.WithAnnotations("other-anno-1", "other-value-1", "other-anno-2", "other-value-2"), + ).Result(), + }, + { + name: "a persistent volume claim with other annotation and selected-node annotation", + pvc: builder.ForPersistentVolumeClaim("source-ns", "pvc-1"). + ObjectMeta( + builder.WithAnnotations("other-anno", "other-value", "volume.kubernetes.io/selected-node", "source-node"), + ).Result(), + want: builder.ForPersistentVolumeClaim("source-ns", "pvc-1").ObjectMeta( + builder.WithAnnotations("other-anno", "other-value"), + ).Result(), }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { clientset := fake.NewSimpleClientset() - logger := logrus.StandardLogger() - buf := bytes.Buffer{} - logrus.SetOutput(&buf) + a := NewPVCAction( - logger, + velerotest.NewLogger(), clientset.CoreV1().ConfigMaps("velero"), clientset.CoreV1().Nodes(), ) // set up test data - if tc.configMap != nil { - _, err := clientset.CoreV1().ConfigMaps(tc.configMap.Namespace).Create(t.Context(), tc.configMap, metav1.CreateOptions{}) - require.NoError(t, err) - } - - if tc.node != nil { - _, err := clientset.CoreV1().Nodes().Create(t.Context(), tc.node, metav1.CreateOptions{}) - require.NoError(t, err) - } - if tc.newNode != nil { - _, err := clientset.CoreV1().Nodes().Create(t.Context(), tc.newNode, metav1.CreateOptions{}) - require.NoError(t, err) - } unstructuredMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(tc.pvc) require.NoError(t, err) @@ -156,10 +106,6 @@ func TestPVCActionExecute(t *testing.T) { // execute method under test res, err := a.Execute(input) - // Make sure mapped selected-node exists. - logOutput := buf.String() - assert.NotContains(t, logOutput, "Selected-node's mapped node doesn't exist") - // validate for both error and non-error cases switch { case tc.wantErr != nil: diff --git a/site/content/docs/main/restore-reference.md b/site/content/docs/main/restore-reference.md index cf5418f7b..6c5394cf0 100644 --- a/site/content/docs/main/restore-reference.md +++ b/site/content/docs/main/restore-reference.md @@ -215,37 +215,9 @@ data: ### PVC selected-node -Velero by default removes PVC's `volume.kubernetes.io/selected-node` annotation during restore, so that the restored PVC could be provisioned appropriately according to ```WaitForFirstConsumer``` rules, storage topologies and the restored pod's schedule result, etc. +Velero removes PVC's `volume.kubernetes.io/selected-node` annotation during restore, so that the restored PVC could be provisioned appropriately according to ```WaitForFirstConsumer``` rules, storage topologies and the restored pod's schedule result, etc. -For more information of how this selected-node annotation matters to PVC restore, see issue https://github.com/vmware-tanzu/velero/issues/9053. - -As an expectation, when you provide the selected-node configuration, Velero sets the annotation to the node in the configuration, if the node doesn't exist in the cluster then the annotation will also be removed. -Note: This feature is under deprecation as of Velero 1.15, following Velero deprecation policy. This feature is primarily used to remedy some problems in old Kubernetes versions as described [here](https://github.com/vmware-tanzu/velero/pull/2377). It may not work with the new features of Kubernetes and Velero. For more information, see issue https://github.com/vmware-tanzu/velero/issues/9053 for more information. -To configure a selected-node, create a config map in the Velero namespace like the following: - -```yaml -apiVersion: v1 -kind: ConfigMap -metadata: - # any name can be used; Velero uses the labels (below) - # to identify it rather than the name - name: change-pvc-node-selector-config - # must be in the velero namespace - namespace: velero - # the below labels should be used verbatim in your - # ConfigMap. - labels: - # this value-less label identifies the ConfigMap as - # config for a plugin (i.e. the built-in restore item action plugin) - velero.io/plugin-config: "" - # this label identifies the name and kind of plugin - # that this ConfigMap is for. - velero.io/change-pvc-node-selector: RestoreItemAction -data: - # add 1+ key-value pairs here, where the key is the old - # node name and the value is the new node name. - : -``` +For more information of how this selected-node annotation matters to PVC restore, see issue https://github.com/vmware-tanzu/velero/issues/9053. ## Restoring into a different namespace From b9159c22ca6e4d117d009ffd0634a18b6a6cb270 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Wed, 17 Sep 2025 15:22:42 +0800 Subject: [PATCH 037/104] deprecate pvc node selection Signed-off-by: Lyndon-Li --- changelogs/unreleased/9269-Lyndon-Li | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/unreleased/9269-Lyndon-Li diff --git a/changelogs/unreleased/9269-Lyndon-Li b/changelogs/unreleased/9269-Lyndon-Li new file mode 100644 index 000000000..2ed7cdd4f --- /dev/null +++ b/changelogs/unreleased/9269-Lyndon-Li @@ -0,0 +1 @@ +Fix issue #7904, remove the code and doc for PVC node selection \ No newline at end of file From 9b6c4b1d471aa0d6205feb617321b8badfb79e4e Mon Sep 17 00:00:00 2001 From: Tiger Kaovilai Date: Wed, 17 Sep 2025 16:36:41 -0400 Subject: [PATCH 038/104] Fix E2E tests: Build MinIO from Bitnami Dockerfile to replace deprecated image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Bitnami MinIO image bitnami/minio:2021.6.17-debian-10-r7 is no longer available on Docker Hub, causing E2E tests to fail. This change implements a solution to build the MinIO image locally from Bitnami's public Dockerfile and cache it for subsequent runs: - Fetches the latest commit hash of the Bitnami MinIO Dockerfile - Uses GitHub Actions cache to store/retrieve built images - Only rebuilds when the upstream Dockerfile changes - Maintains compatibility with existing environment variables Fixes #9279 🤖 Generated with [Claude Code](https://claude.ai/code) Update .github/workflows/e2e-test-kind.yaml Signed-off-by: Tiger Kaovilai Co-Authored-By: Claude Signed-off-by: Tiger Kaovilai --- .github/workflows/e2e-test-kind.yaml | 37 ++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e-test-kind.yaml b/.github/workflows/e2e-test-kind.yaml index 65517804c..662fe0488 100644 --- a/.github/workflows/e2e-test-kind.yaml +++ b/.github/workflows/e2e-test-kind.yaml @@ -11,6 +11,8 @@ jobs: # Build the Velero CLI and image once for all Kubernetes versions, and cache it so the fan-out workers can get it. build: runs-on: ubuntu-latest + outputs: + minio-dockerfile-sha: ${{ steps.minio-version.outputs.dockerfile_sha }} steps: - name: Check out the code uses: actions/checkout@v5 @@ -44,6 +46,26 @@ jobs: run: | IMAGE=velero VERSION=pr-test BUILD_OUTPUT_TYPE=docker make container docker save velero:pr-test-linux-amd64 -o ./velero.tar + # Check and build MinIO image once for all e2e tests + - name: Check Bitnami MinIO Dockerfile version + id: minio-version + run: | + DOCKERFILE_SHA=$(curl -s https://api.github.com/repos/bitnami/containers/commits?path=bitnami/minio/2025/debian-12/Dockerfile\&per_page=1 | jq -r '.[0].sha') + echo "dockerfile_sha=${DOCKERFILE_SHA}" >> $GITHUB_OUTPUT + - name: Cache MinIO Image + uses: actions/cache@v4 + id: minio-cache + with: + path: ./minio-image.tar + key: minio-bitnami-${{ steps.minio-version.outputs.dockerfile_sha }} + - name: Build MinIO Image from Bitnami Dockerfile + if: steps.minio-cache.outputs.cache-hit != 'true' + run: | + echo "Building MinIO image from Bitnami Dockerfile..." + git clone --depth 1 https://github.com/bitnami/containers.git /tmp/bitnami-containers + cd /tmp/bitnami-containers/bitnami/minio/2025/debian-12 + docker build -t bitnami/minio:local . + docker save bitnami/minio:local > ${{ github.workspace }}/minio-image.tar # Create json of k8s versions to test # from guide: https://stackoverflow.com/a/65094398/4590470 setup-test-matrix: @@ -86,9 +108,20 @@ jobs: uses: actions/setup-go@v5 with: go-version-file: 'go.mod' + # Fetch the pre-built MinIO image from the build job + - name: Fetch built MinIO Image + uses: actions/cache@v4 + id: minio-cache + with: + path: ./minio-image.tar + key: minio-bitnami-${{ needs.build.outputs.minio-dockerfile-sha }} + - name: Load MinIO Image + run: | + echo "Loading MinIO image..." + docker load < ./minio-image.tar - name: Install MinIO - run: - docker run -d --rm -p 9000:9000 -e "MINIO_ACCESS_KEY=minio" -e "MINIO_SECRET_KEY=minio123" -e "MINIO_DEFAULT_BUCKETS=bucket,additional-bucket" bitnami/minio:2021.6.17-debian-10-r7 + run: | + docker run -d --rm -p 9000:9000 -e "MINIO_ROOT_USER=minio" -e "MINIO_ROOT_PASSWORD=minio123" -e "MINIO_DEFAULT_BUCKETS=bucket,additional-bucket" bitnami/minio:local - uses: engineerd/setup-kind@v0.6.2 with: skipClusterLogsExport: true From e21b21c19ec882df38111fc07c146385124bab19 Mon Sep 17 00:00:00 2001 From: 0xLeo258 Date: Thu, 18 Sep 2025 17:21:25 +0800 Subject: [PATCH 039/104] fix 9234: Add safe VolumeSnapshotterCache Signed-off-by: 0xLeo258 --- pkg/backup/backup.go | 2 +- pkg/backup/item_backupper.go | 36 +++------------------- pkg/backup/volume_snapshotter_cache.go | 42 ++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 32 deletions(-) create mode 100644 pkg/backup/volume_snapshotter_cache.go diff --git a/pkg/backup/backup.go b/pkg/backup/backup.go index a11acd52a..824c44875 100644 --- a/pkg/backup/backup.go +++ b/pkg/backup/backup.go @@ -366,7 +366,7 @@ func (kb *kubernetesBackupper) BackupWithResolvers( discoveryHelper: kb.discoveryHelper, podVolumeBackupper: podVolumeBackupper, podVolumeSnapshotTracker: podvolume.NewTracker(), - volumeSnapshotterGetter: volumeSnapshotterGetter, + volumeSnapshotterCache: NewVolumeSnapshotterCache(volumeSnapshotterGetter), itemHookHandler: &hook.DefaultItemHookHandler{ PodCommandExecutor: kb.podCommandExecutor, }, diff --git a/pkg/backup/item_backupper.go b/pkg/backup/item_backupper.go index b890b23c3..b0e5fadfa 100644 --- a/pkg/backup/item_backupper.go +++ b/pkg/backup/item_backupper.go @@ -70,13 +70,11 @@ type itemBackupper struct { discoveryHelper discovery.Helper podVolumeBackupper podvolume.Backupper podVolumeSnapshotTracker *podvolume.Tracker - volumeSnapshotterGetter VolumeSnapshotterGetter kubernetesBackupper *kubernetesBackupper - - itemHookHandler hook.ItemHookHandler - snapshotLocationVolumeSnapshotters map[string]vsv1.VolumeSnapshotter - hookTracker *hook.HookTracker - volumeHelperImpl volumehelper.VolumeHelper + volumeSnapshotterCache *VolumeSnapshotterCache + itemHookHandler hook.ItemHookHandler + hookTracker *hook.HookTracker + volumeHelperImpl volumehelper.VolumeHelper } type FileForArchive struct { @@ -502,30 +500,6 @@ func (ib *itemBackupper) executeActions( return obj, itemFiles, nil } -// volumeSnapshotter instantiates and initializes a VolumeSnapshotter given a VolumeSnapshotLocation, -// or returns an existing one if one's already been initialized for the location. -func (ib *itemBackupper) volumeSnapshotter(snapshotLocation *velerov1api.VolumeSnapshotLocation) (vsv1.VolumeSnapshotter, error) { - if bs, ok := ib.snapshotLocationVolumeSnapshotters[snapshotLocation.Name]; ok { - return bs, nil - } - - bs, err := ib.volumeSnapshotterGetter.GetVolumeSnapshotter(snapshotLocation.Spec.Provider) - if err != nil { - return nil, err - } - - if err := bs.Init(snapshotLocation.Spec.Config); err != nil { - return nil, err - } - - if ib.snapshotLocationVolumeSnapshotters == nil { - ib.snapshotLocationVolumeSnapshotters = make(map[string]vsv1.VolumeSnapshotter) - } - ib.snapshotLocationVolumeSnapshotters[snapshotLocation.Name] = bs - - return bs, nil -} - // zoneLabelDeprecated is the label that stores availability-zone info // on PVs this is deprecated on Kubernetes >= 1.17.0 // zoneLabel is the label that stores availability-zone info @@ -641,7 +615,7 @@ func (ib *itemBackupper) takePVSnapshot(obj runtime.Unstructured, log logrus.Fie for _, snapshotLocation := range ib.backupRequest.SnapshotLocations { log := log.WithField("volumeSnapshotLocation", snapshotLocation.Name) - bs, err := ib.volumeSnapshotter(snapshotLocation) + bs, err := ib.volumeSnapshotterCache.SetNX(snapshotLocation) if err != nil { log.WithError(err).Error("Error getting volume snapshotter for volume snapshot location") continue diff --git a/pkg/backup/volume_snapshotter_cache.go b/pkg/backup/volume_snapshotter_cache.go new file mode 100644 index 000000000..620ebc337 --- /dev/null +++ b/pkg/backup/volume_snapshotter_cache.go @@ -0,0 +1,42 @@ +package backup + +import ( + "sync" + + velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + vsv1 "github.com/vmware-tanzu/velero/pkg/plugin/velero/volumesnapshotter/v1" +) + +type VolumeSnapshotterCache struct { + cache map[string]vsv1.VolumeSnapshotter + mutex sync.Mutex + getter VolumeSnapshotterGetter +} + +func NewVolumeSnapshotterCache(getter VolumeSnapshotterGetter) *VolumeSnapshotterCache { + return &VolumeSnapshotterCache{ + cache: make(map[string]vsv1.VolumeSnapshotter), + getter: getter, + } +} + +func (c *VolumeSnapshotterCache) SetNX(location *velerov1api.VolumeSnapshotLocation) (vsv1.VolumeSnapshotter, error) { + c.mutex.Lock() + defer c.mutex.Unlock() + + if snapshotter, exists := c.cache[location.Name]; exists { + return snapshotter, nil + } + + snapshotter, err := c.getter.GetVolumeSnapshotter(location.Spec.Provider) + if err != nil { + return nil, err + } + + if err := snapshotter.Init(location.Spec.Config); err != nil { + return nil, err + } + + c.cache[location.Name] = snapshotter + return snapshotter, nil +} From 25de1bb3b6bf646e233ad401ee498c7f6d92287a Mon Sep 17 00:00:00 2001 From: 0xLeo258 Date: Thu, 18 Sep 2025 17:36:07 +0800 Subject: [PATCH 040/104] add changelog Signed-off-by: 0xLeo258 --- changelogs/unreleased/9281-0xLeo258 | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/unreleased/9281-0xLeo258 diff --git a/changelogs/unreleased/9281-0xLeo258 b/changelogs/unreleased/9281-0xLeo258 new file mode 100644 index 000000000..eb5bf3f5d --- /dev/null +++ b/changelogs/unreleased/9281-0xLeo258 @@ -0,0 +1 @@ +Implement concurrency control for cache of native VolumeSnapshotter plugin. From 1ec281a64eae4dbd37c7ddf5f6b0ba4a9f5678da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Sep 2025 12:29:45 -0400 Subject: [PATCH 041/104] Bump actions/setup-go from 5 to 6 (#9231) Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5 to 6. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/setup-go dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/e2e-test-kind.yaml | 4 ++-- .github/workflows/pr-ci-check.yml | 2 +- .github/workflows/pr-linter-check.yml | 2 +- .github/workflows/push.yml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/e2e-test-kind.yaml b/.github/workflows/e2e-test-kind.yaml index 662fe0488..df092d5d3 100644 --- a/.github/workflows/e2e-test-kind.yaml +++ b/.github/workflows/e2e-test-kind.yaml @@ -17,7 +17,7 @@ jobs: - name: Check out the code uses: actions/checkout@v5 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' # Look for a CLI that's made for this PR @@ -105,7 +105,7 @@ jobs: - name: Check out the code uses: actions/checkout@v5 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' # Fetch the pre-built MinIO image from the build job diff --git a/.github/workflows/pr-ci-check.yml b/.github/workflows/pr-ci-check.yml index 0a394560a..84c63047f 100644 --- a/.github/workflows/pr-ci-check.yml +++ b/.github/workflows/pr-ci-check.yml @@ -10,7 +10,7 @@ jobs: - name: Check out the code uses: actions/checkout@v5 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' - name: Make ci diff --git a/.github/workflows/pr-linter-check.yml b/.github/workflows/pr-linter-check.yml index 997466ccf..586acc5fd 100644 --- a/.github/workflows/pr-linter-check.yml +++ b/.github/workflows/pr-linter-check.yml @@ -14,7 +14,7 @@ jobs: - name: Check out the code uses: actions/checkout@v5 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' - name: Linter check diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 8dee8799a..99f42a498 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -17,7 +17,7 @@ jobs: - name: Check out the code uses: actions/checkout@v5 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' - name: Set up QEMU From 4847eeaf62c9359038eb4edc26b6be5cd3c61f31 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Thu, 11 Sep 2025 16:58:33 +0800 Subject: [PATCH 042/104] Use different go version check logic for main and other branches. main branch will read go version from go.mod's go primitive, and only keep major and minor version, because we want the actions to use the lastest patch version automatically, even the go.mod specify version like 1.24.0. release branch can read the go version from go.mod file by setup-go action's own logic. Refactor the get Go version to reusable workflow. Signed-off-by: Xun Jiang --- .github/workflows/e2e-test-kind.yaml | 19 +++++++++++---- .github/workflows/get-go-version.yaml | 33 +++++++++++++++++++++++++++ .github/workflows/pr-ci-check.yml | 12 ++++++++-- .github/workflows/pr-linter-check.yml | 12 ++++++++-- .github/workflows/push.yml | 11 +++++++-- 5 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/get-go-version.yaml diff --git a/.github/workflows/e2e-test-kind.yaml b/.github/workflows/e2e-test-kind.yaml index df092d5d3..47979a27c 100644 --- a/.github/workflows/e2e-test-kind.yaml +++ b/.github/workflows/e2e-test-kind.yaml @@ -8,18 +8,26 @@ on: - "design/**" - "**/*.md" jobs: + get-go-version: + uses: ./.github/workflows/get-go-version.yaml + with: + ref: ${{ github.event.pull_request.base.ref }} + # Build the Velero CLI and image once for all Kubernetes versions, and cache it so the fan-out workers can get it. build: runs-on: ubuntu-latest + needs: get-go-version outputs: minio-dockerfile-sha: ${{ steps.minio-version.outputs.dockerfile_sha }} steps: - name: Check out the code uses: actions/checkout@v5 - - name: Set up Go + + - name: Set up Go version uses: actions/setup-go@v6 with: - go-version-file: 'go.mod' + go-version: ${{ needs.get-go-version.outputs.version }} + # Look for a CLI that's made for this PR - name: Fetch built CLI id: cli-cache @@ -97,6 +105,7 @@ jobs: needs: - build - setup-test-matrix + - get-go-version runs-on: ubuntu-latest strategy: matrix: ${{fromJson(needs.setup-test-matrix.outputs.matrix)}} @@ -104,10 +113,12 @@ jobs: steps: - name: Check out the code uses: actions/checkout@v5 - - name: Set up Go + + - name: Set up Go version uses: actions/setup-go@v6 with: - go-version-file: 'go.mod' + go-version: ${{ needs.get-go-version.outputs.version }} + # Fetch the pre-built MinIO image from the build job - name: Fetch built MinIO Image uses: actions/cache@v4 diff --git a/.github/workflows/get-go-version.yaml b/.github/workflows/get-go-version.yaml new file mode 100644 index 000000000..3bc3f8e53 --- /dev/null +++ b/.github/workflows/get-go-version.yaml @@ -0,0 +1,33 @@ +on: + workflow_call: + inputs: + ref: + description: "The target branch's ref" + required: true + type: string + outputs: + version: + description: "The expected Go version" + value: ${{ jobs.extract.outputs.version }} + +jobs: + extract: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.pick-version.outputs.version }} + steps: + - name: Check out the code + uses: actions/checkout@v5 + + - id: pick-version + run: | + if [ "${{ inputs.ref }}" == "main" ]; then + version=$(grep '^go ' go.mod | awk '{print $2}' | cut -d. -f1-2) + else + goDirectiveVersion=$(grep '^go ' go.mod | awk '{print $2}') + toolChainVersion=$(grep '^toolchain ' go.mod | awk '{print $2}') + version=$(printf "%s\n%s\n" "$goDirectiveVersion" "$toolChainVersion" | sort -V | tail -n1) + fi + + echo "version=$version" + echo "version=$version" >> $GITHUB_OUTPUT diff --git a/.github/workflows/pr-ci-check.yml b/.github/workflows/pr-ci-check.yml index 84c63047f..c97f216b4 100644 --- a/.github/workflows/pr-ci-check.yml +++ b/.github/workflows/pr-ci-check.yml @@ -1,18 +1,26 @@ name: Pull Request CI Check on: [pull_request] jobs: + get-go-version: + uses: ./.github/workflows/get-go-version.yaml + with: + ref: ${{ github.event.pull_request.base.ref }} + build: name: Run CI + needs: get-go-version runs-on: ubuntu-latest strategy: fail-fast: false steps: - name: Check out the code uses: actions/checkout@v5 - - name: Set up Go + + - name: Set up Go version uses: actions/setup-go@v6 with: - go-version-file: 'go.mod' + go-version: ${{ needs.get-go-version.outputs.version }} + - name: Make ci run: make ci - name: Upload test coverage diff --git a/.github/workflows/pr-linter-check.yml b/.github/workflows/pr-linter-check.yml index 586acc5fd..81a2bdd64 100644 --- a/.github/workflows/pr-linter-check.yml +++ b/.github/workflows/pr-linter-check.yml @@ -7,16 +7,24 @@ on: - "design/**" - "**/*.md" jobs: + get-go-version: + uses: ./.github/workflows/get-go-version.yaml + with: + ref: ${{ github.event.pull_request.base.ref }} + build: name: Run Linter Check runs-on: ubuntu-latest + needs: get-go-version steps: - name: Check out the code uses: actions/checkout@v5 - - name: Set up Go + + - name: Set up Go version uses: actions/setup-go@v6 with: - go-version-file: 'go.mod' + go-version: ${{ needs.get-go-version.outputs.version }} + - name: Linter check uses: golangci/golangci-lint-action@v8 with: diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 99f42a498..8e1bc1219 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -9,17 +9,24 @@ on: - '*' jobs: + get-go-version: + uses: ./.github/workflows/get-go-version.yaml + with: + ref: ${ github.ref } build: name: Build runs-on: ubuntu-latest + needs: get-go-version steps: - name: Check out the code uses: actions/checkout@v5 - - name: Set up Go + + - name: Set up Go version uses: actions/setup-go@v6 with: - go-version-file: 'go.mod' + go-version: ${{ needs.get-go-version.outputs.version }} + - name: Set up QEMU id: qemu uses: docker/setup-qemu-action@v3 From f2a27c3864606e82f98b2ea0058598f179aec54f Mon Sep 17 00:00:00 2001 From: 0xLeo258 Date: Thu, 11 Sep 2025 14:45:39 +0800 Subject: [PATCH 043/104] fix9247: Protect VolumeSnapshot field Signed-off-by: 0xLeo258 --- pkg/backup/item_backupper.go | 2 ++ pkg/backup/request.go | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/backup/item_backupper.go b/pkg/backup/item_backupper.go index b890b23c3..7b7f5cf62 100644 --- a/pkg/backup/item_backupper.go +++ b/pkg/backup/item_backupper.go @@ -699,6 +699,8 @@ func (ib *itemBackupper) takePVSnapshot(obj runtime.Unstructured, log logrus.Fie snapshot.Status.Phase = volume.SnapshotPhaseCompleted snapshot.Status.ProviderSnapshotID = snapshotID } + ib.backupRequest.requestLock.Lock() + defer ib.backupRequest.requestLock.Unlock() ib.backupRequest.VolumeSnapshots = append(ib.backupRequest.VolumeSnapshots, snapshot) // nil errors are automatically removed diff --git a/pkg/backup/request.go b/pkg/backup/request.go index 3ec05ee04..b81bde74d 100644 --- a/pkg/backup/request.go +++ b/pkg/backup/request.go @@ -17,6 +17,8 @@ limitations under the License. package backup import ( + "sync" + "github.com/vmware-tanzu/velero/internal/hook" "github.com/vmware-tanzu/velero/internal/resourcepolicies" "github.com/vmware-tanzu/velero/internal/volume" @@ -36,7 +38,7 @@ type itemKey struct { // materialized (e.g. backup/snapshot locations, includes/excludes, etc.) type Request struct { *velerov1api.Backup - + requestLock sync.Mutex StorageLocation *velerov1api.BackupStorageLocation SnapshotLocations []*velerov1api.VolumeSnapshotLocation NamespaceIncludesExcludes *collections.IncludesExcludes From 9df17eb02b621722a4000481e67634344aa12fda Mon Sep 17 00:00:00 2001 From: 0xLeo258 Date: Thu, 11 Sep 2025 14:45:39 +0800 Subject: [PATCH 044/104] add changelog Signed-off-by: 0xLeo258 --- changelogs/unreleased/9248-0xLeo258 | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/unreleased/9248-0xLeo258 diff --git a/changelogs/unreleased/9248-0xLeo258 b/changelogs/unreleased/9248-0xLeo258 new file mode 100644 index 000000000..8332dcade --- /dev/null +++ b/changelogs/unreleased/9248-0xLeo258 @@ -0,0 +1 @@ +Protect VolumeSnapshot field from race condition during multi-thread backup From 1ebe357d189c6184a7a5d8f7ca30eb270aa48555 Mon Sep 17 00:00:00 2001 From: 0xLeo258 Date: Tue, 16 Sep 2025 13:25:54 +0800 Subject: [PATCH 045/104] Add built-in mutex for SynchronizedVSList && Update unit tests Signed-off-by: 0xLeo258 --- pkg/backup/backup_test.go | 4 ++-- pkg/backup/item_backupper.go | 4 +--- pkg/backup/request.go | 22 +++++++++++++++++++--- pkg/controller/backup_controller.go | 6 +++--- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/pkg/backup/backup_test.go b/pkg/backup/backup_test.go index 1cf80fe0f..eb6c2d9d4 100644 --- a/pkg/backup/backup_test.go +++ b/pkg/backup/backup_test.go @@ -3269,7 +3269,7 @@ func TestBackupWithSnapshots(t *testing.T) { err := h.backupper.Backup(h.log, tc.req, backupFile, nil, nil, tc.snapshotterGetter) require.NoError(t, err) - assert.Equal(t, tc.want, tc.req.VolumeSnapshots) + assert.Equal(t, tc.want, tc.req.VolumeSnapshots.Get()) }) } } @@ -4213,7 +4213,7 @@ func TestBackupWithPodVolume(t *testing.T) { assert.Equal(t, tc.want, req.PodVolumeBackups) // this assumes that we don't have any test cases where some PVs should be snapshotted using a VolumeSnapshotter - assert.Nil(t, req.VolumeSnapshots) + assert.Nil(t, req.VolumeSnapshots.Get()) }) } } diff --git a/pkg/backup/item_backupper.go b/pkg/backup/item_backupper.go index 7b7f5cf62..068ea2315 100644 --- a/pkg/backup/item_backupper.go +++ b/pkg/backup/item_backupper.go @@ -699,9 +699,7 @@ func (ib *itemBackupper) takePVSnapshot(obj runtime.Unstructured, log logrus.Fie snapshot.Status.Phase = volume.SnapshotPhaseCompleted snapshot.Status.ProviderSnapshotID = snapshotID } - ib.backupRequest.requestLock.Lock() - defer ib.backupRequest.requestLock.Unlock() - ib.backupRequest.VolumeSnapshots = append(ib.backupRequest.VolumeSnapshots, snapshot) + ib.backupRequest.VolumeSnapshots.Add(snapshot) // nil errors are automatically removed return kubeerrs.NewAggregate(errs) diff --git a/pkg/backup/request.go b/pkg/backup/request.go index b81bde74d..c3dae48a6 100644 --- a/pkg/backup/request.go +++ b/pkg/backup/request.go @@ -34,11 +34,27 @@ type itemKey struct { name string } +type SynchronizedVSList struct { + sync.Mutex + VolumeSnapshotList []*volume.Snapshot +} + +func (s *SynchronizedVSList) Add(vs *volume.Snapshot) { + s.Lock() + defer s.Unlock() + s.VolumeSnapshotList = append(s.VolumeSnapshotList, vs) +} + +func (s *SynchronizedVSList) Get() []*volume.Snapshot { + s.Lock() + defer s.Unlock() + return s.VolumeSnapshotList +} + // Request is a request for a backup, with all references to other objects // materialized (e.g. backup/snapshot locations, includes/excludes, etc.) type Request struct { *velerov1api.Backup - requestLock sync.Mutex StorageLocation *velerov1api.BackupStorageLocation SnapshotLocations []*velerov1api.VolumeSnapshotLocation NamespaceIncludesExcludes *collections.IncludesExcludes @@ -46,7 +62,7 @@ type Request struct { ResourceHooks []hook.ResourceHook ResolvedActions []framework.BackupItemResolvedActionV2 ResolvedItemBlockActions []framework.ItemBlockResolvedAction - VolumeSnapshots []*volume.Snapshot + VolumeSnapshots SynchronizedVSList PodVolumeBackups []*velerov1api.PodVolumeBackup BackedUpItems *backedUpItemsMap itemOperationsList *[]*itemoperation.BackupOperation @@ -82,7 +98,7 @@ func (r *Request) FillVolumesInformation() { } r.VolumesInformation.SkippedPVs = skippedPVMap - r.VolumesInformation.NativeSnapshots = r.VolumeSnapshots + r.VolumesInformation.NativeSnapshots = r.VolumeSnapshots.Get() r.VolumesInformation.PodVolumeBackups = r.PodVolumeBackups r.VolumesInformation.BackupOperations = *r.GetItemOperationsList() r.VolumesInformation.BackupName = r.Backup.Name diff --git a/pkg/controller/backup_controller.go b/pkg/controller/backup_controller.go index 532a5f332..c9728ea82 100644 --- a/pkg/controller/backup_controller.go +++ b/pkg/controller/backup_controller.go @@ -734,8 +734,8 @@ func (b *backupReconciler) runBackup(backup *pkgbackup.Request) error { // native snapshots phase will either be failed or completed right away // https://github.com/vmware-tanzu/velero/blob/de3ea52f0cc478e99efa7b9524c7f353514261a4/pkg/backup/item_backupper.go#L632-L639 - backup.Status.VolumeSnapshotsAttempted = len(backup.VolumeSnapshots) - for _, snap := range backup.VolumeSnapshots { + backup.Status.VolumeSnapshotsAttempted = len(backup.VolumeSnapshots.Get()) + for _, snap := range backup.VolumeSnapshots.Get() { if snap.Status.Phase == volume.SnapshotPhaseCompleted { backup.Status.VolumeSnapshotsCompleted++ } @@ -882,7 +882,7 @@ func persistBackup(backup *pkgbackup.Request, } // Velero-native volume snapshots (as opposed to CSI ones) - nativeVolumeSnapshots, errs := encode.ToJSONGzip(backup.VolumeSnapshots, "native volumesnapshots list") + nativeVolumeSnapshots, errs := encode.ToJSONGzip(backup.VolumeSnapshots.Get(), "native volumesnapshots list") if errs != nil { persistErrs = append(persistErrs, errs...) } From 0b40702900cda4a5fb23d526e8d788772828e291 Mon Sep 17 00:00:00 2001 From: Joseph Date: Mon, 22 Sep 2025 17:31:22 -0400 Subject: [PATCH 046/104] Updates Signed-off-by: Joseph --- design/wildcard-namespace-support-design.md | 43 +++++++++------------ 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/design/wildcard-namespace-support-design.md b/design/wildcard-namespace-support-design.md index d95390812..3de0e155c 100644 --- a/design/wildcard-namespace-support-design.md +++ b/design/wildcard-namespace-support-design.md @@ -1,11 +1,13 @@ -# Wildcard Namespace Includes/Excludes Support for Backups and Restores +# Wildcard (*) support for Include/Exclude Namespaces ## Abstract -Velero currently does not support wildcard characters in namespace specifications, requiring all namespaces to be specified as string literals. The only exception is the standalone "*" character, which includes all namespaces and ignores excludes. +- Velero currently does **not** support wildcard characters in namespace specifications, they must be specified as string literals +- The only exception is the standalone `*` character, which includes all namespaces and ignores excludes -This document details the approach to implementing wildcard namespace support for `--include-namespaces` and `--exclude-namespaces` flags, while preserving the existing "*" behavior for backward compatibility. + - This design details an approach to implementing wildcard namespace support for `--include-namespaces` and `--exclude-namespaces` flags +- Preserves standalone `*` for backwards compatibility ## Background @@ -14,32 +16,33 @@ This feature was requested in Issue [#1874](https://github.com/vmware-tanzu/vele ## Goals - Add support for wildcard patterns in `--include-namespaces` and `--exclude-namespaces` flags for both backup and restore -- Ensure legacy "*" behavior remains unchanged for backward compatibility +- Ensure existing `*` behavior remains unchanged for backward compatibility ## Non-Goals - Completely rethinking the way "*" is treated and allowing it to work with wildcard excludes -- Supporting complex regex patterns beyond basic glob patterns +- Supporting complex regex patterns beyond basic glob patterns: this could be explored later ## High-Level Design -## Backup +### NamespaceIncludesExcludes struct -The wildcard expansion implementation focuses on two key functions in `pkg/backup/item_collector.go`: +- `NamespaceIncludesExcludes` is a wrapper around `IncludesExcludes` +- It has a field `activeNamespaces`, which will be used by the wildcard expansion logic to run the expansion -- [`collectNamespaces`](https://github.com/vmware-tanzu/velero/blob/1535afb45e33a3d3820088e4189800a21ba55293/pkg/backup/item_collector.go#L742) - Retrieves all active namespaces and processes include/exclude filters -- [`getNamespacesToList`](https://github.com/vmware-tanzu/velero/blob/1535afb45e33a3d3820088e4189800a21ba55293/pkg/backup/item_collector.go#L638) - Resolves namespace includes/excludes to final list +### Backup -The `collectNamespaces` function is the ideal integration point because it: -- Already retrieves all active namespaces from the cluster -- Processes the user-specified namespace filters -- Can expand wildcard patterns against the complete namespace list -- Stores the resolved namespaces in new backup status fields for visibility +The wildcard expansion implementation focuses on -This approach ensures wildcard namespaces are handled consistently with the existing "*" behavior, bypassing individual namespace existence checks. +- [`getNamespacesToList`](https://github.com/vmware-tanzu/velero/blob/1535afb45e33a3d3820088e4189800a21ba55293/pkg/backup/item_collector.go#L638) - Resolves namespace includes/excludes to final list. -## Restore +- Wildcard expansion is conditionally run when the `NamespaceIncludesExcludes.ResolveNamespaceList()` func is run. + - It overwrites the `NamespaceIncludeExclude` struct's `Includes` and `Excludes` with the expanded string literal namespaces + - If there are no candidate strings for expansion, it proceeds normally + + +### Restore The wildcard expansion implementation for restore operations focuses on the main execution flow in `pkg/restore/restore.go`: @@ -154,14 +157,6 @@ type RestoreStatus struct { **Implementation**: In `pkg/backup/item_collector.go`: -```go -// collectNamespaces function (line 748-803) -if wildcard.ShouldExpandWildcards(namespaceSelector.GetIncludes(), namespaceSelector.GetExcludes()) { - if err := r.expandNamespaceWildcards(activeNamespacesList, namespaceSelector); err != nil { - return nil, errors.WithMessage(err, "failed to expand namespace wildcard patterns") - } -} -``` The expansion occurs when collecting namespaces, after retrieving all active namespaces from the cluster. The `expandNamespaceWildcards` method: - Calls `wildcard.ExpandWildcards()` with active namespaces and original patterns From a0aac09f0ad0c3130f1328a85a196bf72794bd50 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Mon, 1 Sep 2025 19:02:41 +0800 Subject: [PATCH 047/104] don't connect repo in repo controller Signed-off-by: Lyndon-Li --- changelogs/unreleased/9291-Lyndon-Li | 1 + pkg/repository/provider/unified_repo.go | 15 +-- pkg/repository/provider/unified_repo_test.go | 98 ++++++++-------- pkg/repository/udmrepo/kopialib/lib_repo.go | 23 ++-- pkg/repository/udmrepo/kopialib/repo_init.go | 55 +++++++-- .../udmrepo/kopialib/repo_init_test.go | 108 +++++++++++++++++- .../udmrepo/mocks/BackupRepoService.go | 68 +++++++++-- pkg/repository/udmrepo/repo.go | 13 ++- 8 files changed, 288 insertions(+), 93 deletions(-) create mode 100644 changelogs/unreleased/9291-Lyndon-Li diff --git a/changelogs/unreleased/9291-Lyndon-Li b/changelogs/unreleased/9291-Lyndon-Li new file mode 100644 index 000000000..8dd7c8090 --- /dev/null +++ b/changelogs/unreleased/9291-Lyndon-Li @@ -0,0 +1 @@ +Fix issue #9193, don't connect repo in repo controller \ No newline at end of file diff --git a/pkg/repository/provider/unified_repo.go b/pkg/repository/provider/unified_repo.go index 251845dac..338069325 100644 --- a/pkg/repository/provider/unified_repo.go +++ b/pkg/repository/provider/unified_repo.go @@ -26,7 +26,6 @@ import ( "strings" "time" - "github.com/kopia/kopia/repo" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -116,7 +115,7 @@ func (urp *unifiedRepoProvider) InitRepo(ctx context.Context, param RepoParam) e return errors.Wrap(err, "error to get repo options") } - err = urp.repoService.Init(ctx, *repoOption, true) + err = urp.repoService.Create(ctx, *repoOption) if err != nil { return errors.Wrap(err, "error to init backup repo") } @@ -152,7 +151,7 @@ func (urp *unifiedRepoProvider) ConnectToRepo(ctx context.Context, param RepoPar return errors.Wrap(err, "error to get repo options") } - err = urp.repoService.Init(ctx, *repoOption, false) + err = urp.repoService.Connect(ctx, *repoOption) if err != nil { return errors.Wrap(err, "error to connect backup repo") } @@ -188,20 +187,18 @@ func (urp *unifiedRepoProvider) PrepareRepo(ctx context.Context, param RepoParam return errors.Wrap(err, "error to get repo options") } - err = urp.repoService.Init(ctx, *repoOption, false) - if err == nil { + if created, err := urp.repoService.IsCreated(ctx, *repoOption); err != nil { + return errors.Wrap(err, "error to check backup repo") + } else if created { log.Debug("Repo has already been initialized remotely") return nil } - if !errors.Is(err, repo.ErrRepositoryNotInitialized) { - return errors.Wrap(err, "error to connect to backup repo") - } if param.BackupLocation.Spec.AccessMode == velerov1api.BackupStorageLocationAccessModeReadOnly { return errors.Errorf("cannot create new backup repo for read-only backup storage location %s/%s", param.BackupLocation.Namespace, param.BackupLocation.Name) } - err = urp.repoService.Init(ctx, *repoOption, true) + err = urp.repoService.Create(ctx, *repoOption) if err != nil { return errors.Wrap(err, "error to create backup repo") } diff --git a/pkg/repository/provider/unified_repo_test.go b/pkg/repository/provider/unified_repo_test.go index 9cd49742c..05f9acd3b 100644 --- a/pkg/repository/provider/unified_repo_test.go +++ b/pkg/repository/provider/unified_repo_test.go @@ -23,7 +23,6 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/aws" - "github.com/kopia/kopia/repo" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -613,7 +612,8 @@ func TestPrepareRepo(t *testing.T) { funcTable localFuncTable getter *credmock.SecretStore repoService *reposervicenmocks.BackupRepoService - retFuncInit func(context.Context, udmrepo.RepoOptions, bool) error + retFuncCreate func(context.Context, udmrepo.RepoOptions) error + retFuncCheck func(context.Context, udmrepo.RepoOptions) (bool, error) credStoreReturn string credStoreError error readOnlyBSL bool @@ -643,6 +643,24 @@ func TestPrepareRepo(t *testing.T) { }, expectedErr: "error to get repo options: error to get storage variables: fake-store-option-error", }, + { + name: "check error", + getter: new(credmock.SecretStore), + credStoreReturn: "fake-password", + funcTable: localFuncTable{ + getStorageVariables: func(*velerov1api.BackupStorageLocation, string, string, map[string]string) (map[string]string, error) { + return map[string]string{}, nil + }, + getStorageCredentials: func(*velerov1api.BackupStorageLocation, velerocredentials.FileStore) (map[string]string, error) { + return map[string]string{}, nil + }, + }, + repoService: new(reposervicenmocks.BackupRepoService), + retFuncCheck: func(ctx context.Context, repoOption udmrepo.RepoOptions) (bool, error) { + return false, errors.New("fake-error") + }, + expectedErr: "error to check backup repo: fake-error", + }, { name: "already initialized", getter: new(credmock.SecretStore), @@ -656,10 +674,10 @@ func TestPrepareRepo(t *testing.T) { }, }, repoService: new(reposervicenmocks.BackupRepoService), - retFuncInit: func(ctx context.Context, repoOption udmrepo.RepoOptions, createNew bool) error { - if !createNew { - return nil - } + retFuncCheck: func(ctx context.Context, repoOption udmrepo.RepoOptions) (bool, error) { + return true, nil + }, + retFuncCreate: func(ctx context.Context, repoOption udmrepo.RepoOptions) error { return errors.New("fake-error") }, }, @@ -677,35 +695,14 @@ func TestPrepareRepo(t *testing.T) { }, }, repoService: new(reposervicenmocks.BackupRepoService), - retFuncInit: func(ctx context.Context, repoOption udmrepo.RepoOptions, createNew bool) error { - if !createNew { - return repo.ErrRepositoryNotInitialized - } + retFuncCheck: func(ctx context.Context, repoOption udmrepo.RepoOptions) (bool, error) { + return false, nil + }, + retFuncCreate: func(ctx context.Context, repoOption udmrepo.RepoOptions) error { return errors.New("fake-error-2") }, expectedErr: "cannot create new backup repo for read-only backup storage location velero/fake-bsl", }, - { - name: "connect fail", - getter: new(credmock.SecretStore), - credStoreReturn: "fake-password", - funcTable: localFuncTable{ - getStorageVariables: func(*velerov1api.BackupStorageLocation, string, string, map[string]string) (map[string]string, error) { - return map[string]string{}, nil - }, - getStorageCredentials: func(*velerov1api.BackupStorageLocation, velerocredentials.FileStore) (map[string]string, error) { - return map[string]string{}, nil - }, - }, - repoService: new(reposervicenmocks.BackupRepoService), - retFuncInit: func(ctx context.Context, repoOption udmrepo.RepoOptions, createNew bool) error { - if !createNew { - return errors.New("fake-error-1") - } - return errors.New("fake-error-2") - }, - expectedErr: "error to connect to backup repo: fake-error-1", - }, { name: "initialize error", getter: new(credmock.SecretStore), @@ -719,10 +716,10 @@ func TestPrepareRepo(t *testing.T) { }, }, repoService: new(reposervicenmocks.BackupRepoService), - retFuncInit: func(ctx context.Context, repoOption udmrepo.RepoOptions, createNew bool) error { - if !createNew { - return repo.ErrRepositoryNotInitialized - } + retFuncCheck: func(ctx context.Context, repoOption udmrepo.RepoOptions) (bool, error) { + return false, nil + }, + retFuncCreate: func(ctx context.Context, repoOption udmrepo.RepoOptions) error { return errors.New("fake-error-2") }, expectedErr: "error to create backup repo: fake-error-2", @@ -740,10 +737,10 @@ func TestPrepareRepo(t *testing.T) { }, }, repoService: new(reposervicenmocks.BackupRepoService), - retFuncInit: func(ctx context.Context, repoOption udmrepo.RepoOptions, createNew bool) error { - if !createNew { - return repo.ErrRepositoryNotInitialized - } + retFuncCheck: func(ctx context.Context, repoOption udmrepo.RepoOptions) (bool, error) { + return false, nil + }, + retFuncCreate: func(ctx context.Context, repoOption udmrepo.RepoOptions) error { return nil }, }, @@ -767,7 +764,8 @@ func TestPrepareRepo(t *testing.T) { log: velerotest.NewLogger(), } - tc.repoService.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(tc.retFuncInit) + tc.repoService.On("IsCreated", mock.Anything, mock.Anything).Return(tc.retFuncCheck) + tc.repoService.On("Create", mock.Anything, mock.Anything, mock.Anything).Return(tc.retFuncCreate) if tc.readOnlyBSL { bsl.Spec.AccessMode = velerov1api.BackupStorageLocationAccessModeReadOnly @@ -1134,7 +1132,7 @@ func TestInitRepo(t *testing.T) { }, }, repoService: new(reposervicenmocks.BackupRepoService), - retFuncInit: func(context.Context, udmrepo.RepoOptions, bool) error { + retFuncInit: func(context.Context, udmrepo.RepoOptions) error { return errors.New("fake-error-1") }, expectedErr: "error to init backup repo: fake-error-1", @@ -1152,7 +1150,7 @@ func TestInitRepo(t *testing.T) { }, }, repoService: new(reposervicenmocks.BackupRepoService), - retFuncInit: func(context.Context, udmrepo.RepoOptions, bool) error { + retFuncInit: func(context.Context, udmrepo.RepoOptions) error { return nil }, }, @@ -1177,7 +1175,7 @@ func TestInitRepo(t *testing.T) { } if tc.repoService != nil { - tc.repoService.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(tc.retFuncInit) + tc.repoService.On("Create", mock.Anything, mock.Anything).Return(tc.retFuncInit) } if tc.readOnlyBSL { @@ -1228,7 +1226,7 @@ func TestConnectToRepo(t *testing.T) { }, }, repoService: new(reposervicenmocks.BackupRepoService), - retFuncInit: func(context.Context, udmrepo.RepoOptions, bool) error { + retFuncInit: func(context.Context, udmrepo.RepoOptions) error { return errors.New("fake-error-1") }, expectedErr: "error to connect backup repo: fake-error-1", @@ -1246,7 +1244,7 @@ func TestConnectToRepo(t *testing.T) { }, }, repoService: new(reposervicenmocks.BackupRepoService), - retFuncInit: func(context.Context, udmrepo.RepoOptions, bool) error { + retFuncInit: func(context.Context, udmrepo.RepoOptions) error { return nil }, }, @@ -1271,7 +1269,7 @@ func TestConnectToRepo(t *testing.T) { } if tc.repoService != nil { - tc.repoService.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(tc.retFuncInit) + tc.repoService.On("Connect", mock.Anything, mock.Anything).Return(tc.retFuncInit) } err := urp.ConnectToRepo(t.Context(), RepoParam{ @@ -1329,7 +1327,7 @@ func TestBoostRepoConnect(t *testing.T) { return errors.New("fake-error-1") }, }, - retFuncInit: func(context.Context, udmrepo.RepoOptions, bool) error { + retFuncInit: func(context.Context, udmrepo.RepoOptions) error { return errors.New("fake-error-2") }, expectedErr: "error to connect backup repo: fake-error-2", @@ -1356,7 +1354,7 @@ func TestBoostRepoConnect(t *testing.T) { return errors.New("fake-error-1") }, }, - retFuncInit: func(context.Context, udmrepo.RepoOptions, bool) error { + retFuncInit: func(context.Context, udmrepo.RepoOptions) error { return nil }, }, @@ -1383,7 +1381,7 @@ func TestBoostRepoConnect(t *testing.T) { return nil }, }, - retFuncInit: func(context.Context, udmrepo.RepoOptions, bool) error { + retFuncInit: func(context.Context, udmrepo.RepoOptions) error { return nil }, }, @@ -1411,7 +1409,7 @@ func TestBoostRepoConnect(t *testing.T) { if tc.repoService != nil { tc.repoService.On("Open", mock.Anything, mock.Anything).Return(tc.retFuncOpen[0], tc.retFuncOpen[1]) - tc.repoService.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(tc.retFuncInit) + tc.repoService.On("Connect", mock.Anything, mock.Anything).Return(tc.retFuncInit) } if tc.backupRepo != nil { diff --git a/pkg/repository/udmrepo/kopialib/lib_repo.go b/pkg/repository/udmrepo/kopialib/lib_repo.go index d1eeb88d0..92336bbd4 100644 --- a/pkg/repository/udmrepo/kopialib/lib_repo.go +++ b/pkg/repository/udmrepo/kopialib/lib_repo.go @@ -92,19 +92,28 @@ func NewKopiaRepoService(logger logrus.FieldLogger) udmrepo.BackupRepoService { return ks } -func (ks *kopiaRepoService) Init(ctx context.Context, repoOption udmrepo.RepoOptions, createNew bool) error { +func (ks *kopiaRepoService) Create(ctx context.Context, repoOption udmrepo.RepoOptions) error { repoCtx := kopia.SetupKopiaLog(ctx, ks.logger) - if createNew { - if err := CreateBackupRepo(repoCtx, repoOption, ks.logger); err != nil { - return err - } - - return writeInitParameters(repoCtx, repoOption, ks.logger) + if err := CreateBackupRepo(repoCtx, repoOption, ks.logger); err != nil { + return err } + + return writeInitParameters(repoCtx, repoOption, ks.logger) +} + +func (ks *kopiaRepoService) Connect(ctx context.Context, repoOption udmrepo.RepoOptions) error { + repoCtx := kopia.SetupKopiaLog(ctx, ks.logger) + return ConnectBackupRepo(repoCtx, repoOption, ks.logger) } +func (ks *kopiaRepoService) IsCreated(ctx context.Context, repoOption udmrepo.RepoOptions) (bool, error) { + repoCtx := kopia.SetupKopiaLog(ctx, ks.logger) + + return IsBackupRepoCreated(repoCtx, repoOption, ks.logger) +} + func (ks *kopiaRepoService) Open(ctx context.Context, repoOption udmrepo.RepoOptions) (udmrepo.BackupRepo, error) { repoConfig := repoOption.ConfigFilePath if repoConfig == "" { diff --git a/pkg/repository/udmrepo/kopialib/repo_init.go b/pkg/repository/udmrepo/kopialib/repo_init.go index 76f8b0e45..872d2df5c 100644 --- a/pkg/repository/udmrepo/kopialib/repo_init.go +++ b/pkg/repository/udmrepo/kopialib/repo_init.go @@ -24,6 +24,7 @@ import ( "github.com/kopia/kopia/repo" "github.com/kopia/kopia/repo/blob" + "github.com/kopia/kopia/repo/format" "github.com/pkg/errors" "github.com/vmware-tanzu/velero/pkg/repository/udmrepo" @@ -47,10 +48,6 @@ var backendStores = []kopiaBackendStore{ // CreateBackupRepo creates a Kopia repository and then connect to it. // The storage must be empty, otherwise, it will fail func CreateBackupRepo(ctx context.Context, repoOption udmrepo.RepoOptions, logger logrus.FieldLogger) error { - if repoOption.ConfigFilePath == "" { - return errors.New("invalid config file path") - } - backendStore, err := setupBackendStore(ctx, repoOption.StorageType, repoOption.StorageOptions, logger) if err != nil { return errors.Wrap(err, "error to setup backend storage") @@ -66,11 +63,6 @@ func CreateBackupRepo(ctx context.Context, repoOption udmrepo.RepoOptions, logge return errors.Wrap(err, "error to create repo with storage") } - err = connectWithStorage(ctx, st, repoOption) - if err != nil { - return errors.Wrap(err, "error to connect repo with storage") - } - return nil } @@ -99,6 +91,34 @@ func ConnectBackupRepo(ctx context.Context, repoOption udmrepo.RepoOptions, logg return nil } +func IsBackupRepoCreated(ctx context.Context, repoOption udmrepo.RepoOptions, logger logrus.FieldLogger) (bool, error) { + backendStore, err := setupBackendStore(ctx, repoOption.StorageType, repoOption.StorageOptions, logger) + if err != nil { + return false, errors.Wrap(err, "error to setup backend storage") + } + + st, err := backendStore.store.Connect(ctx, false, logger) + if err != nil { + return false, errors.Wrap(err, "error to connect to storage") + } + + var formatBytes byteBuffer + if err := st.GetBlob(ctx, format.KopiaRepositoryBlobID, 0, -1, &formatBytes); err != nil { + if errors.Is(err, blob.ErrBlobNotFound) { + return false, nil + } + + return false, errors.Wrap(err, "error to read format blob") + } + + _, err = format.ParseKopiaRepositoryJSON(formatBytes.buffer) + if err != nil { + return false, err + } + + return true, nil +} + func findBackendStore(storage string) *kopiaBackendStore { for _, options := range backendStores { if strings.EqualFold(options.name, storage) { @@ -160,3 +180,20 @@ func ensureEmpty(ctx context.Context, s blob.Storage) error { return errors.Wrap(err, "error to list blobs") } + +type byteBuffer struct { + buffer []byte +} + +func (b *byteBuffer) Write(p []byte) (n int, err error) { + b.buffer = append(b.buffer, p...) + return len(p), nil +} + +func (b *byteBuffer) Reset() { + b.buffer = nil +} + +func (b *byteBuffer) Length() int { + return len(b.buffer) +} diff --git a/pkg/repository/udmrepo/kopialib/repo_init_test.go b/pkg/repository/udmrepo/kopialib/repo_init_test.go index 481ca4a98..d4333f634 100644 --- a/pkg/repository/udmrepo/kopialib/repo_init_test.go +++ b/pkg/repository/udmrepo/kopialib/repo_init_test.go @@ -17,12 +17,16 @@ limitations under the License. package kopialib import ( + "context" "testing" + "github.com/kopia/kopia/repo/blob" + velerotest "github.com/vmware-tanzu/velero/pkg/test" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" "github.com/vmware-tanzu/velero/pkg/repository/udmrepo" storagemocks "github.com/vmware-tanzu/velero/pkg/repository/udmrepo/kopialib/backend/mocks" @@ -55,10 +59,6 @@ func TestCreateBackupRepo(t *testing.T) { listBlobErr error expectedErr string }{ - { - name: "invalid config file", - expectedErr: "invalid config file path", - }, { name: "storage setup fail, invalid type", repoOptions: udmrepo.RepoOptions{ @@ -238,3 +238,103 @@ func TestConnectBackupRepo(t *testing.T) { }) } } + +func TestIsBackupRepoCreated(t *testing.T) { + testCases := []struct { + name string + backendStore *storagemocks.Store + repoOptions udmrepo.RepoOptions + connectErr error + setupError error + returnStore *storagemocks.Storage + retFuncGetBlob func(context.Context, blob.ID, int64, int64, blob.OutputBuffer) error + expected bool + expectedErr string + }{ + { + name: "storage setup fail, invalid type", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "fake-file", + }, + expectedErr: "error to setup backend storage: error to find storage type", + }, + { + name: "storage setup fail, backend store steup fail", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "fake-file", + StorageType: udmrepo.StorageTypeAzure, + }, + backendStore: new(storagemocks.Store), + setupError: errors.New("fake-setup-error"), + expectedErr: "error to setup backend storage: error to setup storage: fake-setup-error", + }, + { + name: "storage connect fail", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "fake-file", + StorageType: udmrepo.StorageTypeAzure, + }, + backendStore: new(storagemocks.Store), + connectErr: errors.New("fake-connect-error"), + expectedErr: "error to connect to storage: fake-connect-error", + }, + { + name: "get blob error", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "fake-file", + StorageType: udmrepo.StorageTypeAzure, + }, + backendStore: new(storagemocks.Store), + returnStore: new(storagemocks.Storage), + retFuncGetBlob: func(context.Context, blob.ID, int64, int64, blob.OutputBuffer) error { + return errors.New("fake-get-blob-error") + }, + expectedErr: "error to read format blob: fake-get-blob-error", + }, + { + name: "wrong format", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "fake-file", + StorageType: udmrepo.StorageTypeAzure, + }, + backendStore: new(storagemocks.Store), + returnStore: new(storagemocks.Storage), + retFuncGetBlob: func(ctx context.Context, id blob.ID, offset int64, length int64, output blob.OutputBuffer) error { + output.Write([]byte("fake-buffer")) + return nil + }, + expectedErr: "invalid format blob: invalid character 'k' in literal false (expecting 'l')", + }, + } + + logger := velerotest.NewLogger() + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + backendStores = []kopiaBackendStore{ + {udmrepo.StorageTypeAzure, "fake store", tc.backendStore}, + {udmrepo.StorageTypeFs, "fake store", tc.backendStore}, + {udmrepo.StorageTypeGcs, "fake store", tc.backendStore}, + {udmrepo.StorageTypeS3, "fake store", tc.backendStore}, + } + + if tc.backendStore != nil { + tc.backendStore.On("Connect", mock.Anything, mock.Anything, mock.Anything).Return(tc.returnStore, tc.connectErr) + tc.backendStore.On("Setup", mock.Anything, mock.Anything, mock.Anything).Return(tc.setupError) + } + + if tc.returnStore != nil { + tc.returnStore.On("GetBlob", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.retFuncGetBlob) + } + + created, err := IsBackupRepoCreated(t.Context(), tc.repoOptions, logger) + + if tc.expectedErr == "" { + require.NoError(t, err) + } else { + require.EqualError(t, err, tc.expectedErr) + } + + assert.Equal(t, tc.expected, created) + }) + } +} diff --git a/pkg/repository/udmrepo/mocks/BackupRepoService.go b/pkg/repository/udmrepo/mocks/BackupRepoService.go index 2acf94816..2d3a697d5 100644 --- a/pkg/repository/udmrepo/mocks/BackupRepoService.go +++ b/pkg/repository/udmrepo/mocks/BackupRepoService.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.53.2. DO NOT EDIT. package mocks @@ -16,7 +16,43 @@ type BackupRepoService struct { mock.Mock } -// DefaultMaintenanceFrequency provides a mock function with given fields: +// Connect provides a mock function with given fields: ctx, repoOption +func (_m *BackupRepoService) Connect(ctx context.Context, repoOption udmrepo.RepoOptions) error { + ret := _m.Called(ctx, repoOption) + + if len(ret) == 0 { + panic("no return value specified for Connect") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, udmrepo.RepoOptions) error); ok { + r0 = rf(ctx, repoOption) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Create provides a mock function with given fields: ctx, repoOption +func (_m *BackupRepoService) Create(ctx context.Context, repoOption udmrepo.RepoOptions) error { + ret := _m.Called(ctx, repoOption) + + if len(ret) == 0 { + panic("no return value specified for Create") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, udmrepo.RepoOptions) error); ok { + r0 = rf(ctx, repoOption) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DefaultMaintenanceFrequency provides a mock function with no fields func (_m *BackupRepoService) DefaultMaintenanceFrequency() time.Duration { ret := _m.Called() @@ -34,22 +70,32 @@ func (_m *BackupRepoService) DefaultMaintenanceFrequency() time.Duration { return r0 } -// Init provides a mock function with given fields: ctx, repoOption, createNew -func (_m *BackupRepoService) Init(ctx context.Context, repoOption udmrepo.RepoOptions, createNew bool) error { - ret := _m.Called(ctx, repoOption, createNew) +// IsCreated provides a mock function with given fields: ctx, repoOption +func (_m *BackupRepoService) IsCreated(ctx context.Context, repoOption udmrepo.RepoOptions) (bool, error) { + ret := _m.Called(ctx, repoOption) if len(ret) == 0 { - panic("no return value specified for Init") + panic("no return value specified for IsCreated") } - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, udmrepo.RepoOptions, bool) error); ok { - r0 = rf(ctx, repoOption, createNew) + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, udmrepo.RepoOptions) (bool, error)); ok { + return rf(ctx, repoOption) + } + if rf, ok := ret.Get(0).(func(context.Context, udmrepo.RepoOptions) bool); ok { + r0 = rf(ctx, repoOption) } else { - r0 = ret.Error(0) + r0 = ret.Get(0).(bool) } - return r0 + if rf, ok := ret.Get(1).(func(context.Context, udmrepo.RepoOptions) error); ok { + r1 = rf(ctx, repoOption) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } // Maintain provides a mock function with given fields: ctx, repoOption diff --git a/pkg/repository/udmrepo/repo.go b/pkg/repository/udmrepo/repo.go index 0adb39751..44f1a457b 100644 --- a/pkg/repository/udmrepo/repo.go +++ b/pkg/repository/udmrepo/repo.go @@ -77,10 +77,17 @@ type AdvancedFeatureInfo struct { // BackupRepoService is used to initialize, open or maintain a backup repository type BackupRepoService interface { - // Init creates a backup repository or connect to an existing backup repository. + // Create creates a new backup repository. // repoOption: option to the backup repository and the underlying backup storage. - // createNew: indicates whether to create a new or connect to an existing backup repository. - Init(ctx context.Context, repoOption RepoOptions, createNew bool) error + Create(ctx context.Context, repoOption RepoOptions) error + + // Connect connects to an existing backup repository. + // repoOption: option to the backup repository and the underlying backup storage. + Connect(ctx context.Context, repoOption RepoOptions) error + + // IsCreated checks if the backup repository has been created in the underlying backup storage. + // repoOption: option to the underlying backup storage + IsCreated(ctx context.Context, repoOption RepoOptions) (bool, error) // Open opens an backup repository that has been created/connected. // repoOption: options to open the backup repository and the underlying storage. From 14a6315667a2e3e2ead461f331fcabbaf2defa24 Mon Sep 17 00:00:00 2001 From: Joseph Date: Thu, 25 Sep 2025 04:09:59 -0400 Subject: [PATCH 048/104] update Signed-off-by: Joseph --- design/wildcard-namespace-support-design.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/design/wildcard-namespace-support-design.md b/design/wildcard-namespace-support-design.md index 3de0e155c..be293b39e 100644 --- a/design/wildcard-namespace-support-design.md +++ b/design/wildcard-namespace-support-design.md @@ -29,17 +29,25 @@ This feature was requested in Issue [#1874](https://github.com/vmware-tanzu/vele ### NamespaceIncludesExcludes struct - `NamespaceIncludesExcludes` is a wrapper around `IncludesExcludes` -- It has a field `activeNamespaces`, which will be used by the wildcard expansion logic to run the expansion +- It has a field `activeNamespaces`, which will be used to match wildcard patterns against active namespaces ### Backup -The wildcard expansion implementation focuses on +The wildcard expansion implementation expands the patterns before the normal flow. It focuses on two key functions in `pkg/backup/item_collector.go`: -- [`getNamespacesToList`](https://github.com/vmware-tanzu/velero/blob/1535afb45e33a3d3820088e4189800a21ba55293/pkg/backup/item_collector.go#L638) - Resolves namespace includes/excludes to final list. +- [`getResourceItems`](https://github.com/vmware-tanzu/velero/blob/main/pkg/backup/item_collector.go#L356) - Integration point +- [`collectNamespaces`](https://github.com/vmware-tanzu/velero/blob/main/pkg/backup/item_collector.go#L742) +- [`getNamespacesToList`](https://github.com/vmware-tanzu/velero/blob/main/pkg/backup/item_collector.go#L638) -- Wildcard expansion is conditionally run when the `NamespaceIncludesExcludes.ResolveNamespaceList()` func is run. - - It overwrites the `NamespaceIncludeExclude` struct's `Includes` and `Excludes` with the expanded string literal namespaces - - If there are no candidate strings for expansion, it proceeds normally +The `getResourceItems` function is the ideal integration point, as the other two funcs depend on it + +Wildcard expansion is conditionally run when the [`NamespaceIncludesExcludes.ResolveNamespaceList()`](https://github.com/vmware-tanzu/velero/blob/main/pkg/util/collections/includes_excludes.go#L146) function is called: +- It calls [`wildcard.ShouldExpandWildcards()`](https://github.com/vmware-tanzu/velero/blob/main/pkg/util/wildcard/wildcard.go) to determine if expansion is needed +- If wildcards are detected, it uses [`wildcard.ExpandWildcards()`](https://github.com/vmware-tanzu/velero/blob/main/pkg/util/wildcard/wildcard.go) to resolve them against active namespaces +- It overwrites the `NamespaceIncludesExcludes` struct's `Includes` and `Excludes` with the expanded literal namespaces using [`SetIncludes()`](https://github.com/vmware-tanzu/velero/blob/main/pkg/util/collections/includes_excludes.go#L100) and [`SetExcludes()`](https://github.com/vmware-tanzu/velero/blob/main/pkg/util/collections/includes_excludes.go#L107) +- If no wildcard patterns are found, it proceeds with normal glob-based processing via [`resolveNamespaceListTraditional()`](https://github.com/vmware-tanzu/velero/blob/main/pkg/util/collections/includes_excludes.go#L170) + +This approach ensures wildcard namespaces are handled consistently with the existing "*" behavior, bypassing individual namespace existence checks. ### Restore From cf7a9495c5f82cfcc1bd3c2f0ae8d0150cc3761d Mon Sep 17 00:00:00 2001 From: Joseph Date: Thu, 25 Sep 2025 04:40:13 -0400 Subject: [PATCH 049/104] Leaner design Signed-off-by: Joseph --- design/wildcard-namespace-support-design.md | 53 ++++++++------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/design/wildcard-namespace-support-design.md b/design/wildcard-namespace-support-design.md index be293b39e..6f81af668 100644 --- a/design/wildcard-namespace-support-design.md +++ b/design/wildcard-namespace-support-design.md @@ -3,11 +3,8 @@ ## Abstract -- Velero currently does **not** support wildcard characters in namespace specifications, they must be specified as string literals -- The only exception is the standalone `*` character, which includes all namespaces and ignores excludes - - - This design details an approach to implementing wildcard namespace support for `--include-namespaces` and `--exclude-namespaces` flags -- Preserves standalone `*` for backwards compatibility +- Velero currently does **not** support wildcard characters in namespace include/exclude specs, they must be specified as string literals +- This design details an approach to implementing wildcard namespace support ## Background @@ -20,7 +17,6 @@ This feature was requested in Issue [#1874](https://github.com/vmware-tanzu/vele ## Non-Goals -- Completely rethinking the way "*" is treated and allowing it to work with wildcard excludes - Supporting complex regex patterns beyond basic glob patterns: this could be explored later @@ -33,21 +29,28 @@ This feature was requested in Issue [#1874](https://github.com/vmware-tanzu/vele ### Backup -The wildcard expansion implementation expands the patterns before the normal flow. It focuses on two key functions in `pkg/backup/item_collector.go`: +The wildcard expansion implementation expands the patterns before the normal execution of the backup. +The goal here is ensuring wildcard namespaces are expanded before they're required. +It focuses on two key functions in `pkg/backup/item_collector.go`: -- [`getResourceItems`](https://github.com/vmware-tanzu/velero/blob/main/pkg/backup/item_collector.go#L356) - Integration point - [`collectNamespaces`](https://github.com/vmware-tanzu/velero/blob/main/pkg/backup/item_collector.go#L742) - [`getNamespacesToList`](https://github.com/vmware-tanzu/velero/blob/main/pkg/backup/item_collector.go#L638) -The `getResourceItems` function is the ideal integration point, as the other two funcs depend on it +Call to expand wildcards is made at: +- [`getResourceItems`](https://github.com/vmware-tanzu/velero/blob/main/pkg/backup/item_collector.go#L356) - Integration point + Wildcard expansion is conditionally run when the [`NamespaceIncludesExcludes.ResolveNamespaceList()`](https://github.com/vmware-tanzu/velero/blob/main/pkg/util/collections/includes_excludes.go#L146) function is called: + +unc (nie *NamespaceIncludesExcludes) ResolveNamespaceList() ([]string, bool, error) { + - It calls [`wildcard.ShouldExpandWildcards()`](https://github.com/vmware-tanzu/velero/blob/main/pkg/util/wildcard/wildcard.go) to determine if expansion is needed - If wildcards are detected, it uses [`wildcard.ExpandWildcards()`](https://github.com/vmware-tanzu/velero/blob/main/pkg/util/wildcard/wildcard.go) to resolve them against active namespaces - It overwrites the `NamespaceIncludesExcludes` struct's `Includes` and `Excludes` with the expanded literal namespaces using [`SetIncludes()`](https://github.com/vmware-tanzu/velero/blob/main/pkg/util/collections/includes_excludes.go#L100) and [`SetExcludes()`](https://github.com/vmware-tanzu/velero/blob/main/pkg/util/collections/includes_excludes.go#L107) -- If no wildcard patterns are found, it proceeds with normal glob-based processing via [`resolveNamespaceListTraditional()`](https://github.com/vmware-tanzu/velero/blob/main/pkg/util/collections/includes_excludes.go#L170) +- It returns the effective list of namespaces to be backed up and a bool indicating whether wildcard expansion occured + + -This approach ensures wildcard namespaces are handled consistently with the existing "*" behavior, bypassing individual namespace existence checks. ### Restore @@ -231,12 +234,11 @@ The status fields are populated immediately after successful wildcard expansion, Several implementation approaches were considered for the wildcard expansion logic: -### 1. Wildcard expansion in `getNamespacesToList` +### 1. Wildcard expansion in `getNamespacesToList` or `collectNamespaces` This approach was ruled out because: -- The `collectNamespaces` function encounters wildcard patterns first in the processing flow -- `collectNamespaces` already has access to the complete list of active namespaces, eliminating the need for additional API calls -- Placing the logic in `getNamespacesToList` would require redundant namespace retrieval +- Both funcs expect non-wildcard namespaces in the NamespaceIncludesExcludes struct +- Calling it at a higher level within getResourceItems is ideal ### 2. Client-side wildcard expansion @@ -254,29 +256,16 @@ This feature does not introduce any security vulnerabilities as it only affects ### Backward Compatibility The implementation maintains full backward compatibility with existing behavior: -- The standalone "*" character continues to work as before (include all namespaces, ignore excludes) -- Existing backup configurations remain unaffected +- The standalone "*" character continues to work as before ### Known Limitations -1. **Mixed "*" and wildcard usage**: When using the standalone "*" in includes, the legacy implementation takes precedence and wildcard expansion is skipped. This means you cannot combine "*" (all namespaces) in includes with wildcard patterns in excludes. - -2. **Selective exclusion limitation**: The current design does not support selective pattern-based exclusion when including all namespaces via "*". +N/A ## Implementation -The implementation follows the detailed design outlined above, with the following timeline: - -1. **Phase 1**: Add backup CRD status fields for expanded namespaces -2. **Phase 2**: Implement wildcard utility package with validation -3. **Phase 3**: Integrate expansion logic into backup item collection -4. **Phase 4**: Add status field population and logging +Aiming for 1.18 ## Open Issues -**Restore Integration**: Restore operations are completely decoupled from backup wildcard specifications and work safely with wildcard-created backups. The restore process reads the actual tar file contents to determine available namespaces, not the original backup spec. Since the tar file contains real, materialized namespaces (e.g., `test01`, `test02`) rather than wildcard patterns (e.g., `test*`), restore operations work with concrete namespace names. - -When wildcard patterns are specified in restore operations, they are expanded against the namespaces that actually exist in the backup tar file. This ensures that restore wildcard expansion is based on what was actually backed up, not what was originally intended to be backed up. - -**Crucially, restore does not treat `*` as a catch all case**. -This means that if `*` is mentioned in restore, wildcard expansion is skipped owing to how it's treated in backup. +N/A From 78ddeef96c2a8d877bfbe7e78182dde8a55525d0 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Thu, 25 Sep 2025 18:19:23 +0800 Subject: [PATCH 050/104] add cache dir to VGDP Signed-off-by: Lyndon-Li --- pkg/cmd/cli/datamover/restore.go | 4 +++- pkg/cmd/cli/podvolume/restore.go | 4 +++- pkg/datamover/restore_micro_service.go | 5 ++++- pkg/datapath/file_system.go | 7 ++++--- pkg/podvolume/restore_micro_service.go | 5 ++++- pkg/repository/provider/provider.go | 1 + 6 files changed, 19 insertions(+), 7 deletions(-) diff --git a/pkg/cmd/cli/datamover/restore.go b/pkg/cmd/cli/datamover/restore.go index 7e11df822..b2efdbc34 100644 --- a/pkg/cmd/cli/datamover/restore.go +++ b/pkg/cmd/cli/datamover/restore.go @@ -53,6 +53,7 @@ type dataMoverRestoreConfig struct { volumePath string volumeMode string ddName string + cacheDir string resourceTimeout time.Duration } @@ -89,6 +90,7 @@ func NewRestoreCommand(f client.Factory) *cobra.Command { command.Flags().StringVar(&config.volumePath, "volume-path", config.volumePath, "The full path of the volume to be restored") command.Flags().StringVar(&config.volumeMode, "volume-mode", config.volumeMode, "The mode of the volume to be restored") command.Flags().StringVar(&config.ddName, "data-download", config.ddName, "The data download name") + command.Flags().StringVar(&config.cacheDir, "cache-volume-path", config.cacheDir, "The full path of the cache volume") command.Flags().DurationVar(&config.resourceTimeout, "resource-timeout", config.resourceTimeout, "How long to wait for resource processes which are not covered by other specific timeout parameters.") _ = command.MarkFlagRequired("volume-path") @@ -288,5 +290,5 @@ func (s *dataMoverRestore) createDataPathService() (dataPathService, error) { return datamover.NewRestoreMicroService(s.ctx, s.client, s.kubeClient, s.config.ddName, s.namespace, s.nodeName, datapath.AccessPoint{ ByPath: s.config.volumePath, VolMode: uploader.PersistentVolumeMode(s.config.volumeMode), - }, s.dataPathMgr, repoEnsurer, credGetter, duInformer, s.logger), nil + }, s.dataPathMgr, repoEnsurer, credGetter, duInformer, s.config.cacheDir, s.logger), nil } diff --git a/pkg/cmd/cli/podvolume/restore.go b/pkg/cmd/cli/podvolume/restore.go index 8d5924532..4c1596a04 100644 --- a/pkg/cmd/cli/podvolume/restore.go +++ b/pkg/cmd/cli/podvolume/restore.go @@ -51,6 +51,7 @@ import ( type podVolumeRestoreConfig struct { volumePath string pvrName string + cacheDir string resourceTimeout time.Duration } @@ -86,6 +87,7 @@ func NewRestoreCommand(f client.Factory) *cobra.Command { command.Flags().Var(formatFlag, "log-format", fmt.Sprintf("The format for log output. Valid values are %s.", strings.Join(formatFlag.AllowedValues(), ", "))) command.Flags().StringVar(&config.volumePath, "volume-path", config.volumePath, "The full path of the volume to be restored") command.Flags().StringVar(&config.pvrName, "pod-volume-restore", config.pvrName, "The PVR name") + command.Flags().StringVar(&config.cacheDir, "cache-volume-path", config.cacheDir, "The full path of the cache volume") command.Flags().DurationVar(&config.resourceTimeout, "resource-timeout", config.resourceTimeout, "How long to wait for resource processes which are not covered by other specific timeout parameters.") _ = command.MarkFlagRequired("volume-path") @@ -294,5 +296,5 @@ func (s *podVolumeRestore) createDataPathService() (dataPathService, error) { return podvolume.NewRestoreMicroService(s.ctx, s.client, s.kubeClient, s.config.pvrName, s.namespace, s.nodeName, datapath.AccessPoint{ ByPath: s.config.volumePath, VolMode: uploader.PersistentVolumeFilesystem, - }, s.dataPathMgr, repoEnsurer, credGetter, pvrInformer, s.logger), nil + }, s.dataPathMgr, repoEnsurer, credGetter, pvrInformer, s.config.cacheDir, s.logger), nil } diff --git a/pkg/datamover/restore_micro_service.go b/pkg/datamover/restore_micro_service.go index 25a3f3ff3..1b7ebcc09 100644 --- a/pkg/datamover/restore_micro_service.go +++ b/pkg/datamover/restore_micro_service.go @@ -61,11 +61,12 @@ type RestoreMicroService struct { ddInformer cache.Informer ddHandler cachetool.ResourceEventHandlerRegistration nodeName string + cacheDir string } func NewRestoreMicroService(ctx context.Context, client client.Client, kubeClient kubernetes.Interface, dataDownloadName string, namespace string, nodeName string, sourceTargetPath datapath.AccessPoint, dataPathMgr *datapath.Manager, repoEnsurer *repository.Ensurer, cred *credentials.CredentialGetter, - ddInformer cache.Informer, log logrus.FieldLogger) *RestoreMicroService { + ddInformer cache.Informer, cacheDir string, log logrus.FieldLogger) *RestoreMicroService { return &RestoreMicroService{ ctx: ctx, client: client, @@ -80,6 +81,7 @@ func NewRestoreMicroService(ctx context.Context, client client.Client, kubeClien nodeName: nodeName, resultSignal: make(chan dataPathResult), ddInformer: ddInformer, + cacheDir: cacheDir, } } @@ -172,6 +174,7 @@ func (r *RestoreMicroService) RunCancelableDataPath(ctx context.Context) (string RepoIdentifier: "", RepositoryEnsurer: r.repoEnsurer, CredentialGetter: r.credentialGetter, + CacheDir: r.cacheDir, }); err != nil { return "", errors.Wrap(err, "error to initialize data path") } diff --git a/pkg/datapath/file_system.go b/pkg/datapath/file_system.go index 7e8b292df..1ddf4b346 100644 --- a/pkg/datapath/file_system.go +++ b/pkg/datapath/file_system.go @@ -44,6 +44,7 @@ type FSBRInitParam struct { RepositoryEnsurer *repository.Ensurer CredentialGetter *credentials.CredentialGetter Filesystem filesystem.Interface + CacheDir string } // FSBRStartParam define the input param for FSBR start @@ -112,7 +113,7 @@ func (fs *fileSystemBR) Init(ctx context.Context, param any) error { return errors.Wrapf(err, "error to ensure backup repository %s-%s-%s", initParam.BSLName, initParam.SourceNamespace, initParam.RepositoryType) } - err = fs.boostRepoConnect(ctx, initParam.RepositoryType, initParam.CredentialGetter) + err = fs.boostRepoConnect(ctx, initParam.RepositoryType, initParam.CredentialGetter, initParam.CacheDir) if err != nil { return errors.Wrapf(err, "error to boost backup repository connection %s-%s-%s", initParam.BSLName, initParam.SourceNamespace, initParam.RepositoryType) } @@ -245,9 +246,9 @@ func (fs *fileSystemBR) Cancel() { fs.log.WithField("user", fs.jobName).Info("FileSystemBR is canceled") } -func (fs *fileSystemBR) boostRepoConnect(ctx context.Context, repositoryType string, credentialGetter *credentials.CredentialGetter) error { +func (fs *fileSystemBR) boostRepoConnect(ctx context.Context, repositoryType string, credentialGetter *credentials.CredentialGetter, cacheDir string) error { if repositoryType == velerov1api.BackupRepositoryTypeKopia { - if err := repoProvider.NewUnifiedRepoProvider(*credentialGetter, repositoryType, fs.log).BoostRepoConnect(ctx, repoProvider.RepoParam{BackupLocation: fs.backupLocation, BackupRepo: fs.backupRepo}); err != nil { + if err := repoProvider.NewUnifiedRepoProvider(*credentialGetter, repositoryType, fs.log).BoostRepoConnect(ctx, repoProvider.RepoParam{BackupLocation: fs.backupLocation, BackupRepo: fs.backupRepo, CacheDir: cacheDir}); err != nil { return err } } else { diff --git a/pkg/podvolume/restore_micro_service.go b/pkg/podvolume/restore_micro_service.go index 9bfc0a287..40d6aa1fb 100644 --- a/pkg/podvolume/restore_micro_service.go +++ b/pkg/podvolume/restore_micro_service.go @@ -63,11 +63,12 @@ type RestoreMicroService struct { pvrInformer cache.Informer pvrHandler cachetool.ResourceEventHandlerRegistration nodeName string + cacheDir string } func NewRestoreMicroService(ctx context.Context, client client.Client, kubeClient kubernetes.Interface, pvrName string, namespace string, nodeName string, sourceTargetPath datapath.AccessPoint, dataPathMgr *datapath.Manager, repoEnsurer *repository.Ensurer, cred *credentials.CredentialGetter, - pvrInformer cache.Informer, log logrus.FieldLogger) *RestoreMicroService { + pvrInformer cache.Informer, cacheDir string, log logrus.FieldLogger) *RestoreMicroService { return &RestoreMicroService{ ctx: ctx, client: client, @@ -82,6 +83,7 @@ func NewRestoreMicroService(ctx context.Context, client client.Client, kubeClien nodeName: nodeName, resultSignal: make(chan dataPathResult), pvrInformer: pvrInformer, + cacheDir: cacheDir, } } @@ -175,6 +177,7 @@ func (r *RestoreMicroService) RunCancelableDataPath(ctx context.Context) (string RepoIdentifier: "", RepositoryEnsurer: r.repoEnsurer, CredentialGetter: r.credentialGetter, + CacheDir: r.cacheDir, }); err != nil { return "", errors.Wrap(err, "error to initialize data path") } diff --git a/pkg/repository/provider/provider.go b/pkg/repository/provider/provider.go index d27d269da..822e69aba 100644 --- a/pkg/repository/provider/provider.go +++ b/pkg/repository/provider/provider.go @@ -27,6 +27,7 @@ import ( type RepoParam struct { BackupLocation *velerov1api.BackupStorageLocation BackupRepo *velerov1api.BackupRepository + CacheDir string } // Provider defines the methods to manipulate a backup repository From 75f1817cba52b7cd36a56a8ece3d97669a884936 Mon Sep 17 00:00:00 2001 From: Joseph Date: Thu, 25 Sep 2025 09:28:20 -0400 Subject: [PATCH 051/104] Simplify Signed-off-by: Joseph --- design/wildcard-namespace-support-design.md | 272 +++++--------------- 1 file changed, 58 insertions(+), 214 deletions(-) diff --git a/design/wildcard-namespace-support-design.md b/design/wildcard-namespace-support-design.md index 6f81af668..45c4d4641 100644 --- a/design/wildcard-namespace-support-design.md +++ b/design/wildcard-namespace-support-design.md @@ -1,271 +1,115 @@ -# Wildcard (*) support for Include/Exclude Namespaces +# Wildcard Namespace Support ## Abstract -- Velero currently does **not** support wildcard characters in namespace include/exclude specs, they must be specified as string literals -- This design details an approach to implementing wildcard namespace support +Velero currently treats namespace patterns with glob characters as literal strings. This design adds wildcard expansion to support flexible namespace selection using patterns like `app-*` or `test-{dev,staging}`. ## Background -This feature was requested in Issue [#1874](https://github.com/vmware-tanzu/velero/issues/1874) to provide more flexible namespace selection using wildcard patterns. +Requested in [#1874](https://github.com/vmware-tanzu/velero/issues/1874) for more flexible namespace selection. ## Goals -- Add support for wildcard patterns in `--include-namespaces` and `--exclude-namespaces` flags for both backup and restore -- Ensure existing `*` behavior remains unchanged for backward compatibility +- Support glob pattern expansion in namespace includes/excludes +- Maintain backward compatibility with existing `*` behavior ## Non-Goals -- Supporting complex regex patterns beyond basic glob patterns: this could be explored later - +- Complex regex patterns beyond basic globs ## High-Level Design -### NamespaceIncludesExcludes struct +Wildcard expansion occurs early in both backup and restore flows, converting patterns to literal namespace lists before normal processing. -- `NamespaceIncludesExcludes` is a wrapper around `IncludesExcludes` -- It has a field `activeNamespaces`, which will be used to match wildcard patterns against active namespaces +### Backup Flow -### Backup +Expansion happens in `getResourceItems()` before namespace collection: +1. Check if wildcards exist using `ShouldExpandWildcards()` +2. Expand patterns against active cluster namespaces +3. Replace includes/excludes with expanded literal namespaces +4. Continue with normal backup processing -The wildcard expansion implementation expands the patterns before the normal execution of the backup. -The goal here is ensuring wildcard namespaces are expanded before they're required. -It focuses on two key functions in `pkg/backup/item_collector.go`: +### Restore Flow -- [`collectNamespaces`](https://github.com/vmware-tanzu/velero/blob/main/pkg/backup/item_collector.go#L742) -- [`getNamespacesToList`](https://github.com/vmware-tanzu/velero/blob/main/pkg/backup/item_collector.go#L638) +Expansion occurs in `execute()` after parsing backup contents: +1. Extract available namespaces from backup tar +2. Expand patterns against backup namespaces (not cluster namespaces) +3. Update restore context with expanded namespaces +4. Continue with normal restore processing -Call to expand wildcards is made at: -- [`getResourceItems`](https://github.com/vmware-tanzu/velero/blob/main/pkg/backup/item_collector.go#L356) - Integration point - - -Wildcard expansion is conditionally run when the [`NamespaceIncludesExcludes.ResolveNamespaceList()`](https://github.com/vmware-tanzu/velero/blob/main/pkg/util/collections/includes_excludes.go#L146) function is called: - -unc (nie *NamespaceIncludesExcludes) ResolveNamespaceList() ([]string, bool, error) { - -- It calls [`wildcard.ShouldExpandWildcards()`](https://github.com/vmware-tanzu/velero/blob/main/pkg/util/wildcard/wildcard.go) to determine if expansion is needed -- If wildcards are detected, it uses [`wildcard.ExpandWildcards()`](https://github.com/vmware-tanzu/velero/blob/main/pkg/util/wildcard/wildcard.go) to resolve them against active namespaces -- It overwrites the `NamespaceIncludesExcludes` struct's `Includes` and `Excludes` with the expanded literal namespaces using [`SetIncludes()`](https://github.com/vmware-tanzu/velero/blob/main/pkg/util/collections/includes_excludes.go#L100) and [`SetExcludes()`](https://github.com/vmware-tanzu/velero/blob/main/pkg/util/collections/includes_excludes.go#L107) -- It returns the effective list of namespaces to be backed up and a bool indicating whether wildcard expansion occured - - - - - -### Restore - -The wildcard expansion implementation for restore operations focuses on the main execution flow in `pkg/restore/restore.go`: - -- [`execute`](https://github.com/vmware-tanzu/velero/blob/main/pkg/restore/restore.go#L430) - Main restore execution that parses backup contents and processes namespace filters -- [`extractNamespacesFromBackup`](https://github.com/vmware-tanzu/velero/blob/main/pkg/restore/restore.go#L2407) - Extracts available namespaces from backup tar contents - -The `execute` function is the ideal integration point because it: -- Already parses the backup tar file to understand available resources -- Processes the user-specified namespace filters for the restore operation -- Can expand wildcard patterns against namespaces that actually exist in the backup -- Stores the resolved namespaces in new restore status fields for visibility - -This approach ensures wildcard namespaces in restore operations are based on actual backup contents rather than original backup specifications, providing safety and consistency regardless of how the backup was created. +This ensures restore wildcards match actual backup contents, not current cluster state. ## Detailed Design -The implementation involves four main components that can be developed incrementally: +### Status Fields -### Add new status fields to the backup and restore CRDs to store expanded wildcard namespaces - -#### Backup +Add wildcard expansion tracking to backup and restore CRDs: ```go -// WildcardNamespaceStatus contains information about wildcard namespace matching results type WildcardNamespaceStatus struct { - // IncludeWildcardMatches records the namespaces that matched include wildcard patterns + // IncludeWildcardMatches records namespaces that matched include patterns // +optional - // +nullable IncludeWildcardMatches []string `json:"includeWildcardMatches,omitempty"` - - // ExcludeWildcardMatches records the namespaces that matched exclude wildcard patterns + + // ExcludeWildcardMatches records namespaces that matched exclude patterns // +optional - // +nullable ExcludeWildcardMatches []string `json:"excludeWildcardMatches,omitempty"` - - // WildcardResult records the final namespaces after applying wildcard include/exclude logic + + // WildcardResult records final namespaces after wildcard processing // +optional - // +nullable WildcardResult []string `json:"wildcardResult,omitempty"` } -// BackupStatus captures the current status of a Velero backup. +// Added to both BackupStatus and RestoreStatus type BackupStatus struct { - // ... existing fields ... - - // WildcardNamespaces contains information about wildcard namespace processing + // WildcardNamespaces contains wildcard expansion results // +optional - // +nullable WildcardNamespaces *WildcardNamespaceStatus `json:"wildcardNamespaces,omitempty"` - - // ... other fields ... } ``` -#### Restore +### Wildcard Expansion Package +New `pkg/util/wildcard/expand.go` package provides: + +- `ShouldExpandWildcards()` - Skip expansion for simple "*" case +- `ExpandWildcards()` - Main expansion function using `github.com/gobwas/glob` +- Pattern validation rejecting unsupported regex symbols + +**Supported patterns**: `*`, `?`, `[abc]`, `{a,b,c}` +**Unsupported**: `|()`, `**` + +### Implementation Details + +#### Backup Integration (`pkg/backup/item_collector.go`) + +Expansion in `getResourceItems()`: +- Call `wildcard.ExpandWildcards()` with cluster namespaces +- Update `NamespaceIncludesExcludes` with expanded results +- Populate status fields with expansion results + +#### Restore Integration (`pkg/restore/restore.go`) + +Expansion in `execute()`: ```go -// WildcardNamespaceStatus contains information about wildcard namespace matching results -type WildcardNamespaceStatus struct { - // IncludeWildcardMatches records the namespaces that matched include wildcard patterns - // +optional - // +nullable - IncludeWildcardMatches []string `json:"includeWildcardMatches,omitempty"` - - // ExcludeWildcardMatches records the namespaces that matched exclude wildcard patterns - // +optional - // +nullable - ExcludeWildcardMatches []string `json:"excludeWildcardMatches,omitempty"` - - // WildcardResult records the final namespaces after applying wildcard include/exclude logic - // +optional - // +nullable - WildcardResult []string `json:"wildcardResult,omitempty"` -} - -// RestoreStatus captures the current status of a Velero restore. -type RestoreStatus struct { - // ... existing fields ... - - // WildcardNamespaces contains information about wildcard namespace processing - // +optional - // +nullable - WildcardNamespaces *WildcardNamespaceStatus `json:"wildcardNamespaces,omitempty"` - - // ... other fields ... -} -``` - -**Implementation**: Added a structured `WildcardNamespaceStatus` type and `WildcardNamespaces` field to `pkg/apis/velero/v1/backup_types.go` and `pkg/apis/velero/v1/restore_types.go` to track the resolved namespace lists after wildcard expansion in a well-organized manner. - -### Create a util package for wildcard expansion - -**Implementation**: Created `pkg/util/wildcard/expand.go` package containing: - -- `ShouldExpandWildcards(includes, excludes []string) bool` - Determines if wildcard expansion is needed (excludes simple "*" case) -- `ExpandWildcards(activeNamespaces, includes, excludes []string) ([]string, []string, error)` - Main expansion function -- `containsWildcardPattern(pattern string) bool` - Detects wildcard patterns (`*`, `?`, `[abc]`, `{a,b,c}`) -- `validateWildcardPatterns(patterns []string) error` - Validates patterns and rejects unsupported regex symbols -- Uses `github.com/gobwas/glob` library for glob pattern matching - -**Supported patterns**: -- `*` (any characters) -- `?` (single character) -- `[abc]` (character classes) -- `{a,b,c}` (alternatives) - -**Unsupported**: Regex symbols `|()`, consecutive asterisks `**` - -### If required, expand wildcards and replace the request's includes and excludes with expanded namespaces - -### Backup: - -**Implementation**: In `pkg/backup/item_collector.go`: - - -The expansion occurs when collecting namespaces, after retrieving all active namespaces from the cluster. The `expandNamespaceWildcards` method: -- Calls `wildcard.ExpandWildcards()` with active namespaces and original patterns -- Updates the namespace selector with expanded results using `SetIncludes()` and `SetExcludes()` -- Preserves backward compatibility by skipping expansion for simple "*" pattern - -**Performance Improvement**: As part of this implementation, active namespaces are stored in a hashset rather than being iterated for each resolved/literal namespace check. This eliminates a [nested loop anti-pattern](https://github.com/vmware-tanzu/velero/blob/1535afb45e33a3d3820088e4189800a21ba55293/pkg/backup/item_collector.go#L767) and improves performance. - -### Restore - -**Implementation**: In `pkg/restore/restore.go`: - -```go -// Lines 478-509: Wildcard expansion in restore context -if wildcard.ShouldExpandWildcards(ctx.restore.Spec.IncludedNamespaces, ctx.restore.Spec.ExcludedNamespaces) { +if wildcard.ShouldExpandWildcards(includes, excludes) { availableNamespaces := extractNamespacesFromBackup(backupResources) expandedIncludes, expandedExcludes, err := wildcard.ExpandWildcards( - availableNamespaces, - ctx.restore.Spec.IncludedNamespaces, - ctx.restore.Spec.ExcludedNamespaces, - ) - // Update restore context with expanded patterns - ctx.namespaceIncludesExcludes = collections.NewIncludesExcludes(). - Includes(expandedIncludes...). - Excludes(expandedExcludes...) + availableNamespaces, includes, excludes) + // Update context and status } ``` -The restore expansion occurs after parsing the backup tar contents, using `extractNamespacesFromBackup` to determine which namespaces are actually available for restoration. This ensures wildcard patterns are applied against materialized backup contents rather than original backup specifications. - - - -### Populate the expanded namespace status field with the namespaces - -#### Backup Status Fields - -**Implementation**: In `expandNamespaceWildcards` function (line 889-891): - -```go -// Record the expanded wildcard includes/excludes in the request status -r.backupRequest.Status.WildcardNamespaces = &velerov1api.WildcardNamespaceStatus{ - IncludeWildcardMatches: expandedIncludes, - ExcludeWildcardMatches: expandedExcludes, - WildcardResult: wildcardResult, -} -``` - -#### Restore Status Fields - -**Implementation**: In `pkg/restore/restore.go` (lines 499-502): - -```go -// Record the expanded wildcard includes/excludes in the restore status -ctx.restore.Status.WildcardNamespaces = &velerov1api.WildcardNamespaceStatus{ - IncludeWildcardMatches: expandedIncludes, - ExcludeWildcardMatches: expandedExcludes, - WildcardResult: wildcardResult, -} -``` - -The status fields are populated immediately after successful wildcard expansion, providing visibility into which namespaces were actually matched by the wildcard patterns and the final list of namespaces that will be processed. - ## Alternatives Considered -Several implementation approaches were considered for the wildcard expansion logic: - -### 1. Wildcard expansion in `getNamespacesToList` or `collectNamespaces` - -This approach was ruled out because: -- Both funcs expect non-wildcard namespaces in the NamespaceIncludesExcludes struct -- Calling it at a higher level within getResourceItems is ideal - -### 2. Client-side wildcard expansion - -Expanding wildcards on the CLI side was considered but rejected because: -- It would only work for command-line initiated backups -- Scheduled backups would not benefit from this approach -- The server-side approach provides consistent behavior across all backup initiation methods - -## Security Considerations - -This feature does not introduce any security vulnerabilities as it only affects namespace selection logic within the existing backup authorization framework. +1. **Client-side expansion**: Rejected because it wouldn't work for scheduled backups +2. **Expansion in `collectNamespaces`**: Rejected because these functions expect literal namespaces ## Compatibility -### Backward Compatibility - -The implementation maintains full backward compatibility with existing behavior: -- The standalone "*" character continues to work as before - -### Known Limitations - -N/A +Maintains full backward compatibility - existing "*" behavior unchanged. ## Implementation -Aiming for 1.18 - -## Open Issues - -N/A +Target: Velero 1.18 From 4ade8cf8a2ebcf80cab841e39756042930a0ceea Mon Sep 17 00:00:00 2001 From: Scott Seago Date: Mon, 22 Sep 2025 11:50:05 -0400 Subject: [PATCH 052/104] Add option for privileged fs-backup pod Signed-off-by: Scott Seago --- changelogs/unreleased/9295-sseago | 1 + pkg/cmd/cli/nodeagent/server.go | 6 +++-- .../pod_volume_backup_controller.go | 5 +++- .../pod_volume_backup_controller_test.go | 3 ++- .../pod_volume_restore_controller.go | 5 +++- .../pod_volume_restore_controller_test.go | 2 +- pkg/exposer/pod_volume.go | 12 ++++++++-- pkg/exposer/pod_volume_test.go | 23 +++++++++++++++++++ pkg/types/node_agent.go | 3 +++ .../docs/main/customize-installation.md | 2 ++ 10 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 changelogs/unreleased/9295-sseago diff --git a/changelogs/unreleased/9295-sseago b/changelogs/unreleased/9295-sseago new file mode 100644 index 000000000..92f44c7ba --- /dev/null +++ b/changelogs/unreleased/9295-sseago @@ -0,0 +1 @@ +Add option for privileged fs-backup pod diff --git a/pkg/cmd/cli/nodeagent/server.go b/pkg/cmd/cli/nodeagent/server.go index 873e03beb..d3563c0f5 100644 --- a/pkg/cmd/cli/nodeagent/server.go +++ b/pkg/cmd/cli/nodeagent/server.go @@ -308,6 +308,8 @@ func (s *nodeAgentServer) run() { s.logger.Infof("Using customized backupPVC config %v", backupPVCConfig) } + privilegedFsBackup := s.dataPathConfigs != nil && s.dataPathConfigs.PrivilegedFsBackup + podResources := corev1api.ResourceRequirements{} if s.dataPathConfigs != nil && s.dataPathConfigs.PodResources != nil { if res, err := kube.ParseResourceRequirements(s.dataPathConfigs.PodResources.CPURequest, s.dataPathConfigs.PodResources.MemoryRequest, s.dataPathConfigs.PodResources.CPULimit, s.dataPathConfigs.PodResources.MemoryLimit); err != nil { @@ -327,12 +329,12 @@ func (s *nodeAgentServer) run() { } } - pvbReconciler := controller.NewPodVolumeBackupReconciler(s.mgr.GetClient(), s.mgr, s.kubeClient, s.dataPathMgr, s.vgdpCounter, s.nodeName, s.config.dataMoverPrepareTimeout, s.config.resourceTimeout, podResources, s.metrics, s.logger, dataMovePriorityClass) + pvbReconciler := controller.NewPodVolumeBackupReconciler(s.mgr.GetClient(), s.mgr, s.kubeClient, s.dataPathMgr, s.vgdpCounter, s.nodeName, s.config.dataMoverPrepareTimeout, s.config.resourceTimeout, podResources, s.metrics, s.logger, dataMovePriorityClass, privilegedFsBackup) if err := pvbReconciler.SetupWithManager(s.mgr); err != nil { s.logger.Fatal(err, "unable to create controller", "controller", constant.ControllerPodVolumeBackup) } - pvrReconciler := controller.NewPodVolumeRestoreReconciler(s.mgr.GetClient(), s.mgr, s.kubeClient, s.dataPathMgr, s.vgdpCounter, s.nodeName, s.config.dataMoverPrepareTimeout, s.config.resourceTimeout, podResources, s.logger, dataMovePriorityClass) + pvrReconciler := controller.NewPodVolumeRestoreReconciler(s.mgr.GetClient(), s.mgr, s.kubeClient, s.dataPathMgr, s.vgdpCounter, s.nodeName, s.config.dataMoverPrepareTimeout, s.config.resourceTimeout, podResources, s.logger, dataMovePriorityClass, privilegedFsBackup) if err := pvrReconciler.SetupWithManager(s.mgr); err != nil { s.logger.WithError(err).Fatal("Unable to create the pod volume restore controller") } diff --git a/pkg/controller/pod_volume_backup_controller.go b/pkg/controller/pod_volume_backup_controller.go index 3a446379f..625ec8337 100644 --- a/pkg/controller/pod_volume_backup_controller.go +++ b/pkg/controller/pod_volume_backup_controller.go @@ -60,7 +60,7 @@ const ( // NewPodVolumeBackupReconciler creates the PodVolumeBackupReconciler instance func NewPodVolumeBackupReconciler(client client.Client, mgr manager.Manager, kubeClient kubernetes.Interface, dataPathMgr *datapath.Manager, counter *exposer.VgdpCounter, nodeName string, preparingTimeout time.Duration, resourceTimeout time.Duration, podResources corev1api.ResourceRequirements, - metrics *metrics.ServerMetrics, logger logrus.FieldLogger, dataMovePriorityClass string) *PodVolumeBackupReconciler { + metrics *metrics.ServerMetrics, logger logrus.FieldLogger, dataMovePriorityClass string, privileged bool) *PodVolumeBackupReconciler { return &PodVolumeBackupReconciler{ client: client, mgr: mgr, @@ -77,6 +77,7 @@ func NewPodVolumeBackupReconciler(client client.Client, mgr manager.Manager, kub exposer: exposer.NewPodVolumeExposer(kubeClient, logger), cancelledPVB: make(map[string]time.Time), dataMovePriorityClass: dataMovePriorityClass, + privileged: privileged, } } @@ -97,6 +98,7 @@ type PodVolumeBackupReconciler struct { resourceTimeout time.Duration cancelledPVB map[string]time.Time dataMovePriorityClass string + privileged bool } // +kubebuilder:rbac:groups=velero.io,resources=podvolumebackups,verbs=get;list;watch;create;update;patch;delete @@ -837,6 +839,7 @@ func (r *PodVolumeBackupReconciler) setupExposeParam(pvb *velerov1api.PodVolumeB Resources: r.podResources, // Priority class name for the data mover pod, retrieved from node-agent-configmap PriorityClassName: r.dataMovePriorityClass, + Privileged: r.privileged, } } diff --git a/pkg/controller/pod_volume_backup_controller_test.go b/pkg/controller/pod_volume_backup_controller_test.go index 51e75edb2..a76b32b58 100644 --- a/pkg/controller/pod_volume_backup_controller_test.go +++ b/pkg/controller/pod_volume_backup_controller_test.go @@ -151,7 +151,8 @@ func initPVBReconcilerWithError(needError ...error) (*PodVolumeBackupReconciler, corev1api.ResourceRequirements{}, metrics.NewServerMetrics(), velerotest.NewLogger(), - "", // dataMovePriorityClass + "", // dataMovePriorityClass + false, // privileged ), nil } diff --git a/pkg/controller/pod_volume_restore_controller.go b/pkg/controller/pod_volume_restore_controller.go index ce0d312a0..0ed06b980 100644 --- a/pkg/controller/pod_volume_restore_controller.go +++ b/pkg/controller/pod_volume_restore_controller.go @@ -56,7 +56,7 @@ import ( func NewPodVolumeRestoreReconciler(client client.Client, mgr manager.Manager, kubeClient kubernetes.Interface, dataPathMgr *datapath.Manager, counter *exposer.VgdpCounter, nodeName string, preparingTimeout time.Duration, resourceTimeout time.Duration, podResources corev1api.ResourceRequirements, - logger logrus.FieldLogger, dataMovePriorityClass string) *PodVolumeRestoreReconciler { + logger logrus.FieldLogger, dataMovePriorityClass string, privileged bool) *PodVolumeRestoreReconciler { return &PodVolumeRestoreReconciler{ client: client, mgr: mgr, @@ -72,6 +72,7 @@ func NewPodVolumeRestoreReconciler(client client.Client, mgr manager.Manager, ku exposer: exposer.NewPodVolumeExposer(kubeClient, logger), cancelledPVR: make(map[string]time.Time), dataMovePriorityClass: dataMovePriorityClass, + privileged: privileged, } } @@ -90,6 +91,7 @@ type PodVolumeRestoreReconciler struct { resourceTimeout time.Duration cancelledPVR map[string]time.Time dataMovePriorityClass string + privileged bool } // +kubebuilder:rbac:groups=velero.io,resources=podvolumerestores,verbs=get;list;watch;create;update;patch;delete @@ -896,6 +898,7 @@ func (r *PodVolumeRestoreReconciler) setupExposeParam(pvr *velerov1api.PodVolume Resources: r.podResources, // Priority class name for the data mover pod, retrieved from node-agent-configmap PriorityClassName: r.dataMovePriorityClass, + Privileged: r.privileged, } } diff --git a/pkg/controller/pod_volume_restore_controller_test.go b/pkg/controller/pod_volume_restore_controller_test.go index 409672c32..e993815b5 100644 --- a/pkg/controller/pod_volume_restore_controller_test.go +++ b/pkg/controller/pod_volume_restore_controller_test.go @@ -617,7 +617,7 @@ func initPodVolumeRestoreReconcilerWithError(objects []runtime.Object, cliObj [] dataPathMgr := datapath.NewManager(1) - return NewPodVolumeRestoreReconciler(fakeClient, nil, fakeKubeClient, dataPathMgr, nil, "test-node", time.Minute*5, time.Minute, corev1api.ResourceRequirements{}, velerotest.NewLogger(), ""), nil + return NewPodVolumeRestoreReconciler(fakeClient, nil, fakeKubeClient, dataPathMgr, nil, "test-node", time.Minute*5, time.Minute, corev1api.ResourceRequirements{}, velerotest.NewLogger(), "", false), nil } func TestPodVolumeRestoreReconcile(t *testing.T) { diff --git a/pkg/exposer/pod_volume.go b/pkg/exposer/pod_volume.go index ea1fb2d1f..6747ceeed 100644 --- a/pkg/exposer/pod_volume.go +++ b/pkg/exposer/pod_volume.go @@ -73,6 +73,9 @@ type PodVolumeExposeParam struct { // PriorityClassName is the priority class name for the data mover pod PriorityClassName string + + // Privileged indicates whether to create the pod with a privileged container + Privileged bool } // PodVolumeExposer is the interfaces for a pod volume exposer @@ -153,7 +156,7 @@ func (e *podVolumeExposer) Expose(ctx context.Context, ownerObject corev1api.Obj curLog.WithField("path", path).Infof("Host path is retrieved for pod %s, volume %s", param.ClientPodName, param.ClientPodVolume) - hostingPod, err := e.createHostingPod(ctx, ownerObject, param.Type, path.ByPath, param.OperationTimeout, param.HostingPodLabels, param.HostingPodAnnotations, param.HostingPodTolerations, pod.Spec.NodeName, param.Resources, nodeOS, param.PriorityClassName) + hostingPod, err := e.createHostingPod(ctx, ownerObject, param.Type, path.ByPath, param.OperationTimeout, param.HostingPodLabels, param.HostingPodAnnotations, param.HostingPodTolerations, pod.Spec.NodeName, param.Resources, nodeOS, param.PriorityClassName, param.Privileged) if err != nil { return errors.Wrapf(err, "error to create hosting pod") } @@ -269,7 +272,7 @@ func (e *podVolumeExposer) CleanUp(ctx context.Context, ownerObject corev1api.Ob } func (e *podVolumeExposer) createHostingPod(ctx context.Context, ownerObject corev1api.ObjectReference, exposeType string, hostPath string, - operationTimeout time.Duration, label map[string]string, annotation map[string]string, toleration []corev1api.Toleration, selectedNode string, resources corev1api.ResourceRequirements, nodeOS string, priorityClassName string) (*corev1api.Pod, error) { + operationTimeout time.Duration, label map[string]string, annotation map[string]string, toleration []corev1api.Toleration, selectedNode string, resources corev1api.ResourceRequirements, nodeOS string, priorityClassName string, privileged bool) (*corev1api.Pod, error) { hostingPodName := ownerObject.Name containerName := string(ownerObject.UID) @@ -327,6 +330,7 @@ func (e *podVolumeExposer) createHostingPod(ctx context.Context, ownerObject cor args = append(args, podInfo.logLevelArgs...) var securityCtx *corev1api.PodSecurityContext + var containerSecurityCtx *corev1api.SecurityContext nodeSelector := map[string]string{} podOS := corev1api.PodOS{} if nodeOS == kube.NodeOSWindows { @@ -359,6 +363,9 @@ func (e *podVolumeExposer) createHostingPod(ctx context.Context, ownerObject cor securityCtx = &corev1api.PodSecurityContext{ RunAsUser: &userID, } + containerSecurityCtx = &corev1api.SecurityContext{ + Privileged: &privileged, + } nodeSelector[kube.NodeOSLabel] = kube.NodeOSLinux podOS.Name = kube.NodeOSLinux @@ -394,6 +401,7 @@ func (e *podVolumeExposer) createHostingPod(ctx context.Context, ownerObject cor Env: podInfo.env, EnvFrom: podInfo.envFrom, Resources: resources, + SecurityContext: containerSecurityCtx, }, }, PriorityClassName: priorityClassName, diff --git a/pkg/exposer/pod_volume_test.go b/pkg/exposer/pod_volume_test.go index f36fda4f4..3172733f4 100644 --- a/pkg/exposer/pod_volume_test.go +++ b/pkg/exposer/pod_volume_test.go @@ -190,6 +190,29 @@ func TestPodVolumeExpose(t *testing.T) { return "/var/lib/kubelet/pods/pod-id-xxx/volumes/kubernetes.io~csi/pvc-id-xxx/mount", nil }, }, + { + name: "succeed with privileged pod", + ownerBackup: backup, + exposeParam: PodVolumeExposeParam{ + ClientNamespace: "fake-ns", + ClientPodName: "fake-client-pod", + ClientPodVolume: "fake-client-volume", + Privileged: true, + }, + kubeClientObj: []runtime.Object{ + podWithNode, + node, + daemonSet, + }, + funcGetPodVolumeHostPath: func(context.Context, *corev1api.Pod, string, kubernetes.Interface, filesystem.Interface, logrus.FieldLogger) (datapath.AccessPoint, error) { + return datapath.AccessPoint{ + ByPath: "/host_pods/pod-id-xxx/volumes/kubernetes.io~csi/pvc-id-xxx/mount", + }, nil + }, + funcExtractPodVolumeHostPath: func(context.Context, string, kubernetes.Interface, string, string) (string, error) { + return "/var/lib/kubelet/pods/pod-id-xxx/volumes/kubernetes.io~csi/pvc-id-xxx/mount", nil + }, + }, } for _, test := range tests { diff --git a/pkg/types/node_agent.go b/pkg/types/node_agent.go index 778aefcf1..b335df275 100644 --- a/pkg/types/node_agent.go +++ b/pkg/types/node_agent.go @@ -84,4 +84,7 @@ type NodeAgentConfigs struct { // PriorityClassName is the priority class name for data mover pods created by the node agent PriorityClassName string `json:"priorityClassName,omitempty"` + + // PrivilegedFsBackup determines whether to create fs-backup pods as privileged pods + PrivilegedFsBackup bool `json:"privilegedFsBackup,omitempty"` } diff --git a/site/content/docs/main/customize-installation.md b/site/content/docs/main/customize-installation.md index 2ac23e5cd..d62945a35 100644 --- a/site/content/docs/main/customize-installation.md +++ b/site/content/docs/main/customize-installation.md @@ -23,6 +23,8 @@ By default, `velero install` does not install Velero's [File System Backup][3]. If you've already run `velero install` without the `--use-node-agent` flag, you can run the same command again, including the `--use-node-agent` flag, to add the file system backup to your existing install. +Note that for some use cases (including installation on OpenShift clusters) the fs-backup pods must run in a Privileged security context. This is configured through the node-agent configmap (see below) by setting `privilegedFsBackup` to `true` in the configmap. + ## CSI Snapshot Data Movement Velero node-agent is required by [CSI Snapshot Data Movement][12] when Velero built-in data mover is used. By default, `velero install` does not install Velero's node-agent. To enable it, specify the `--use-node-agent` flag. From cabb04575e5c5055e83b3ff87d2ec079d56d6933 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Sat, 27 Sep 2025 23:33:37 +0800 Subject: [PATCH 053/104] Fix the push action invalid variable ref issue. Signed-off-by: Xun Jiang --- .github/workflows/push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 8e1bc1219..a9f19b09f 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -12,7 +12,7 @@ jobs: get-go-version: uses: ./.github/workflows/get-go-version.yaml with: - ref: ${ github.ref } + ref: ${{ github.ref }} build: name: Build From f8938e7feddfd9810f3d14c44e55b34b4020cab4 Mon Sep 17 00:00:00 2001 From: Xun Jiang/Bruce Jiang <59276555+blackpiglet@users.noreply.github.com> Date: Tue, 30 Sep 2025 03:08:05 +0800 Subject: [PATCH 054/104] VerifyJSONConfigs verify every elements in Data. (#9302) Add error message in the velero install CLI output if VerifyJSONConfigs fail. Only allow one element in node-agent-configmap's Data. Signed-off-by: Xun Jiang --- changelogs/unreleased/9302-blackpiglet | 1 + pkg/cmd/cli/install/install.go | 10 ++++------ pkg/nodeagent/node_agent.go | 4 ++++ pkg/nodeagent/node_agent_test.go | 9 +++++++++ pkg/util/kube/utils.go | 11 ++++++----- 5 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 changelogs/unreleased/9302-blackpiglet diff --git a/changelogs/unreleased/9302-blackpiglet b/changelogs/unreleased/9302-blackpiglet new file mode 100644 index 000000000..63576a535 --- /dev/null +++ b/changelogs/unreleased/9302-blackpiglet @@ -0,0 +1 @@ +VerifyJSONConfigs verify every elements in Data. diff --git a/pkg/cmd/cli/install/install.go b/pkg/cmd/cli/install/install.go index c7a7dfe7a..6698010bd 100644 --- a/pkg/cmd/cli/install/install.go +++ b/pkg/cmd/cli/install/install.go @@ -545,24 +545,22 @@ func (o *Options) Validate(c *cobra.Command, args []string, f client.Factory) er return fmt.Errorf("fail to create go-client %w", err) } - // If either Linux or Windows node-agent is installed, and the node-agent-configmap - // is specified, need to validate the ConfigMap. - if (o.UseNodeAgent || o.UseNodeAgentWindows) && len(o.NodeAgentConfigMap) > 0 { + if len(o.NodeAgentConfigMap) > 0 { if err := kubeutil.VerifyJSONConfigs(c.Context(), o.Namespace, crClient, o.NodeAgentConfigMap, &velerotypes.NodeAgentConfigs{}); err != nil { - return fmt.Errorf("--node-agent-configmap specified ConfigMap %s is invalid", o.NodeAgentConfigMap) + return fmt.Errorf("--node-agent-configmap specified ConfigMap %s is invalid: %w", o.NodeAgentConfigMap, err) } } if len(o.RepoMaintenanceJobConfigMap) > 0 { if err := kubeutil.VerifyJSONConfigs(c.Context(), o.Namespace, crClient, o.RepoMaintenanceJobConfigMap, &velerotypes.JobConfigs{}); err != nil { - return fmt.Errorf("--repo-maintenance-job-configmap specified ConfigMap %s is invalid", o.RepoMaintenanceJobConfigMap) + return fmt.Errorf("--repo-maintenance-job-configmap specified ConfigMap %s is invalid: %w", o.RepoMaintenanceJobConfigMap, err) } } if len(o.BackupRepoConfigMap) > 0 { config := make(map[string]any) if err := kubeutil.VerifyJSONConfigs(c.Context(), o.Namespace, crClient, o.BackupRepoConfigMap, &config); err != nil { - return fmt.Errorf("--backup-repository-configmap specified ConfigMap %s is invalid", o.BackupRepoConfigMap) + return fmt.Errorf("--backup-repository-configmap specified ConfigMap %s is invalid: %w", o.BackupRepoConfigMap, err) } } diff --git a/pkg/nodeagent/node_agent.go b/pkg/nodeagent/node_agent.go index 7268b589a..a5de2465c 100644 --- a/pkg/nodeagent/node_agent.go +++ b/pkg/nodeagent/node_agent.go @@ -143,6 +143,10 @@ func GetConfigs(ctx context.Context, namespace string, kubeClient kubernetes.Int return nil, errors.Errorf("data is not available in config map %s", configName) } + if len(cm.Data) > 1 { + return nil, errors.Errorf("more than one keys are found in ConfigMap %s's data. only expect one", configName) + } + jsonString := "" for _, v := range cm.Data { jsonString = v diff --git a/pkg/nodeagent/node_agent_test.go b/pkg/nodeagent/node_agent_test.go index bdc1085b4..cb46ee569 100644 --- a/pkg/nodeagent/node_agent_test.go +++ b/pkg/nodeagent/node_agent_test.go @@ -249,6 +249,7 @@ func TestGetConfigs(t *testing.T) { cmWithValidData := builder.ForConfigMap("fake-ns", "node-agent-config").Data("fake-key", "{\"loadConcurrency\":{\"globalConfig\": 5}}").Result() cmWithPriorityClass := builder.ForConfigMap("fake-ns", "node-agent-config").Data("fake-key", "{\"priorityClassName\": \"high-priority\"}").Result() cmWithPriorityClassAndOther := builder.ForConfigMap("fake-ns", "node-agent-config").Data("fake-key", "{\"priorityClassName\": \"low-priority\", \"loadConcurrency\":{\"globalConfig\": 3}}").Result() + cmWithMultipleKeysInData := builder.ForConfigMap("fake-ns", "node-agent-config").Data("fake-key-1", "{}", "fake-key-2", "{}").Result() tests := []struct { name string @@ -331,6 +332,14 @@ func TestGetConfigs(t *testing.T) { }, }, }, + { + name: "ConfigMap's Data has more than one key", + namespace: "fake-ns", + kubeClientObj: []runtime.Object{ + cmWithMultipleKeysInData, + }, + expectErr: "more than one keys are found in ConfigMap node-agent-config's data. only expect one", + }, } for _, test := range tests { diff --git a/pkg/util/kube/utils.go b/pkg/util/kube/utils.go index 002070376..5e5e97603 100644 --- a/pkg/util/kube/utils.go +++ b/pkg/util/kube/utils.go @@ -371,15 +371,16 @@ func VerifyJSONConfigs(ctx context.Context, namespace string, crClient client.Cl return errors.Errorf("data is not available in ConfigMap %s", configName) } + // Verify all the keys in ConfigMap's data. jsonString := "" for _, v := range cm.Data { jsonString = v - } - configs := configType - err = json.Unmarshal([]byte(jsonString), configs) - if err != nil { - return errors.Wrapf(err, "error to unmarshall data from ConfigMap %s", configName) + configs := configType + err = json.Unmarshal([]byte(jsonString), configs) + if err != nil { + return errors.Wrapf(err, "error to unmarshall data from ConfigMap %s", configName) + } } return nil From e6aab8ca93ba1cd2ff6ed85c65248806d570fe7c Mon Sep 17 00:00:00 2001 From: lyndon-li <98304688+Lyndon-Li@users.noreply.github.com> Date: Fri, 10 Oct 2025 02:13:43 +0800 Subject: [PATCH 055/104] add events to diagnose (#9296) Signed-off-by: Lyndon-Li --- changelogs/unreleased/9296-Lyndon-Li | 1 + pkg/exposer/csi_snapshot.go | 11 ++- pkg/exposer/csi_snapshot_test.go | 75 +++++++++++++++++++ pkg/exposer/generic_restore.go | 9 ++- pkg/exposer/generic_restore_test.go | 58 +++++++++++++++ pkg/exposer/pod_volume.go | 7 +- pkg/exposer/pod_volume_test.go | 44 +++++++++++ pkg/util/csi/volume_snapshot.go | 10 ++- pkg/util/csi/volume_snapshot_test.go | 73 ++++++++++++++++++- pkg/util/kube/pod.go | 10 ++- pkg/util/kube/pod_test.go | 105 ++++++++++++++++++++++++++- pkg/util/kube/pvc_pv.go | 14 +++- pkg/util/kube/pvc_pv_test.go | 77 +++++++++++++++++++- 13 files changed, 479 insertions(+), 15 deletions(-) create mode 100644 changelogs/unreleased/9296-Lyndon-Li diff --git a/changelogs/unreleased/9296-Lyndon-Li b/changelogs/unreleased/9296-Lyndon-Li new file mode 100644 index 000000000..696943ede --- /dev/null +++ b/changelogs/unreleased/9296-Lyndon-Li @@ -0,0 +1 @@ +Fix issue #9267, add events to data mover prepare diagnostic \ No newline at end of file diff --git a/pkg/exposer/csi_snapshot.go b/pkg/exposer/csi_snapshot.go index 781739ff5..d20638d7a 100644 --- a/pkg/exposer/csi_snapshot.go +++ b/pkg/exposer/csi_snapshot.go @@ -381,8 +381,13 @@ func (e *csiSnapshotExposer) DiagnoseExpose(ctx context.Context, ownerObject cor diag += fmt.Sprintf("error getting backup vs %s, err: %v\n", backupVSName, err) } + events, err := e.kubeClient.CoreV1().Events(ownerObject.Namespace).List(ctx, metav1.ListOptions{}) + if err != nil { + diag += fmt.Sprintf("error listing events, err: %v\n", err) + } + if pod != nil { - diag += kube.DiagnosePod(pod) + diag += kube.DiagnosePod(pod, events) if pod.Spec.NodeName != "" { if err := nodeagent.KbClientIsRunningInNode(ctx, ownerObject.Namespace, pod.Spec.NodeName, e.kubeClient); err != nil { @@ -392,7 +397,7 @@ func (e *csiSnapshotExposer) DiagnoseExpose(ctx context.Context, ownerObject cor } if pvc != nil { - diag += kube.DiagnosePVC(pvc) + diag += kube.DiagnosePVC(pvc, events) if pvc.Spec.VolumeName != "" { if pv, err := e.kubeClient.CoreV1().PersistentVolumes().Get(ctx, pvc.Spec.VolumeName, metav1.GetOptions{}); err != nil { @@ -404,7 +409,7 @@ func (e *csiSnapshotExposer) DiagnoseExpose(ctx context.Context, ownerObject cor } if vs != nil { - diag += csi.DiagnoseVS(vs) + diag += csi.DiagnoseVS(vs, events) if vs.Status != nil && vs.Status.BoundVolumeSnapshotContentName != nil && *vs.Status.BoundVolumeSnapshotContentName != "" { if vsc, err := e.csiSnapshotClient.VolumeSnapshotContents().Get(ctx, *vs.Status.BoundVolumeSnapshotContentName, metav1.GetOptions{}); err != nil { diff --git a/pkg/exposer/csi_snapshot_test.go b/pkg/exposer/csi_snapshot_test.go index 7e8e6d883..d419b6126 100644 --- a/pkg/exposer/csi_snapshot_test.go +++ b/pkg/exposer/csi_snapshot_test.go @@ -1288,6 +1288,7 @@ func Test_csiSnapshotExposer_DiagnoseExpose(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: velerov1.DefaultNamespace, Name: "fake-backup", + UID: "fake-pod-uid", OwnerReferences: []metav1.OwnerReference{ { APIVersion: backup.APIVersion, @@ -1313,6 +1314,7 @@ func Test_csiSnapshotExposer_DiagnoseExpose(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: velerov1.DefaultNamespace, Name: "fake-backup", + UID: "fake-pod-uid", OwnerReferences: []metav1.OwnerReference{ { APIVersion: backup.APIVersion, @@ -1341,6 +1343,7 @@ func Test_csiSnapshotExposer_DiagnoseExpose(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: velerov1.DefaultNamespace, Name: "fake-backup", + UID: "fake-pvc-uid", OwnerReferences: []metav1.OwnerReference{ { APIVersion: backup.APIVersion, @@ -1359,6 +1362,7 @@ func Test_csiSnapshotExposer_DiagnoseExpose(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: velerov1.DefaultNamespace, Name: "fake-backup", + UID: "fake-pvc-uid", OwnerReferences: []metav1.OwnerReference{ { APIVersion: backup.APIVersion, @@ -1404,6 +1408,7 @@ func Test_csiSnapshotExposer_DiagnoseExpose(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: velerov1.DefaultNamespace, Name: "fake-backup", + UID: "fake-vs-uid", OwnerReferences: []metav1.OwnerReference{ { APIVersion: backup.APIVersion, @@ -1419,6 +1424,7 @@ func Test_csiSnapshotExposer_DiagnoseExpose(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: velerov1.DefaultNamespace, Name: "fake-backup", + UID: "fake-vs-uid", OwnerReferences: []metav1.OwnerReference{ { APIVersion: backup.APIVersion, @@ -1436,6 +1442,7 @@ func Test_csiSnapshotExposer_DiagnoseExpose(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: velerov1.DefaultNamespace, Name: "fake-backup", + UID: "fake-vs-uid", OwnerReferences: []metav1.OwnerReference{ { APIVersion: backup.APIVersion, @@ -1633,6 +1640,74 @@ PVC velero/fake-backup, phase Pending, binding to fake-pv PV fake-pv, phase Pending, reason , message fake-pv-message VS velero/fake-backup, bind to fake-vsc, readyToUse false, errMessage fake-vs-message VSC fake-vsc, readyToUse false, errMessage fake-vsc-message, handle +end diagnose CSI exposer`, + }, + { + name: "with events", + ownerBackup: backup, + kubeClientObj: []runtime.Object{ + &backupPodWithNodeName, + &backupPVCWithVolumeName, + &backupPV, + &nodeAgentPod, + &corev1api.Event{ + ObjectMeta: metav1.ObjectMeta{Namespace: velerov1.DefaultNamespace, Name: "event-1"}, + Type: corev1api.EventTypeWarning, + InvolvedObject: corev1api.ObjectReference{UID: "fake-uid-1"}, + Reason: "reason-1", + Message: "message-1", + }, + &corev1api.Event{ + ObjectMeta: metav1.ObjectMeta{Namespace: velerov1.DefaultNamespace, Name: "event-2"}, + Type: corev1api.EventTypeWarning, + InvolvedObject: corev1api.ObjectReference{UID: "fake-pod-uid"}, + Reason: "reason-2", + Message: "message-2", + }, + &corev1api.Event{ + ObjectMeta: metav1.ObjectMeta{Namespace: velerov1.DefaultNamespace, Name: "event-3"}, + Type: corev1api.EventTypeWarning, + InvolvedObject: corev1api.ObjectReference{UID: "fake-pvc-uid"}, + Reason: "reason-3", + Message: "message-3", + }, + &corev1api.Event{ + ObjectMeta: metav1.ObjectMeta{Namespace: velerov1.DefaultNamespace, Name: "event-4"}, + Type: corev1api.EventTypeWarning, + InvolvedObject: corev1api.ObjectReference{UID: "fake-vs-uid"}, + Reason: "reason-4", + Message: "message-4", + }, + &corev1api.Event{ + ObjectMeta: metav1.ObjectMeta{Namespace: "other-namespace", Name: "event-5"}, + Type: corev1api.EventTypeWarning, + InvolvedObject: corev1api.ObjectReference{UID: "fake-pod-uid"}, + Reason: "reason-5", + Message: "message-5", + }, + &corev1api.Event{ + ObjectMeta: metav1.ObjectMeta{Namespace: velerov1.DefaultNamespace, Name: "event-6"}, + Type: corev1api.EventTypeWarning, + InvolvedObject: corev1api.ObjectReference{UID: "fake-pod-uid"}, + Reason: "reason-6", + Message: "message-6", + }, + }, + snapshotClientObj: []runtime.Object{ + &backupVSWithVSC, + &backupVSC, + }, + expected: `begin diagnose CSI exposer +Pod velero/fake-backup, phase Pending, node name fake-node +Pod condition Initialized, status True, reason , message fake-pod-message +Pod event reason reason-2, message message-2 +Pod event reason reason-6, message message-6 +PVC velero/fake-backup, phase Pending, binding to fake-pv +PVC event reason reason-3, message message-3 +PV fake-pv, phase Pending, reason , message fake-pv-message +VS velero/fake-backup, bind to fake-vsc, readyToUse false, errMessage fake-vs-message +VS event reason reason-4, message message-4 +VSC fake-vsc, readyToUse false, errMessage fake-vsc-message, handle end diagnose CSI exposer`, }, } diff --git a/pkg/exposer/generic_restore.go b/pkg/exposer/generic_restore.go index 26019d5d4..8691eedfc 100644 --- a/pkg/exposer/generic_restore.go +++ b/pkg/exposer/generic_restore.go @@ -287,8 +287,13 @@ func (e *genericRestoreExposer) DiagnoseExpose(ctx context.Context, ownerObject diag += fmt.Sprintf("error getting restore pvc %s, err: %v\n", restorePVCName, err) } + events, err := e.kubeClient.CoreV1().Events(ownerObject.Namespace).List(ctx, metav1.ListOptions{}) + if err != nil { + diag += fmt.Sprintf("error listing events, err: %v\n", err) + } + if pod != nil { - diag += kube.DiagnosePod(pod) + diag += kube.DiagnosePod(pod, events) if pod.Spec.NodeName != "" { if err := nodeagent.KbClientIsRunningInNode(ctx, ownerObject.Namespace, pod.Spec.NodeName, e.kubeClient); err != nil { @@ -298,7 +303,7 @@ func (e *genericRestoreExposer) DiagnoseExpose(ctx context.Context, ownerObject } if pvc != nil { - diag += kube.DiagnosePVC(pvc) + diag += kube.DiagnosePVC(pvc, events) if pvc.Spec.VolumeName != "" { if pv, err := e.kubeClient.CoreV1().PersistentVolumes().Get(ctx, pvc.Spec.VolumeName, metav1.GetOptions{}); err != nil { diff --git a/pkg/exposer/generic_restore_test.go b/pkg/exposer/generic_restore_test.go index b5679889b..2e528d6a2 100644 --- a/pkg/exposer/generic_restore_test.go +++ b/pkg/exposer/generic_restore_test.go @@ -549,6 +549,7 @@ func Test_ReastoreDiagnoseExpose(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: velerov1.DefaultNamespace, Name: "fake-restore", + UID: "fake-pod-uid", OwnerReferences: []metav1.OwnerReference{ { APIVersion: restore.APIVersion, @@ -574,6 +575,7 @@ func Test_ReastoreDiagnoseExpose(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: velerov1.DefaultNamespace, Name: "fake-restore", + UID: "fake-pod-uid", OwnerReferences: []metav1.OwnerReference{ { APIVersion: restore.APIVersion, @@ -602,6 +604,7 @@ func Test_ReastoreDiagnoseExpose(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: velerov1.DefaultNamespace, Name: "fake-restore", + UID: "fake-pvc-uid", OwnerReferences: []metav1.OwnerReference{ { APIVersion: restore.APIVersion, @@ -620,6 +623,7 @@ func Test_ReastoreDiagnoseExpose(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: velerov1.DefaultNamespace, Name: "fake-restore", + UID: "fake-pvc-uid", OwnerReferences: []metav1.OwnerReference{ { APIVersion: restore.APIVersion, @@ -758,6 +762,60 @@ Pod velero/fake-restore, phase Pending, node name fake-node Pod condition Initialized, status True, reason , message fake-pod-message PVC velero/fake-restore, phase Pending, binding to fake-pv PV fake-pv, phase Pending, reason , message fake-pv-message +end diagnose restore exposer`, + }, + { + name: "with events", + ownerRestore: restore, + kubeClientObj: []runtime.Object{ + &restorePodWithNodeName, + &restorePVCWithVolumeName, + &restorePV, + &nodeAgentPod, + &corev1api.Event{ + ObjectMeta: metav1.ObjectMeta{Namespace: velerov1.DefaultNamespace, Name: "event-1"}, + Type: corev1api.EventTypeWarning, + InvolvedObject: corev1api.ObjectReference{UID: "fake-uid-1"}, + Reason: "reason-1", + Message: "message-1", + }, + &corev1api.Event{ + ObjectMeta: metav1.ObjectMeta{Namespace: velerov1.DefaultNamespace, Name: "event-2"}, + Type: corev1api.EventTypeWarning, + InvolvedObject: corev1api.ObjectReference{UID: "fake-pod-uid"}, + Reason: "reason-2", + Message: "message-2", + }, + &corev1api.Event{ + ObjectMeta: metav1.ObjectMeta{Namespace: velerov1.DefaultNamespace, Name: "event-3"}, + Type: corev1api.EventTypeWarning, + InvolvedObject: corev1api.ObjectReference{UID: "fake-pvc-uid"}, + Reason: "reason-3", + Message: "message-3", + }, + &corev1api.Event{ + ObjectMeta: metav1.ObjectMeta{Namespace: "other-namespace", Name: "event-4"}, + Type: corev1api.EventTypeWarning, + InvolvedObject: corev1api.ObjectReference{UID: "fake-pod-uid"}, + Reason: "reason-4", + Message: "message-4", + }, + &corev1api.Event{ + ObjectMeta: metav1.ObjectMeta{Namespace: velerov1.DefaultNamespace, Name: "event-5"}, + Type: corev1api.EventTypeWarning, + InvolvedObject: corev1api.ObjectReference{UID: "fake-pod-uid"}, + Reason: "reason-5", + Message: "message-5", + }, + }, + expected: `begin diagnose restore exposer +Pod velero/fake-restore, phase Pending, node name fake-node +Pod condition Initialized, status True, reason , message fake-pod-message +Pod event reason reason-2, message message-2 +Pod event reason reason-5, message message-5 +PVC velero/fake-restore, phase Pending, binding to fake-pv +PVC event reason reason-3, message message-3 +PV fake-pv, phase Pending, reason , message fake-pv-message end diagnose restore exposer`, }, } diff --git a/pkg/exposer/pod_volume.go b/pkg/exposer/pod_volume.go index 6747ceeed..591600eb3 100644 --- a/pkg/exposer/pod_volume.go +++ b/pkg/exposer/pod_volume.go @@ -251,8 +251,13 @@ func (e *podVolumeExposer) DiagnoseExpose(ctx context.Context, ownerObject corev diag += fmt.Sprintf("error getting hosting pod %s, err: %v\n", hostingPodName, err) } + events, err := e.kubeClient.CoreV1().Events(ownerObject.Namespace).List(ctx, metav1.ListOptions{}) + if err != nil { + diag += fmt.Sprintf("error listing events, err: %v\n", err) + } + if pod != nil { - diag += kube.DiagnosePod(pod) + diag += kube.DiagnosePod(pod, events) if pod.Spec.NodeName != "" { if err := nodeagent.KbClientIsRunningInNode(ctx, ownerObject.Namespace, pod.Spec.NodeName, e.kubeClient); err != nil { diff --git a/pkg/exposer/pod_volume_test.go b/pkg/exposer/pod_volume_test.go index 3172733f4..f48e9376b 100644 --- a/pkg/exposer/pod_volume_test.go +++ b/pkg/exposer/pod_volume_test.go @@ -466,6 +466,7 @@ func TestPodVolumeDiagnoseExpose(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: velerov1.DefaultNamespace, Name: "fake-backup", + UID: "fake-pod-uid", OwnerReferences: []metav1.OwnerReference{ { APIVersion: backup.APIVersion, @@ -491,6 +492,7 @@ func TestPodVolumeDiagnoseExpose(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Namespace: velerov1.DefaultNamespace, Name: "fake-backup", + UID: "fake-pod-uid", OwnerReferences: []metav1.OwnerReference{ { APIVersion: backup.APIVersion, @@ -587,6 +589,48 @@ end diagnose pod volume exposer`, expected: `begin diagnose pod volume exposer Pod velero/fake-backup, phase Pending, node name fake-node Pod condition Initialized, status True, reason , message fake-pod-message +end diagnose pod volume exposer`, + }, + { + name: "with events", + ownerBackup: backup, + kubeClientObj: []runtime.Object{ + &backupPodWithNodeName, + &nodeAgentPod, + &corev1api.Event{ + ObjectMeta: metav1.ObjectMeta{Namespace: velerov1.DefaultNamespace, Name: "event-1"}, + Type: corev1api.EventTypeWarning, + InvolvedObject: corev1api.ObjectReference{UID: "fake-uid-1"}, + Reason: "reason-1", + Message: "message-1", + }, + &corev1api.Event{ + ObjectMeta: metav1.ObjectMeta{Namespace: velerov1.DefaultNamespace, Name: "event-2"}, + Type: corev1api.EventTypeWarning, + InvolvedObject: corev1api.ObjectReference{UID: "fake-pod-uid"}, + Reason: "reason-2", + Message: "message-2", + }, + &corev1api.Event{ + ObjectMeta: metav1.ObjectMeta{Namespace: "other-namespace", Name: "event-3"}, + Type: corev1api.EventTypeWarning, + InvolvedObject: corev1api.ObjectReference{UID: "fake-pod-uid"}, + Reason: "reason-3", + Message: "message-3", + }, + &corev1api.Event{ + ObjectMeta: metav1.ObjectMeta{Namespace: velerov1.DefaultNamespace, Name: "event-4"}, + Type: corev1api.EventTypeWarning, + InvolvedObject: corev1api.ObjectReference{UID: "fake-pod-uid"}, + Reason: "reason-4", + Message: "message-4", + }, + }, + expected: `begin diagnose pod volume exposer +Pod velero/fake-backup, phase Pending, node name fake-node +Pod condition Initialized, status True, reason , message fake-pod-message +Pod event reason reason-2, message message-2 +Pod event reason reason-4, message message-4 end diagnose pod volume exposer`, }, } diff --git a/pkg/util/csi/volume_snapshot.go b/pkg/util/csi/volume_snapshot.go index 8e59dd69f..57e6f2e1d 100644 --- a/pkg/util/csi/volume_snapshot.go +++ b/pkg/util/csi/volume_snapshot.go @@ -689,7 +689,7 @@ func WaitUntilVSCHandleIsReady( return vsc, nil } -func DiagnoseVS(vs *snapshotv1api.VolumeSnapshot) string { +func DiagnoseVS(vs *snapshotv1api.VolumeSnapshot, events *corev1api.EventList) string { vscName := "" readyToUse := false errMessage := "" @@ -710,6 +710,14 @@ func DiagnoseVS(vs *snapshotv1api.VolumeSnapshot) string { diag := fmt.Sprintf("VS %s/%s, bind to %s, readyToUse %v, errMessage %s\n", vs.Namespace, vs.Name, vscName, readyToUse, errMessage) + if events != nil { + for _, e := range events.Items { + if e.InvolvedObject.UID == vs.UID && e.Type == corev1api.EventTypeWarning { + diag += fmt.Sprintf("VS event reason %s, message %s\n", e.Reason, e.Message) + } + } + } + return diag } diff --git a/pkg/util/csi/volume_snapshot_test.go b/pkg/util/csi/volume_snapshot_test.go index 91c9a1ea3..2f735559c 100644 --- a/pkg/util/csi/volume_snapshot_test.go +++ b/pkg/util/csi/volume_snapshot_test.go @@ -1699,6 +1699,7 @@ func TestDiagnoseVS(t *testing.T) { testCases := []struct { name string vs *snapshotv1api.VolumeSnapshot + events *corev1api.EventList expected string }{ { @@ -1781,11 +1782,81 @@ func TestDiagnoseVS(t *testing.T) { }, expected: "VS fake-ns/fake-vs, bind to fake-vsc, readyToUse true, errMessage fake-message\n", }, + { + name: "VS with VSC and empty event", + vs: &snapshotv1api.VolumeSnapshot{ + ObjectMeta: metav1.ObjectMeta{ + Name: "fake-vs", + Namespace: "fake-ns", + }, + Status: &snapshotv1api.VolumeSnapshotStatus{ + BoundVolumeSnapshotContentName: &vscName, + ReadyToUse: &readyToUse, + Error: &snapshotv1api.VolumeSnapshotError{}, + }, + }, + events: &corev1api.EventList{}, + expected: "VS fake-ns/fake-vs, bind to fake-vsc, readyToUse true, errMessage \n", + }, + { + name: "VS with VSC and events", + vs: &snapshotv1api.VolumeSnapshot{ + ObjectMeta: metav1.ObjectMeta{ + Name: "fake-vs", + Namespace: "fake-ns", + UID: "fake-vs-uid", + }, + Status: &snapshotv1api.VolumeSnapshotStatus{ + BoundVolumeSnapshotContentName: &vscName, + ReadyToUse: &readyToUse, + Error: &snapshotv1api.VolumeSnapshotError{}, + }, + }, + events: &corev1api.EventList{Items: []corev1api.Event{ + { + InvolvedObject: corev1api.ObjectReference{UID: "fake-uid-1"}, + Type: corev1api.EventTypeWarning, + Reason: "reason-1", + Message: "message-1", + }, + { + InvolvedObject: corev1api.ObjectReference{UID: "fake-uid-2"}, + Type: corev1api.EventTypeWarning, + Reason: "reason-2", + Message: "message-2", + }, + { + InvolvedObject: corev1api.ObjectReference{UID: "fake-vs-uid"}, + Type: corev1api.EventTypeWarning, + Reason: "reason-3", + Message: "message-3", + }, + { + InvolvedObject: corev1api.ObjectReference{UID: "fake-vs-uid"}, + Type: corev1api.EventTypeNormal, + Reason: "reason-4", + Message: "message-4", + }, + { + InvolvedObject: corev1api.ObjectReference{UID: "fake-vs-uid"}, + Type: corev1api.EventTypeNormal, + Reason: "reason-5", + Message: "message-5", + }, + { + InvolvedObject: corev1api.ObjectReference{UID: "fake-vs-uid"}, + Type: corev1api.EventTypeWarning, + Reason: "reason-6", + Message: "message-6", + }, + }}, + expected: "VS fake-ns/fake-vs, bind to fake-vsc, readyToUse true, errMessage \nVS event reason reason-3, message message-3\nVS event reason reason-6, message message-6\n", + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - diag := DiagnoseVS(tc.vs) + diag := DiagnoseVS(tc.vs, tc.events) assert.Equal(t, tc.expected, diag) }) } diff --git a/pkg/util/kube/pod.go b/pkg/util/kube/pod.go index 6b9cf7d58..86aa2e47b 100644 --- a/pkg/util/kube/pod.go +++ b/pkg/util/kube/pod.go @@ -268,13 +268,21 @@ func ToSystemAffinity(loadAffinities []*LoadAffinity) *corev1api.Affinity { return nil } -func DiagnosePod(pod *corev1api.Pod) string { +func DiagnosePod(pod *corev1api.Pod, events *corev1api.EventList) string { diag := fmt.Sprintf("Pod %s/%s, phase %s, node name %s\n", pod.Namespace, pod.Name, pod.Status.Phase, pod.Spec.NodeName) for _, condition := range pod.Status.Conditions { diag += fmt.Sprintf("Pod condition %s, status %s, reason %s, message %s\n", condition.Type, condition.Status, condition.Reason, condition.Message) } + if events != nil { + for _, e := range events.Items { + if e.InvolvedObject.UID == pod.UID && e.Type == corev1api.EventTypeWarning { + diag += fmt.Sprintf("Pod event reason %s, message %s\n", e.Reason, e.Message) + } + } + } + return diag } diff --git a/pkg/util/kube/pod_test.go b/pkg/util/kube/pod_test.go index f01d5ab35..ba930019e 100644 --- a/pkg/util/kube/pod_test.go +++ b/pkg/util/kube/pod_test.go @@ -896,10 +896,11 @@ func TestDiagnosePod(t *testing.T) { testCases := []struct { name string pod *corev1api.Pod + events *corev1api.EventList expected string }{ { - name: "pod with all info", + name: "pod with all info but event", pod: &corev1api.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: "fake-pod", @@ -928,11 +929,111 @@ func TestDiagnosePod(t *testing.T) { }, expected: "Pod fake-ns/fake-pod, phase Pending, node name fake-node\nPod condition Initialized, status True, reason fake-reason-1, message fake-message-1\nPod condition PodScheduled, status False, reason fake-reason-2, message fake-message-2\n", }, + { + name: "pod with all info and empty event list", + pod: &corev1api.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "fake-pod", + Namespace: "fake-ns", + }, + Spec: corev1api.PodSpec{ + NodeName: "fake-node", + }, + Status: corev1api.PodStatus{ + Phase: corev1api.PodPending, + Conditions: []corev1api.PodCondition{ + { + Type: corev1api.PodInitialized, + Status: corev1api.ConditionTrue, + Reason: "fake-reason-1", + Message: "fake-message-1", + }, + { + Type: corev1api.PodScheduled, + Status: corev1api.ConditionFalse, + Reason: "fake-reason-2", + Message: "fake-message-2", + }, + }, + }, + }, + events: &corev1api.EventList{}, + expected: "Pod fake-ns/fake-pod, phase Pending, node name fake-node\nPod condition Initialized, status True, reason fake-reason-1, message fake-message-1\nPod condition PodScheduled, status False, reason fake-reason-2, message fake-message-2\n", + }, + { + name: "pod with all info and events", + pod: &corev1api.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "fake-pod", + Namespace: "fake-ns", + UID: "fake-pod-uid", + }, + Spec: corev1api.PodSpec{ + NodeName: "fake-node", + }, + Status: corev1api.PodStatus{ + Phase: corev1api.PodPending, + Conditions: []corev1api.PodCondition{ + { + Type: corev1api.PodInitialized, + Status: corev1api.ConditionTrue, + Reason: "fake-reason-1", + Message: "fake-message-1", + }, + { + Type: corev1api.PodScheduled, + Status: corev1api.ConditionFalse, + Reason: "fake-reason-2", + Message: "fake-message-2", + }, + }, + }, + }, + events: &corev1api.EventList{Items: []corev1api.Event{ + { + InvolvedObject: corev1api.ObjectReference{UID: "fake-uid-1"}, + Type: corev1api.EventTypeWarning, + Reason: "reason-1", + Message: "message-1", + }, + { + InvolvedObject: corev1api.ObjectReference{UID: "fake-uid-2"}, + Type: corev1api.EventTypeWarning, + Reason: "reason-2", + Message: "message-2", + }, + { + InvolvedObject: corev1api.ObjectReference{UID: "fake-pod-uid"}, + Type: corev1api.EventTypeWarning, + Reason: "reason-3", + Message: "message-3", + }, + { + InvolvedObject: corev1api.ObjectReference{UID: "fake-pod-uid"}, + Type: corev1api.EventTypeNormal, + Reason: "reason-4", + Message: "message-4", + }, + { + InvolvedObject: corev1api.ObjectReference{UID: "fake-pod-uid"}, + Type: corev1api.EventTypeNormal, + Reason: "reason-5", + Message: "message-5", + }, + { + InvolvedObject: corev1api.ObjectReference{UID: "fake-pod-uid"}, + Type: corev1api.EventTypeWarning, + Reason: "reason-6", + Message: "message-6", + }, + }}, + expected: "Pod fake-ns/fake-pod, phase Pending, node name fake-node\nPod condition Initialized, status True, reason fake-reason-1, message fake-message-1\nPod condition PodScheduled, status False, reason fake-reason-2, message fake-message-2\nPod event reason reason-3, message message-3\nPod event reason reason-6, message message-6\n", + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - diag := DiagnosePod(tc.pod) + diag := DiagnosePod(tc.pod, tc.events) assert.Equal(t, tc.expected, diag) }) } diff --git a/pkg/util/kube/pvc_pv.go b/pkg/util/kube/pvc_pv.go index e18d33c77..786cef2a5 100644 --- a/pkg/util/kube/pvc_pv.go +++ b/pkg/util/kube/pvc_pv.go @@ -463,8 +463,18 @@ func GetPVCForPodVolume(vol *corev1api.Volume, pod *corev1api.Pod, crClient crcl return pvc, nil } -func DiagnosePVC(pvc *corev1api.PersistentVolumeClaim) string { - return fmt.Sprintf("PVC %s/%s, phase %s, binding to %s\n", pvc.Namespace, pvc.Name, pvc.Status.Phase, pvc.Spec.VolumeName) +func DiagnosePVC(pvc *corev1api.PersistentVolumeClaim, events *corev1api.EventList) string { + diag := fmt.Sprintf("PVC %s/%s, phase %s, binding to %s\n", pvc.Namespace, pvc.Name, pvc.Status.Phase, pvc.Spec.VolumeName) + + if events != nil { + for _, e := range events.Items { + if e.InvolvedObject.UID == pvc.UID && e.Type == corev1api.EventTypeWarning { + diag += fmt.Sprintf("PVC event reason %s, message %s\n", e.Reason, e.Message) + } + } + } + + return diag } func DiagnosePV(pv *corev1api.PersistentVolume) string { diff --git a/pkg/util/kube/pvc_pv_test.go b/pkg/util/kube/pvc_pv_test.go index f52cdeb98..d94efa62e 100644 --- a/pkg/util/kube/pvc_pv_test.go +++ b/pkg/util/kube/pvc_pv_test.go @@ -1593,10 +1593,11 @@ func TestDiagnosePVC(t *testing.T) { testCases := []struct { name string pvc *corev1api.PersistentVolumeClaim + events *corev1api.EventList expected string }{ { - name: "pvc with all info", + name: "pvc with all info but events", pvc: &corev1api.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ Name: "fake-pvc", @@ -1611,11 +1612,83 @@ func TestDiagnosePVC(t *testing.T) { }, expected: "PVC fake-ns/fake-pvc, phase Pending, binding to fake-pv\n", }, + { + name: "pvc with all info and empty events", + pvc: &corev1api.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "fake-pvc", + Namespace: "fake-ns", + }, + Spec: corev1api.PersistentVolumeClaimSpec{ + VolumeName: "fake-pv", + }, + Status: corev1api.PersistentVolumeClaimStatus{ + Phase: corev1api.ClaimPending, + }, + }, + events: &corev1api.EventList{}, + expected: "PVC fake-ns/fake-pvc, phase Pending, binding to fake-pv\n", + }, + { + name: "pvc with all info and events", + pvc: &corev1api.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "fake-pvc", + Namespace: "fake-ns", + UID: "fake-pvc-uid", + }, + Spec: corev1api.PersistentVolumeClaimSpec{ + VolumeName: "fake-pv", + }, + Status: corev1api.PersistentVolumeClaimStatus{ + Phase: corev1api.ClaimPending, + }, + }, + events: &corev1api.EventList{Items: []corev1api.Event{ + { + InvolvedObject: corev1api.ObjectReference{UID: "fake-uid-1"}, + Type: corev1api.EventTypeWarning, + Reason: "reason-1", + Message: "message-1", + }, + { + InvolvedObject: corev1api.ObjectReference{UID: "fake-uid-2"}, + Type: corev1api.EventTypeWarning, + Reason: "reason-2", + Message: "message-2", + }, + { + InvolvedObject: corev1api.ObjectReference{UID: "fake-pvc-uid"}, + Type: corev1api.EventTypeWarning, + Reason: "reason-3", + Message: "message-3", + }, + { + InvolvedObject: corev1api.ObjectReference{UID: "fake-pvc-uid"}, + Type: corev1api.EventTypeNormal, + Reason: "reason-4", + Message: "message-4", + }, + { + InvolvedObject: corev1api.ObjectReference{UID: "fake-pvc-uid"}, + Type: corev1api.EventTypeNormal, + Reason: "reason-5", + Message: "message-5", + }, + { + InvolvedObject: corev1api.ObjectReference{UID: "fake-pvc-uid"}, + Type: corev1api.EventTypeWarning, + Reason: "reason-6", + Message: "message-6", + }, + }}, + expected: "PVC fake-ns/fake-pvc, phase Pending, binding to fake-pv\nPVC event reason reason-3, message message-3\nPVC event reason reason-6, message message-6\n", + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - diag := DiagnosePVC(tc.pvc) + diag := DiagnosePVC(tc.pvc, tc.events) assert.Equal(t, tc.expected, diag) }) } From e9666f9aea3553cf076ef4a0141e61b384eda5dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 19:04:02 +0000 Subject: [PATCH 056/104] Bump actions/stale from 10.0.0 to 10.1.0 Bumps [actions/stale](https://github.com/actions/stale) from 10.0.0 to 10.1.0. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v10.0.0...v10.1.0) --- updated-dependencies: - dependency-name: actions/stale dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/stale-issues.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale-issues.yml b/.github/workflows/stale-issues.yml index 8f94ea65b..34f9dd11a 100644 --- a/.github/workflows/stale-issues.yml +++ b/.github/workflows/stale-issues.yml @@ -7,7 +7,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v10.0.0 + - uses: actions/stale@v10.1.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: "This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 14 days. If a Velero team member has requested log or more information, please provide the output of the shared commands." From b34f2deff24a6a8c8e07a9c1b0615075d4bb91bf Mon Sep 17 00:00:00 2001 From: Daniel Wituschek Date: Mon, 13 Oct 2025 15:58:20 +0200 Subject: [PATCH 057/104] Fix typos Signed-off-by: Daniel Wituschek --- .../main/data-movement-pod-resource-configuration.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/site/content/docs/main/data-movement-pod-resource-configuration.md b/site/content/docs/main/data-movement-pod-resource-configuration.md index 9dfab4a32..53e56d4af 100644 --- a/site/content/docs/main/data-movement-pod-resource-configuration.md +++ b/site/content/docs/main/data-movement-pod-resource-configuration.md @@ -15,7 +15,7 @@ Note: If less resources are assigned to data mover pods, the data movement activ Refer to [Performance Guidance][3] for a guidance of performance vs. resource usage, and it is highly recommended that you perform your own testing to find the best resource limits for your data. Velero introduces a new section in the node-agent configMap, called ```podResources```, through which you can set customized resources configurations for data mover pods. -If it is not there, a configMap should be created manually. The configMap should be in the same namespace where Velero is installed. If multiple Velero instances are installed in different namespaces, there should be one configMap in each namespace which applies to node-agent in that namespace only. The name of the configMap should be specified in the node-agent server parameter ```--node-agent-config```. +If it is not there, a configMap should be created manually. The configMap should be in the same namespace where Velero is installed. If multiple Velero instances are installed in different namespaces, there should be one configMap in each namespace which applies to node-agent in that namespace only. The name of the configMap should be specified in the node-agent server parameter ```--node-agent-configmap```. Node-agent server checks these configurations at startup time. Therefore, you could edit this configMap any time, but in order to make the changes effective, node-agent server needs to be restarted. ### Sample @@ -39,19 +39,19 @@ To create the configMap, save something like the above sample to a json file and kubectl create cm node-agent-config -n velero --from-file= ``` -To provide the configMap to node-agent, edit the node-agent daemonset and add the ```- --node-agent-config``` argument to the spec: +To provide the configMap to node-agent, edit the node-agent daemonset and add the ```- --node-agent-configmap``` argument to the spec: 1. Open the node-agent daemonset spec ``` kubectl edit ds node-agent -n velero ``` -2. Add ```- --node-agent-config``` to ```spec.template.spec.containers``` +2. Add ```- --node-agent-configmap``` to ```spec.template.spec.containers``` ``` spec: template: spec: containers: - args: - - --node-agent-config= + - --node-agent-configmap= ``` ### Priority Class @@ -126,4 +126,4 @@ kubectl create cm node-agent-config -n velero --from-file=node-agent-config.json [1]: csi-snapshot-data-movement.md [2]: file-system-backup.md [3]: https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/ -[4]: performance-guidance.md \ No newline at end of file +[4]: performance-guidance.md From 8b3ba78c8c3e58569d890849fa9f2a95b1601c98 Mon Sep 17 00:00:00 2001 From: Daniel Wituschek Date: Mon, 13 Oct 2025 16:00:23 +0200 Subject: [PATCH 058/104] Fix typos Signed-off-by: Daniel Wituschek --- site/content/docs/main/node-agent-prepare-queue-length.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/site/content/docs/main/node-agent-prepare-queue-length.md b/site/content/docs/main/node-agent-prepare-queue-length.md index aa2770175..58f81ecf0 100644 --- a/site/content/docs/main/node-agent-prepare-queue-length.md +++ b/site/content/docs/main/node-agent-prepare-queue-length.md @@ -27,22 +27,22 @@ To create the configMap, save something like the above sample to a json file and kubectl create cm node-agent-config -n velero --from-file= ``` -To provide the configMap to node-agent, edit the node-agent daemonset and add the ```- --node-agent-config``` argument to the spec: +To provide the configMap to node-agent, edit the node-agent daemonset and add the ```- --node-agent-configmap`` argument to the spec: 1. Open the node-agent daemonset spec ``` kubectl edit ds node-agent -n velero ``` -2. Add ```- --node-agent-config``` to ```spec.template.spec.containers``` +2. Add ```- --node-agent-configmap``` to ```spec.template.spec.containers``` ``` spec: template: spec: containers: - args: - - --node-agent-config= + - --node-agent-configmap= ``` [1]: csi-snapshot-data-movement.md [2]: file-system-backup.md [3]: node-agent-concurrency.md -[4]: data-movement-node-selection.md \ No newline at end of file +[4]: data-movement-node-selection.md From 93e83795305ef945acc1b527548008767c3f7c5d Mon Sep 17 00:00:00 2001 From: Daniel Wituschek Date: Tue, 14 Oct 2025 14:58:05 +0200 Subject: [PATCH 059/104] Add changelog file Signed-off-by: Daniel Wituschek --- changelogs/unreleased/9329-T4iFooN-IX | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/unreleased/9329-T4iFooN-IX diff --git a/changelogs/unreleased/9329-T4iFooN-IX b/changelogs/unreleased/9329-T4iFooN-IX new file mode 100644 index 000000000..2209ecb73 --- /dev/null +++ b/changelogs/unreleased/9329-T4iFooN-IX @@ -0,0 +1 @@ +Fix typos in documentation From 9a3fabbc5564375dd6ad7aac986aa8f27eb8eef5 Mon Sep 17 00:00:00 2001 From: lyndon-li <98304688+Lyndon-Li@users.noreply.github.com> Date: Fri, 17 Oct 2025 00:41:21 +0800 Subject: [PATCH 060/104] issue 9332: make bytesDone correct for incremental backup (#9333) Signed-off-by: Lyndon-Li --- changelogs/unreleased/9333-Lyndon-Li | 1 + pkg/uploader/kopia/progress.go | 1 + 2 files changed, 2 insertions(+) create mode 100644 changelogs/unreleased/9333-Lyndon-Li diff --git a/changelogs/unreleased/9333-Lyndon-Li b/changelogs/unreleased/9333-Lyndon-Li new file mode 100644 index 000000000..91d551881 --- /dev/null +++ b/changelogs/unreleased/9333-Lyndon-Li @@ -0,0 +1 @@ +Fix issue #9332, add bytesDone for cache files \ No newline at end of file diff --git a/pkg/uploader/kopia/progress.go b/pkg/uploader/kopia/progress.go index 1fe0c41fe..b4e9ce1f2 100644 --- a/pkg/uploader/kopia/progress.go +++ b/pkg/uploader/kopia/progress.go @@ -121,6 +121,7 @@ func (p *Progress) UploadStarted() {} // CachedFile statistic the total bytes been cached currently func (p *Progress) CachedFile(fname string, numBytes int64) { atomic.AddInt64(&p.cachedBytes, numBytes) + atomic.AddInt64(&p.processedBytes, numBytes) p.UpdateProgress() } From 6bd8033d240b5f6f7299988462d45950cf166800 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Fri, 17 Oct 2025 18:00:03 +0800 Subject: [PATCH 061/104] add cache dir to VGDP Signed-off-by: Lyndon-Li --- changelogs/unreleased/9342-Lyndon-Li | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/unreleased/9342-Lyndon-Li diff --git a/changelogs/unreleased/9342-Lyndon-Li b/changelogs/unreleased/9342-Lyndon-Li new file mode 100644 index 000000000..444643232 --- /dev/null +++ b/changelogs/unreleased/9342-Lyndon-Li @@ -0,0 +1 @@ +Add cache configuration to VGDP \ No newline at end of file From 3e39cb4b0f4683412a48aa3ce9973dce27f61a55 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Tue, 21 Oct 2025 13:36:35 +0800 Subject: [PATCH 062/104] udmrepo support cache dir Signed-off-by: Lyndon-Li --- pkg/repository/provider/unified_repo.go | 21 ++++--- .../udmrepo/kopialib/backend/common.go | 6 +- pkg/repository/udmrepo/kopialib/lib_repo.go | 31 ++++++++++ .../udmrepo/kopialib/lib_repo_test.go | 60 +++++++++++++++++++ .../udmrepo/mocks/BackupRepoService.go | 22 ++++++- pkg/repository/udmrepo/repo.go | 3 + pkg/repository/udmrepo/repo_options.go | 6 +- pkg/repository/udmrepo/service/service.go | 2 +- pkg/uploader/provider/kopia.go | 2 +- pkg/uploader/provider/kopia_test.go | 2 +- 10 files changed, 137 insertions(+), 18 deletions(-) diff --git a/pkg/repository/provider/unified_repo.go b/pkg/repository/provider/unified_repo.go index 251845dac..8ec5c454c 100644 --- a/pkg/repository/provider/unified_repo.go +++ b/pkg/repository/provider/unified_repo.go @@ -20,6 +20,7 @@ import ( "context" "encoding/base64" "fmt" + "maps" "net/url" "path" "strconv" @@ -81,11 +82,16 @@ func NewUnifiedRepoProvider( log: log, } - repo.repoService = createRepoService(log) + repo.repoService = createRepoService(repoBackend, log) return &repo } +func GetUnifiedRepoClientSideCacheLimit(repoOption map[string]string, repoBackend string, log logrus.FieldLogger) int64 { + repoService := createRepoService(repoBackend, log) + return repoService.ClientSideCacheLimit(repoOption) +} + func (urp *unifiedRepoProvider) InitRepo(ctx context.Context, param RepoParam) error { log := urp.log.WithFields(logrus.Fields{ "BSL name": param.BackupLocation.Name, @@ -416,12 +422,11 @@ func (urp *unifiedRepoProvider) GetStoreOptions(param any) (map[string]string, e } storeOptions := make(map[string]string) - for k, v := range storeVar { - storeOptions[k] = v - } + maps.Copy(storeOptions, storeVar) + maps.Copy(storeOptions, storeCred) - for k, v := range storeCred { - storeOptions[k] = v + if repoParam.CacheDir != "" { + storeOptions[udmrepo.StoreOptionCacheDir] = repoParam.CacheDir } return storeOptions, nil @@ -597,6 +602,6 @@ func getStorageVariables(backupLocation *velerov1api.BackupStorageLocation, repo return result, nil } -func createRepoService(log logrus.FieldLogger) udmrepo.BackupRepoService { - return reposervice.Create(log) +func createRepoService(repoBackend string, log logrus.FieldLogger) udmrepo.BackupRepoService { + return reposervice.Create(repoBackend, log) } diff --git a/pkg/repository/udmrepo/kopialib/backend/common.go b/pkg/repository/udmrepo/kopialib/backend/common.go index 646811da9..a54923003 100644 --- a/pkg/repository/udmrepo/kopialib/backend/common.go +++ b/pkg/repository/udmrepo/kopialib/backend/common.go @@ -33,7 +33,7 @@ import ( ) const ( - defaultCacheLimitMB = 5000 + DefaultCacheLimitMB = 5000 maxCacheDurationSecond = 30 ) @@ -66,7 +66,8 @@ func SetupNewRepositoryOptions(ctx context.Context, flags map[string]string) rep // SetupConnectOptions setups the options when connecting to an existing Kopia repository func SetupConnectOptions(ctx context.Context, repoOptions udmrepo.RepoOptions) repo.ConnectOptions { - cacheLimit := optionalHaveIntWithDefault(ctx, udmrepo.StoreOptionCacheLimit, repoOptions.StorageOptions, defaultCacheLimitMB) << 20 + cacheLimit := optionalHaveIntWithDefault(ctx, udmrepo.StoreOptionCacheLimit, repoOptions.StorageOptions, DefaultCacheLimitMB) << 20 + cacheDir := optionalHaveString(udmrepo.StoreOptionCacheDir, repoOptions.StorageOptions) // 80% for data cache and 20% for metadata cache and align to KB dataCacheLimit := (cacheLimit / 5 * 4) >> 10 @@ -74,6 +75,7 @@ func SetupConnectOptions(ctx context.Context, repoOptions udmrepo.RepoOptions) r return repo.ConnectOptions{ CachingOptions: content.CachingOptions{ + CacheDirectory: cacheDir, // softLimit 80% ContentCacheSizeBytes: (dataCacheLimit / 5 * 4) << 10, MetadataCacheSizeBytes: (metadataCacheLimit / 5 * 4) << 10, diff --git a/pkg/repository/udmrepo/kopialib/lib_repo.go b/pkg/repository/udmrepo/kopialib/lib_repo.go index d1eeb88d0..2bfa8901f 100644 --- a/pkg/repository/udmrepo/kopialib/lib_repo.go +++ b/pkg/repository/udmrepo/kopialib/lib_repo.go @@ -18,6 +18,7 @@ package kopialib import ( "context" + "encoding/json" "os" "strings" "sync/atomic" @@ -35,6 +36,7 @@ import ( "github.com/vmware-tanzu/velero/pkg/kopia" "github.com/vmware-tanzu/velero/pkg/repository/udmrepo" + "github.com/vmware-tanzu/velero/pkg/repository/udmrepo/kopialib/backend" ) type kopiaRepoService struct { @@ -79,6 +81,7 @@ const ( defaultMaintainCheckPeriod = time.Hour overwriteFullMaintainInterval = time.Duration(0) overwriteQuickMaintainInterval = time.Duration(0) + repoBackend = "kopia" ) var kopiaRepoOpen = repo.Open @@ -211,6 +214,34 @@ func (ks *kopiaRepoService) DefaultMaintenanceFrequency() time.Duration { return defaultMaintainCheckPeriod } +func (ks *kopiaRepoService) ClientSideCacheLimit(repoOption map[string]string) int64 { + defaultLimit := int64(backend.DefaultCacheLimitMB << 20) + if repoOption == nil { + return defaultLimit + } + + if v, found := repoOption[repoBackend]; found { + var configs map[string]any + if err := json.Unmarshal([]byte(v), &configs); err != nil { + ks.logger.WithError(err).Warnf("error unmarshalling config data from data %v", v) + return defaultLimit + } + + limit := defaultLimit + if v, found := configs[udmrepo.StoreOptionCacheLimit]; found { + if iv, ok := v.(float64); ok { + limit = int64(iv) << 20 + } else { + ks.logger.Warnf("ignore cache limit from data %v", v) + } + } + + return limit + } + + return defaultLimit +} + func (km *kopiaMaintenance) runMaintenance(ctx context.Context, rep repo.DirectRepositoryWriter) error { err := snapshotmaintenance.Run(kopia.SetupKopiaLog(ctx, km.logger), rep, km.mode, false, maintenance.SafetyFull) if err != nil { diff --git a/pkg/repository/udmrepo/kopialib/lib_repo_test.go b/pkg/repository/udmrepo/kopialib/lib_repo_test.go index ba7aaa93c..a363ef807 100644 --- a/pkg/repository/udmrepo/kopialib/lib_repo_test.go +++ b/pkg/repository/udmrepo/kopialib/lib_repo_test.go @@ -1345,3 +1345,63 @@ func TestMaintainProgress(t *testing.T) { }) } } + +func TestClientSideCacheLimit(t *testing.T) { + testCases := []struct { + name string + repoOption map[string]string + expected int64 + }{ + { + name: "nil option", + expected: 5000 << 20, + }, + { + name: "no option", + repoOption: map[string]string{ + "other-repo": "\"enableCompression\": true", + }, + expected: 5000 << 20, + }, + { + name: "unmarshall fails", + repoOption: map[string]string{ + "kopia": "wrong-json", + }, + expected: 5000 << 20, + }, + { + name: "no cache limit", + repoOption: map[string]string{ + "kopia": "{\"enableCompression\": true}", + }, + expected: 5000 << 20, + }, + { + name: "wrong cache value type", + repoOption: map[string]string{ + "kopia": "{\"cacheLimitMB\": \"abcd\",\"enableCompression\": true}", + }, + expected: 5000 << 20, + }, + { + name: "succeed", + repoOption: map[string]string{ + "kopia": "{\"cacheLimitMB\": 1,\"enableCompression\": true}", + }, + expected: 1048576, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ks := &kopiaRepoService{ + logger: velerotest.NewLogger(), + } + + limit := ks.ClientSideCacheLimit(tc.repoOption) + + assert.Equal(t, tc.expected, limit) + }) + } +} diff --git a/pkg/repository/udmrepo/mocks/BackupRepoService.go b/pkg/repository/udmrepo/mocks/BackupRepoService.go index 2acf94816..346901d38 100644 --- a/pkg/repository/udmrepo/mocks/BackupRepoService.go +++ b/pkg/repository/udmrepo/mocks/BackupRepoService.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.53.2. DO NOT EDIT. package mocks @@ -16,7 +16,25 @@ type BackupRepoService struct { mock.Mock } -// DefaultMaintenanceFrequency provides a mock function with given fields: +// ClientSideCacheLimit provides a mock function with given fields: repoOption +func (_m *BackupRepoService) ClientSideCacheLimit(repoOption map[string]string) int64 { + ret := _m.Called(repoOption) + + if len(ret) == 0 { + panic("no return value specified for ClientSideCacheLimit") + } + + var r0 int64 + if rf, ok := ret.Get(0).(func(map[string]string) int64); ok { + r0 = rf(repoOption) + } else { + r0 = ret.Get(0).(int64) + } + + return r0 +} + +// DefaultMaintenanceFrequency provides a mock function with no fields func (_m *BackupRepoService) DefaultMaintenanceFrequency() time.Duration { ret := _m.Called() diff --git a/pkg/repository/udmrepo/repo.go b/pkg/repository/udmrepo/repo.go index 0adb39751..8ba2fb071 100644 --- a/pkg/repository/udmrepo/repo.go +++ b/pkg/repository/udmrepo/repo.go @@ -93,6 +93,9 @@ type BackupRepoService interface { // DefaultMaintenanceFrequency returns the defgault frequency of maintenance, callers refer this // frequency to maintain the backup repository to get the best maintenance performance DefaultMaintenanceFrequency() time.Duration + + // ClientSideCacheLimit returns the max cache size required on client side + ClientSideCacheLimit(repoOption map[string]string) int64 } // BackupRepo provides the access to the backup repository diff --git a/pkg/repository/udmrepo/repo_options.go b/pkg/repository/udmrepo/repo_options.go index efddfdcd1..a8371b7c1 100644 --- a/pkg/repository/udmrepo/repo_options.go +++ b/pkg/repository/udmrepo/repo_options.go @@ -17,6 +17,7 @@ limitations under the License. package udmrepo import ( + "maps" "os" "path/filepath" "strings" @@ -65,6 +66,7 @@ const ( StoreOptionGenReadOnly = "readOnly" StoreOptionCacheLimit = "cacheLimitMB" + StoreOptionCacheDir = "cacheDir" ThrottleOptionReadOps = "readOPS" ThrottleOptionWriteOps = "writeOPS" @@ -184,9 +186,7 @@ func WithStoreOptions(getter StoreOptionsGetter, param any) func(*RepoOptions) e options.StorageType = storeType - for k, v := range storeOptions { - options.StorageOptions[k] = v - } + maps.Copy(options.StorageOptions, storeOptions) return nil } diff --git a/pkg/repository/udmrepo/service/service.go b/pkg/repository/udmrepo/service/service.go index c2f0a9b0e..195b67b11 100644 --- a/pkg/repository/udmrepo/service/service.go +++ b/pkg/repository/udmrepo/service/service.go @@ -24,6 +24,6 @@ import ( ) // Create creates an instance of BackupRepoService -func Create(logger logrus.FieldLogger) udmrepo.BackupRepoService { +func Create(repoBackend string, logger logrus.FieldLogger) udmrepo.BackupRepoService { return kopialib.NewKopiaRepoService(logger) } diff --git a/pkg/uploader/provider/kopia.go b/pkg/uploader/provider/kopia.go index b09b8a571..7cde36911 100644 --- a/pkg/uploader/provider/kopia.go +++ b/pkg/uploader/provider/kopia.go @@ -74,7 +74,7 @@ func NewKopiaUploaderProvider( return nil, errors.Wrapf(err, "error to get repo options") } - repoSvc := BackupRepoServiceCreateFunc(log) + repoSvc := BackupRepoServiceCreateFunc(backupRepo.Spec.RepositoryType, log) log.WithField("repoUID", repoUID).Info("Opening backup repo") kp.bkRepo, err = repoSvc.Open(ctx, *repoOpt) diff --git a/pkg/uploader/provider/kopia_test.go b/pkg/uploader/provider/kopia_test.go index 6231d5d62..728c26da2 100644 --- a/pkg/uploader/provider/kopia_test.go +++ b/pkg/uploader/provider/kopia_test.go @@ -373,7 +373,7 @@ func TestNewKopiaUploaderProvider(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { credGetter := &credentials.CredentialGetter{FromSecret: tc.mockCredGetter} - BackupRepoServiceCreateFunc = func(logger logrus.FieldLogger) udmrepo.BackupRepoService { + BackupRepoServiceCreateFunc = func(string, logrus.FieldLogger) udmrepo.BackupRepoService { return tc.mockBackupRepoService } // Call the function being tested. From 6c9699a06da6153928cb70ed407e7292a4e80153 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Tue, 21 Oct 2025 13:39:37 +0800 Subject: [PATCH 063/104] udmrepo support cache dir Signed-off-by: Lyndon-Li --- changelogs/unreleased/9353-Lyndon-Li | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/unreleased/9353-Lyndon-Li diff --git a/changelogs/unreleased/9353-Lyndon-Li b/changelogs/unreleased/9353-Lyndon-Li new file mode 100644 index 000000000..ba022edb0 --- /dev/null +++ b/changelogs/unreleased/9353-Lyndon-Li @@ -0,0 +1 @@ +Add cache dir configuration for udmrepo \ No newline at end of file From 166f50d776b2ad59446279d2c2bbf8a667b6eb2b Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Tue, 21 Oct 2025 14:13:59 +0800 Subject: [PATCH 064/104] add snapshot size to data mover CRs Signed-off-by: Lyndon-Li --- .../v1/bases/velero.io_podvolumebackups.yaml | 4 +++ .../v1/bases/velero.io_podvolumerestores.yaml | 4 +++ config/crd/v1/crds/crds.go | 4 +-- .../bases/velero.io_datadownloads.yaml | 4 +++ .../v2alpha1/bases/velero.io_datauploads.yaml | 4 +++ config/crd/v2alpha1/crds/crds.go | 4 +-- pkg/apis/velero/v1/pod_volume_backup_types.go | 4 +++ pkg/apis/velero/v1/pod_volume_restore_type.go | 4 +++ .../velero/v2alpha1/data_download_types.go | 4 +++ pkg/apis/velero/v2alpha1/data_upload_types.go | 8 ++++++ pkg/builder/data_upload_builder.go | 12 +++++++++ .../backup_repository_controller.go | 2 +- pkg/controller/data_upload_controller.go | 1 + pkg/controller/data_upload_controller_test.go | 13 +++++++++- .../pod_volume_backup_controller.go | 1 + pkg/podvolume/restorer.go | 5 ++-- pkg/podvolume/restorer_test.go | 26 +++++++++---------- pkg/podvolume/util.go | 9 ++++++- pkg/restore/actions/csi/pvc_action.go | 1 + .../actions/dataupload_retrieve_action.go | 6 +++++ .../dataupload_retrieve_action_test.go | 14 ++++++++-- 21 files changed, 110 insertions(+), 24 deletions(-) diff --git a/config/crd/v1/bases/velero.io_podvolumebackups.yaml b/config/crd/v1/bases/velero.io_podvolumebackups.yaml index f77c5df4a..714f567c3 100644 --- a/config/crd/v1/bases/velero.io_podvolumebackups.yaml +++ b/config/crd/v1/bases/velero.io_podvolumebackups.yaml @@ -225,6 +225,10 @@ spec: description: SnapshotID is the identifier for the snapshot of the pod volume. type: string + snapshotSize: + description: SnapshotSize is the logical size of the snapshot. + format: int64 + type: integer startTimestamp: description: |- StartTimestamp records the time a backup was started. diff --git a/config/crd/v1/bases/velero.io_podvolumerestores.yaml b/config/crd/v1/bases/velero.io_podvolumerestores.yaml index 09eda5b28..9603e8520 100644 --- a/config/crd/v1/bases/velero.io_podvolumerestores.yaml +++ b/config/crd/v1/bases/velero.io_podvolumerestores.yaml @@ -133,6 +133,10 @@ spec: snapshotID: description: SnapshotID is the ID of the volume snapshot to be restored. type: string + snapshotSize: + description: SnapshotSize is the logical size of the snapshot. + format: int64 + type: integer sourceNamespace: description: SourceNamespace is the original namespace for namaspace mapping. diff --git a/config/crd/v1/crds/crds.go b/config/crd/v1/crds/crds.go index 7bc100e51..84ba2e746 100644 --- a/config/crd/v1/crds/crds.go +++ b/config/crd/v1/crds/crds.go @@ -34,8 +34,8 @@ var rawCRDs = [][]byte{ []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xccYK\x8f\x1b\xb9\x11\xbe\xebW\x14v\x0f{ٖ\xec\x04\t\x02\xdd\xc6r\x02\x18\x19\xc7\x03k2\xb9.EVK\\\xb1\xc9\x0e\x1f\x92\x95\xc7\x7f\x0f\x8a\x0f\xa9\xd5\x0fK\xe3\x04\x9b\xe5eF|\x14\xeb\xf9U\x15\xbb\xaa\xaa\x19k\xe5\vZ'\x8d^\x02k%~\xf1\xa8闛\xef\xff\xe0\xe6\xd2,\x0eog{\xa9\xc5\x12V\xc1y\xd3|Fg\x82\xe5\xf8\x1ek\xa9\xa5\x97F\xcf\x1a\xf4L0ϖ3\x00\xa6\xb5\xf1\x8c\xa6\x1d\xfd\x04\xe0F{k\x94B[mQ\xcf\xf7a\x83\x9b \x95@\x1b\x89\x97\xab\x0fo\xe6o\x7f?\xff\xdd\f@\xb3\x06\x97\xb0a|\x1fZ\xe7\x8de[T\x86'\x92\xf3\x03*\xb4f.\xcd̵\xc8醭5\xa1]\xc2e!Qȷ'\xce\xdfEb\xebD\xec1\x13\x8b\xebJ:\xff\xe7\xe9=\x8f\xd2\xf9\xb8\xafU\xc125\xc5V\xdc\xe2v\xc6\xfa\xbf\\\xae\xae`\xe3TZ\x91z\x1b\x14\xb3\x13\xc7g\x00\x8e\x9b\x16\x97\x10O\xb7\x8c\xa3\x98\x01d\xd5Dj\x150!\xa2\xb2\x99z\xb2R{\xb4+\xa3B\xa3\xcfw\tt\xdc\xca\xd6Ge&Y \v\x03E\x1ap\x9e\xf9\xe0\xc0\x05\xbe\x03\xe6\xe0\xe1\xc0\xa4b\x1b\x85\x8b\xbfjV\xfe\x8f\xf4\x00~vF?1\xbf[\xc2<\x9d\x9a\xb7;\xe6\xcaj\xb2\xd1SgƟH\x00\xe7\xad\xd4\xdb1\x96\x1e\x99\xf3/LI\x119y\x96\r\x82t\xe0w\b\x8a9\x0f\x9e&\xe8W\xd2\x10\x90\x8a\x10\x8a\x86\xe0\xc8\\\xbe\a\xe0\x90\xa8D\x1d\x8ds\xaa\x06w]\xb1M\xac\xc0K\x8fJ\xe2\x9ff2\xf7\x1d\xb2ſ\xe7\xdc♤\xf3\xaci\xaf\xe8>lq\x8aؕ*\xdec͂\xf2]Q\xc9J\xaa\xeb\x97\xd7b\xb5\xc8\xe7\"\x9d\xba\xba\xf1\xfd\xd5\\\xbauc\x8cB\x96\xa8\xa4]\x87\xb7\xc9\v\xf9\x0e\x1b\xb6̛M\x8b\xfa\xe1\xe9\xc3\xcbo\xd7W\xd30\xe6H\xbd\xa0 ñ\x8emvh\x11^b\xfc%\xbb\xb9,ڙ&\x80\xd9\xfc\x8c\xdc_\x8c\xd8ZӢ\xf5\xb2\x04K\x1a\x1d,\xea\xcc\xf6x\xfaWu\xb5\x06@b\xa4S \b\x940\xf9U\x8e\x1f\x14Yr05\xf8\x9dt`\xb1\xb5\xe8P'\x98\xa2i\xa63\x83\xf3\x1e\xe95Z\"C\xb1\x1d\x94 ,;\xa0\xf5`\x91\x9b\xad\x96\xff8\xd3v\xe0Mvf\x8f\xceC\x8cP\xcd\x149k\xc0\x1f\x81iѣܰ\x13X\xa4;!\xe8\x0e\xbdx\xc0\xf5\xf9\xf8H\xd1 um\x96\xb0\xf3\xbeu\xcb\xc5b+}Ahn\x9a&h\xe9O\x8b\b\xb6r\x13\xbc\xb1n!\xf0\x80j\xe1\xe4\xb6b\x96\xef\xa4G\xee\x83\xc5\x05ke\x15\x05\xd1\tR\x1b\xf1\xbd͘\uebae\x1d\x84t\x1a\x11R_a\x1e\x82\xd7\xe42\x89T\x12\xf1b\x05\x9a\"\xd5}\xfe\xe3\xfa\x19\n'\xc9R\xc9(\x97\xad\x03\xbd\x14\xfb\x906\xa5\xaeѦs\xb55M\xa4\x89Z\xb4Fj\x1f\x7fp%Q{pa\xd3HOn\xf0\xf7\x80Γ\xe9\xfadW1\x8b\xc1\x06!\xb4\x11$\xfa\x1b>hX\xb1\x06Պ9\xfc\x85mEVq\x15\x19\xe1.kuss\x7fsRog\xa1\xe4\xd4\tӎ\xa2\xc1\xbaE~\x15w\x02\x9d\xb4\x14\x19\x9ey\x8c\xd1\xd5SP\x86\x8a\xe9\xa4\\\xc68H\xd0`\x9c\xa3s\x1f\x8d\xc0\xfeJ\x8f\xe5\x87\xf3\xc6+\x1e[\xb4\x8dt1\xbdBml?\xf3\xb03\x92wGA\xbc\xbe\xc1\x01P\x87f\xc8H\x05\x9f\x91\x89OZ\x9d&\x96\xfef\xa5\x1f^4aH\x1a\x89\xc5\xf5I\xf3'\xb4҈\x1b¿\xebm?\xab`g\x8ePG\xff\xd7^\x9d\b\xbb\xdcI\xf3!j\x97\xf1\xf0\xf4\xa1 x\x8a\xad\x1c\x98YWsx\xc8Amjx\x03B:*$\\$:T\x96\x0e*\x16\x1aK\xf06\xbcJ|nt-\xb7C\xa1\xbb\xb5є\xc7\xdc \xdd\xd3\xdc*\xdeD\xa8E\xde\xd1Zs\x90\x02mE\xf1!k\xc93'\xc1\xa6\fRKTb\x80M\x93Q\x16E\xb1((\xa8\x99\xbaa\xc3\xd5yc\xac\xa4\x99\xd4Ƀ/\x04\"\xd6\xd8&\xa7f\xedQ\v\xecg\x9bȍ\x89\x80\xe6P\xc0Q\xfa]BJ5\x16w\xf0\xd5أ\xb1\xc7\xd3\xd8t\x8f\xf7\xe7\x1d\xd2Δx\x11\x1cr\x8b>z\x1b*r\x1fr\xa59\xc0\xc7\xe0\"\xd6\xf6q\xa2\x8cX\xf0\x95\xd3{<\r\x15\r\xb7\x8c\x9bK\xa1\t\x96c\x11\xb5\x84ᄏ-\xd2 \xbb\x95A\xa5{\x11\xd4b\x8d\x16\xf5\xa0\x9a(\xe39\xe6(r\x1a\xf20\xack\xe4^\x1eP\x9dbN\"\xf0\xfc\x116\xc1\x83\b\x18\xad\xc6\xf8\xfeȬp\xc0M\xd32/7RI\x7f\x02\xe9&\xe83\xa5\xcc\x11E\xb686\xad?\xcd\xe1\x83v\x9ei\x8e\xee\\\a\x91ƒ+0\x9dv\xe5(\x8e\x05\x1d\xb3c\x18\x98\xc87\xc6y\xe0h\xc9\x1d\xd5\t\x8e\xd6\xe8픰#\xe9\x90z@\xab\xd1c̈\xc2pGɐc\xeb\xdd\xc2\x1c\xd0\x1e$\x1e\x17Gc\xf7Ro+b\xb0\xcaೈ\x9d\xdd\xe2\xfb\xf8\xe7[\xbc\xc0\xb4\t'\xeep\xdeu\x8c\xf5\x13\x95\xb7~\x87)E\xac\x93\x0f\x1a\vT@\x90k7\xd9w\x13\xb2\x8e\x85\xddX]\xde\x1d\xc5\xe4c\xf9c\x8f\xc3\xd4\xf1\x15P\x01\xf8R]t[5\xac\xad\xd2n\xe6M#\xf9\xac/m\xf2\xfb\xaf\xe3OiV\xa4\x16\x92Sq{\x8d\x1b\xa5\x89\x13W=͈\x1a\xfa]\xce\x14Z\x8e\xab)\x89\x9bk\x85\x1b\x1c\x7f\xea\uef74\xbe\t\xbas\xfew\xe8\xa9\xeet\xa0\x91\xea\x03f\x87z\x8e\x80ɍքT\xde\x00;\xa7\x81\x1f\\?\xff\xbd\x12=7\x81\xefqD\xf1\x03Q\xdeōE\xc7\xe9\x18\xf1\x12\x1c\xc6\xc4t\x8b\r\xb8\x1d\x11\x9c\xad\xd0\xde\xc3\xcb\xea\x816\x9eK\b\x06\xab\a\xd8\x04-\x14\x16\x8e\x8e;\xd4\xd4u\xc9\xfa4~\x17\x8d\xe7\xc7u\xd1j\xac\xber\xdfTt;.C\xcaoK\u061cF\xea\xa5;\x84l-\xd6\xf2\xcb\x1dB>ōE\xe1-\xf3;\x90\xdaI\x81\xc0Fԟ\n\xd9\tAϵѧ\x8c9\xdf`\x9e\xafaCb\xe75\xf0Pt|#~\x9e\xf2\xb6\xb3\x16\xca\xef\x9cݮ\xeb\xe4\xa98\x1e\x95\xe8p~\x94\xf9S\xaa>\xf9H\x19q\xc5\xcc\xcb\xf0\xc4W\xaa\xd8\xf244\x16\xccT3\x19kѵF\v\xea9\xef\xaba/,\xff\xef*\xd9q\xb3V\xd7(\xd7[+V\xb8\xab\x8d\x8b\xcf`\xafn\xe4\xd2\xe3`\xb7M2\x1bG\r\xf6\xa5\x97\xeb\xc9\xf8\x8b\xb4p\xa3%W\xa7\xaf\x93\x8eꗠce\x1b\xab\xaa\xf9l\xe4\xc4{l-R\x06\x13K\x92\xcdƃ\xda\x1c\xe9p\x87Z*ˌN\xf9\x9ez[\xa6E~U\xa0\xa5\x11\xcaG\xa9\x14\xd5\x00\x16\x1bCʢ\xb2\xdcR5\xc7b\xadu\xf8\xcd\xfc\xcd\xff\xafeT\xccy\xea\x00Q|ƃ\x1c>\xadݧ\xee\xc7\x01\x95\x82\x0e瘡\x1f?\x95׆\x85\xcd\xdb~\x82Z*\xaa\xff:\xd0qGu0\xf20\xfcn\xfd\xf8\x83\x8b=\x10j\xef\xe0H\x16t\x91%jzL~\xe1\t\xceS\x12\xb9i\xffn\x01\xae\r(\xa3\xb7h\xcbk\x0f\x15xɛ\x8c\x05\x81\x9er\x95\xde\x02\xdf1\xbd\xa5\xc8\x18\x83\xfc\xc8p\xe6\xbe\xcb'yϤ\x83H=\xe1\x1dw\x19\xf4Y\x8e\xb54\xaf1\xe6\xf43\xfc\x99\xffl\xd9\xcbkoO\xefSP[,\xd1_,\xa9\x9c\x14]\xf9\xcb\xd3\xfce|\xfb\xfb\xc0\xf0\xdd\xff[\xd5\xf3_}\xa9\x18|\xa1\xf8U(\xa7\xa1:\xf7f\xf1\xfc1\xedJ\xef\xb5\xf9\b\xb0\x8d\t~$\xf7w\x1c~4\xa6\xe3ǘ\xd7\xf0\x18?1\xdd*OhO\xb1\b\x0f\xd6\xc67\xdd\xf2\xd6\x18\x91b,+ݏ\xc0\x0f\xbd/aݵ\xe1w\xb2;\xe4\x1a\xcd҃ɔi;v\xcdJ\xee΄\xcd\xf9\xa5~\t\xff\xfc\xf7\xec?\x01\x00\x00\xff\xff\x03f\x86Y\xc0\x1d\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcVMo\x1b7\x10\xbd\xebW\f\xd0kwU\xa3hQ\xec\xadqr0\xda\x06\x82\x1d\xe4N\x91#-c.\xc9\xce\f\xe5\xba\x1f\xff\xbd \xb9+K\xab\x95\x93\\\xb27\x91Ù\xc7\xf7f\x1e\xd54\xcdJE\xfb\x11\x89m\xf0\x1d\xa8h\xf1/A\x9f\x7fq\xfb\xf8\v\xb76\xac\x0f7\xabG\xebM\a\xb7\x89%\f\xf7\xc8!\x91Ʒ\xb8\xb3ފ\r~5\xa0(\xa3Du+\x00\xe5}\x10\x95\x979\xff\x04\xd0\xc1\v\x05琚=\xfa\xf61mq\x9b\xac3H%\xf9T\xfa\xf0C{\xf3s\xfb\xd3\n\xc0\xab\x01;0\xe8Pp\xab\xf4c\x8a\x84\x7f&d\xe1\xf6\x80\x0e)\xb46\xac8\xa2\xce\xf9\xf7\x14R\xec\xe0e\xa3\x9e\x1fkW\xdcoK\xaa7%\xd5}MUv\x9de\xf9\xedZ\xc4\xefv\x8c\x8a.\x91rˀJ\x00[\xbfON\xd1b\xc8\n\x80u\x88\xd8\xc1\xfb\f+*\x8df\x050^\xbb\xc0l@\x19S\x88TnC\xd6\v\xd2mpi\x98\bl\xc0 k\xb2Q\nQ\x1fz,W\x84\xb0\x03\xe9\x11j9\x90\x00[\x1c\x11\x98r\x0e\xe0\x13\a\xbfQ\xd2w\xd0f\xbe\xda\x1a\x9a\x81\x8c\x01\x95\xea7\xf3ey\u0380Y\xc8\xfa\xfd5\b,J\x12O J]\x1b<\xd0\t\xbf\xe7\x00J|\x1b{\xc5\xe7\xd5\x1f\xcaƵ\xca5\xe6pS\x99\xd6=\x0e\xaa\x1bcCD\xff\xeb\xe6\xee\xe3\x8f\x0fg\xcbp\x8euAZ\xb0\fjB\x9a\x89\xab\xacA\xf0\b\x81`\b4\xb1\xca\xed1i\xa4\x10\x91\xc4N\xadU\xbf\x93\xe19Y\x9dA\xf8\xb79\xdb\x03Ȩ\xeb)0y\x8a\x90\v\x89cS\xa0\x19/Zɵ\f\x84\x91\x90\xd1\u05f9\xca\xcb\xcaC\xd8~B-\xed,\xf5\x03RN\x03܇\xe4L\x1e\xbe\x03\x92\x00\xa1\x0e{o\xff>\xe6\xe6|\xef\\\xd4))\x94\xe4\xb6\xf3\xca\xc1A\xb9\x84߃\xf2f\x96yP\xcf@\x98kB\xf2'\xf9\xca\x01\x9e\xe3\xf8#\x93h\xfd.tЋD\xee\xd6뽕\xc9Rt\x18\x86\xe4\xad<\xaf\x8b;\xd8m\x92@\xbc6x@\xb7f\xbbo\x14\xe9\xde\njI\x84k\x15mS.⋭\xb4\x83\xf9\x8eF\x13Ⳳ\x17\xddS\xbf\xe2\x02_!O\xf6\x84\xda#5U\xbd\xe2\x8b\ny)Sw\xff\xee\xe1\x03LH\xaaRU\x94\x97\xd0\v^&}2\x9b\xd6\xef\x90\xea\xb9\x1d\x85\xa1\xe4Dob\xb0^\xca\x0f\xed,z\x01N\xdb\xc1\nO\x1d\x9b\xa5\x9b\xa7\xbd-\xb6\x9b\x1d E\xa3\x04\xcd<\xe0\xceí\x1a\xd0\xdd*\xc6o\xacUV\x85\x9b,\xc2\x17\xa9u\xfa\x98̃+\xbd'\x1b\xd33pEڅ\xe1\x7f\x88\xa8\xb3\xb8\x99\xdf|\xda\ueb2ec\xb5\v\x04O\xbd\xd5\xfd4\xfc3\x9a\x8eFq\xce߲1\xe4\xef\xc5n\xe7;W/\x0fEdK8k\xd8\x06.\xbc\xfbu^\x8a\xa9~%3\xd5\xd1Gnt\"*\xcdw\xf4y\xb5t\xe8K\xb9@\xa2@\x17\xab3P\xefJP\xf9Ǡ\xacgP\xfey<\b\xd2+\x81'\xa4\r\x97\x95\x1ax\x8fO\v\xabw~CaO\xc8\xf3\x96ϛ\x9b\xca\x1e\xce߃WXZlʋE\xceVhNXd\t\xa4\xf6\xa7\xbcr\xda\x1e\x9d\xbe\x83\x7f\xfe[\xfd\x1f\x00\x00\xff\xff\xbeM\x1a\xea\xb1\n\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcWMo\xe36\x10\xbd\xfbW\f\xd0K\v\xac\xe4\x06E\x8b·\xd6\xd9C\xb0\xe96\x88\xb7\xb9S\xd4HbC\x91,9t6E\x7f|1\xa4\xe4\x0fYv\x9c\xcb\xea\xe6\xe1p\xf8\xe6\xcd\xcc#]\x14\xc5B8\xf5\x84>(kV \x9c¯\x84\x86\x7f\x85\xf2\xf9\xd7P*\xbb\xdc\xde,\x9e\x95\xa9W\xb0\x8e\x81l\xff\x88\xc1F/\xf1\x16\x1be\x14)k\x16=\x92\xa8\x05\x89\xd5\x02@\x18cI\xb09\xf0O\x00i\ry\xab5\xfa\xa2ES>\xc7\n\xab\xa8t\x8d>\x05\x1f\x8f\xde\xfeX\xde\xfcR\xfe\xbc\x000\xa2\xc7\x15\xd4\xf6\xc5h+j\x8f\xffD\f\x14\xca-j\xf4\xb6Tv\x11\x1cJ\x8e\xddz\x1b\xdd\n\xf6\vy\xefpn\xc6|;\x84y\xccaҊV\x81>ͭޫ\xc1\xc3\xe9\xe8\x85>\x05\x91\x16\x832m\xd4\u009f,/\x00\x82\xb4\x0eW\xf0\x99a8!\xb1^\x00\f)&XŐ\xdd\xf6&\x87\x92\x1d\xf6\"\xe3\x05\xb0\x0e\xcdo\x0fwO?m\x8e\xcc\x005\x06镣D\xd4\x7f\xc5\xce\x0e\xd3\x04@\x05\x100\xc0\x01\xb2;\x84 \f\bO\xaa\x11\x92\xa0\xf1\xb6\x87J\xc8\xe7\xe8\xc0V\x7f\xa3$\bd\xbdh\xf1\x03\x84(;\x10\x1c%;\x1c\x9c\xa5m\v\x8d\xd2X\xeel\xce[\x87\x9e\xd4Hy\xfe\x0e\x1a\xea\xc0z)\v\xfe8\xf1\xbc\vj\xee,\f@\x1d\x8e\xe4a=p\x05\xb6\x01\xeaT\x00\x8f\xcec@\x93{\x8d\xcd\xc2\fٔ\x93\xd0\x1b\xf4\x1c\x06Bg\xa3\xae\xb9!\xb7\xe8\t\x1aE\xaf\xcb41\xaa\x8ad}XָE\xbd\f\xaa-\x84\x97\x9d\"\x94\x14=.\x85SEJĤQ+\xfb\xfa;?\ff8:\x96^\xb9!\x03yeڃ\x854\x1d\xef(\x0f\xcfK\xee\xae\x1c*\xa7\xb8\xaf\x02\x9b\x98\xbaǏ\x9b/0\"ɕ\x1aZl\xe7z\xc2\xcbX\x1ffS\x99\x06}ޗڔc\xa2\xa9\x9dU\x86\xd2\x0f\xa9\x15\x1a\x82\x10\xab^Q\x18{\x9dK7\r\xbbNR\x04\x15Bt\xb5 \xac\xa7\x0ew\x06֢G\xbd\x16\x01\xbfq\xad\xb8*\xa1\xe0\"\\U\xadC\x81\x9d:gz\x0f\x16Fy&j^\x01\x128\xe1[\xa4\xa9u\x82\xe5Kr\xe2\xe3_:q,X\xdfcٖ\xac9a\x00\x92\xf5\xe8\x87i\xa1.a\x80\xd9F\x9fE2\xf67\xd3\xc0\xbc\xb2\xa0\xb0\xd8\x1db:=\x9a?4\xb1\x9f?\xa0\x80\xdf\x13\xe6{\xdb^\\_[C<\x17\x17\x9d\x9e\xac\x8e=n\x8cp\xa1\xb3o\xf8\xde\x11\xf6\x7f:\xf4\xf9\x1a\xbe\xe8:\xde滫\xef\x82c\xd4g\xcf}D\xbeA\xf0|\xa6\x83\xc3UQ\xae\xc04x^\x95\xe8zs\xf7\x1e\nϸ\xbf\xa3Hw\xa6\xb1o\xa4\xb8w\x9c\xf5;#\x03\xe3\x97\xde\x10o\xf74\xbfBƞ\xe6-\xf9\xeeD\xf8\x14+\xf4\x06\t\xc3^\xa9_\x14u\xb3\x11\x01^:%\xbb\xb41\r\x04_\x02!X\xa9\xe6$\xf5\n\xf8\xac#\xca\xe3\xccP\x16iXg\xcc\f\xfe\xc4|F\xfd\xce\x1dP\f\x8at\x95\x82\x92\xa0\x18ޡ\xa1\xc9\x7f\xa4ZF\xef\xd3\x15\x95\xad\xfc2\x99n\xb8VDG\xe5\xf9\xeb\xf1\xfe\r%\xbd\xdd{\xa6\x17\xb7P&\xa3q\x1e\x8b\xa0Z~A\xf1\x1akiҸS2\xf2w\xfc\xc2;&j\xb6\xa2\xf8թ<\x80o@\xfc\xb8ŝ\x8f&\xdf\xf3\xd37l\n\x88\x81\x9f[ \x85\x99\xc1X!Ԩ\x91\xb0\x86\xea5\xdf\\\xaf\x81\xb0?\xc5\xddX\xdf\vZ\x01\xdf\xff\x05\xa9\x9962QkQi\\\x01\xf9x\xae\xcbf\x13w\x9d\b3cx\x94\xf3\x03\xfb\xcc5\xc6n\x18/v\x06\x9c\xbd_\n\xf8\x8c/3\xd6\ao%\x86\x80\xa7ct6\x93\xd9!81\x06~\xa4\xd5\a,\r\x7f\x19\x06\xcb\xff\x01\x00\x00\xff\xffx\xae@\xbaJ\x0e\x00\x00"), - []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4ZK\x93\x1b\xb7\x11\xbe\xef\xaf\xe8Z\x1flWi\xc8HI\\)ޤU\x9c\xda\xc4V\xb6ĕ..\x1f\xc0A\x93\x03\xef\f\x80\x00\x18R\x8c\xe3\xff\x9ej<\x86\xf3\x00\xc9]\xca\xf2\xe2\xb2K<\x1a\x8d\xaf\x1b\xfd\xc2\x14EqŴ\xf8\x88\xc6\n%\x17\xc0\xb4\xc0O\x0e%\xfd\xb2\xb3\x87\xbfٙP\xf3\xed˫\a!\xf9\x02nZ\xebT\xf3\x1e\xadjM\x89oq-\xa4pBɫ\x06\x1d\xe3̱\xc5\x15\x00\x93R9Fݖ~\x02\x94J:\xa3\xea\x1aM\xb1A9{hW\xb8jE\xcd\xd1x\xe2i\xeb\xed\x9ff/\xbf\x9b\xfd\xf5\n@\xb2\x06\x17\xa0\x15ߪ\xbamp\xc5ʇV\xdb\xd9\x16k4j&ԕ\xd5X\x12\xed\x8dQ\xad^\xc0a \xac\x8d\xfb\x06\x9e\xef\x14\xff\xe8ɼ\xf1d\xfcH-\xac\xfbWn\xf4\aa\x9d\x9f\xa1\xebְzʄ\x1f\xb4Bnښ\x99\xc9\xf0\x15\x80-\x95\xc6\x05\xbc#64+\x91_\x01\xc4#z\xb6\n`\x9c{\xd0X}g\x84thn\x88B\x02\xab\x00\x8e\xb64B;\x0fʈ?\xb0\x8e\xb9ւm\xcb\n\x98\x85w\xb8\x9b\xdf\xca;\xa36\x06m`\x0e\xe0\x17\xab\xe4\x1ds\xd5\x02fa\xfaLW\xccb\x1c\r\xe0.\xfd@\xecr{b\xd9:#\xe4&\xc7Ľh\x10xk\xbcP\xe9\xf4%\x82\xab\x84\x9dp\xb7c\x9684\xce\x1f;ϋ\x1f'\x8aֱF\x8f\x99\xea-\r\\q\xe60\xc7Ӎjt\x8d\x0e9\xac\xf6\x0e\xd3I\xd6\xca4\xcc-@H\xf7\xdd_\x8e\xc3\x11\xf1\x9a\xf9\xa5o\x95\x1cb\xf3\x86z\xa1\xd7\x1d8!Ym\xd0d\x01R\x8e՟È#\x02oz\xeb\x03'\x81n\xbf\xff,+\xa4x\xa0\xd6\xe0*\x84(\x95\xa5S\x86m\x10~Pe\x90\xe0\xaeB\x13%\xb8\x8ajU\xa9\xb6\xe6\xb0J'\x06\xb0N\x99\xac\x145\x96\xb3\xb0*\xd2MdG\xa2\x1c\xee\xf9%4\xad4Ȳ\x9a\x96\xac\xd1\xcc\xcf\x10J\xe6\xd5\xed\xf5\x06\x1f\xa5j}H\xa5\xe2\xd8\xe1\x87\x13\xb6\x84\x05mT\x89֞\xb8\x01Dc\xc0ȻC\xc7Y\x80*\xf4s\x12?\xad\xae\x15\xe3h\xc0)\xa8\x98\xe45\xd21\x188ä]G\x15\x99\n0-\xbb\xdf\xeb!+\x1f\xe2\xc01v¬\xed\xcb`\a\xcb\n\x1b\xb6\x88s\x95F\xf9\xfa\xee\xf6㟗\x83n D4\x1a'\x92]\x0e\xad\xe7uz\xbd0<\xee\xff\x8a\xc1\x18\x00m\x10V\x01'\xf7\x83\xd6\xc3\x10-,\xf2\xc8S\x80GX0\xa8\rZ\x94\xc1!Q7\x93\xa0V\xbf`\xe9f#\xd2K4D&݅R\xc9-\x1a\a\x06K\xb5\x91\xe2\xbf\x1dmKXӦ5sh\x9d\xbf\x8cF\xb2\x1a\xb6\xacn\xf1\x050\xc9G\x94\x1b\xb6\a\x83\xb4'\xb4\xb2G\xcf/\xb0c>~T\x06AȵZ@圶\x8b\xf9|#\\\xf2ťj\x9aV\n\xb7\x9f{\xb7*V\xadS\xc6\xce9n\xb1\x9e[\xb1)\x98)+\xe1\xb0t\xad\xc19Ӣ\xf0\a\x91\xde\x1f\xcf\x1a\xfe\x95\x89\xde\xdb\x0e\xb6\x9d\b:4\xefB\x9f \x1er\xaat\tX$\x15\x8ex\x90\x02u\x11t\xef\xff\xbe\xbc\x87\xc4I\x90T\x10\xcaa\xea\x04\x97$\x1fBS\xc85\xe9<\xad[\x1b\xd5x\x9a(\xb9VB:\xff\xa3\xac\x05J\a\xb6]5\u0091\x1a\xfc\xa7E\xebHtc\xb27>^\x81\x15\xdd%\xb2\x00|<\xe1V\xc2\rk\xb0\xbea\x16\xff`Y\x91TlABx\x94\xb4\xfaQ\xd8xr\x80\xb77\x90b\xa8#\xa2\x1dY\xb6\xa5ƒ\x04K\xd8\xd2J\xb1\x16љ\xac\x95\x016\x9e>\xc4)o\x00\xa8e\x1d\xc9x\xd29\xa5\xa3\xf6&G(1,{\x06<9\xbc\xe8\x9f\xea\xa1\x7f귃\x95\x8fk\fje\x85SfO\x84\x83\x83\x1c+\xc4Q\xd9P+\x99,\xb1\xbe\xe4x7~%\b\xc9\tv\xec\x14\x9aLQ\xa0\xea\x19Ur\xa3芍\xa5\x01\xb7\x8e\xa6\x91\x92[t\xf9\xb3\xcac\x0eMH8\x84\x98\xd0\x0f%LJ^)U#\x1bcI\xee\xee̙\xc9\x01\xe6\x84彭\xab\x98K\xbc\xd1$\xd3J9Ŗ\x9a\x92O\x12\x87V\xfc\f_qG\x06\x06\xd7h\xd0G#\xc1\xf6k\xe5=\x84cB&\x9b\x16\x12\x01p*\xc3\xd9*(\x11r\x18\xdf\r8y?\xe0\x84\xa3\xccr\xfc\xfa\xee69\xc3\x04b\xe4}\xe2\xef\xce\xe2Cm-\xb0\xe6>r8\xbfwVs\xa9ݮ\x03\x13\xde#8\x05\f\xb4\xc0\x12\a\xde\x18\x84\xb4\x0e\x19\x8f\x9dd\x04\rƱ\x17\xc1\xd2\x1fe\x92\xda\xc1k\x93L\x80\x91\xe7\x11\x1c\xfe\xb9\xfc\xf7\xbb\xf9?T8\a\xb0\x92B3\x9fDa\x83ҽ\xe8\x12)\x8eV\x18\xe4\x94\x16\xe1\xacaR\xacѺY\xa4\x86\xc6\xfe\xf4\xea\xe7<~\x00\xdf+\x03\xf8\x89Q:\xf2\x02D\xc0\xbcsfIm\x84\r\a\xef(\xc2N\xb8\xca3\xaa\x15\x8f\a\xdc\xf9#8\xf6@79\x1c\xa1E\xa8\xc5C\xe6\xfe\x84v\xed\xa3\xb9\x03\x9b\xbf\xd2\xed\xf9\xed\x1a\xbe\t\xc6\xeb\x9a~^\a6\xba\xb0\xa5\x7f\xc1\x0e\xec\x84[f\xc4f\x83\x87\xb8\x7f\xa2,\xe4f\xc9A}\v\xca\xd0Y\xa5\xea\x91\xf0\x84IN\xc1? \x9f\xb0\xf7ӫ\x9f\xaf\xe1\x9b!\x06G\xb6\x12\x92\xe3'xE\xd6\xc7c\xa3\x15\xffv\x06\xf7^\x0f\xf6ұO\xb4SY)\x8b\x12\x94\xac\xf7!\x00\xde\"X\xd5 찮\x8b\x10 rر=\xa8\xf5\x91}\x92\x88H5\x19hf\xdc\xc9 1\xe2p\xfa\xd2L\xa3\xa6\xd4\x1ew_|\x14\xf5\xa8\xdb\xfbl\x11\xc8#\x91\xf0\xe9\xc2g \xd1O\xbd.@\xe2\xa1]\xa1\x91\xe8Ѓ\xc1Ui\t\x87\x12\xb5\xb3s\xb5E\xb3\x15\xb8\x9b\xef\x94y\x10rS\x902\x16A\xeav\xee\xcbH\xf3\xaf\xfc\x9fK\x0f\xee\xeb?\x9f{zO\xe4\xf9 \xa0\xdd\xed\xfc\x12\x04Rt\xffx\xdfu\x14\x87e\f8\xc74\xe9\xce\xef*QV)\xd7\xebYۆ\xf1`\x8e\x99\xdc?\xd3\xdd!\x9c[C\x1c\xed\x8bX\x03-\x98\xe4\xf4\xbf\x15\xd6Q\xff%\xc0\xb6Ⳍˇ۷\xcfy\xa3Zq\x89%9\x92Ä\xf6\xa98pU4L\x17a6s\xaa\x11\xe5h6\xc5\U00037704\xb4\x16h΄\x7f\xef\a\x93S\x80\x9a\xc9\x06\xba9O\x8a?\x1d\xdbd\x02\xbe~y\xf8TXx\x12\xaf\xf3\xaap\xcf6\x16\x98A`\xd00M\x1a\xf1\x80\xfb\"D\x1c\x9a\t\n\x17(\"\xe8\n\x83\xc0\xb4\xaeɧ\x87(\"C1ƿ\x11\x1ef\xfd\xf9\x8e\x01\x92\x15e\xaaJ-\xd19!\x9f\x11\x9c\x0f#F~_\xa0\xba\x9a]\xa9\xe4Zlb\xb5s\x8a\x94l뚭j\\\x803\xed\xb1\x9c\xeb$\x90\xf74\xe5\xf4\xf9?\xf4\xa6&\r?S`̟jPv\x9c\x1e\x06e\xdbLY)\xe0Ai\xc12\xfd\x06\xad\x9b\xdc^\x1a\xb8\xbe~\xca\x1d\vJyI\xca\x1d\xd2\xe0\\V\x1a\x15=\x06\xf0)3u\xea\x90\xe5e\x85\xfe\x04\xdb@\xd9=\xa5#C\xbe\x8b|\xb9d4\xa7W]N]Z\xf1Q\xcf\xd0\f\x8e\x06\xc3\xf9\x1eUC\xf2\x05\xed'T\x91\xc2\xebU\xc448G\x97\u07b4(쾴\x8eD\x89\x9dvȻB\xff%\x12\x7f=&\xe2k\xbf\x86\xc7K!\x1a\xecR\xff\xa1\xad\v\xc9\xdd\nA\x1b\xd4,[\x15\x02_\xb9\xb7\xbe\x84\xf9\xb5\rĄ\x85\xd6\"\xf7\x15\xb4\xc9\xde\x13\n\xe9E\x893\x87\x05\xad\xbf\xcc^\xe4\vS\xe11\xad\xffRrQ\x95jJf\n!K\xa8\xf9'\x9c\xf4\x8a\x97C\xec@\xae\xc3+PC\xee\xb3PJ\x92\xd7L\xd4\xc8!=\x11?\x91\xca\n\xd7\x14\xe2\x04\x1b\x97\xea8\x91\xbd\xe3\xf9\xdfiIf@\x98\x06<_R\x98\rZ\xcb6\xe7lޏaV(o\xc5%\xc0V\xaauy%\xff\xda\xc6{\xfa\xb4\x12[\xb6r44\x11\xccU\xc9\"\xacۺ\xf6k\xfa\xc6\xf5\xf0\xf9\x80\xe7j\x85\xf9\xb0\xf8D}\xed\x14\x83\x15\xb3砺\xa399\xa3\xd5y\x84\x93V\vNx\xbfw\xb8\xcb\xf4&c\x90\x19\xba\x8b\x16&34\xf9\x0e\xa0?\x18\n\xc89\xe4\xd2X\x96f\xf7ʞ\x19\xfb\xde_\xbd'\x81\x1d\xf9\xbbĶt\x05\xe8J\xd5ɜ\xf8\xd7q\xd96+4$\t\xff\xfe>r\xd2L\xf2\xbe\xd8r\x99\xfaa}Ҡ@)V\x9bb\xdd\xdc\xdfo\xa7\x80\v\xabk\xb6\xef\xce\xe2\xf3#\xba\xcc\xf9G\x84ÍJfE\xe3\xb1x\xeft\x19\xb8\xfbV!\x9f\xfc\xe5>8\x18\xb6\xe9\xa7\x03\xa3\xf1\xee\x1b\x84/\xb3Éx\xd5J\xa6m\xa5\xdc\xed\xdb3\xaa\xb1\xec&\xa6\xfbxȽ\xbc\xf5\xf5\xefSqRT\x85\f\xab\a\xeb\xf6$c1\xfct\xe5\x12-^\x0e(\x9cq\x8e\xf1K\x9a\x9c\vZ\x92\x15 \x03\xe4_?oƟ9\xbc\xe8>\x9d`.V\x91ˊ\xc9M\xb6\x96\xa5\xa4\x0f\xb6\x95\x99>E\xc3Yo7<\xd0\x1f\xe9\xe8\xb2\xea4\xe9\xf4\x9c\xf3\x1e\xed\xf8\xf0\xd7\xefiWݛ\xf8\x02~\xfd\xed\xea\xff\x01\x00\x00\xff\xff\xd9H\xdbA\x14'\x00\x00"), - []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4Z_\x93۶\x11\x7fקع<$\x991\xa5\xc6m3\x1d\xbd\xd9\xe7\xa6smr\xbd\xb1l\xbfd\xf2\xb0\"V\x12\"\x12@\x01P\xb2\x9a\xe6\xbbw\x16 )\xfe\x81\xa4\x93<\x8e\xf9b\v\x00\x97?\xfc\xf6/\x16\x97e\xd9\x04\x8d\xfc@\xd6I\xad\xe6\x80F\xd2GO\x8a\x7f\xb9\xe9\xf6on*\xf5l\xf7\xddd+\x95\x98\xc3}\xe5\xbc.ߒӕ\xcd\xe9\r\xad\xa4\x92^j5)ɣ@\x8f\xf3\t\x00*\xa5=\xf2\xb0\xe3\x9f\x00\xb9V\xde\xea\xa2 \x9b\xadIM\xb7Ւ\x96\x95,\x04\xd9 \xbc\xf9\xf4\xeeO\xd3゚\xfeu\x02\xa0\xb0\xa49\x18-v\xba\xa8J\xb2伶\xe4\xa6;*\xc8\xea\xa9\xd4\x13g(g\xe1k\xab+3\x87\xe3D|\xb9\xfep\x04\xfd\xa4Ň \xe7m\x94\x13\xa6\n\xe9\xfc\xbf\x92\xd3?J\xe7\xc3\x12ST\x16\x8b\x04\x8e0\xeb\xa4ZW\x05\xda\xf1\xfc\x04\xc0\xe5\xda\xd0\x1c\x1e\x19\x8a\xc1\x9c\xc4\x04\xa0\xdeg\x80\x96\x01\n\x11\x98\xc3\xe2\xc9J\xe5\xc9\u07b3\x88\x86\xb1\f\x04\xb9\xdcJ\xe3\x033C\x88\xe0<\xfaʁ\xab\xf2\r\xa0\x83G\xda\xcf\x1eԓ\xd5kK.\xc2\x03\xf8\xd5i\xf5\x84~3\x87i\\>5\x1btT\xcfF\x8a\x17a\xa2\x1e\xf2\a\xc6켕j\x9dB\xf1N\x96\x04\xa2\xb2A\xb5\xbc\xff\x9c\xc0o\xa4\x1b\xc3ۣc\x88և\x8d\xa7\xc1\x84y\x16\xe9<\x96f\x88\xaa\xf3j\x84%\xd0S\nԽ.MA\x9e\x04,\x0f\x9e\x9a\xad\xac\xb4-\xd1\xcfA*\xff\xfd_N\xf3Q\x136\r\xaf\xbeѪO\xcek\x1e\x85\xcepD\xc2\xdaZ\x93M2\xa4=\x16\x9f\x02ij\x80ם\xf7#\x92(\xb7;~\x11\n\x9b\x1e\xe8\x15\xf8\r\xc1k̷\x95\x81\x85\xd7\x16\xd7\x04?\xea<\xaap\xbf!Ka\xc52\xae`\x0f\x06ɺ\xd36\xa9:C\xf94\xae\xad\x855\xb2\x06\xfa\xeb\x7f\xe8\xb3\xd8Wn\t\x93\xf6Մ\xa2iX!\xb5J\x1b٫5=\xcb\xc0\xbaD*-\xa8\xc3\xda\b\x97t`\xac\xceɹ3\x86\xcfBzH\x1e\x8f\x03\x17)\xdaPX\xd3\x00\xaaL\xa1Q\x90\x05\xafa\x83J\x14\x14u\xe8-*\xb7\xaa-c\xac\xc2\xe6\xb5w\aӇ\xf2\xbe\x91י\x19a\x8aKw\xdf\xc50\x98o\xa8\xc4y\xbdV\x1bR\xaf\x9e\x1e>\xfcy\xd1\x1b\x06\xa6Ő\xf5\xb2\x89\xcc\xf1\xe9$\x9e\xce(\xf4\xf7\xfc\xbf\xac7\a\xc0\x1f\x88o\x81\xe0\fD.pQ\xc7W\x125\xa6ȑt`\xc9Xr\xa4bN\xe2aT\xa0\x97\xbfR\xee\xa7\x03\xd1\v\xb2,\x06\xdcFW\x85\xe0ĵ#\xeb\xc1R\xae\xd7J\xfe\xb7\x95\xed\x98p\xfeh\x81\x9e\x9c\x0f\x8eh\x15\x16\xb0â\xa2\x17\x80J\f$\x97x\x00K\xfcM\xa8TG^x\xc1\rq\xfc\x14\xacI\xad\xf4\x1c6\xde\x1b7\x9f\xcd\xd6\xd27\xe98\xd7eY)\xe9\x0f\xb3\x90Y\xe5\xb2\xf2ں\x99\xa0\x1d\x153'\xd7\x19\xda|#=徲4C#\xb3\xb0\x11\x15R\xf2\xb4\x14_\xd9:\x81\xbb\xdegG\x8a\x8eOH\xa2W\xa8\x87\xb3*{\x02֢\xe2\x16\x8fZ\xe0!\xa6\xee\xed\xdf\x17\xef\xa0A\x125\x15\x95r\\:\xe2\xa5\xd1\x0f\xb3)Պ\r\x9f\xdf[Y]\x06\x99\xa4\x84\xd1R\xf9\xf0#/$)\x0f\xaeZ\x96ҳ\x19\xfc\xa7\"\xe7YuC\xb1\xf7\xa1d\x81%;\x14\xc7\x011\\\xf0\xa0\xe0\x1eK*\xee\xd1\xd1\x1f\xac+֊\xcbX\t\xcf\xd2V\xb7\x10\x1b.\x8e\xf4v&\x9a*\xea\x84j\x87\xf1ma(g\xcd2\xb9\xfc\xaa\\\xc9:\x93\xac\xb4\x05\x1c\xad\xef3\x95\x0e\x01\xfc$3\xcap\xd1%\xb3\xe3\xe7uJP\x83Xu\x02y\x9d\xef\\\x9d\xa8\x8a~\xa2\xea>\xa3\x1ci\xc9h'\xbd\xb6\x87c\xa6\x1c\x9a\xc4I\xed\xf0\x93\xa3ʩ\xb8e{\xf7\xe1M\x90J0\xefԚ4\a\xa3(5\x00\xd5j\xad\xd9\xc9F\xea\x80\a\xcf\xeb\xd8\xce\x1d\xf9\xf4f\xd5\xc9\xcc&\x15\x1ckL\xe8֒\xc3m/\xb5.\b\x87l\x1a-.l\xfaIׁ\xc3Ҋ,\x85\xfc\x1fì\xd1!\x18{\x94\xaa\t\x1f\xb1\xe4\x06\xaf\x13\xfbXr\xb89\xa5\x9a\xd3v\bgRR\x12𫧇&\xed4\x96UC\x1fe\x96.?I\xb3\xe0g%\xa9\x10!Q_\xfev\xd2B\xf8yXE\x10!\xf6z\r\bFRN\xbd\xbc\aR9O(\xeaA\x0e7\x96\xea\xb9\x171\xa6\x9e\x04\xc9\xcf1?\xb2J\x009\xc6K\x01\xff\\\xfc\xfbq\xf6\x0f\x1d\xf7\x01\x98s%\x14\xce*T\x92\xf2/\xda\xf3\x8a '-\t>}дD%W\xe4\xfc\xb4\x96F\xd6\xfd\xfc\xf2\x974\x7f\x00?h\v\xf4\x11\xb9\xe8\x7f\x012rަ\x8d\xc6j\xa4\x8b\x1bo%\xc2^\xfaM\x00j\xb4\xa87\xb8\x0f[\xf0\xb8e\x8f\x89[\xa8\b\n\xb9\xa54\xfb\x00w\xa1x:\xc2\xfc\x8dC\xca\xefw\xf0M\f\x12w\xfc\xf3.\xc2h\v\x84n\xd49\xc2\xf1\x1b\xf4\xe0\xad\\\xaf\xe9Xh\x8f\x8c\x85\x13\x1a\xa7\x82oA[ޫ\xd2\x1d\x11A0\xeb)\x06b\x12#x?\xbf\xfc\xe5\x0e\xbe\xe9sp\xe2SR\t\xfa\b/\xd9\xc7\x037F\x8bo\xa7\xf0.\xd8\xc1Ay\xfc\xc8_\xca7ڑ\x02\xad\x8aC\xac7w\x04N\x97\x04{*\x8a,\x96b\x02\xf6x\x00\xbd:\xf1\x9dFEl\x9a\b\x06\xad?[\x8e\xd5<\x9cw\x9aq}\xd2<\xcf\xf3\x97P\xaf<\xcb{\xbfX\xae\x7f&\x13\xa10\xff\x04&\xbaG\x9d\x1b\x98\xd8VK\xb2\x8a<\x052\x84\xce\x1d\xf3\x90\x93\xf1n\xa6wdw\x92\xf6\xb3\xbd\xb6[\xa9\xd6\x19\x1bc\x16\xb5\xeef\xa1e3\xfb*\xfcs\xeb\xc6C\x9f\xe5Sw\x1f\x84|9\n\xf8\xebnv\v\x03M\x1d\xfd\xfc\xdcu\x92\x87E]\xd9\re\xb2\xcf\xef72\xdf4\xa7\xaaN\xb4-Q\xc4p\x8c\xea\xf0\x85|\x87y\xae,#:du\xc31C%\xf8\xffN:\xcf\xe3\xb7\x10[\xc9O\n.\xef\x1f\xde|I\x8f\xaa\xe4-\x91\xe4\xc4i!>\x1f\xb3#\xaa\xacD\x93\xc5\xd5\xe8u)\xf3\xc1j\xae\x95\x1f\x04+i%\xc9^\xa8\xfe\xde\xf6\x167U{\xa2\xean\xd7\\Uv;\x85\xc6m\xb4\x7fxs\x01Ǣ]\xd8`8\xea\xb0.:\x1bY\xec\x12gk\xcdsx\x82o=\x9e\x8e\\}P\xfd\xd5\r2m\xe5Z*,\x8e\x110\x1c\xc5\x14\x96\x18~%t_\xa21R\xad\xaf\xc2\xda\xf4\x8b\x16\xe4\xf9\xf8\x9e(\x9c\xbb\xed\xecs\xe5\xf5Y\xbb\xbb\xecR\xef\a@\x00-\x01\xf2\x9eXC[:d\xb1\x8a3(\xb9\x04\xe3*\xab.U\x97\x04hL\xc1uR\xac\xccR\xbe\xdet\xbfr\xadVr]w\"\xc7L\xa9\xaa(pY\xd0\x1c\xbc\xadN\x1d\x82\x92\xee\xd3m\xbc]\xd0\xf8\xfb\xce\xd2F\xdd\x17Z\x7f\xe9]\xf5\x1a\x82\xe3͐\xaa\xca1\x94\f\xb6\xdaHL\x8c\xb3\xb1\x8f\x1c\x9d'\xee\xee\xae1\xa9\xe8I\x178\x88g\xd0\xd4\x01\xbevĺ\xac\xaf\x8f\xac\xd1\x1d\xd3\xd9\xf1Z\a\xe5\xa35\x9fQ\xfa\b\xb3t\xafb\xb0\xc6h1\x19\x92֍m\x83\xc9cd\x1aN\xf4\x9d~0\x1b)xV\x9b'4\x9e\xafi\xf4\xc4륚\xf7\x98V}s\xe9\xc4\x05\xfbͭ\x1e>\x13\x1aO\xa2\xed\xc9\xdf\xd2\ay5\x14\x12\x1a\xb4V\xd4N\"Kj\x9b\x06\xb5\x9d\xd8c\x1b#\x86lc\xc9`\xd2\" 4\xd9]h4~\xed\xa24\xe9\xa0r$Bl\x1d}|$\xa1\xb9\xf3\x11\xe8)\xe3\xf7o\v \xe9\xe6Q\xbc\xee\xea\xdej\xdc\xd4I\x1a\x8b\x19s\x88-mᾥ\xb9hKQv\x94\xd7\x12\x16ő\bGX>a\xafP\x16$\xa0\xbd̽\x9a\xf9\x04\xe8qq\xf39\xc9/\xc99\\_\nZ?\xc5U\xb1\x93U\xbf\x02\xb8ԕ?a\x95_\xbbڵ\xae\xca\xc9J\x8bKH\x1e\xb5\b0\xd4\xe9+\xac1\x9a\x84Z\xba\xd7ZWa\fM\xc2KM?^\x93\n5-\xe4\xf3\xb1\x06\xce\xe4\xb0G\xda'F\x1b\x0fNL=\xd5a!15\xba_\xefN\xc6\xcel\xaa\xa6i\xe6\x922\xdb\xcb\xeb\xc4\xdc\x0f\xc1]\xaeb\xbb\xc6wK@h\xfb\xba\x1b]41 \\:\xab\xaa\\\x92eU\x84k\xedF'm\x05\x8cJt5\x97:\x9c\xb7\x12\x9a4\x1cE\xd5\xfd\xa5\xba!\x1d\xbc\xdck\x10ҙ\x02\x0f\xedf\u0089\x88]:ݞ?\xfaU\x13\xab8\xf3\x9c\xa8\xdb\xcew~\xdb?\x02H\x9f\xf7R7\xf9\xfdg|'?\x98o/\xf7?\xcf\x17\xceԝ\xfd?\xb6\xb8\xc5@\x16=\t\x97\x92E\xfd\xc7\x1f\xd7\xc7\xf8\xfeg\xfe\xc8\xf0\x9edo4\x18\x90\x8b\x8e\xec\xfa\n\xa9;R-\xdb\xfb\xd59\xfc\xf6\xfb\xe4\xff\x01\x00\x00\xff\xff\xec\xe3\xc3\ac%\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4ZK\x93\x1b\xb7\x11\xbe\xef\xaf\xe8Z\x1flWi\xc8HI\\)ޤU\x9c\xda\xc4V\xb6ĕ..\x1f\xc0A\x93\x03\xef\f\x80\x00\x18R\xb4\xe3\xff\x9ej<\x86\xf3\x00\xc9]*\xf2\xcee\x97x\xf44\xbe~7\xa6(\x8a+\xa6\xc5G4V(\xb9\x00\xa6\x05~r(闝=\xfc\xcd΄\x9ao_^=\b\xc9\x17p\xd3Z\xa7\x9a\xf7hUkJ|\x8bk!\x85\x13J^5\xe8\x18g\x8e-\xae\x00\x98\x94\xca1\x1a\xb6\xf4\x13\xa0T\xd2\x19U\xd7h\x8a\r\xca\xd9C\xbb\xc2U+j\x8e\xc6\x13O\xaf\xde\xfei\xf6\xf2\xbb\xd9_\xaf\x00$kp\x01Z\xf1\xad\xaa\xdb\x06W\xac|h\xb5\x9dm\xb1F\xa3fB]Y\x8d%\xd1\xde\x18\xd5\xea\x05\x1c&\xc2\xde\xf8\xde\xc0\xf3\x9d\xe2\x1f=\x997\x9e\x8c\x9f\xa9\x85u\xff\xca\xcd\xfe \xac\xf3+t\xdd\x1aVO\x99\xf0\x93V\xc8M[33\x99\xbe\x02\xb0\xa5Ҹ\x80wĆf%\xf2+\x80xD\xcfV\x01\x8cs\x0f\x1a\xab\uf310\x0e\xcd\rQH`\x15\xc0іFh\xe7A\x19\xf1\a\xd61\xd7Z\xb0mY\x01\xb3\xf0\x0ew\xf3[yg\xd4Ơ\r\xcc\x01\xfcb\x95\xbcc\xaeZ\xc0,,\x9f\xe9\x8aY\x8c\xb3\x01ܥ\x9f\x88CnO,[g\x84\xdc䘸\x17\r\x02o\x8d\x17*\x9d\xbeDp\x95\xb0\x13\xeev\xcc\x12\x87\xc6\xf9c\xe7y\xf1\xf3D\xd1:\xd6\xe81S\xbd\xad\x81+\xce\x1c\xe6x\xbaQ\x8d\xae\xd1!\x87\xd5\xdea:\xc9Z\x99\x86\xb9\x05\b\xe9\xbe\xfb\xcbq8\"^3\xbf\xf5\xad\x92Cl\xde\xd0(\xf4\x86\x03'$\xab\r\x9a,@ʱ\xfas\x18qD\xe0Mo\x7f\xe0$\xd0폟e\x85\x14\x0f\xd4\x1a\\\x85\x10\xa5\xb2tʰ\r\xc2\x0f\xaa\f\x12\xdcUh\xa2\x04WQ\xad*\xd5\xd6\x1cV\xe9\xc4\x00\xd6)\x93\x95\xa2\xc6r\x16vE\xba\x89\xecH\x94\xc3w~\tM+\r\xb2\xac\xa6%o4\xf3+\x84\x92yu{\xbd\xc1G\xa9Z\x1fR\xa98v\xf8\xe1\x84-aA\x1bU\xa2\xb5',\x80h\f\x18yw\x188\vP\x85~M\xe2\xa7յb\x1c\r8\x05\x15\x93\xbcF:\x06\x03g\x98\xb4\xeb\xa8\"S\x01\xa6m\xf7{=d\xe5C\x9c8\xc6NX\xb5}\x19\xfc`Ya\xc3\x16q\xad\xd2(_\xdf\xdd~\xfc\xf3r0\f\x84\x88F\xe3D\xf2\xcb\xe1\xe9E\x9d\xde(\f\x8f\xfb\xdfb0\a@/\b\xbb\x80S\xf8A\xeba\x88\x1e\x16y\xe4)\xc0#,\x18\xd4\x06-\xca\x10\x90h\x98IP\xab_\xb0t\xb3\x11\xe9%\x1a\"\x93l\xa1Tr\x8bƁ\xc1Rm\xa4\xf8\xb5\xa3m\tkzi\xcd\x1cZ\xe7\x8d\xd1HVÖ\xd5-\xbe\x00&\xf9\x88r\xc3\xf6`\x90\xde\t\xad\xec\xd1\xf3\x1b옏\x1f\x95A\x10r\xad\x16P9\xa7\xedb>\xdf\b\x97bq\xa9\x9a\xa6\x95\xc2\xed\xe7>\xac\x8aU딱s\x8e[\xac\xe7Vl\nf\xcaJ8,]kpδ(\xfcA\xa4\x8fdz\x86\x7feb\xf4\xb6\x83\xd7N\x04\x1d\x1e\x1fB\x9f \x1e\n\xaad\x04,\x92\nGI\x1cZ\xf13|\xc5720\xb8F\x83>\x1b\t\xbe_+\x1f!\x1c\x132\xf9\xb4P\b\x80S\x19\xceVA\x89\x90\xc3\xd86\xe0\xa4}\xc0\x89@\x99\xe5\xf8\xf5\xddm\n\x86\t\xc4\xc8\xfb$ޝŇ\x9e\xb5\xc0\x9a\xfb\xcc\xe1\xfc\xbb\xb3\x9aK\xcf\xed:0\xe1#\x82S\xc0@\v,q\x10\x8dAH\xeb\x90\xf18HN\xd0`\x9c{\x11<\xfdQ&\xe99Dm\x92\t0\x8a<\x82\xc3?\x97\xff~7\xff\x87\n\xe7\x00VRj\xe6\x8b(lP\xba\x17]!\xc5\xd1\n\x83\x9c\xca\"\x9c5L\x8a5Z7\x8b\xd4\xd0؟^\xfd\x9c\xc7\x0f\xe0{e\x00?1*G^\x80\b\x98w\xc1,\xa9\x8d\xb0\xe1\xe0\x1dE\xd8\tWyF\xb5\xe2\xf1\x80;\x7f\x04\xc7\x1eȒ\xc3\x11Z\x84Z\x9b;\xb0\xf9\x1bY\xcf\xef\xd7\xf0Mp^\xd7\xf4\xf3:\xb0ѥ-}\x03;\xb0\x13\xac̈\xcd\x06\x0fy\xffDY(\xccR\x80\xfa\x16\x94\xa1\xb3J\xd5#\xe1\t\x93\x9cB|@>a\xef\xa7W?_\xc37C\f\x8e\xbcJH\x8e\x9f\xe0\x15y\x1f\x8f\x8dV\xfc\xdb\x19\xdc{=\xd8K\xc7>ћ\xcaJY\x94\xa0d\xbd\x0f\t\xf0\x16\xc1\xaa\x06a\x87u]\x84\x04\x91Î\xedA\xad\x8f\xbc'\x89\x88T\x93\x81fƝL\x12#\x0e\xa7\x8df\x9a5\xa5\xe7q\xf6⳨GY\xef\xb3e \x8fD\u0097\v\x9f\x81D\xbf\xf4\xba\x00\x89\x87v\x85F\xa2C\x0f\x06W\xa5%\x1cJ\xd4\xce\xce\xd5\x16\xcdV\xe0n\xbeS\xe6A\xc8MA\xcaX\x04\xa9۹o#Ϳ\xf2\x7f.=\xb8\xef\xff|\xee\xe9=\x91烀\xden\xe7\x97 \x90\xb2\xfb\xc7Ǯ\xa38,c\xc29\xa6I6\xbf\xabDY\xa5Z\xaf\xe7m\x1bƃ;fr\xffL\xb6C8\xb7\x868\xda\x17\xb1\aZ0\xc9\xe9\x7f+\xac\xa3\xf1K\x80m\xc5g9\x97\x0f\xb7o\x9fӢZq\x89'9RÄ\xe7Sq\xe0\xaah\x98.\xc2j\xe6T#\xca\xd1j\xca\xe1o9\ti-МI\xff\xde\x0f\x16\xa7\x045S\rtk\x9e\x94\x7f:\xb6\xc9$|\xfd\xf6\xf0\xa9\xb4\xf0$^\xe7U\xe1\x9em,0\x83\xc0\xa0a\x9a4\xe2\x01\xf7E\xc884\x13\x94.PF\xd05\x06\x81i]SL\x0fYD\x86b\xcc\x7f#<\xcc\xfa\xf3\x1d\x03$+\xcaԕZ\xa2sB>#8\x1fF\x8c\xfc\x7f\x81\xeazv\xa5\x92k\xb1\x89\xdd\xce)R\xb2\xadk\xb6\xaaq\x01δ\xc7j\xae\x93@\xdeӒ\xd3\xe7\xff\xd0[\x9a4\xfcL\x831\x7f\xaaA\xdbqz\x18\x94m3e\xa5\x80\a\xa5\x05ˌ\x1b\xb4nb\xbd4q}\xfd\x14\x1b\vJyI\xc9\x1d\xca\xe0\\U\x1a\x15=&\xf0\xa92u\xeaP\xe5e\x85\xfe\x04\xdf@\xd5=\x95#C\xbe\x8b|\xbbd\xb4\xa6\xd7]NCZ\xf1\xd1\xc8\xd0\r\x8e&\xc3\xf9\x1e\xd5C\xf2\r\xed't\x91\xc2\xedU\xc44\x04G\x97\xee\xb4(\xed\xbe\xb4\x8fD\x85\x9dvȻF\xff%\x12\x7f=&\xe2{\xbf\x86G\xa3\x10\rv\xa5\xff\xd0ׅ\xe2n\x85\xa0\rj\x96\xed\n\x81\xef\xdc[\xdf\xc2\xfc\xda\x06b\xc2Bk\x91\xfb\x0e\xda\xe4\xdd\x13\n\xe9F\x893\x87\x05\xed\xbf\xcc_\xe4\x1bS\xe12\xad\x7fSrQ\x97jJf\n!K\xa8\xf9+\x9ct\x8b\x97C\xec@\xae\xc3+PC\xee\xabP*\x92\xd7L\xd4\xc8!]\x11?\x91\xca\nה\xe2\x04\x1f\x97\xfa8\x91\xbd\xe3\xf5\xdfiIf@\x98&<_R\x98\rZ\xcb6\xe7|ޏaUho\xc5-\xc0V\xaauy%\xff\xdaF;}Z\x8b-\xdb9\x1a\xba\b\xe6\xaa\xe4\x11\xd6m]\xfb=}\xe7z\xf8|\xc0s\xb5\xc2|Z|\xa2\xbfv\x8a\xc1\x8a\xd9sP\xddњ\x9c\xd3\xea\"\xc2I\xaf\x05'\xa2\xdf;\xdceF\x933\xc8L\xddE\x0f\x93\x99\x9a|\aП\f\r\xe4\x1cri.K\xb3\xbbe\xcf\xcc}\xefM\xefI`G\xfe.\xf1-]\x03\xbaRur'\xfev\\\xb6\xcd\n\rI\xc2߿\x8f\x824\x93\xbc/\xb6\\\xa5~؟4(P\x8aݦ\xd87\xf7\xf6\xed\x14pau\xcd\xf6\xddY|}DƜ\xbfD8XTr+\x1a\x8f\xe5{\xa7\xdb\xc0ݷ\n\xf9\xe2/\xf7\xc1\xc1\xf0\x99~:0\x9a\xef\xbeA\xf82o8\x91\xafZɴ\xad\x94\xbb}{F5\x96\xdd\xc2d\x8f\x87\xda\xcb{_\x7f?\x15\x17EUȰz\xf0nOr\x16\x89\xf0R\xfcz\xceg,{K\x13\xab\xb5ڈ\x92\xd5`i,\xaai\"9\xe5\xe34ܧ\xa0\x1e~as\x89\xb1-\a\x14\xce\xc4\xf0\xf8\xc1O.R.\xc9Y\x91\x9f\xf4\x97\xb47\xe3\xaf1^t_x0\x17\x9b\xdde\xc5\xe4&\xdbrS\xd2\xd7\x04\xcaLo\xcc\xe1lP\x1e\x1e菌\xc7Y\xad\x9f\fz\xcey\x8fv\xbc\x9f쏴\xab\xee\xea~\x01\xbf\xfd~\xf5\xbf\x00\x00\x00\xff\xffXO骻'\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4ZO\x93۶\x15\xbf\xef\xa7x\xb39$\x991\xa5\xdam3\x1d\xdd\xecu\xd3\xd96\xd9\xeeX\xb6/\x99\x1c \xe2\x89DD\x02\b\x00J\xab\xa4\xf9\xee\x9d\a\x80\x14\xff@\xd2J\x1eǼ\xd8\v\x80\x8f?\xfc\xde_<(˲\x1b\xa6\xc5G4V(\xb9\x00\xa6\x05>9\x94\xf4\x97\x9dm\xfeagBͷ/o6B\xf2\x05\xdc5֩\xfa\x1dZ\u0558\x1c\xdf\xe2ZHᄒ75:ƙc\x8b\x1b\x00&\xa5r\x8c\x86-\xfd\t\x90+錪*4Y\x81r\xb6iV\xb8jD\xc5\xd1x\xe1\xed\xa7\xb7\x7f\x99\xbd\xfcn\xf6\xf7\x1b\x00\xc9j\\\x80V|\xab\xaa\xa6F\x83\xd6)\x83v\xb6\xc5\n\x8d\x9a\tuc5\xe6$\xbc0\xaa\xd1\v8L\x84\x97\xe3\x87\x03\xe8G\xc5?z9\xef\x82\x1c?U\t\xeb\xfe\x93\x9c\xfeAX\xe7\x97\xe8\xaa1\xacJ\xe0\xf0\xb3VȢ\xa9\x98\x99\xce\xdf\x00\xd8\\i\\\xc0\x03A\xd1,G~\x03\x10\xf7\xe9\xa1e\xc08\xf7̱\xea\xd1\b\xe9\xd0ܑ\x88\x96\xb1\f8\xda\xdc\b\xed<3c\x88`\x1ds\x8d\x05\xdb\xe4%0\v\x0f\xb8\x9b\xdf\xcbG\xa3\n\x836\xc0\x03\xf8\xc5*\xf9\xc8\\\xb9\x80YX>\xd3%\xb3\x18g\x03\xc5K?\x11\x87ܞ0[g\x84,R(ދ\x1a\x817ƫ\x96\xf6\x9f#\xb8R\xd8)\xbc\x1d\xb3\x04\xd18\xbf\xf14\x18?O\"\xadc\xb5\x1e\xa3\xea\xbd\x1a`q\xe60\x05\xeaNպB\x87\x1cV{\x87\xedV\xd6\xca\xd4\xcc-@H\xf7\xddߎ\xf3\x11\t\x9b\xf9W\xdf*9$\xe7\r\x8dBo8 !m\x15h\x92\f)ǪO\x01\xe2H\xc0\x9b\xde\xfb\x01I\x90\xdb\x1f?\v\x85L\x0f\xd4\x1a\\\x89\xf0\x86\xe5\x9bF\xc3\xd2)\xc3\n\x84\x1fT\x1eT\xb8+Ѡ_\xb1\n+ȃA\x90\xee\x94I\xaaNc>\vk\xa3\xb0V\xd6H\x7f\xc3\x0f}\x16\xfb\xca\r\xb2\xa4}\xb5\xa1h\xe6W\b%\xd3F\xf6\xba\xc0g\x19X\x9fH\xa98\xf6X\x9b\xe0\x12\x16\xb4Q9Z{\xc2\xf0I\xc8\x00\xc9\xc3a\xe0,E%\xfa5-\xa0FW\x8aq4\xe0\x14\x94L\xf2\n\x83\x0e\x9daҮ\xa3eLUؾ\xf6~\xaf\x87P>\xb4\xf2z3\x13La\xe9\xf6e\b\x83y\x895[ĵJ\xa3|\xfdx\xff\xf1\xaf\xcb\xc10\x10-\x1a\x8d\x13md\x0eO/\xf1\xf4Fa\xb8\xe7\xffe\x839\x00\xfa@x\v8e \xb4\x9e\x8b\x18_\x91GL\x81#a\xc1\xa06hQ\x86\x9cD\xc3L\x82Z\xfd\x82\xb9\x9b\x8dD/ѐ\x18\xb0\xa5j*N\x89k\x8bƁ\xc1\\\x15R\xfc\xd6ɶD8}\xb4b\x0e\xad\xf3\x8eh$\xab`˪\x06_\x00\x93|$\xb9f{0H߄F\xf6\xe4\xf9\x17\xec\x18Ǐޚ\xe4Z-\xa0tN\xdb\xc5|^\bצ\xe3\\\xd5u#\x85\xdb\xcf}f\x15\xab\xc6)c\xe7\x1c\xb7Xͭ(2f\xf2R8\xcc]cpδ\xc8\xfcF\xa4Oɳ\x9a\x7feb\x02\xb7\x83\xcfN\x14\x1d\x1e\x9fD/P\x0feU\xf2\x04\x16E\x85-\x1e\xb4@CDݻ\x7f.\xdfC\x8b$h*(\xe5\xb0t\xc2K\xab\x1fbS\xc85\x19>\xbd\xb76\xaa\xf62Qr\xad\x84t\xfe\x8f\xbc\x12(\x1d\xd8fU\vGf\xf0k\x83֑\xea\xc6b\xef|\xc9\x02+r(\x8a\x03|\xbc\xe0^\xc2\x1d\xab\xb1\xbac\x16\xffd]\x91VlFJx\x96\xb6\xfa\x85\xd8xq\xa0\xb77\xd1VQGT;\x8eoK\x8d9i\x96ȥW\xc5Z\xc4L\xb2V\x06\xd8d\xfd\x90\xa9t\b\xa0'\x99QƋΙ\x1d=oR\x82ZIJ\x17\xc8c\xbe\xb31QU\xc3D\xd5\x7f&9ҠVV8e\xf6\x87L96\x89\xa3ڡ'g2\xc7\xea\x9a\xed\xdd\xf97AHN\xbccg\xd2\x14\x8c\x82T\x0fT\xc9B\x91\x93M\xd4\x01\xf7\x8e֑\x9d[t\xe9\xcdʣ\x99MH8ԘЯ%\xc7\xdb^)U!\x1b\xb3\xa9\x15?\xb3\xe9G\x15\x03\x87\xc15\x1a\xf4\xf9?\x84Y\xad|0vL\xc86|\x84\x92\x1b\x9cJ\xeccE\xe1\xe6\x98j\x8e\xdb!\x9cHII\xc0\xaf\x1f\xef۴\xd3ZV\x84>\xc9,}~\x92fA\xcfZ`\xc5}\xa2>\xff\xed\xa4\x85\xd0s\xbf\x0e |\xecu\n\x18h\x819\x0e\xf2\x1e\bi\x1d2\x1e\a)\xdc\x18\x8cs/BL=\n\x92\x9eC~$\x95\x00\xa3\x18/8\xfc{\xf9߇\xf9\xbfT\xd8\a\xb0\x9c*!\x7fV\xc1\x1a\xa5{ѝW8Za\x90\xd3\xe9\x03g5\x93b\x8d\xd6͢44\xf6\xa7W?\xa7\xf9\x03\xf8^\x19\xc0'FE\xff\v\x10\x81\xf3.m\xb4V#l\xd8x'\x11v\u0095\x1e\xa8Vԛ[\x04\xabj\x84\x1dVU\x16J1\x0e;\xb6\a\xb5>\xf2\x9dVEd\x9a\f43\xeed9\x16y8\xed4\xd3\xfa\xa4}\x9e\xe7/\xbe^y\x96\xf7~\xb1\\\xffL&|a\xfe\tL\xf4\x8f:W0\xb1iVh$:\xf4dp\x95[\xe2!G\xed\xec\\m\xd1l\x05\xee\xe6;e6B\x16\x19\x19c\x16\xb4n\xe7\xbee3\xff\xca\xffs\xed\xc6}\x9f\xe5Sw\xef\x85|9\n\xe8\xebv~\r\x03m\x1d\xfd\xfc\xdcu\x94\x87e\xac\xec\xc62\xc9\xe7w\xa5\xc8\xcb\xf6TՋ\xb65\xe3!\x1c3\xb9\xffB\xbeC<7\x86\x10\xed\xb3\xd8p̘\xe4\xf4\x7f+\xac\xa3\xf1k\x88m\xc4'\x05\x97\x0f\xf7o\xbf\xa4G5\xe2\x9aHr\xe4\xb4\x10\x9e\xa7\xec\x80*\xab\x99\xce\xc2j\xe6T-\xf2\xd1j\xaa\x95\xef9)i-М\xa9\xfe\xde\r\x16\xb7U{\xa2\xea\xee\xd6\\Tv[ɴ-\x95\xbb\x7f{\x06Dz[\xd8b8\xe80\x16\x9d\xad,r\x89\x93\xb5\xe63\xf0,\xc5o\x89\xb0\x95DDK[L\x95*D\xce*\xb04\x16ѵ\"\xa78Rm\xc81\xca~3\xb1\aӇ\x80\x87\xe3\x01v\x88t\xb8\xba\x05\xab\x8c(\x84d\xd5!P\xfb\x13\xa3d5\xf3\x7f%L\xb4fZ\vY\\Di\xdb\xd6Z\xa2sB\x16\x89\xfa\xbe\xdfu?u\n8\xe9\x1e\xe7=\xff\xc3\b\b0\x83\xc0hO\xa4\xaa\r\xee\xb3Plj&\xa8R\xa4b0V\xd4+\x04\xa6uE\xe5\\( S!\xa9m\xd2\xe5J\xaeE\x11\x1b\xa6S\xa6dSUlU\xe1\x02\x9ci\x8e\x9dՒ^\xde\xef\x0f\x9e\xd1\xf8\x87\xde\xd2V\xddg:\x94\xe9]\r\xfa\x96\xd3͠l\xea)\x94\f6J\v\x96\x18'\x9f\x9c\xc4#\x9a\xb8\xbd\xbdĤ\x82ß\xe1 \x1c\x95S}\x86\x18/\xe2\xe9#\x9e\xacC\xd4H'\xf1K\xe3\x88\xc1_\x1b:J\r\x11f\xe9\x96\xcah\x8dV\xfcfLZ?\x04\x8f&\x0f\x01t<1t\xfa\xd1l\xa0\xe0Y\xdd(\xdf\x1f\xbf\xa4\x1f\x15n\xc1\"\xef!\xfb\xbb\xf6n\x8c\xce\x15Ww\xa4\xe8\xe8\xaa\x1d\xf2\xee\xea\xe0\x9av\xcd\xeb\xb1\x10\xdfG6<:\x89\xa8\xb1\xebmD;1\x87nK\xc8,ڠfI\x8b\x00\x7f\x17`}?\xf4k\x1b\xa4\t\v\x8dE\xeec\xeb\xe4\xe3Gs\x02g\x0e3z\xff\xba\x00\x92\xeeq\x85[\xb9\xfe\xe5\xcbU\r\xaf\xa9\x98)\x87\xac\xa3\xcd_\v\xb5\xf7\x81)\xca\x0e\xf2:\u00828\xe4\xfe\xa4\rJ\u009a\x89\n9tw\xce\x173\x9f\x00=\xad\xc1>'\xf95ZˊsA\xebǰ*4\xdc\xe2+\xc0V\xaaqG\xac\xf2k\x1b]뢜,\x15?\x87\xe4Aq\x0fC\x1e\xbfi\x9b\xa2I\xa8\xa5\x7f\xfbv\x11F\xdf\xcb<כ\xa45\xa9P\xd3A>\x1dk\xe0D\x0e{\xc0]b\xb4\xf5\xe0\xc4\xd4c\f\v\x89\xa9\xc9\xcf\x00\xfa\x93\xa1\x81\x9c\xaaiڹ\xa4\xcc\xee\x8e=1\xf7\xbdw\x97\x8b؎\xf8\xae\t\b]\xfb\xb9TU\x1b\x03\xfcݸl\xea\x15\x1aR\x85\xbf}\x1fW\xc4\xc0$\xefk.\xd5C\xe8$\xb4i8\x88\x8am\xb0\xd87\xf7^\xee\x14pau\xc5\xf6\xddf\xfc\xc1\x8d\\:}\x8bp\xf0\xab6VQ\xe69R\xb7\x9dnPw\xbfUH\x1fKOW\xfap\xa6\xda\xf7\xf3\xddo\x10>\xcf\x17Nԝ\xc3߄\\c ˁ\x84s\xc9\"\xfeF\xe5\xf2\x18?\xfc̟\x19ޓ\xecM\x06=rޓ\x1do\xba\xfa#ͪ\xbb\x06^\xc0\xef\x7f\xdc\xfc?\x00\x00\xff\xff\xbb:E#\n&\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xdc=[s\xdb8w\xef\xf9\x15\x98\xf4a\xdb\x19\xcbi\xa6\x97\xe9\xf8\xcd\xf5:\x8d\xfb}\xebx\xec4\xfb\f\x91G\">\x83\x00\x17\x00\xa5h\xdb\xfe\xf7\x0e\x0e.$%\x90\x84d˛-^2\xa6\x80\x03\xe0\xdc\xcf\xc1\x01\xb2X,\xdeц}\x03\xa5\x99\x14W\x846\f\xbe\x1b\x10\xf6/}\xf9\xfco\xfa\x92\xc9\x0f\x9b\x8f\uf799(\xaf\xc8M\xab\x8d\xac\x1fA\xcbV\x15\xf03\xac\x98`\x86I\xf1\xae\x06CKj\xe8\xd5;B\xa8\x10\xd2P\xfbY\xdb?\t)\xa40Jr\x0ej\xb1\x06q\xf9\xdc.a\xd92^\x82B\xe0a\xea\xcd?^~\xfc\xd7\xcb\x7fyG\x88\xa05\\\x11\x05\xdaH\x05\xfar\x03\x1c\x94\xbcd\xf2\x9dn\xa0\xb00\xd7J\xb6\xcd\x15\xe9~pc\xfc|n\xad\x8fn8~\xe1L\x9b\xbf\xf4\xbf\xfe\x95i\x83\xbf4\xbcU\x94w\x93\xe1G\xcdĺ\xe5T\xc5\xcf\xef\bхl\xe0\x8a\xdc\xdbi\x1aZ@\xf9\x8e\x10\xbft\x9cv\xe1W\xbd\xf9\xe8@\x14\x15\xd4ԭ\x87\x10ـ\xb8~\xb8\xfb\xf6OO\x83τ\x94\xa0\v\xc5\x1a\x83\b\xf8\x9fE\xfcN\xc2B\tӄ\x92o\xb8Q\xbb\x1aD<1\x155DA\xa3@\x830\x9a\x98\n\bm\x1a\xce\n\xc4;\x91\xab\x1e\xa40J\x93\x95\x92u\amI\x8b\xe7\xb6!F\x12J\fUk0\xe4/\xed\x12\x94\x00\x03\x9a\x14\xbc\xd5\x06\xd4e\x04\xd4(ـ2,`ٵ\x1e\xef\xf4\xbeNm\xcc6\x8b\v7\x8a\x94\x96\x89\xc0m\xc1\xe3\x13J\x8f>\"W\xc4TLw[\r\xdb#T\x10\xb9\xfc\x1b\x14\xe6r\x0f\xf4\x13(\v\x86\xe8J\xb6\xbc\xb4\xbc\xb7\x01e\x91Uȵ`\xbfG\xd8\xdan\xdcNʩ\x01m\b\x13\x06\x94\xa0\x9cl(o\xe1\x82PQ\xeeA\xae\xe9\x8e(\xb0s\x92V\xf4\xe0\xe1\x00\xbd\xbf\x8e_\x90xb%\xafHeL\xa3\xaf>|X3\x13$\xaa\x90u\xdd\nfv\x1fP8ز5R\xe9\x0f%l\x80\x7f\xd0l\xbd\xa0\xaa\xa8\x98\x81´\n>І-p#\x02\xa5\xea\xb2.\xff.\x12u0\xad\xd9Y\x1e\xd5F1\xb1\xee\xfd\x80\x02q\x04y\xac\xa88\xc6s\xa0\xdc\x16;*\xd8O\x16u\x8f\xb7O_\xfbLɴ'J\x8f7\xc7\xe8c\xb1\xc9\xc4\n\x94\x1b\x87\xacia\x82(\x1bɄ\xc1?\n\xce@\x18\xa2\xdbe͌e\x83\xdfZЖ\xdf\xe5>\xd8\x1b\xd4:d\t\xa4mJj\xa0\xdc\xefp'\xc8\r\xad\x81\xdfP\roL+K\x15\xbd\xb0DȢV_\x97\xeewv\xe8\xed\xfd\x104\xe2\bi\xbd\x16yj\xa0\x18H\x9a\x1d\xc6VA]\xac\xa4\x1a(\x19;d\x88\xa3\xb4\xf0\xdb洈U\x8b\xfb\xbf\xccq\x99m\xff\x1eG[~\xb3+k\x05\xfb\xad\x05T\xa6N\xfc\xe1P_\xa9\x9ej\x1f6\xcbF\xfb\xd4\x1dE\xb4m\xf0\xbd\xe0m\te\xd4\xeb\a\x1b\xcc\xd9\xc6\xed\x01\x144z\x94\t+D\xd6\xfaؽ\x88\xeeWT\xe0T\x01\x11\xd2$\xe01\xe1\xe0\x11&\x10\x03I\x9a`G\x03ubœ[&D\xb4\x9c\xd3%\x87+bT{\x88F7\x96*Ew#\xd8\n\x1e\xc0\x8b\x90\x15\x81xU\xc3Y\x81$\x8f\n\x05\xf1\xf5\xe7E\x15\xd3VQ\x86]>HΊ\xdd\f\xben\x93\x83\x82\xb4z\xd9\xf5;$K\xa8\xe8\x86I\x95\x12\x03\xa9\xb0kϞwjZZ-\xe9\x81\xec۸\xcc\r'\x91UI\xf9<\xc7\x10\x9fm\x9f\xce:\x90\x02\x1dʸ\x15Omo\xbb\x97@\xe0;\x14\xadI,\x93\x90\xb2E\xd3$\x15i\xa46\xe3t\x1fW]\xa4\xef\x1c\xa5~\x9c`\x9a\x83\x9d%Y\xdd5\xaf\x84\x03Q-\x0e\x06\nY\n\xb0ۨ-Q\xbb\xbeJ\xb6\xae\xef(RȒj(\x89\x14\xa33#\xbb\xb4\x1c\xb4\x9f\xabD\xce\xe8\xf4\xd0E\xb7\x7f\xf4x\b\xa7K\xe0D\x03\x87\xc2Hu\x88\xcc\x1c\x94\xba\x96\xa3XGP\x99ЦC\t\xe860\x01\x92XN\xdfV\xac\xa8\x9c\x87a\xd9\x13\xe1\x90R\x82\xb6\xda\x04]\xe6\xdd\xd8&\xc9\x1c\xf9\xfd$Sڣk3b\xb5\x0f/\xa5Q\xba\x96\xa1\x86\xbb\x96Dm\xa7{\x0ft\x8b\xffn\xe4\xe4\xb6\xff\x7f\"6\x18\x93\x13\x98vB\xfe\t\xba\x9f\xd9<=ʷ\x18ၾ$w+\x02ucv\x17\x84\x99\xf0uN\x12(\xe7\xbd9\xfeĴ9\x9e\xe93I\x93#\x13g\"L\x9c\xe2OH\x174\x19O\xdebd\xd3\xe4\xaf\xfdQ\x17\x84\xad\"\xd2\xcb\v\xb2b܀\xda\xc3\xfeI\xaa>P\xe65\x90\x91c\xf5\b\xe6\tLQ\xdd~\xb7.\x8e\xee\x92`\x99x\xd9\x1f\xec|\xe3\x10A\f\xcd\xf3\f\\\x82\xf12SPc\x1cN\xbe\"6\xbb/\xe8T_\xdf\xff|\x18+\xef\xb7\f\xce;\xd8Ȍйv\xbd\xb7\xa3\xfe\xfa|T\x10~A\x1f(\x06U.\xe7rA(y\x86\x9ds]\xa8 \x96>4tΘ^\x01&\x7f\x90Ϟa\x87`\xd2ٜÖ\xcb\r\xae=C\xc2\xf5O\xb5\x01\x0e\xed\x9a|X\xec\xf0d? \"0\x86\xcfe\x03\u05fc($r'閩KB\v\xb8?a\x9bY\xacҟ\xa3\x9f\xfaD\x0e\xf8I;ZZ\x89\xa9\x98\xcfij@\x99\xc9%\xa8k\xdf(ge\x9c\xc8\xc9ȝ\xb8 \xf7\xd2\xd8\x7f0@\xd3\xc8(?K\xd0\xf7\xd2\xe0\x97\xb3`\xd4-\xfc\x9c\xf8t3\xa0\xa0\t\xa7\xe5-\xc2\xfa9?g\xd3,\xb7E\xdc3M\ue10dW\x1cJ2\xa7\xc2\xf4\xae\x9b\xceMT\xb7\x1a\xd3uB\x8a\x05\xda\xcc\xe4L\x1e\xdfR\r\xd0\xfd\xe2I\xfd\x84_\xad\xb1p\xbf\xb8$3\xa7\x05\x94!\xb2\xc4\xec'5\xb0fE\xe6|5\xa85\x90ƪ\xf0<\x8e\xc8T\xac~7DZO\x9e\xf5\xee\xb7\xef\x8b\xe7\x98/XX\x93\xb3\xf0\x10\x8c\xac3p\xe0uw9\xbf\x9f\x85\x95ٌ^\x81\x13f\xbb\x8e$Gǻ\xe6 \xe5\x05\xe8@+\x8e.\xce,uiY\xe2\x11\x1a\xe5\x0fGX\x94#x\xe1X\xd5\xd0[\xbb3\xc15m\xacZ\xf8okiQ\x9a\xfe\x974\x94)}I\xae\xf1\xa4\x8c\xc3\xe07\x9f\x87\xeb\x81ɘ\xb2\xb1SY\xfe\xd9Pnm\xbfU\xe0\x82\x00w\x9e\x80\\\x1d\xf8E\x17d[I\xed\xcc\xf6\x8a\x01\xc7\xf3\x8a\xf7ϰ{\x7fa\xa7\x9f\x9d\xb2\xafd\xde߉\xf7·8P\x18\xd1ᐂ\xef\xc8{\xfc\xed\xfdK\\\xa9LN\xcd\xec6`њ6y\x1c*\x92\xc9\xfa\xae\r8\xa6\x9f\x9b\xef\x92\xf2\xdeɞ\xdam\x16\x8b6R\x9b\xcf\xe9\xbc\xe1\xc8z\x1e\u0088\xa1g\x9cȱ\xcdF\f>\x8f\x16\xf5\xbdu\"W\x06\x94\xcf%:\x1b\x10\xe2\x8f\x17Ff\xa9S\x99\xfebc2\x90\xc6\xfc\xaeE\xf0\f7\xb9\x83\x9b\x9c%\x1e\xe3\xb0Z\xbc\x1c\xe9\xed\xdf~\xef\xe53\xad\xe4ڿ\xfb\x1bym\x87\xba\x90uM\xf7O5\xb3\x96z\xe3F\x06\x9e\xf6\x80\x1c\xf5պEyε\xc8\x1d\x0f\xe1\xf9喙\x8a\tB\x83\xda\x00\xe5\x19\x8a\x92F\xa6rةVQM\x96\x00\"\xa6\xe8\x7f\x04W\xa2f\xe2\x0e' \x1f\xcf\xe0zDt\x9d\xd3ٽ\x894\x89\x94\x8f\x1f\x9c\xc9jdI\xb6\x15(\x180\xc6a\xde\x1d=U!M/eq\x84C\xda\xc8\xf2'MVLi\xd3_\x82&\xadΥ\xf5\x91\xe4\xb3\xeb\xfe\xcaj\x90\xad9'\x82o\xbbi\x06g\xcd5\xfd\xce\xea\xb6&\xb4\x96\xad3\xe6\x86\xd5\xf1TףwK\x99\x89\xc7V\x98\xbf1Ғ\xa0\xe1`\x80,a\x95>\xefM\xb5B\n\xcdJP\xa1J\xc1\x91\x8dI+\x98+\xcax\x9b:%J\xb5c#`q\xab\xd4I\x01\xf0\x177\xb2\x97w\xac\xe4v\x88\xa0̽\xe3A\x1a\x10\xb6\"\xcc\x10\x10\x85\xc58(\xa7\x92q\n\x8f\fD\r\xcb\xd5sy\n\xdc6\x10m\x9d\x87\x80\x05\n$\x13\x93)\xb7~\xf7O\x94\xf1s\x90\xcdr\xde'\xa9\x1e\x81\x96\xa7\xe4h~\xed\r' t\xab\xf0\xf0\xdf\xe9\x8e-\xe3yk\xb6\x94#\x9c\xb6\xa2\xa8\x00\x95\x90\x18\xea\x06\a\x9e\tm\x80\xe6\xf2\x82\xf5\x8aZ!\x98X\xe7\xd1.;\x11\xda5\x87\ua954\x1c\xe8\xf8)d\xd7,\xae\xdf@\x13\xfd\xdaM\xf3BM\xd4\x11\xc1\x1d\x9b#\x1d\xb2)j\x95\x16\xa1\xc6@\xdd8\x91\x93D\xb5\xa2o]Π\x88\x8e\t\xc3\xfd*^3\xbef\x82e\xd0v@\xd7;\xc1L\xdfy\xb4 \xce\xea<\xda\t\xa2;pJ\x86\xedn\x00\xc0\nh\x88Cp\xed\x91k\x8ep$\x97@hYB\xe9r\x97\xd6\x15\xf1a\x89+|\x1b)nH\xee\xeexO0\x8b\xb2\xa1\r\x82N\xccê\r,Z\xf1,\xe4V,0\x18\xd7G\xeb\x90\x13\xb3T/\x9dޜ\xac\x8c\xe6\xf5K\xbe\x9a\x9e\xd3BC~\xcd\xe7\xa9\xe0?\x9dA\xcbd\xf3\xcdQ\t\x8f).\x98\xd3k\xae\x00{\xe4\xc7\xd9UL\xcd?1\xd8\x1fJ߸b\xe9\x17\x95\xc5ݥA\xf5\x9c\xc2m\x05\xa6\x02\x15J\xb3\x17X\x92^N\x9e\x90v\xc1K\xac\x93\xb3L\x15\\dW\xfe\xb9W9\x87\xd1M\xcb\xf9\x85\xe5m\xda\xf2d8l$\x8a\xd8!geՏ\xa5=\x86\x9c\xea\x8bl<\xf6+-\x86\xf5\x85\xb1\n\"\x14\x18\xca0\xb3\xa7qj\xbfXX\xda;\xdf\x1f\x96S`\xfe/,\xff\x0f/=̨\x94\xc8Gcn\x95fDb\x02V\x82\xc1zh\xec\xea+|?_\xe8\xfbc\xe1\xd4@\xfd\xa5\xf1\x123\xea\xc2f\xa05\x01g\xaf\xde\x04\xadA\xab\x9d+\x10\xed\x80\xcf\x19\xda\xf1ׅ\xbb\x05\x11\xc0\xa4\xf8\xf5k\x05A|}\xf5>\xd3\xe4\x9fI%\xdbDU\xdf\x04\xcaf\xaa;\xe67<(\xf4\xf0\a\n`\xe8\xe6\xe3\xe5\xf0\x17#}\xd9\af\xd1\x12\x800(\xea2\xb3L\x94l\xc3ʖ\xf2 \xb5\xdd\x1d\x02\xc7@\x1d\x9f%\xa0IE\x04\xe3\x8e\x01\xc3\xf8\x01Ñ/\x8d;\x969Z\xc5M\xfb\xa2y\xd5!'ׄ\fk>F\xac\xe1\xb1\xc7\x17\xafR\x05\xfb\x87\xd4z\x1c_\xe1\x91\x13I\xccTs\x9cPÑY,\xf6\xe2\xf3\x96\x9c*\x8dcb\xee\xb3Ud\xbc~\x1dF\x16~\xe6k.\x8e\xc1\xce\xd9\xeb+ް\xaa\xe2mj)2+(^\xaf\x142/\xfa<\xa9\x14`>`\x19\xaf\x82\x98\xad}xQ@sҖfk\x1a\x8e\xa9d\x98\xa5N\x9e\x98\xbdY\xad\u009bU(\xbcm]\xc2$\x17M\xfexL\xe5A\x8c\x93~\xa1M\xc3\xc4\xfa\x90)rYg\x92m\xe6Y\xe6~o!\x03\x9e\xe9\x873]t8\x12\xfa\xba\xeb҉H2\xa4-\x990\xf2\x92\\\x8b\x9d\x87\x9b\x80\xd3\v\x1f\x854\a\x17\xd9첶\x8c\xf3\xfem-\x04;\r\xcaߙԴv\xab\x1a\xf3\xf6\x93t\x95j\xe0\x94\x9f\x148~ك\xd1ώ\xbe\xa5\xe7_\xb7ܰ\x86\x83\xf5\xe86\xacL\xde!3\x15\xec\"\x92\xff&\xf1\x86\xd4r\x87\x90\xbe]\xf4\x9eQ\xec\x9eq\x926\xbf\xc9\x13\xb6\x97Q\xcc~\\\x11{\x06\xcdrE\xf1\r\x8b\xd5߰H\xfd\xad\x8b\xd3g8k\xe6\xe7\xe3\x8a\xd0O>\x81\tG\xfd\xf7\xb2\x84\a\xa9\xcc\\p\xf2\xb0\xdf?q\x92\xda\v\xd8$/\x89\b]\x13\xbb\xc4\x10Ç\x17\xa7m*}\xe8\x19\xdc\xe9_di\xd76w\xc6\xf2\xb8\xd7\xfd\xe0\xae\xf2\n\x14\b\xf7\xcc\xc7\x7f>}\xb9\x8f\xf0S>\xaf\xf7\x8c\xf7\x9e\x97p\x1eL\xe9\x91\xe3\x8f\xe6|1\x93\xc3\x16\xfa\x00\xaf|.B\x1b\xf6\x1f\xf8\xaa\xdb\v\xd2A\xd7\x0fw\b#\xf8i\xf8L\\\xac\xa2\x88'\x96K\xb0\x16+\xa2jT,\xeeV\x03\x88Ê\xdf\xfe3JP\xba'\xb3\x82\xc5d\xa1\xc6\xcb\n\xdeÝ[\xc7\xd8,\x9f\xac\xd3(vD:\x8e\xac\x98*\x17\rUf\x87l\xa3/\x06k\bff*\x9d3\xaaX\x0f\x9f\x01K\xa27\xbc\xfe\x85g\x91\xbbfxڻ\x8f\xbbS\xd61~\xffd\xf6\xe6\xc9+\xaec\xdcb/\x10S\x89\xcf\xc9\x02\x93WK\x93yM\xf4\xf0\xed\xa4\xb4\xcbc\x1c=\xad\xe7l\x14\x1dRM\t0v<\xaa:-h\xa3\xabēK/\xd3u\xf8\x1a\x99\xa1\xa6}\xc9&\x1d\x80\xc1>YQ\xf5\xb4\xd5\x16\x82>\v\xdbFi\xc5a)\xddnm\xb3\xab{a\xfc\xa2\x97)x\x9b#\xe1\xcc\xe7\\N~\xc8šgD\xfd`\xf6˪\xb6CL\x9dp\x18<\xeb\xdae\x14\x19O;\xb1\x99π\xe4\x19\x8c\x13\x9e\xfe@|\xe5\xe2\x8a$_\x04\xc9|\xf5\xe3\x0fE\xf4\x84V\xd3E\x05e\xcb\xe1\xd47\xff\x9ez\xe3\xe7_\xfd\v\xb3e\xbc\xfbg\x91\xdd3\xd0\xd6g\x1e\xbe/\xe8)\xe1!\xf7)9\xe6\xf0ap\xe0\x9e\x17+\xdcK\x94E\x01Z\xafZ\x1e\xaa\x94\n\x05\xd4@\x19\xba3\x1dW|T\x9dM\xdbpIKP7R\xacX\xe2\x84d\x80\xd6\xff\x1at\xde\xe3\xd9\x02?\xb6\xaa{\xdaq\xf2Y\xbc\x17i\xae\x86*\xca9\xf0O\x8c\x83\xfeYn\x85]W\x86@>\xa4\xc6\xf5\xeee\x15\xad\xb2f}GD[/\xad\x93\vƌ\a\x8b+\xa9\xa6+\xa4\x1dޙ0\xb0\x86T|\xbdU\xcc\xc0SC\x95\x06\\Q\xc6\x0e~\xdd\x1b\xe2\xa2\xcf\x15\xa7kW\nW\xb2\x82\x1a\x88\x06\x18g\x18[>\x8e\xd7\b\x8b\xef\xb02I\x8e$\xbd\xb2\x85z\xecJƨX\x8f=/\x9a0\xd5\xc9\aF\x9dE.hc\xf0\x02\f\xd2\x11\x89h<\f|\xb4w\xef\x8d\xd1\x01\xd8qN\xf3e̾`N\x1bZ'\xa2\x84y\xbdss\b\x06\x9f\x05Ve\xaf\xee\xae\xff\xc0b,\xb0#[\xaac1u\xd2\xf7\xee`;0\xe8\xaa[\xd0P\x12\u0600 V\x14)\xe3PNq\xeaWL$\xab\r\xa8\x9ft\x84\x83\x95\x80\x96ş\fU&.\xfdЏYIUSsEJj`aG\x9f溥\x9fIU\xea\xc4\xe3@\xbc\xd9\xe6ţ\b\xd7n\xac\xf5s\xf7\xd1jК\xaeC\x10\xba\x05\x05d\r\xc2\xe2=\xe6\x16\x93\x1eS\xb8\xd2\xe7\x8dE,-\xb5(\xa4\x85i\xa9\x9f\xc0\xb9p\xf1\xf44\xbcO\x8cQ\xeczTE\xa7U\x85\xbf<\xf8\bT\xef?w}\x80\x8bO\xfd\xbe>I\xecv\xec\xceF\xa8+\xf0\xc4\a\x8f\r\x8b\x91uJ\xa6\x8dę\x8f2'\x95\x94\xcfYn\xf6\xe7رK'1\xe1X\t\xafL.ekz~\x8eGxb\x99\xf8\xfc\xe7+\xdb\x17\x84y\xed.P\x8d\xe5V\xf3<\xbd\xcf\x03H1\xbc\x95\x86\xf2`d,_\xc6\x0e\xd5\xc4\x03\x02O\xe1\xf1d\xcew\x17\xfb\x90\xf7^e\xef`W\xddS\x9e^\x13t\xd7\xc7\xc7Ҫ>\xeb\x97\x04\x12_\x01\xed|\x92\xb17\x17\xe7\xec\x1fB\xfd\x84\x8b\xca\xc0\xf1\xe7\xae\xf7\x18\x1e\xdd2\x9d\xc3\f\"\x1di\x12\f>L\x15%ㄥOx\xa9ME\xf5\x9c{\xfa`\xfbD\xb7\xa3g\xae\xa2\x13\xfa8\"\x95\xe9{\xae\vr\x0f\xdb\xc4W\x87,<\xfdB\xa9Jt\xb9\x13\x0fJ\xae\x15\xe8C\xa6[\xe0}F&֟\xa4z\xe0횉/\xe3\x95\xdfS\x9d\x1f\xa82\xcc2\xad[Ob\xecM\xb0q\x89\xdf\xe6G\x8f\xff\xc0\x04\xe5\xec\xf7\x94.\xef\xff87Ä\xbek<\xf2N\xb1P\x01\xf1s\n\xd0k\xe8\x9ft\xcf\xfc\x84y/ɽL\x8a\xb1? fC\xa0L\x93%h\xb3\x80\xd5J*\xe3\xf2\xf7\x8b\x05a\xab\xe0 Y\r\x81q\xa2{͞\xb0T\xe2=\x1e\xbd\x05\x87e\xe5S\x89\n\xad\x0e\x86\x9c5ݹ\x8c$-\n\x1b\x13\xc0\amh*6y\x91\x9e\xc6P\xd5\xcbJ\x8e\n\xb9\xeb\xf7\x8f9\xbe\xa8>\x10\x9cC\x1d^gw\x06\x9d\x8f\x9di\r^\xcb \xdab\xef\x14eB\x9c\x1a\xbb\x1b\x0f\xbb\xf3L\xcd\xd7\beL=\xfa\xfd\r\x1e\xe2\xf6\a\xac\xbe\x93%[QQ\xb1\x1e\xbd\xd0V)ٮ\xab\xc0\x9bc\x0e\x11)[\x8c\x9c\x1bT\x05:\xfc\xc7!\xa6U\xa2wh\xe7k,ƴt\\\uee0f\xf2\x02E\xad\xba\x8b-\x9d\xaa\x9a\xb0\xf9\xd9Y\xc2\x11\x88\xb3\xb6?\x01\x91\xea\x9d(&\xaf\xe0\xf8@\x9bM\xdc՝\xc2P\x12\tQ\x1b\xbf\x1a\x12\"\xc41$\xf4}\x89.\xe2\xf9a02棜\x88\x8ei'\x06\xb78\rj~\xd3}'h\xe8\xee\x1c\x87\x0e=\b\xfeNJ\xbb\r \x1c\x13\xf9\xe2\xdc\xe9\xb8\xf7ǍX7\xd1ۺ=9v\xfd\xb6\ac\xef\n\xa4\x8db\xbbiB\xbc\xf9\xf7l\x95\x92\x17\xf7\xbf3-9\xfc\xc3\xc1\xafo|\x95qK\x95`b}\x12F~\xf5c\x13\xf1\xbc\a{Έ>\xac\xfc\xd5b\xfa\xa4Y:\xf8\x88\f^\xf6\xf0\xecg\xf2_\xfe/\x00\x00\xff\xffP\a\xb5\x16Cm\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec=]s\x1c)\x92\xef\xfa\x15\x84\xeea?B\xdd^\xc7}ą\xde|\xb2gO\xb1\x1e[ai\xf4\xbctU\xb6\x9aQ\x15\xd4\x00\xd5r\xdf\xde\xfe\xf7\x8dL\xa0\xbe\xba\xe8\xa2Z-ygǼت\x86$\xc9L\xf2\x03\x12X,\x16g\xbc\x12\xf7\xa0\x8dP\xf2\x92\xf1J\xc0W\v\x12\xff2\xcb\xc7\xff6K\xa1\xdelߞ=\n\x99_\xb2\xab\xdaXU~\x01\xa3j\x9d\xc1{X\v)\xacP\xf2\xac\x04\xcbsn\xf9\xe5\x19c\\Je9~6\xf8'c\x99\x92V\xab\xa2\x00\xbdx\x00\xb9|\xacW\xb0\xaaE\x91\x83&\xe0\xa1\xebퟖo\xffk\xf9\x9fg\x8cI^\xc2%3\xd9\x06\xf2\xba\x00\xb3\xdcB\x01Z-\x85:3\x15d\b\xf4A\xab\xba\xbad\xed\x0f\xae\x91\xef\xd0!{\xeb\xdbӧB\x18\xfb\x97\xde\xe7\x8f\xc2X\xfa\xa9*j͋N\x7f\xf4\xd5\b\xf9P\x17\\\xb7\xdf\xcf\x183\x99\xaa\xe0\x92}®*\x9eA~Ƙǟ\xba^0\x9e\xe7D\x11^\xdch!-\xe8+U\xd4e\xa0Ă\xe5`2-*K#\xbe\xb5\xdcֆ\xa95\xb3\x1b\xe8\xf6\x83\xe5g\xa3\xe4\r\xb7\x9bK\xb64ToYm\xb8\t\xbf:\x129\x00\xfe\x93\xdd!n\xc6j!\x1f\xc6z{Ǯ\xb4\x92\f\xbeV\x1a\f\xa2\xccrb\xa0|`O\x1b\x90\xcc*\xa6kI\xa8\xfc\x0f\xcf\x1e\xebj\x04\x91\n\xb2\xe5\x00O\x8fI\xff\xe3\x14.w\x1b`\x057\x96YQ\x02\xe3\xbeC\xf6\xc4\r\xe1\xb0V\x9aٍ0\xd34A =l\x1d:\x1f\x87\x9f\x1dB9\xb7\xe0\xd1\xe9\x80\n»\xcc4\x90\xdcމ\x12\x8c\xe5e\x1f\xe6\xbb\aH\x00F$\xaaxmH8\xda\xd67\xddO\x0e\xc0J\xa9\x02\xb8\x80vX4\xb6\nu%\xa0\x80\xe6\f\xddN\x8d\x16FH\xb6\xae\xd1#]2\xd4\x12Q\x19\x11\xd2X\xe0\x11a>\x01\xef\xe0kV\xd49\xe4WEm,\xe8\xdbLU\x90\x87E\xa6Q͜\xca\xc3\x0f\a!\xfb\xf8\xa5\x10\x19 \x1f2WiA\x8b<1\xd1nC\x99]\x05n\xcd\tY\xed\x87\xd0\xc6(\x93\xbaŀņ\xe7\x7f<\xbf \t\xe8\xf7\xde\xef\xc70\xae\xa1!\xd3,\xddL\x16\x7f\xbc\x85\xb0PF\xa8;\xa9\xa3f\xf0\x9dk\xcdw\a\xb8\xde,\xa6\xbd\x00\xdfc\xb0\a\x9c\x97\xa1\xda7\xe2\xfd\xb0\xff\xdf\"\xf7O\xcboC\x8b\xce\\H\xe4s!\x8c\xed\xb1ٸU,$\xebX\b\xe9\t$\x1dLT\x93S\\\xfd'!\xe6I\xe7Nl\xb24\xb2\xe9'\xc0\xbf\x14%7J=\xa6P\xef\x7f\xb1^\xbb\x84\xc52\xda\x18a+\xd8\xf0\xadP\xda\f\x97I\xe1+d\xb5\x8dj\x16nY.\xd6k\xd0\b\x8b\x96\xf9\x9b]\x81C\xc4:\x1c\xbe\xb0\x8eʊV\x18\x8c\xabe:\xb2\x94\xa8\x11\x1b\n\x05\xa8Q\xa8\xce\xc1\xc1Ђ\x1c\x88\\lE^\xf3\x82|\t.37>\xde\xe0\x17\xd3j\x13\x02\xb1\x87\x7fT\xaa]q\x0eM\x18$2\xb1\xb7\xea\xa5$\xa0\x8f_bl\xb4_5N\x89\xb0\x94p\xb0od\xa6\xae\v0\xbe\xbb\x9c\xdc\xe4V']\xb4\xccrk\f\x05_A\xc1\f\x14\x90Y\xa5\xe3\x14J\x91\x03WR\x95n\x84\xb8#Z\xb6\x1fm\xb5\x83\x99\x00\xcb(\xc4݈l\xe3\xdcW\x144\x82\xc5r\x05\x86VExU\x15\x11\xd3ՖI\xe1\xf0\x9dM鍶$h\x90!ܘ.iK\xa2~n\xcb(\xd9۹٧\xfa\xf8:\xff(\xbe\xbf%\xa2\a\xabs\xa4\xb0Oh\x12F\xfb\x05\xc9\xf3!Jz\xa4\xb8\x00\xb3\xec\xac\xce\t\x1b\xbe\xa60\xb4\xe7?\xeem\xa5\xec\x11\xe5\xd7Ż\xe3&\xcc\f\xd6MΩ\x97e\\\xd3Ϳ\b\xdf\xc8d\xddz\x8b5\x8bg\x1f\xbb-/hW\xc03$\xbf`kQX \xa7j\nQ6\x83s\xa7$P\xaa\x05f\xb4Il\xb3͇f\xef(\xa1ŀVC\x00\xceA\x0fQ\x0e\xf1 \x01$k\\\v\xda4\x15\x1aJڌ\xa5H\xb2\xfb\x85\\\xc1w\x9f\xde\xc7c\xcfnI\x94ԽA%LZW\xde\r\x1c\xa3.\xae>T\t\xbf\x90\xbf\xd6\x04\x82n\x13\xfe\x82q\xf6\b;\xe7bqɐo)\x8b\xff|\xf8*\fv,s\xf6^\x81\xf9\xa4,}yQ*\xbbA\xbc\x06\x8d]O4A\xa5\xb3$H\xc4n\U00088ce5(\xa8\r?\x84a\xd7\x12C2G\xa2\x19\xddQ\xae\x90\xeb\xd2uVֆ\xb6Z\xa5\x92\v\xb7,6֛\xe7\x81\xd2=\x16\x9c\xa4c\xdf\xe9\x1d\x1a#\xf7\x8b\xcbZ*x\x06yآ\xa3t\x1an\xe1Ad3\xfa,A?\x00\xab\xd0,\xa4K\xcb\fE\xedG6_\xbc\xd2=\x87n\xf9\xbax\xacW\xa0%X0\v4k\v\x0fŪ2\x91.\xde&\x8c䜌\x95\x05\xce\xf5ĚAZ\x92\xaaG2r\x0eWO%\xd63\xc9D^\x04\xb9]IR\xd0Ml\x9dg\xbdf\xca\xcd1*\xa63\x16\xe7\x02\x94\x9c\xb6\xd6\xfe\x86\x96\x9ef\xe3\xdfYŅ6K\xf6\x8e2{\v\xe8\xfd\xe6\x17&;`\x12\xbb\xadh\x95\xfd\x97Zly\x81\xfe\a\x1a\bɠpވZ\xef\xf9j\x17\xeci\xa3\x8cs\x1b\x9aM\xbb\xf3Gع\x1d\xe5\xa4n\xbb\n\xeb\xfcZ\x9e;_fO\xf14\x8e\x8f\x92Ŏ\x9d\xd3o\xe7\xcfu\xeffH\xf4\x8c\xaa=Q.y\x95.ɔ7;'\xd0\xc0`=8DظI \xc5\x00a\x8a\x02ɢ\\)\x13I\x16\x89\xa0\x95 \xe87\xcaX\xb7\x0e\xd9\xf3\xf7G\x17*UX\x9cd|mA3c\x95\x0e)\x99\xa8\xf8S\x96\xe2\xbb\xe5n\x03\x06\xfc>\x94_\xf4t\x801\x8a=ou\x83\xb3*\xe7n/\x8c:\xe2\x19yOԶ\xd2*\x03\x13͋hK\xa2m\xeaQp\x9f\x0eͺ.w\xd1\xdf:Ik\xa7,J\x872ϑG\xd2\x1d\x11\x19}\xf8\xdaY\xa2F\xed\x82\x7f\xa7H\xeb182:\xafQ\x96|\x98\x0e\x9c\x8c\xee\x95k\x1d\xe6\x98\a\xe6\xc2-\xfdP\x93Ι\xe3u4\xa2\xfc\xcf\xe6ڔB^SG\xec\xed\v\xbaC^\x8b\xc7ң\xc6\xca\xf1N\xfaU\xe8\xac\xe5^\xf3\xc1\xe7\xd4)\xda\xf8\xd1\xd0c\xee\xfe\x9e\by\xd7R\xd9\xce2\xceL'\xbaR\xf9\xef\f[\vml\x17\rs \xb1j\x14\xd4\x11\xa1\xa7\xfc\xa0\xf5ё\xe7g\u05fa\xb3\xa0\xb8QO>qzN\xbc\x1dH\xba\xe1[\xf0\x99\xab 3UKZ\nC=\x80\xdd̀\xe8X\xe3\xac@\xa2\xbd\xeb4\x96u\x99N\x90\x05I\x92\x90\x93\xebf\xdd&?p\x91\xb6nŎc\xab=\x94\xc39V\x8e\x9fG!\xc1\xb3\x9bN_\U000af8acK\xc6K\xe4!\xb9\x1d\xa2\x84&\xa3ޱ\xbbI\xfb\xc4\x16d\xb4\xac\xc2YV\x15`\xc1\xa7m\xce\xc0#S҈\x1c\x1a\xd3\xefE@I\xc6ٚ\x8b\xa2\xd63\xb4\xeal\x92\xcf\r¼69}d\x95\x8eȂH\x94\xb8\xce>\xc3\v\x9e\xd6\xf8\x95\x9e\xe7Ǧ8\x8c\x1a\xe6\xfb\x8b\x95\x16\xca\x1d\x068\xbd\xcb\xe8ӎ\xb9\xdc}\xf7\x19\xbf\xfb\x8c\xdf}\xc69\x1d}\xf7\x19'\xcaw\x9f\xf1\xbb\xcfx\xb8|\xf7\x19S\xcaw\x9fq&\"\xdf\xcagL\xc1pAk\x9c\a*$a\x95\x98\n1\x85\xf6D_>\xe9ǟ\xd58I.\xf3\xf58ȑC<\x91\xe3\x171\xaf\xa35^Mr3\xce\xc00w\xdc)\xca\x04\x87\xf9\x04\xa7g\x02\x02\xa7?=s}\x10\xf2\tO\xcf\xf8!\xa4E\x18G\x9d\x9d\tD\x9a\x7fz\xe2\xc2'\x11\x95\xc0\xc3V\x8aK\xff\x88\x8d1&I\tx|\xe3\xe4\xf7\xbd\x8c\xc9\x17\x90\xa5W9\x913K\x9eFY\x7f\xfe\xc7\xf3_\a\x8bN˔(\x1b\xf6i\xeb\xd4xL?b,\xdfM\x8d\xecg\xa9\xfez\xa6\xc2Ie?\xf5DMC\xe4\b\xbc\xbeX\x0f\xa8\xfck\xd27\x16\xcaϕ\xb7\x96'8a\x7f=\x02/\xe9\x8c=7;\x99m\xb4\x92\xaa6~M\ba\xbd\xcbܽ\x03\x01dL\xd8G5\xc8\x7f\xb0\x8d\xaa#\xa76&H\x9b\x90E\x9bF\x90^R\xadO\x8c\x00˷o\x97\xfd_\xac\xf2)\xb6\xecI\xd8M\x04\x18\xddG\xc1\xf3\x1c\xe3\x82\u0381\x1e\xaf\a\xc2UIC\xa1\x8c\x00S\x9aIQ8\x89\r\x10z\xf2\xca>Wnu\xf0h\xbfiz\r+=\x11wn\xfam\x93-9\xed\xbe?#\xe9\xf6\xa4G\xa3\xbeYZ\xedqɴ\xa9+\x94\t\x89\xb3\xe9\xe9\xb2)lu%=I69BNM\x88\x9d\xbb\x02\xf1\xa2ɯ/\x93\xf2\x9aL\xb3\xb4\xf4ֹ\x14{\x95T\xd6WN`}\xbd\xb4\xd5\x19ɪ\xa7?\xf5\x92\xbe\x96~tveڲ\xcc\xe1\x84Ӥ4Ӥ\xa5\x9b\x94\x01\x1f5Ԥ\xf4ѹI\xa3I\x9cL\x9f\xae\xaf\x9a\x16\xfa\xaaɠ\xaf\x9f\x02:)m\x93\x15\xe6&y\x8e_r\x18ʴ\x03P|\v\xe1|.\x99\x94\xee\xb9\xe6ϊ;?\x0f`\xa1\xb0\x047\xf5\x15〲.\xac\xa8\x8a\xf6>\xb6X\xc0\xb9\x81]sY\xd1ϊ\x8e\xc8\xfb\x9b\xba>\x7fi$~9\x88j\xb8aOP\x14\x8c\xc7\xe6\xe6\x1e\x152w\x0fh\xa6\x16\x80\xb6\x11g\xb9\xbf\x8c\xc9_\x1ez\xe1\xa6\v\xdd\x06@\x16\xb6\x8c-\xf5qy\xf8\xa6\xaf\x83\x06,U\x8f\xedy\xe6.ޠo\xbfԠw\x8c\xee\x1dk|\xb3\xf6P\xa9\x9f\xe8\x06\x03Ӡ~\xbc:<\xb4g\xb2\x17\xe0\xb4ꁽ\x93\xce#\x18\xe2DmP\xef\xb4\x01\x1d*U\x8cӢ\xfdD@H\xd5@\x884Mq\xfe眲|\x89\xf0\xee\x14\x01^\x92\a4\xcf{\xfd\x86\xa7'\x8f=5\x99\x9e\x8c\x92tJ\xf2%½9\x01\xdf,\x7f5\xfd\x14\xe4\xfc\x8d\xe7\x17>\xf5\xf8R\xa7\x1dgP/\xf5t\xe3|ڽ\xd2i\xc6W?\xc5\xf8\x9a\xa7\x17g\x9dZLNϚ\x95q0'\xb5\xea\x19\xc7\xed\xd2r\t\xa6O!&\x9e>L\xcc4H\x1b\xfc\x91\xc3N<]8\xffTa\"\x7f\xe7L\xe9W>=\xf8ʧ\x06\xbf\xc5i\xc1\x04\tL\xa82\xffT\u0cf7\xa4\x94\xceAOn\xfb͑\xdaIyM\x8d\xe5\xfa\x88\r\xf6\xb5\xc2m\xb2X\xab\x17\x03\x90Y\xf2\x17\xf9ӣ\r\x87\xb6\xc1Q2;\x1eQo_\xb2u\xd7\xfa\x0e\xb1\x7f\xcd\xc1m]\x1a\xa88\x1a\x00\n\xdc(5+\xea*|\xe0\xd9f\xd0Æ\x1b\xb6V\xba䖝7\x9b\xc5o\\\a\xf8\xf7\xf9\x92\xb1\x1fT\x93\xabӽ/͈\xb2*v\x18\x89\xb1\xf3n\x83\xe7IIT:C\xcf7\xaa\x10Y\xc4\xe7\x1c\xbdW\xcf5ػl\x88n\xfe\xcb:\xd9\"\xb1\xc0\a\x9b\x8bp\xebb\xffJfw\x9f\xfb\x91k%\xbc\x12\x7f\xa6'\x95N\xb0\xea\xf6\xee\xe6\x9a`\x051\xa2\xb7\x9a\x9a\x04ņ\xe5+@\x97\xa1\x1d\xfb!}r\xbd\xeeA\xed\xe7\bw\x1f\xab\x80ܽL\x12\xdc\x16\xaf\x9a3\x85Z\xeb\xe6\xda\xe1r\xa8'\x94/.wL\xf9\xa7'\x84\xce\x17\x15\xd7v璉.zx\x04\xbb>\xb5jv\xd0Z\xed\xbf\xbc\xd2-=\xb2\x87GWh'{W\xf5\x93\a\x86\xf4|\x0eN\x87OUO\x9e\xa7~\x01\x9c\x0e\xbbP\v\xa2b\xe4\xa7h\x06\xe4\xc9W,\x8d\xbf\xa1\xffG\xb5\x85\xf7ѕ\xcb\xfe\xeb+\x83&#\xa9\x89\x01*]2\x1f\xa1`\x9b\x8fHw|?O\xed\xc5s\r\x03*\xfe\x8e\xf0\xe7,N\xde\xf6A\x8d?HB7\xa8\x87Nc^\x15=\xf5\xb4c7\xf7\x14\xb76\xaa\xd4O}\x1f\xb7\x86\xe5ɐ`\x10\x81%\xe4\xc17ZNEF\xab4\x7f\x80\x8fʽ\xad\x93\"&\xfd\x16\xbd\x97\x97\xbc\xe7\x16\xf2\xb5\xfd$\x8c)z?\xb6!\xc0\xf6|\xc6\xdeE\xff\x88\xed\x91O\x19X[\xba\x91ғ&\xef\xfd\xeb$\xa8\x8f\r \v\x02\x05\x1c\xb4\x15\xfew\xa3\x9e\xe8\x02\xfc\xf8\x1asx@\xa4\xf3\x86\x19\xd0A\x11J\xe1=j\x98uU(\x9e\x83\xbe\xa2GT\x12F\xfcS\xaf\xc1\xc0\x1d\xe8?\xc5\xe2\xedfd<\xa1\xe7\x17̒A\x8f\xae(\xa0\xf8A\x14`\x1c≦\xe1f\xbfec)\xear\xe5<\xd55\xfe\xd8tr\xc02\xbb\xa1\xd2\x06C\x05\x1a\xfdD\xb7\x15Q\x9b \xf9\x87\x89\xc1\x1a>\ni\xe1\x01\xc6c\xe8\t\x9b\xe0\xdeh \a (0\x8a\xf8\xfe\x12[y\xec\x11\xe4>\xdez \x03\xcdbdL\x8e\x95w\xabn\xee\xaf\f\xabeN\x1b\x00\xf7\x7f\xbe=J~\xb7\xbd\xf7e\x82NHQ\xef\xf7\xe3-;!BG;\x91O\x1fW\xe21X\xdc\x18\x95\t\x8a*\x9e\x84\xf5\xd79\xbe\xdc\x1d\xe2\x87\x02\xc4\x03\xd2Q\x1b\xf8\xfc$A\x7f\t\x16\xc8\\\xcbػ-\xd3\xda\xef\xa7=h\xd1\xf7Z\xac¾G`\f\x000\x15\xf6\xb9\x8c{\t(l\xaf\t\xd3H\x1c\xc4>\x01\xdcyG\xc8ik\x85\xb4\xe3\x9c!n\x9bVt\xd8tDCN\x8b\xed\xfd\x00\xc6 \x93\x9d\x1e}j\xaa\xb8Ӧ\x86\xfd^\x8cy\xa3\xb4c\x96\xe1@\xff\xb0\xf7kT\x83\x1f\xd4\xde1\xcd=\xaaF\xf6>\xd2CxyGr\xbc\x97\xde\xfdR\xaf\xda\a\x15\xd8\xdf\xfe~\xf6\x8f\x00\x00\x00\xff\xff)\x00\x87w>{\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcV\xcfo+5\x10\xbe\xe7\xaf\x18\x89+\xbb\xa1B \x94\x1b*\x1c*\xe0\xa9j\x9ezw\xbc\x93d\xa8\xd7^f\xc6)A\xfc\xf1\xc8\xf6n\x9b\xee:\xb4\x8f\x03\xbe\xad\xed\xf9\xe6\x9bo~x\x9b\xa6Y\x99\x81\x1e\x91\x85\x82߀\x19\b\xffT\xf4\xe9Kڧ\x1f\xa4\xa5\xb0>ݬ\x9e\xc8w\x1b\xb8\x8d\xa2\xa1\x7f@\t\x91-\xfe\x84{\xf2\xa4\x14\xfc\xaaG5\x9dQ\xb3Y\x01\x18\uf0da\xb4-\xe9\x13\xc0\x06\xaf\x1c\x9cCn\x0e\xe8ۧ\xb8\xc3]$\xd7!g\xf0\xc9\xf5\xe9\x9b\xf6\xe6\xfb\xf6\xbb\x15\x807=n@\x90ә\x1a\x8d\xc2\xf8GDQiO\xe8\x90CKa%\x03ڄ\x7f\xe0\x10\x87\r\xbc\x1e\x14\xfb\xd1w\xe1\xbd\xcdP\xdb\f\xf5P\xa0\xf2\xa9#\xd1_\xae\xdd\xf8\x95\xc6[\x83\x8bl\\\x9dP\xbe \xc7\xc0\xfa\xe9\xd5i\x03\"\\N\xc8\x1f\xa23\\5^\x01\x88\r\x03n \xdb\x0e\xc6b\xb7\x02\x18\x05\xc9Xͨ\xc5\xe9\xa6\xc0\xd9#\xf6\xa68\x01\b\x03\xfa\x1f\xef\xef\x1e\xbfݾ\xd9\x06\xe8P,ӠYֿ\x9b\x97}\xa8\x85\t$``\xa4\x04\x1a\xc0X\x8b\"`#3z\x85B\x19\xc8\xef\x03\xf79\xad`v!\xea\x05\xaa\x1e\x11\x1e\xb3\xfec\x98\xed\xcb\xe1\xc0a@V\x9a\xa4)\xeb\xa2\xe2.v\xff\x8dxZ)\xd6b\x05]*=\x94\xecy\xd4\v\xbbQ\x1e\b{\xd0#\t0\x0e\x8c\x82\xbe\x14c\xda6\x1e\xc2\xeew\xb4\xdaΠ\x8b.\x922\x19]\x97*\xf6\x84\xac\xc0h\xc3\xc1\xd3_/ؒ\x04JN\x9dѬ\x9dWdo\x1c\x9c\x8c\x8b\xf85\x18\xdf͐{s\x06\xc6\xe4\x13\xa2\xbf\xc0\xcb\x062\xe7\xf1[`\xccRo\xe0\xa8:\xc8f\xbd>\x90N}hC\xdfGOz^疢]\xd4\xc0\xb2\xee\xf0\x84n-th\f\xdb#)Z\x8d\x8ck3P\x93\x03\xf1\xb9\x17۾\xfb\x8a\xc7Ε7n\xf5\x9cjP\x94\xc9\x1f.\x0er\xeb|AzR#\x95b*P%\xc4\xd7,\xa4\xad$\xdd\xc3\xcf\xdb\xcf01)\x99*Iy\xbd\xba\xd0e\xcaOR\x93\xfc\x1e\xb9\xd8\xed9\xf4\x19\x13}7\x04\xf2\x9a?\xac\xa3\\\xb8qד\xcaT\xda)us\xd8\xdb<\xab`\x87\x10\x87\xce(v\xf3\vw\x1enM\x8f\xee\xd6\b\xfeϹJY\x91&%\xe1Cٺ\x9c\xc0\xf3\xcbEދ\x83iv^ImeJl\a\xb4)\xb9I\xdfdM{\xb2\xa5\xad\xf6\x81\xc1\xd4L\xda\x0f1\xc9\x16_\xc8e\x9cH\x85\xcdlN\xa5.\x7f\x9fM},哣\x11\x9co\xce8ݧ;s\xff\x8e\xf6h\xcf\xd6a\x81(S\bߧ\x92\x16\xfa\xd8/}6\xf0\t\x9f+\xbb\xf7\x1c҄\xc6\xf9\xa8\xb9Z\x1bP\x1e\xb1\x03\xf9E\xb8\xf3\xc8ʭ\xfc0.G~\x0eh\x04\x02\x8eާ\x96\x0e~\x01Yy\x11\x16wH\xb1\xaf\xb0\xa9\xf2\xb9\xf3\xfb\x90\xff\"Lrl\xb4\xb4\x13\x8e\xc9\x1e\xfd\x14^\x15\xc0\xeb\xb9.k9\xe7>$hY\xf9y\xfeo\xc6i.\x11c\xd5w\x93YU\x0f\x92ǚ\xe2\xf5\xfe\x1aYF\xe7\xcc\xce\xe1\x06\x94\xe3Һ\xd8\x1afs\x9eW\xcdTj\x9f\xa9GQ\xd3\x0f\xef\x14\xd0\xe2UH\xeb~\x81\x92\x9a\xe7\xf9\x88\xfeZ\x8b\xc0\xb3\x91W\xe7\x15\xc8\xdd\xf9\x9a\xe9\xed\xcb\xdf\xe6\xb2\xcfJ=o \xcd\xfaF\xa9\"䇔\xaa\xa6\xb4\xd4y\xf5\xb7f\xa1\xd2\xf6\xf2\xee4H\xde\xf4\xcb\xf4W\xb3\x8c\xe1*\x85j\x05,63|w\x11\x9eh`s\x98\x02\xfe'\x00\x00\xff\xff\xef\xf8\xa6>\x10\f\x00\x00"), diff --git a/config/crd/v2alpha1/bases/velero.io_datadownloads.yaml b/config/crd/v2alpha1/bases/velero.io_datadownloads.yaml index 5239aee61..c36fb6460 100644 --- a/config/crd/v2alpha1/bases/velero.io_datadownloads.yaml +++ b/config/crd/v2alpha1/bases/velero.io_datadownloads.yaml @@ -108,6 +108,10 @@ spec: description: SnapshotID is the ID of the Velero backup snapshot to be restored from. type: string + snapshotSize: + description: SnapshotSize is the logical size of the snapshot. + format: int64 + type: integer sourceNamespace: description: |- SourceNamespace is the original namespace where the volume is backed up from. diff --git a/config/crd/v2alpha1/bases/velero.io_datauploads.yaml b/config/crd/v2alpha1/bases/velero.io_datauploads.yaml index be2bb0861..dff364ea2 100644 --- a/config/crd/v2alpha1/bases/velero.io_datauploads.yaml +++ b/config/crd/v2alpha1/bases/velero.io_datauploads.yaml @@ -219,6 +219,10 @@ spec: description: SnapshotID is the identifier for the snapshot in the backup repository. type: string + snapshotSize: + description: SnapshotSize is the logical size of the snapshot. + format: int64 + type: integer startTimestamp: description: |- StartTimestamp records the time a backup was started. diff --git a/config/crd/v2alpha1/crds/crds.go b/config/crd/v2alpha1/crds/crds.go index 067ba4ae5..f00338a71 100644 --- a/config/crd/v2alpha1/crds/crds.go +++ b/config/crd/v2alpha1/crds/crds.go @@ -29,8 +29,8 @@ import ( ) var rawCRDs = [][]byte{ - []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcYɒ\x1b\xb9\x11\xbd\xf7Wd\xc8\a]D\xb6\xe5e\xc2\xc1\x9bĶ#:\xa0f\xb3\xd9\x033\xe2\r\xad\x13Z-\x80\x19\x81?yT\xf4\xcfͿ\xfd\xcdͅ~\xdc}|\xf8&\x14_\xc028\xaf\xeb\x1f\xd0\xe9`K|\u008dP\xc2\v\xad\x1ej\xf4\x8c3\xcf\x16\x0f\x00L)\xed\x19\r;\xfa\vPj孖\x12\xed\xacB5\xff\x16\n,\x82\x90\x1cmT\xden\xbd\xfb\xe3\xfc\xe3w\xf3\xbf>\x00(V\xe3\x02H\x1f\xd7{%5\xe3n\xbeC\x89Vυ~p\x06KR\\Y\x1d\xcc\x02\x8e\x13ia\xb3i\x02\xfc\xc4<{jt\xc4a)\x9c\xff\xe7d\xea{\xe1|\x9c62X&G{\xc7\x19'T\x15$\xb3ù\a\x00Wj\x83\vx\xa1\xad\r+\x91\xc6\x1a\x9b\"\x94\x190Σ\x97\x98\\Y\xa1<ڥ\x96\xa1n\xbd3\x03\x8e\xae\xb4\xc2\xf8\xe8\x85>,p\x9e\xf9\xe0\xc0\x85r\v\xcc\xc1\v\xee\x1f\x9f\xd5\xca\xeaʢK\xb0\x00~tZ\xad\x98\xdf.`\x9e\xc4\xe7f\xcb\x1c6\xb3ɕ\xeb8\xd1\f\xf9\x03\xe1u\xde\nU\xe5\x10\xbc\x8a\x1a\x81\a\x1bCHv\x97\b~+\xdc\x10ڞ9\x82g=\xf2\x93@\xe2<\xa9s\x9e\xd5f\x8c\xa8\xb74A\xe2\xccc\x0e\xd0R\xd7F\xa2G\x0e\xc5\xc1ck\xc6Fۚ\xf9\x05\b\xe5\xbf\xfb\xcbi_4ΚǥOZ\r\x1d\xf3\x99F\xa17\x9c\x90P\x94*\xb4Y\xefh\xcf\xe4/\x01\xe2I\xc1\xe7\xde\xfa\x84$\xe9\xed\x8f_\x84B)\az\x03~\x8b\xf0\x99\x95߂\x81\xb5זU\b\xdf\xeb2\x85o\xbfE\x8bQ\xa2H\x12\x94\xbd (v\xdafCg\xb0\x9c'\xd9FY\xabk\x14\xbf\xe1F\xbfzn\x95\x16Y6\xb7\xdaR3\x8f\x12B\xab|\x82}\xaa\xf0\xaa\xe4\xea;Qi\x8e=\x8f\r0\t\a\xc6\xea\x12\x9d;\x93\xf0\xa4`\x80\xe2\xe580qM\x92\xd8\xfd\x89I\xb3e\x1fS\x91)\xb7X\xb3E\xb3B\x1bT\x9fV\xcfo\x7f^\x0f\x86\xe1L\xc1`\xa5wT)\b\xbe\xb1\xda\xebRK(\xd0\xef\x11U\n}\xadwh\xa9\xceUB\xb9N#Um\xde\x178\xd6l\xca﨏fӤŘ=\x04\xd0\xf6\xa3\x0f\xb4\xa7A\xebE[\x85\x1b\xdd\xc7\x06\xd3\x1b\x1d\xd9\xf1\xbf\xd9`\x0e\x80LO\xab\x80S\xa7\xc1dVS[\x917\xdeJ\xc1\x13\x0e,\x1a\x8b\x0eU\xea=4\xcc\x14\xe8\xe2G,\xfd|\xa4z\x8d\x96Ԁ\xdb\xea 9\x19\xbbC\xeb\xc1b\xa9+%\xfe\xd3\xe9v\xe0u\xdcT2\x8f\xce\xc7\xc3h\x15\x93\xb0c2\xe0\ar\xdaHs\xcd\x0e`\x91\xf6\x84\xa0z\xfa\xe2\x027\xc6\xf1\x85\xbc(\xd4F/`\xeb\xbdq\x8b\xc7\xc7J\xf8\xb6햺\xae\x83\x12\xfe\xf0\x18\xa3!\x8a\xe0\xb5u\x8f\x1cw(\x1f\x9d\xa8f̖[\xe1\xb1\xf4\xc1\xe2#3b\x16\rQ\xb1\xf5\xcek\xfe\a\xdb4j7\xd8v\x92\x88\xe9\x17\x1b\xe6\r\xe1\xa1.J\xa7\x825\xaa\x92\x89\xc7(\xd0\x10\xb9\ue1ff\xaf_\xa1E\x92\"\x95\x82r\x14\x9d\xf8\xa5\x8d\x0fyS\xa8\rڴncu\x1du\xa2\xe2F\v\xe5\xe3\x9fR\nT\x1e\\(j\xe1)\r\xfe\x1d\xd0y\n\xddX\xed2R\x13(\x10\x82\xa1z\xc0\xc7\x02\xcf\n\x96\xacF\xb9d\x0e\x7f\xe7XQT܌\x82pU\xb4\xfa\x84k,\x9c\xdcۛh\x19Ӊ\xd0\xf6+\xc8\xda`IQ%\xc7\xd22\xb1\x11M'\xa12\xc0\x06\xb2C\x0f\xe5\x8f>\xfd\xb2\xddd,t)\xdd\xe8\xf79\xa7\xa8E\xabz\x85\xbc\xe9u\xaeiRrؤ\xfa\xbfI\x7f\xb4h\xb4\x13^\xdbñK\x8eS\xe1dT\xe8W2U\xa2\xbcǼe\\\tBq\xf29v\xa9LE(i\x8d@\xb5\xaa4\x1d\xaeA(\xe0ٓ\f\xe5\xb6C\x9f7Te\xbb\x9aPp\xe4\x94\xd0\xe7\x8ecs\v\xad%\xb2\xb1\x17)\v\xbfP[Xj\xb5\x11\xd5\xd4\xf0>\xfd=\x95\"\x17|\x9aI\xd8ޖd\x05e'!\x99\xc5\x0e5kS\x97J\xfbFT\xc1\x9e\x8a\xffF\xa0\xe4\x93\xfas\xf2$\xb5\x06\xc7]\xee\x89q\a\xbd=]MW\xeb\xb5^\xafc\x85r\x91\xef\xf6Rs\n\x12\xe0y\xd3\xd3(\x1c\xbc{\a\xda»t'z\xf7!\xad\x0eB\xfa\x99\x18\xf4\xff\xbd\x90\xb2\xdd\xe5\xa6\xec&\x86\xf3u}\xc1\xf2\x97(Dx\xbe\xaeo\xe5VS4\xa8B=\xddp\x06,x\x9d\x19\x96B\x85\x9f2\xe3{\xa1\xb8\u07bb[\x8c\xed\xf8\rQL\x1d\xfc=\x01\xff:\xd21\x8a\xbb'B\x1cc\xed5\xec\x99\xe8q\x8cnw\xf7!\xa3\xb7\xc0\r5$\x8b>XE\xe5\x00\xad\xa5\n\xed\xa2J\x1d&\x9c笥N1\xe3\xb6\xda??]\xb0q\xdd\t\xb6u\xf7\xf9\xa9\r\xf1[̺\xae\xf86\x92\x90\x89\x12\xc1oY$\x8fm\xfd6\xb4\x91Kt7\xee{²\x1e\xaah\x8d\xd1VT\x82\x9c\xaf\xba\x99c\xce\xee\xe8\xda\x1eE\xc9D\xe4\x10\xcc\t\xec@\xe5\x98\xc8K\x81\xc0\xc5f\x83\x96\x18J\xa4/i\xe3\xd5\xdb\xf2\xbd\xebm\"6\xfd?T\xf9kf\fr\xba+Qp\x1b_\xdd\xe4%\xcfl\x85\xfe-\x82\xbe\xe0\xa2מh\xeb\n\xa2:t\xb1m\xb8tL\xd6(\x06\xab\xb7e\x86\xf9\xd2o\xf56Ex\x9a\x17@s\t:\x11\xc4\t\xcaI\xb4\x1a<\x9d\x8e\xac\x8a\xb3m\x05\xc0\xec\xae\xd8y\xf5\x96c\x19\x9d;\xc0o\x99'\x89\xe6\xd2\n\xc5!\xab\x13\xda#҄\xf3>\xbc\xe5U\x80\x97g\x11/ǐO\xe0-\x0e\xbf\x182\x91\x18a\x91\xe7J\xf8\xe9\xc8\xcd\xc0첃\xe5\xf5\xad:\xbf\xf3,\xcfGG2\xe3\xd2?\x9a>\xd6\xcb\xf1İ\xae\x8cf\xfbG\xf2*\xe2\x1e\x9f\x15\xae\xa5\xee鱰\t{\x19l,:\xcd\x13\"݆\xef\"\xef\xac,\xd1x\xe4\x9f\x0f\xd4կh\xfc\x04@\x9d\x7fT\xf9\x979\xb6}4\xecV\x86\xddB\xea\x1e~\xeei\x00\x9f\xc6J\xe2\xed\xdf\xf2^[\x9e\xc2M\xd4\xec4h\x80W\xba7\xc5\xdb\xeb\xfbԉiY\xec\xef\xc4P'\x9bN4\xb4\x8f\x89t=\x9d\xd1\xfa\x89\x84\nR\xb2B\xe2\x02\xbc\r\xa7\xa8z\xfef\x92\xdeQ\xfbOfw]S\xa6j\xa6\xbec\xdd#Q|\xcck_ps.;\xea\xeb\x1c\x96\xd4!\aܡ\x02\xba|2!\x91\xb7:3|\xfd\x92\xe73\xa0\xa7T\xf0\xb7t~\x8dα\xea\xd2\x01\xfa\x92\xa4һJ\xb3\x04XA\xbcq̚\u07fb\xe6l\xdf\xcc\xdf\x7f\x9dC|%{?\x83%\xde5/\x80Y\x91L\xae\xa6u\xd0N\x1758syx\xc1}f\xb4=\x9f\x99\xa9Us\xe83S\x93O2\xfd\xc9t\xa9\xcf5\xc6v.\xab\xb3\xfb摙\xfbG<\f7y\xba\xc1w\xcfq\xef\x9e\x06\xb6Z\xb6'<~\xabP\xa1.\xd0R\x18\xe2א6\x1e\x1d\xefg\x8a\xf7\xa3\x96#\x7f\x9d\x86\xee.\x10U\xcd\xe1uK\xd4$\xbdg\xb4\xb7#.\x9c\x91\xec\xd0\x19\xd3g\xa8\x19\xe5\xc7S3y\xae\xbe\x95\xa4vߎ\xf2\xcc+\xf7\x01h\xf8\x9b~\xca\x19\xcdw߄~\x9b\x1dμf\f\xbf\xd1\xddu\x95\x1ah\xb8\xd4\n\x9ao\x86\xb7W\xf0\xe16\xbfg\xf1\xcezo2\x18\x91\xf3\x9e\xee\xe6\xf5\xb1?\x12\x8a\xeeI~\x01\xff\xfd\xff\xc3\xcf\x01\x00\x00\xff\xff\xb1\xea?f~\x1f\x00\x00"), - []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcZIs\xe3\xb8\x15\xbe\xfbW\xbc\xea\x1c\xe6b\xc9\xe9,S)\xdd\xdarR\xe5ʴ\xdb\xd5r|\x87\xc8'\x11c\x10`\xb0H\xe3,\xff}\xea\x01\x04\x05\x92\x90(i\xa6\x9b\x87\xae\x16\x96\x87\xb7\xe1{\v<\x9b\xcdnX\xc3_Q\x1b\xae\xe4\x02X\xc3\xf1\x17\x8b\x92~\x99\xf9\xdb\xdf̜\xab\xbb\xddǛ7.\xcb\x05,\x9d\xb1\xaa\xfe\x8aF9]\xe0\x03n\xb8\xe4\x96+yS\xa3e%\xb3lq\x03\xc0\xa4T\x96Ѱ\xa1\x9f\x00\x85\x92V+!P϶(\xe7on\x8dk\xc7E\x89\xda\x13\x8fG\xef\xfe8\xff\xf8\xe3\xfc\xaf7\x00\x92ո\x00\xa2\xe7\x1a\xa1Xi\xe6;\x14\xa8՜\xab\x1b\xd3`Ad\xb7Z\xb9f\x01\x87\x89\xb0\xad=2\xb0\xfb\xc0,\xfb\x97\xa7\xe0\a\x057\xf6\x9f\x83\x89\x9f\xb8\xb1~\xb2\x11N3\xd1;Տ\x1b.\xb7N0\x9d\xce\xdc\x00\x98B5\xb8\x80':\xb2a\x05\xd2X+\x89ga\x06\xac,\xbdn\x98x\xd6\\Z\xd4K%\\\x1du2\x83\x12M\xa1yc\xbd\xec\a\x86\xc0Xf\x9d\x01\xe3\x8a\n\x98\x81'\xdc\xdf=\xcag\xad\xb6\x1aM`\t\xe0g\xa3\xe43\xb3\xd5\x02\xe6a\xf9\xbc\xa9\x98\xc1v6\xa8o\xe5'\xda!\xfbN\xdc\x1a\xab\xb9\xdc\xe6\xce\x7f\xe15B\xe9\xb47\x1b\xc9\\ ؊\x9b\x94\xb1=3Ĝ\xb6X\x1ee\xc3\xcf\x131cY\xdd\f\xf9I\xb6\x06\x86Jf1\xc7\xceRՍ@\x8b%\xac\xdf-F!6J\xd7\xcc.\x80K\xfb\xe3_\x8ek\xa2U\xd5\xdco}P\xb2\xaf\x96{\x1a\x85d8pB\x16ڢ\xce\xeaFY&~\v#\x96\b\xdc'\xfb\x03'\x81n:>\xc9\n\xb9\x1b\xa8\r\xd8\n\xe1\x9e\x15o\xae\x81\x95U\x9am\x11~RE0\u07beB\xdd\x1ao\x1d\x96\x98J9Q\xc2:J\f`\xac\xd2Y+6X\xccî\x96n$;0e\xff\xcc\xdf\xd9\xc9\n\x8d,\xebd\x11e\xe6~\x05W2\xefi\x9f\xb6x\x96\x97\xa5ڔ\xaa\xc4Nu\x98r\xc4\r4Z\x15h\xcc\t\xbf\xa7\xed=\x1e\x9e\x0e\x03#\xb5\x84\x15\xbb?1\xd1T\xecc@\x99\xa2\u009a-\xda\x1d\xaaA\xf9\xe9\xf9\xf1\xf5ϫ\xde0\x1c\xc5\fVXC`A\xac7ZYU(\x01k\xb4{D\xe9q\vj\xb5CM \xb7\xe5\xd2\x00\x93eG\x13\xd2\x05\a\xa8&'\xf7\xf4h6L\xb6\xee\xa4\x1aԩف\x8elP[\x1e\xd17|IXIF\aB\xfco֛\x03 \xb9\xc3.()\xbe`\x90\xaa\xc5V,[U\x05\xbbq\x03\x1a\x1b\x8d\x06e\x8884\xcc$\xa8\xf5\xcfX\xd8\xf9\x80\xf4\n5\x91\x89\xf7\xa1Pr\x87ڂ\xc6Bm%\xffOGۀU\xfeP\xc1,\x1a\xeb/\xa4\x96L\xc0\x8e\t\x87\xb7\x03\xed\xd1W\xb3w\xd0Hg\x82\x93\t=\xbf\xc1\f\xf9\xf8\xac4\x02\x97\x1b\xb5\x80\xca\xda\xc6,\xee\xee\xb6\xdc\xc6`[\xa8\xbav\x92\xdb\xf7;o\f\xbevVisW\xe2\x0eŝ\xe1\xdb\x19\xd3E\xc5-\x16\xd6i\xbcc\r\x9fyA\xa4\x0f\xb8\xf3\xba\xfc\x83nó\xe9\x1d;\xf2\xc2\xf0\xf9@y\x81y(~ҕ`-\xa9 \xe2\xc1\n4D\xaa\xfb\xfa\xf7\xd5\vDN\x82\xa5\x82Q\x0eKGz\x89\xf6!mr\xb9A\x1d\xf6m\xb4\xaa=M\x94e\xa3\xb8\xb4\xfeG!8J\vƭkn\xc9\r\xfe\xed\xd0X2ݐ\xec\xd2'$\xb0Fp\rAA9\\\xf0(a\xc9j\x14Kf\xf0;ۊ\xacbfd\x84\xb3\xac\x95\xa6Y\xc3\xc5A\xbd\xc9D̔\x8e\x98\xf6\x00\x1f\xab\x06\v\xb2)\xa9\x956\xf1\roc\ta\x00KV\xf6\xb5\x93\xbf\xf6\xf4eC\xc8pє\xab\xd1w\x9f#\x14y\x95\t~\xc7P\xd7F&яL\xe9w\x00\xf9v\x8f\xc6F\x19n\x95~'\xc2!4\x0e\xdd\xe0\xa8E\xe8+\x98,P\\#\xde\xd2\xef\x04.K\xd28vnL\x00\x14\xa8zF\x95\xdc*\xbaX\x89!\xe0\xd1\xd2\n\xf2j\x836/\xa6̄2.\xe1\x90MB\x9a5\x0eE]+%\x90\r5X\x18\xbe\x92\xac1\x95\xb2\x13\x02?n \xae|yo\x90\x0e_\xae\x1eo\xe9\x9f8N\x1e\xb4\xe3e\v\xf1t\xcb(\xafʛ\xad\xb5\xf3r\xf5\b\xa6\xdd>6\x92tB\xb0\xb5\xc0\x05X\xedƂ\x1dwXϽ\xe6;Թ\x99\xe1\xcd\xf1\v\xa3\x17\x86m\xe0\x8c\xcfV\xfd\xd0+e\xfa\x18\xa5\\*iQ\xe6ltҫ苒.\x053Y\x9e\a\x9c\xad\xd2\xf5\xb9k\x12\tB\xe1W؊\xe5\xf9\x82\x10t\xbd\x1c\x87M\xbc\xcb\xcd`\xcfmu\x95D႞-P\xb2<+O{߃8jsB\x98\xe7ץ\x97wJ2\n7\xd7H\xb6\xeb\x19\xfd\f\xd9\xfa^\x92\x93n\xc0\xe51\xe1\x14\xa1\x00\x81\x19\x96\xe0\x9a\xcby'\xd0\xe1\x1a\xcb1ϳ\x9e\xbd2\xd3}\xa1\x8f \xc9(2A\x9bt~\xa6\xb4r\xa9\xe4\x86o\xc7g\xa7\xf5\xf3\xa9k{R\xb4Q\xc4K\x8e$\x8dS\x80#Nf>Ý\xc5\xe8G\xb9\xe1\x86o\x9d>\x86F\x1b\x8e\xa2\x1c%0\x93\x004\xa1\x0f\xcf\xc45q\xa4\x93,\xc6\xef\x16R\x93\xcc>xI\x8aR!\xfc\x8de\x00\x82\xee\x03En\xe0\xc3\aP\x1a>\x84^ˇ۰\xdbqag\xbcW^\xec\xb9\x10\xf1\x94\x8b\"hWRPA\xa7\xdcTh\xc9\xea\xe0ˀ\xc6@\x15\x96\x8aO/\xbeU\xb0g\x89ȼ\xd2|\xcbIᲛ9$c-ֵ]\v\x8fd\x1e\x8a\xb3\xfe١\xa5!\xb4<\x90\xa3\xeb\x1c\x0e'\xb4g\xb2\xf4\xf9B7_\xb6W/sq'\x15\xf2\xfc\xba\x9c\xb2Wwp\x06\xcaix_\xf1\xa2ꛎ\x8fA\x15\xc0\xb27\xf4\xb9\xf7\x05l\xe61|\x96\xcf\xc4\ak\x86\xb7o0\x9d\xba\xecp\xaao\xe8\xec\xec\xf3\xeb\xf2\xacj\xc57RΫWB\x87\xb4\xd5r\xe1\xb4\xf6\x95`\x18U\x9b\xab*\x16V\x14\xd8X,\xefߟT9\xe5\xf4\x9fz\x8b\x89\x11yN+)cj\xdf\\\u0086]ZrDv\xbb\x06\xd85\xd7\xf4Ӑ\x88o\x85\xe82\x01\xccq\x01\x11\xc0\xe68\xd3\x00/\xe4ྔ\xff!`$m\xf3\xc8K\xd7st\xe8\x88B\xec\xaeR\xad>\xa3\xfd\xd7E\xd9|\xa9\x16\x1a\xcbi\xeb\xf0\xaa\xbamLf\xac;\x16\vL\xdfӌ\x1d\xed\x9c\xc6\x0e\xe4:}\x05jX\x02\xeeP\x02\x95\xe2\x8c\v\x8aݞd\x06\xc0NSi\x83Xx\xbe\x88=\x9a\xd8\xcf\xcb6˦-\x99Q\xc2\x18;\xa51\xbb\x14\xf2+\x1a'2I\xc37L!Ñ\xa1[`\xb2)\xe4\xe9r\x96\x19`\xa0\x03\x91\x167\x8e\x81\xd6\xd9J\xca\xe6\x955\x1aöS\x88\xf69\xac\n\x9d\xbdv\v\xb05\xa5Q}\xd6~0-\xd0^\x04Wr\x1aS/B\xd2^S\xfebN\xbe\xac\xce\xe0\xe5ˊ\x0e\xf9\xb2\xfa\xad\xbc\xa0tu\xae\xb0bΪ̰\xe0\xd2\xfd\x92\x19\xdfsY\xaa\xfd\xf8~\x9d\x10\xb5a\xb6\x9a\x10\xf4\x99\xd9*\xc6э\x13\xc2\xef\x19\xe5\x97mj\xb6F\x02\x8e\xdf+\xcd\xf4\xad\xa7)\xf6hM.\xce\xe39w\xe6\x98\xe6\x9fp\x9f\x19\x8dq)3\xf5\xdc\x06\xbb\xcc\xd4\xe8e6\x9d\fݽ\x1c\xa6Ĺ,\xcd\xee\xf133\xf7\x0f\x1f\x05.\xd2s\xcb\xdf5a\xae\xeb\x13VJ\xc4\xc8\xe6\x1f-\xa5\xabר\xc9\b\xfeYtЯ\xa0\xbc;\xb1X\x86p\xb2\xbfK\xf6=\xa59\xbcT\xdc\xc4\xcef,\xd7Jn\x1a\xc1\xde;Y\xa6\xb0\xb5í\xe1\x8b\xd5\xd8IN\xb7\x04\xbb'\xe4|;'\xf7\x0e\xdc\xff\xc6/\xba\x83\xf9\xeei\xf8ۜp\"0\xc4\xeb\xfd\xf8pf\x1d\xfa\xf8\x10\xaf\"/QZ*\xad\x0f\xaf\x84\x87\x8a\xc6w\x9ds\xba\x1cv\xdb/+\xc2z\x7fXpUQڣ0\x91\xae\xb5\x7f\xe7\x90K\x8aV\x04\x06\x04A\xfe]j9|\x89\xbe\xed\x1e\xb6\x99m\x1fNJ\x8a\xc9-\xe6*=%)\a\xf09\xc4\xe5\xf9W_\xa0\xef\x99ze\xbdj4\xe89/\x13\xdam/1\x1dq\xeb\xee\xb5r\x01\xff\xfd\xffͯ\x01\x00\x00\xff\xff\xee\xe6t\xbc\x8f$\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcYK\x93\xe3\xb8\r\xbe\xf7\xaf@M\x0es\x19\xbb3yl\xa5|\x9bq'U]\xd9\xe9q\xad;}\xa7$X\xe6\x0eE2|\xd8\xebM\xf2\xdfS %\x99\x92\xe8\xe7>|3\t\x82\x1f\x01\x10\xf8@\xcdf\xb3\a\xa6\xf9\x1b\x1a˕\\\x00\xd3\x1c\x7fr(韝\x7f\xfb\x9b\x9ds\xf5\xb8\xfb\xf8\xf0\x8d\xcbj\x01Ko\x9dj~@\xab\xbc)\xf1\t7\\rǕ|hб\x8a9\xb6x\x00`R*\xc7h\xd8\xd2_\x80RIg\x94\x10hf5\xca\xf97_`Ṩ\xd0\x04\xe5\xddֻ?\xce?~7\xff\xeb\x03\x80d\r.\x80\xf4Uj/\x85b\x95\x9d\xefP\xa0Qs\xae\x1e\xacƒ\x14\xd7Fy\xbd\x80\xe3D\\\xd8n\x1a\x01?1ǞZ\x1daXp\xeb\xfe9\x99\xfa\x9e[\x17\xa6\xb5\xf0\x86\x89\xd1\xdea\xc6rY{\xc1\xccp\xee\x01\xc0\x96J\xe3\x02^hk\xcdJ\xa4\xb1\xf6L\x01\xca\fXU\x05+1\xb12\\:4K%|\xd3Yg\x06\x15\xda\xd2p\xed\x82\x15RX`\x1dsނ\xf5\xe5\x16\x98\x85\x17\xdc?>˕Q\xb5A\x1ba\x01\xfch\x95\\1\xb7]\xc0<\x8a\xcf\xf5\x96Ylg\xa3)\xd7a\xa2\x1dr\a\xc2k\x9d\xe1\xb2\xce!x\xe5\rB\xe5Mp!\x9d\xbbDp[n\x87\xd0\xf6\xcc\x12<\xe3\xb0:\t$̓:\xebX\xa3Lj\x92\xa5\x11R\xc5\x1c\xe6\x00-U\xa3\x05:\xac\xa088쎱Q\xa6an\x01\\\xba\xef\xfer\xda\x16\xad\xb1\xe6a铒C\xc3|\xa6QH\x86#\x12\xf2R\x8d&k\x1d\xe5\x98\xf8%@\x1c)\xf8\x9c\xac\x8fH\xa2\xdet\xfc\"\x14\n9P\x1bp[\x84Ϭ\xfc\xe65\xac\x9d2\xacF\xf8^\x95\xd1}\xfb-\x1a\f\x12E\x94\xa0\xe8\x05N\xbeS&\xeb:\x8d\xe5<ʶ\xca:]#\xff\r7\xfa\xd5c\xab4Ȳ\xb1ե\x9ay\x90\xe0J\xe6\x03\xecS\x8dW\x05WjD\xa9*L,6\xc0\xc4-h\xa3J\xb4\xf6L\xc0\x93\x82\x01\x8a\x97\xe3\xc0\xc44Qb\xf7'&\xf4\x96}\x8cI\xa6\xdcb\xc3\x16\xed\n\xa5Q~Z=\xbf\xfdy=\x18\x863\t\x83\x95\xceR\xa6 \xf8\xda(\xa7J%\xa0@\xb7G\x94\xd1\xf5\x8dڡ\xa1\x9a\x8d\x93\x06C\xf4\x10@\x93z\x1fhO\x8d\xc6\xf1.\v\xb7\xba\x8f\x05&\x19\x1d\x9d㿳\xc1\x1c\x00\x1d=\xae\x82\x8a*\r\xc6c\xb5\xb9\x15\xab\xd6Z\xd1y܂AmТ\x8c\xb5\x87\x86\x99\x04U\xfc\x88\xa5\x9b\x8fT\xafѐ\x1a\xb0[\xe5EE\x87ݡq`\xb0T\xb5\xe4?\xf7\xba-8\x156\x15̡u\xe12\x1a\xc9\x04\xec\x98\xf0\xf8\x81\x8c6\xd2ܰ\x03\x18\xa4=\xc1\xcbD_X`\xc78\xbe\x90\x15\xb9ܨ\x05l\x9d\xd3v\xf1\xf8Xsו\xddR5\x8d\x97\xdc\x1d\x1e\x837x\xe1\x9d2\xf6\xb1\xc2\x1d\x8aG\xcb\xeb\x193\xe5\x96;,\x9d7\xf8\xc84\x9f\x85\x83\xc8Pz\xe7M\xf5\a\xd3\x16j;\xd8v\x12\x88\xf1\x17\n\xe6\r\xee\xa1*J\xb7\x82\xb5\xaa\xe2\x11\x8f^\xa0!2\xdd\x0f\x7f_\xbfB\x87$z*:\xe5(:\xb1K\xe7\x1f\xb2&\x97\x1b4q\xddƨ&\xe8DYiť\v\x7fJ\xc1Q:\xb0\xbeh\xb8\xa30\xf8\xb7G\xeb\xc8uc\xb5\xcb@M\xa0@\xf0\x9a\xf2A5\x16x\x96\xb0d\r\x8a%\xb3\xf8;\xfb\x8a\xbcbg䄫\xbc\x95\x12\xae\xb1p4o2\xd11\xa6\x13\xaeM3\xc8ZcI^%\xc3\xd22\xbe\xe1m%\xa14\xc0\x06\xb2C\v\xe5\xaf>\xfd\xb2\xd5d,t)\xdc\xe8\xf79\xa7\xa8C+\x93D\xde\xd6:\xdb\x16)1,R\xe9oR\x1f\rje\xb9S\xe6p\xac\x92\xe3P8\xe9\x15\xfa\x95L\x96(\xee9\xde2\xac\x04.+\xb29\xf6\xa1LI(j\r@\x95\xac\x15]\xae\x81+\xe0ّ\fŶE\x97?\xa8\xccV5.\xe1\xc8)!\xe5\x8e\xe3\xe3\x16J\tdc+R\x14~\xa1\xb2\xb0Tr\xc3\xeb\xe9\xc1S\xfa{*D.\xd84\x13\xb0ɖt\n\x8aNB2\v\x15jօ.\xa5\xf6\r\xaf\xbd9\xe5\xff\rGQM\xf2\xcfɛ\xd4\x1d8\xecr\x8f\x8f{\xe8\xdd\xedj\xabZRz\x9d\n\x19\xca\x06\xbe\x9b\x84\xe6\x14$\xc0\xf3&\xd1\xc8-\xbc{\a\xca\xc0\xbb\xd8\x13\xbd\xfb\x10W{.܌\x0f\xea\xff\x9e\v\xd1\xedrSt\x13\xc3\xf9\xba\xbep\xf2\x97 Dx\xbe\xaeo\xe5VS4(}3\xddp\x06\xcc;\x95\x19\x16\\\xfa\x9f2\xe3{.+\xb5\xb7\xb7\x1c\xb6\xe77D1\x95w\xf78\xfc\xebH\xc7\xc8\xef\x8e\bq\xf0\xb5S\xb0g<\xe1\x18\xfd\xee\xf6CFo\x81\x1b*H\x06\x9d7\x92\xd2\x01\x1aC\x19\xda\x06\x95\xcaO8\xcfٓZɴ\xdd*\xf7\xfct\xe1\x8c\xeb^\xb0˻\xcfO\x9d\x8b\xdfB\xd4\xf5ɷ\x95\x84\x8c\x97\b~\xc7\"\xabP\xd6\xefB\xbb\xe6?\xe3\x95xI\xb4C,T\xcdK&\xc0\xd2X\x8b\xbdS9ők\xef\xc6(\xd3&-\x81\x19(O\xff0pO\xf4\xac\x87*\xba\x13(\xc3kN1\"\xfb\x99\xe3\xd5\xda)\xe1\x9b J\x9e\xc0\n\xbc>ab\xa0\xaaA\x1c\xab@\xa8\xf8f\x83\x86\x88T`Yq\xe3\xd5\xdb\xf2\xbdM6\xe1\x9b\xf4\x0f\x15\xa8\x86i\x8d\x15\xb5t\x14\x83\xadKor\xa6c\xa6F\xf7\x16@_0\xd1k\"ڙ\x82\x18\x199\xa8\xa5\xfc\xe1N\x051X\xbd-3\x04\x9d~\xab\xb7)\xc2\xd3\xf4\x05\xda^\xed\x84\x13'('\xdej\xf1\xf4:\xb2*\xceV?\x00\xbd\xbbb\xe7\xd5[\x8e\f\xf5\xe6\x00\xb7e\x8e$\xda\xde\x1a\x8aCV't7\xb9u\xe7}x˫\x00/\xcf\"^\x8e!\x9f\xc0[\x1c~1d\xe2Z\xdc`\x95\xab4\xa7=7\x03\xbd\xcb\x0e\x96\xd73\x8a\xfcγokf\xb0\x9b\r\xea[\xf9\x89nȾ\x13\xb7\xc6j.\xab\xdc\xf9/\xbcA(\x9d\xf6f#\x99\v\x04[s\x932\xb6c\x86\x98\xd3\x16˃l\xf8y\"f,k\xda1?\xc9\xd6\xc0P\xc9,\xe6\xd8Y\xaa\xa6\x15h\xb1\x84\xf5\xbb\xc5(\xc4F\xe9\x86\xd9\x05pi\x7f\xfc\xcbaMt\xaa\x9a\xfb\xad\x0fJ\x0e\xd5rO\xa3\x90\f\aN\xc8B\x15\xea\xacn\x94e\xe2\xb70b\x89\xc0}\xb2?p\x12\xe8\xa6\xe3'Y!w\x03\xb5\x01[#ܳ\xe2͵\xb0\xb2J\xb3\n\xe1'U\x04\xe3\xedjԝ\xf1\xd6a\x89\xa9\x95\x13%\xac\xa3\xc4\x00\xc6*\x9d\xb5b\x8b\xc5<\xec\xea\xe8F\xb2#S\x0e\xcf\xfc\x9d\x9d\xac\xd0ȲN\x16Qf\xeeWp%\xf3\x9e\xf6\xa9³\xbc,զT%\xf6\xaaÔ#n\xa0ժ@c\x8e\xf8=m\x1f\xf0\xf0\xb4\x1f\x98\xa8%\xac\xd8\xfe\x89\x89\xb6f\x1f\x03\xca\x1456l\xd1\xedP-\xcaOϏ\xaf\x7f^\r\x86\xe1 f\xb0\xc2\x1a\x02\vb\xbd\xd5ʪB\tX\xa3\xdd!J\x8f[Ш-j\x02\xb9\x8aK\x03L\x96=MH\x17졚\x9c\xdcӣ\xd90ٹ\x93jQ\xa7f\a:\xb2EmyD\xdf\xf0%a%\x19\x1d\t\xf1\xdf\xd9`\x0e\x80\xe4\x0e\xbb\xa0\xa4\xf8\x82A\xaa\x0e[\xb1\xecT\x15\xec\xc6\rhl5\x1a\x94!\xe2\xd00\x93\xa0\xd6?ca\xe7#\xd2+\xd4D&އB\xc9-j\v\x1a\vUI\xfekOۀU\xfeP\xc1,\x1a\xeb/\xa4\x96L\xc0\x96\t\x87\xb7#\xed\xd1װw\xd0Hg\x82\x93\t=\xbf\xc1\x8c\xf9\xf8\xac4\x02\x97\x1b\xb5\x80\xda\xda\xd6,\xee\xee*nc\xb0-T\xd38\xc9\xed\xfb\x9d7\x06_;\xab\xb4\xb9+q\x8b\xe2\xce\xf0j\xc6tQs\x8b\x85u\x1a\xefX\xcbg^\x10\xe9\x03\xee\xbc)\xff\xa0\xbb\xf0l\x06\xc7N\xbc0|>P^`\x1e\x8a\x9ft%XG*\x88\xb8\xb7\x02\r\x91\xea\xbe\xfe}\xf5\x02\x91\x93`\xa9`\x94\xfd҉^\xa2}H\x9b\\nP\x87}\x1b\xad\x1aO\x13e\xd9*.\xad\xffQ\b\x8e҂q\xeb\x86[r\x83\x7f;4\x96L7&\xbb\xf4\t\t\xac\x11\\KPP\x8e\x17xI\x8aR!\xfcMe\x00\x82\xee=En\xe0\xc3\aP\x1a>\x84^ˇ۰\xdbqag|P^\xec\xb8\x10\xf1\x94\x8b\"h_RPA\xa7ܩВ\xd5\xc1\x97\x11\x8d\x91*,\x15\x9f^|\xab`\xc7x\x92\xd6\xf7\xa7\x9b\xdb\f\xdd5n(\a\xd4h\x9d\x96\x14\x85QkJ\x8b\x8c'\xa9\\&\f\x1d\x91\xd4$!\xf1\x84\x94\xe3\xe8饠\xff\x8f\xb1<\x05\x80\x8c\x009\x1b\x1f\xe3Ч\xec}c\xeb\x1aS\xac\x86$\"\xf3J\xf3\x8a\x93\xc2e?\xb3O\xc6:\xac\xeb\xba\x16\x1e\xc9<\x14g\xfd\xb3GKCh\xb9'G\xd79\x1cNh\xcfd\xe9\xf3\x85~\xbe\xec\xae^\xe6\xe2\x9eT\xc8\xf3\xeb\xf2\x94\xbd\xfa\x833PNû\x9a\x17\xf5\xd0t|\n\xaa\x00\x96\xbd\xa1Ͻ/`3\x8f\xe1\xb3|&>Z3\xbe}\xa3\xe9\xd4e\xc7SCCgg\x9f_\x97gU+\xbe\x91r^\xbd\x12:\xa4\x9d\x96\v\xa7\xb5\xaf\x04è\xda\\U\xb1\xb0\xa2\xc0\xd6by\xff\xfe\xa4\xcaSN\xffi\xb0\x98\x18\x91紒2\xa6\xf6\xcd%l٥%Gd\xb7o\x80]sM?\x8d\x89\xf8V\x88.\x13\xc0\x9c\x16\x10\x01l\x0e3\r\xf0B\x0e\xeeK\xf9\x1f\x02F\xd26\x8f\xbct='\x87N(\xc4\xee*\xd5\xea3\xda\x7f]\x94͗j\xa1\xb1\x9c\xb6\x0e\xaf\xaaۦd\xa6\xbac\xb1\xc0\xf4=\xcd\xd8\xd1\xceilO\xae\xd7W\xa0\x86%\xe0\x16%P)θ\xa0\xd8\xedIf\x00\xec8\x95.\x88\x85\xe7\x8bأ\x89\xfd\xbcl\xb3\xec\xb4%3J\x98\xa2ٷ4f\x9fB~E\xe3D&i\xf8\x86)d82t\vL6\x85<^\xce2\x03\ft \xd2\xe1\xc6!\xd0:[Iټ\xb2AcXu\n\xd1>\x87U\xa1\xb3\xd7m\x01\xb6\xa64j\xc8\xda\x0f\xa6\x03ڋ\xe0J\x9e\xc6ԋ\x90tД\xbf\x98\x93/\xab3x\xf9\xb2\xa2C\xbe\xac~+/(]\x93+\xac\x98\xb3*3,\xb8t\xbfd\xc6w\\\x96j7\xbd_GDm\x99\xadO\b\xfa\xccl\x1d\xe3\xe8\xc6\t\xe1\xf7L\xf2\xcb.5[#\x01\xc7\xef\x95f\xfa\xd6\xd3)\xf6hM.\xce\xe39w\xe6\x90\xe6\x9fp\x97\x19\x8dq)3\xf5\xdc\x05\xbb\xcc\xd4\xe4e6\x9d\fݽ\x1c\xa6Ĺ,\xcd\xfe\xf133\xf7\x0f\x1f\x05.\xd2s\xc7\xdf5a\xae\xef\x13\xd6J\xc4\xc8\xe6\x1f-\xa5k֨\xc9\b\xfeYtԯ\xa0\xbc;\xb1X\x86p\xb2\xbfO\xf6=\xa59\xbc\xd4\xdc\xc4\xcef,\xd7JnZ\xc1\xde{YNak\x8f[\xe3\x17\xab\xa9\x93\x1co\t\xf6O\xc8\xf9vN\xee\x1dx\xf8M_tG\xf3\xfd\xd3\xf0\xb79\xe1H`\x88\xd7\xfb\xf1\xe1\xcc:\xf4\xf1!^E^\xa2\xb4TZ\xef_\t\xf7\x15\x8d\xef:\xe7t9\xee\xb6_U7\xaf\xf8\xaf\xe7\xd6ʹ4r,T\xc5\v&\xc0\xd0\xd8\bߦ|\x1c\xd7\xfa1\x8d\x0f\xff\xfe\xe1\xaa\xday@\xe1DV\xd9\xfd9F.w[\x11f\x11R\xfa\xe7\xb3\xe5\xf8\xc1\xfc\xb6\x7f\x7fg\xb6{\xc3+j&+\xcc\x15\xa4JR\xaa\xe2S\x9d\xcb\xd3ġ@\xdf3C\xcc:\xffd\xd0s^&\xb4\xbb\x96g:\xe2\xd6\xfd\xa3\xea\x02\xfe\xf3\xbf\x9b\xff\a\x00\x00\xff\xff\xe5\x00\x96\xae6%\x00\x00"), } var CRDs = crds() diff --git a/pkg/apis/velero/v1/pod_volume_backup_types.go b/pkg/apis/velero/v1/pod_volume_backup_types.go index 546616c5a..f0ea8dc38 100644 --- a/pkg/apis/velero/v1/pod_volume_backup_types.go +++ b/pkg/apis/velero/v1/pod_volume_backup_types.go @@ -123,6 +123,10 @@ type PodVolumeBackupStatus struct { // +optional // +nullable AcceptedTimestamp *metav1.Time `json:"acceptedTimestamp,omitempty"` + + // SnapshotSize is the logical size of the snapshot. + // +optional + SnapshotSize int64 `json:"snapshotSize,omitempty"` } // TODO(2.0) After converting all resources to use the runttime-controller client, diff --git a/pkg/apis/velero/v1/pod_volume_restore_type.go b/pkg/apis/velero/v1/pod_volume_restore_type.go index 2d059a14a..5c4ced777 100644 --- a/pkg/apis/velero/v1/pod_volume_restore_type.go +++ b/pkg/apis/velero/v1/pod_volume_restore_type.go @@ -58,6 +58,10 @@ type PodVolumeRestoreSpec struct { // Cancel indicates request to cancel the ongoing PodVolumeRestore. It can be set // when the PodVolumeRestore is in InProgress phase Cancel bool `json:"cancel,omitempty"` + + // SnapshotSize is the logical size of the snapshot. + // +optional + SnapshotSize int64 `json:"snapshotSize,omitempty"` } // PodVolumeRestorePhase represents the lifecycle phase of a PodVolumeRestore. diff --git a/pkg/apis/velero/v2alpha1/data_download_types.go b/pkg/apis/velero/v2alpha1/data_download_types.go index f79af10a8..01069118b 100644 --- a/pkg/apis/velero/v2alpha1/data_download_types.go +++ b/pkg/apis/velero/v2alpha1/data_download_types.go @@ -58,6 +58,10 @@ type DataDownloadSpec struct { // NodeOS is OS of the node where the DataDownload is processed. // +optional NodeOS NodeOS `json:"nodeOS,omitempty"` + + // SnapshotSize is the logical size of the snapshot. + // +optional + SnapshotSize int64 `json:"snapshotSize,omitempty"` } // TargetVolumeSpec is the specification for a target PVC. diff --git a/pkg/apis/velero/v2alpha1/data_upload_types.go b/pkg/apis/velero/v2alpha1/data_upload_types.go index 14daae116..4db59b214 100644 --- a/pkg/apis/velero/v2alpha1/data_upload_types.go +++ b/pkg/apis/velero/v2alpha1/data_upload_types.go @@ -172,6 +172,10 @@ type DataUploadStatus struct { // +optional // +nullable AcceptedTimestamp *metav1.Time `json:"acceptedTimestamp,omitempty"` + + // SnapshotSize is the logical size of the snapshot. + // +optional + SnapshotSize int64 `json:"snapshotSize,omitempty"` } // TODO(2.0) After converting all resources to use the runttime-controller client, @@ -244,4 +248,8 @@ type DataUploadResult struct { // NodeOS is OS of the node where the DataUpload is processed. // +optional NodeOS NodeOS `json:"nodeOS,omitempty"` + + // SnapshotSize is the logical size of the snapshot. + // +optional + SnapshotSize int64 `json:"snapshotSize,omitempty"` } diff --git a/pkg/builder/data_upload_builder.go b/pkg/builder/data_upload_builder.go index 48b4fa1d8..f704bbaee 100644 --- a/pkg/builder/data_upload_builder.go +++ b/pkg/builder/data_upload_builder.go @@ -180,3 +180,15 @@ func (d *DataUploadBuilder) Message(msg string) *DataUploadBuilder { d.object.Status.Message = msg return d } + +// SnapshotSize sets the DataUpload's SnapshotSize. +func (d *DataUploadBuilder) SnapshotSize(size int64) *DataUploadBuilder { + d.object.Status.SnapshotSize = size + return d +} + +// TotalBytes sets the DataUpload's TotalBytes. +func (d *DataUploadBuilder) TotalBytes(size int64) *DataUploadBuilder { + d.object.Status.SnapshotSize = size + return d +} diff --git a/pkg/controller/backup_repository_controller.go b/pkg/controller/backup_repository_controller.go index fe6f71aa2..0356a1f9a 100644 --- a/pkg/controller/backup_repository_controller.go +++ b/pkg/controller/backup_repository_controller.go @@ -608,7 +608,7 @@ func getBackupRepositoryConfig(ctx context.Context, ctrlClient client.Client, co jsonData, found := loc.Data[repoType] if !found { - log.Info("No data for repo type %s in config map %s", repoType, configName) + log.Infof("No data for repo type %s in config map %s", repoType, configName) return nil, nil } diff --git a/pkg/controller/data_upload_controller.go b/pkg/controller/data_upload_controller.go index 46704e5b1..0d8f6c0f3 100644 --- a/pkg/controller/data_upload_controller.go +++ b/pkg/controller/data_upload_controller.go @@ -493,6 +493,7 @@ func (r *DataUploadReconciler) OnDataUploadCompleted(ctx context.Context, namesp du.Status.Path = result.Backup.Source.ByPath du.Status.Phase = velerov2alpha1api.DataUploadPhaseCompleted du.Status.SnapshotID = result.Backup.SnapshotID + du.Status.SnapshotSize = result.Backup.TotalBytes du.Status.CompletionTimestamp = &metav1.Time{Time: r.Clock.Now()} if result.Backup.EmptySnapshot { du.Status.Message = "volume was empty so no data was upload" diff --git a/pkg/controller/data_upload_controller_test.go b/pkg/controller/data_upload_controller_test.go index 037726325..9cfca2f50 100644 --- a/pkg/controller/data_upload_controller_test.go +++ b/pkg/controller/data_upload_controller_test.go @@ -850,11 +850,22 @@ func TestOnDataUploadCompleted(t *testing.T) { // Add the DataUpload object to the fake client require.NoError(t, r.client.Create(ctx, du)) r.snapshotExposerList = map[velerov2alpha1api.SnapshotType]exposer.SnapshotExposer{velerov2alpha1api.SnapshotTypeCSI: exposer.NewCSISnapshotExposer(r.kubeClient, r.csiSnapshotClient, velerotest.NewLogger())} - r.OnDataUploadCompleted(ctx, namespace, duName, datapath.Result{}) + r.OnDataUploadCompleted(ctx, namespace, duName, datapath.Result{ + Backup: datapath.BackupResult{ + SnapshotID: "fake-id", + Source: datapath.AccessPoint{ + ByPath: "fake-path", + }, + TotalBytes: int64(1000), + }, + }) updatedDu := &velerov2alpha1api.DataUpload{} require.NoError(t, r.client.Get(ctx, types.NamespacedName{Name: duName, Namespace: namespace}, updatedDu)) assert.Equal(t, velerov2alpha1api.DataUploadPhaseCompleted, updatedDu.Status.Phase) assert.False(t, updatedDu.Status.CompletionTimestamp.IsZero()) + assert.Equal(t, "fake-id", updatedDu.Status.SnapshotID) + assert.Equal(t, "fake-path", updatedDu.Status.Path) + assert.Equal(t, int64(1000), updatedDu.Status.SnapshotSize) } func TestFindDataUploadForPod(t *testing.T) { diff --git a/pkg/controller/pod_volume_backup_controller.go b/pkg/controller/pod_volume_backup_controller.go index 625ec8337..6073c040f 100644 --- a/pkg/controller/pod_volume_backup_controller.go +++ b/pkg/controller/pod_volume_backup_controller.go @@ -525,6 +525,7 @@ func (r *PodVolumeBackupReconciler) OnDataPathCompleted(ctx context.Context, nam pvb.Status.Path = result.Backup.Source.ByPath pvb.Status.Phase = velerov1api.PodVolumeBackupPhaseCompleted pvb.Status.SnapshotID = result.Backup.SnapshotID + pvb.Status.SnapshotSize = result.Backup.TotalBytes pvb.Status.CompletionTimestamp = &completionTime if result.Backup.EmptySnapshot { pvb.Status.Message = "volume was empty so no snapshot was taken" diff --git a/pkg/podvolume/restorer.go b/pkg/podvolume/restorer.go index e2ca579de..1b15f9d53 100644 --- a/pkg/podvolume/restorer.go +++ b/pkg/podvolume/restorer.go @@ -179,7 +179,7 @@ func (r *restorer) RestorePodVolumes(data RestoreData, tracker *volume.RestoreVo } } - volumeRestore := newPodVolumeRestore(data.Restore, data.Pod, data.BackupLocation, volume, backupInfo.snapshotID, repoIdentifier, backupInfo.uploaderType, data.SourceNamespace, pvc) + volumeRestore := newPodVolumeRestore(data.Restore, data.Pod, data.BackupLocation, volume, backupInfo.snapshotID, backupInfo.snapshotSize, repoIdentifier, backupInfo.uploaderType, data.SourceNamespace, pvc) if err := veleroclient.CreateRetryGenerateName(r.crClient, r.ctx, volumeRestore); err != nil { errs = append(errs, errors.WithStack(err)) continue @@ -252,7 +252,7 @@ ForEachVolume: return errs } -func newPodVolumeRestore(restore *velerov1api.Restore, pod *corev1api.Pod, backupLocation, volume, snapshot, repoIdentifier, uploaderType, sourceNamespace string, pvc *corev1api.PersistentVolumeClaim) *velerov1api.PodVolumeRestore { +func newPodVolumeRestore(restore *velerov1api.Restore, pod *corev1api.Pod, backupLocation, volume, snapshot string, size int64, repoIdentifier, uploaderType, sourceNamespace string, pvc *corev1api.PersistentVolumeClaim) *velerov1api.PodVolumeRestore { pvr := &velerov1api.PodVolumeRestore{ ObjectMeta: metav1.ObjectMeta{ Namespace: restore.Namespace, @@ -281,6 +281,7 @@ func newPodVolumeRestore(restore *velerov1api.Restore, pod *corev1api.Pod, backu }, Volume: volume, SnapshotID: snapshot, + SnapshotSize: size, BackupStorageLocation: backupLocation, RepoIdentifier: repoIdentifier, UploaderType: uploaderType, diff --git a/pkg/podvolume/restorer_test.go b/pkg/podvolume/restorer_test.go index a9d4ddf84..36a1fc034 100644 --- a/pkg/podvolume/restorer_test.go +++ b/pkg/podvolume/restorer_test.go @@ -57,34 +57,34 @@ func TestGetVolumesRepositoryType(t *testing.T) { { name: "empty repository type, first one", volumes: map[string]volumeBackupInfo{ - "volume1": {"fake-snapshot-id-1", "fake-uploader-1", ""}, - "volume2": {"", "", "fake-type"}, + "volume1": {"fake-snapshot-id-1", 0, "fake-uploader-1", ""}, + "volume2": {"", 0, "", "fake-type"}, }, expectedErr: "empty repository type found among volume snapshots, snapshot ID fake-snapshot-id-1, uploader fake-uploader-1", }, { name: "empty repository type, last one", volumes: map[string]volumeBackupInfo{ - "volume1": {"", "", "fake-type"}, - "volume2": {"", "", "fake-type"}, - "volume3": {"fake-snapshot-id-3", "fake-uploader-3", ""}, + "volume1": {"", 0, "", "fake-type"}, + "volume2": {"", 0, "", "fake-type"}, + "volume3": {"fake-snapshot-id-3", 0, "fake-uploader-3", ""}, }, expectedErr: "empty repository type found among volume snapshots, snapshot ID fake-snapshot-id-3, uploader fake-uploader-3", }, { name: "empty repository type, middle one", volumes: map[string]volumeBackupInfo{ - "volume1": {"", "", "fake-type"}, - "volume2": {"fake-snapshot-id-2", "fake-uploader-2", ""}, - "volume3": {"", "", "fake-type"}, + "volume1": {"", 0, "", "fake-type"}, + "volume2": {"fake-snapshot-id-2", 0, "fake-uploader-2", ""}, + "volume3": {"", 0, "", "fake-type"}, }, expectedErr: "empty repository type found among volume snapshots, snapshot ID fake-snapshot-id-2, uploader fake-uploader-2", }, { name: "mismatch repository type", volumes: map[string]volumeBackupInfo{ - "volume1": {"", "", "fake-type1"}, - "volume2": {"fake-snapshot-id-2", "fake-uploader-2", "fake-type2"}, + "volume1": {"", 0, "", "fake-type1"}, + "volume2": {"fake-snapshot-id-2", 0, "fake-uploader-2", "fake-type2"}, }, prefixOnly: true, expectedErr: "multiple repository type in one backup", @@ -92,9 +92,9 @@ func TestGetVolumesRepositoryType(t *testing.T) { { name: "success", volumes: map[string]volumeBackupInfo{ - "volume1": {"", "", "fake-type"}, - "volume2": {"", "", "fake-type"}, - "volume3": {"", "", "fake-type"}, + "volume1": {"", 0, "", "fake-type"}, + "volume2": {"", 0, "", "fake-type"}, + "volume3": {"", 0, "", "fake-type"}, }, expected: "fake-type", }, diff --git a/pkg/podvolume/util.go b/pkg/podvolume/util.go index dab291768..6af666b52 100644 --- a/pkg/podvolume/util.go +++ b/pkg/podvolume/util.go @@ -39,6 +39,7 @@ const ( // volumeBackupInfo describes the backup info of a volume backed up by PodVolumeBackups type volumeBackupInfo struct { snapshotID string + snapshotSize int64 uploaderType string repositoryType string } @@ -92,8 +93,14 @@ func getVolumeBackupInfoForPod(podVolumeBackups []*velerov1api.PodVolumeBackup, continue } + snapshotSize := pvb.Status.SnapshotSize + if snapshotSize == 0 { + snapshotSize = pvb.Status.Progress.TotalBytes + } + volumes[pvb.Spec.Volume] = volumeBackupInfo{ snapshotID: pvb.Status.SnapshotID, + snapshotSize: snapshotSize, uploaderType: getUploaderTypeOrDefault(pvb.Spec.UploaderType), repositoryType: getRepositoryType(pvb.Spec.UploaderType), } @@ -109,7 +116,7 @@ func getVolumeBackupInfoForPod(podVolumeBackups []*velerov1api.PodVolumeBackup, } for k, v := range fromAnnntation { - volumes[k] = volumeBackupInfo{v, uploader.ResticType, velerov1api.BackupRepositoryTypeRestic} + volumes[k] = volumeBackupInfo{v, 0, uploader.ResticType, velerov1api.BackupRepositoryTypeRestic} } return volumes diff --git a/pkg/restore/actions/csi/pvc_action.go b/pkg/restore/actions/csi/pvc_action.go index dcf33f5fc..dee23cf70 100644 --- a/pkg/restore/actions/csi/pvc_action.go +++ b/pkg/restore/actions/csi/pvc_action.go @@ -431,6 +431,7 @@ func newDataDownload( BackupStorageLocation: dataUploadResult.BackupStorageLocation, DataMover: dataUploadResult.DataMover, SnapshotID: dataUploadResult.SnapshotID, + SnapshotSize: dataUploadResult.SnapshotSize, SourceNamespace: dataUploadResult.SourceNamespace, OperationTimeout: backup.Spec.CSISnapshotTimeout, NodeOS: dataUploadResult.NodeOS, diff --git a/pkg/restore/actions/dataupload_retrieve_action.go b/pkg/restore/actions/dataupload_retrieve_action.go index ef8bcb333..e0be8e20f 100644 --- a/pkg/restore/actions/dataupload_retrieve_action.go +++ b/pkg/restore/actions/dataupload_retrieve_action.go @@ -72,10 +72,16 @@ func (d *DataUploadRetrieveAction) Execute(input *velero.RestoreItemActionExecut return nil, errors.Wrapf(err, "error to get backup for restore %s", input.Restore.Name) } + snapshotSize := dataUpload.Status.SnapshotSize + if snapshotSize == 0 { + snapshotSize = dataUpload.Status.Progress.TotalBytes + } + dataUploadResult := velerov2alpha1.DataUploadResult{ BackupStorageLocation: backup.Spec.StorageLocation, DataMover: dataUpload.Spec.DataMover, SnapshotID: dataUpload.Status.SnapshotID, + SnapshotSize: snapshotSize, SourceNamespace: dataUpload.Spec.SourceNamespace, DataMoverResult: dataUpload.Status.DataMoverResult, NodeOS: dataUpload.Status.NodeOS, diff --git a/pkg/restore/actions/dataupload_retrieve_action_test.go b/pkg/restore/actions/dataupload_retrieve_action_test.go index ef5e6dad6..68c9eacf2 100644 --- a/pkg/restore/actions/dataupload_retrieve_action_test.go +++ b/pkg/restore/actions/dataupload_retrieve_action_test.go @@ -58,13 +58,13 @@ func TestDataUploadRetrieveActionExectue(t *testing.T) { }, { name: "DataUploadRetrieve Action test", - dataUpload: builder.ForDataUpload("velero", "testDU").SourceNamespace("testNamespace").SourcePVC("testPVC").Result(), + dataUpload: builder.ForDataUpload("velero", "testDU").SourceNamespace("testNamespace").SourcePVC("testPVC").SnapshotID("fake-id").SnapshotSize(1000).Result(), restore: builder.ForRestore("velero", "testRestore").ObjectMeta(builder.WithUID("testingUID")).Backup("testBackup").Result(), runtimeScheme: scheme, veleroObjs: []runtime.Object{ builder.ForBackup("velero", "testBackup").StorageLocation("testLocation").Result(), }, - expectedDataUploadResult: builder.ForConfigMap("velero", "").ObjectMeta(builder.WithGenerateName("testDU-"), builder.WithLabels(velerov1.PVCNamespaceNameLabel, "testNamespace.testPVC", velerov1.RestoreUIDLabel, "testingUID", velerov1.ResourceUsageLabel, string(velerov1.VeleroResourceUsageDataUploadResult))).Data("testingUID", `{"backupStorageLocation":"testLocation","sourceNamespace":"testNamespace"}`).Result(), + expectedDataUploadResult: builder.ForConfigMap("velero", "").ObjectMeta(builder.WithGenerateName("testDU-"), builder.WithLabels(velerov1.PVCNamespaceNameLabel, "testNamespace.testPVC", velerov1.RestoreUIDLabel, "testingUID", velerov1.ResourceUsageLabel, string(velerov1.VeleroResourceUsageDataUploadResult))).Data("testingUID", `{"backupStorageLocation":"testLocation","snapshotID":"fake-id","sourceNamespace":"testNamespace","snapshotSize":1000}`).Result(), }, { name: "Long source namespace and PVC name should also work", @@ -76,6 +76,16 @@ func TestDataUploadRetrieveActionExectue(t *testing.T) { }, expectedDataUploadResult: builder.ForConfigMap("velero", "").ObjectMeta(builder.WithGenerateName("testDU-"), builder.WithLabels(velerov1.PVCNamespaceNameLabel, "migre209d0da-49c7-45ba-8d5a-3e59fd591ec1.kibishii-data-ki152333", velerov1.RestoreUIDLabel, "testingUID", velerov1.ResourceUsageLabel, string(velerov1.VeleroResourceUsageDataUploadResult))).Data("testingUID", `{"backupStorageLocation":"testLocation","sourceNamespace":"migre209d0da-49c7-45ba-8d5a-3e59fd591ec1"}`).Result(), }, + { + name: "snapshotSize is zero", + dataUpload: builder.ForDataUpload("velero", "testDU").SourceNamespace("testNamespace").SourcePVC("testPVC").TotalBytes(2000).Result(), + restore: builder.ForRestore("velero", "testRestore").ObjectMeta(builder.WithUID("testingUID")).Backup("testBackup").Result(), + runtimeScheme: scheme, + veleroObjs: []runtime.Object{ + builder.ForBackup("velero", "testBackup").StorageLocation("testLocation").Result(), + }, + expectedDataUploadResult: builder.ForConfigMap("velero", "").ObjectMeta(builder.WithGenerateName("testDU-"), builder.WithLabels(velerov1.PVCNamespaceNameLabel, "testNamespace.testPVC", velerov1.RestoreUIDLabel, "testingUID", velerov1.ResourceUsageLabel, string(velerov1.VeleroResourceUsageDataUploadResult))).Data("testingUID", `{"backupStorageLocation":"testLocation","sourceNamespace":"testNamespace","snapshotSize":2000}`).Result(), + }, } for _, tc := range tests { From 2aa319aa302b36ba5b2b02147eea79cf44ceb16b Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Tue, 21 Oct 2025 16:48:48 +0800 Subject: [PATCH 065/104] add snapshot size to data mover CRs Signed-off-by: Lyndon-Li --- changelogs/unreleased/9354-Lyndon-Li | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/unreleased/9354-Lyndon-Li diff --git a/changelogs/unreleased/9354-Lyndon-Li b/changelogs/unreleased/9354-Lyndon-Li new file mode 100644 index 000000000..e0688c17a --- /dev/null +++ b/changelogs/unreleased/9354-Lyndon-Li @@ -0,0 +1 @@ +Add snapshotSize for DataUpload, DataDownload, PodVolumeBackup, PodVolumeRestore \ No newline at end of file From 6dbe77259060f446fc7e5af22f3e471225071811 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Wed, 22 Oct 2025 12:05:12 +0800 Subject: [PATCH 066/104] snapshot size in restore CRs only Signed-off-by: Lyndon-Li --- changelogs/unreleased/9354-Lyndon-Li | 2 +- config/crd/v1/bases/velero.io_podvolumebackups.yaml | 4 ---- config/crd/v1/crds/crds.go | 2 +- config/crd/v2alpha1/bases/velero.io_datauploads.yaml | 4 ---- config/crd/v2alpha1/crds/crds.go | 2 +- pkg/apis/velero/v1/pod_volume_backup_types.go | 4 ---- pkg/apis/velero/v2alpha1/data_upload_types.go | 4 ---- pkg/builder/data_upload_builder.go | 8 +------- pkg/controller/data_upload_controller.go | 1 - pkg/controller/data_upload_controller_test.go | 2 -- pkg/controller/pod_volume_backup_controller.go | 1 - pkg/podvolume/util.go | 7 +------ pkg/restore/actions/dataupload_retrieve_action.go | 7 +------ .../actions/dataupload_retrieve_action_test.go | 12 +----------- 14 files changed, 7 insertions(+), 53 deletions(-) diff --git a/changelogs/unreleased/9354-Lyndon-Li b/changelogs/unreleased/9354-Lyndon-Li index e0688c17a..33871a2c3 100644 --- a/changelogs/unreleased/9354-Lyndon-Li +++ b/changelogs/unreleased/9354-Lyndon-Li @@ -1 +1 @@ -Add snapshotSize for DataUpload, DataDownload, PodVolumeBackup, PodVolumeRestore \ No newline at end of file +Add snapshotSize for DataDownload, PodVolumeRestore \ No newline at end of file diff --git a/config/crd/v1/bases/velero.io_podvolumebackups.yaml b/config/crd/v1/bases/velero.io_podvolumebackups.yaml index 714f567c3..f77c5df4a 100644 --- a/config/crd/v1/bases/velero.io_podvolumebackups.yaml +++ b/config/crd/v1/bases/velero.io_podvolumebackups.yaml @@ -225,10 +225,6 @@ spec: description: SnapshotID is the identifier for the snapshot of the pod volume. type: string - snapshotSize: - description: SnapshotSize is the logical size of the snapshot. - format: int64 - type: integer startTimestamp: description: |- StartTimestamp records the time a backup was started. diff --git a/config/crd/v1/crds/crds.go b/config/crd/v1/crds/crds.go index 84ba2e746..bc688fad2 100644 --- a/config/crd/v1/crds/crds.go +++ b/config/crd/v1/crds/crds.go @@ -34,7 +34,7 @@ var rawCRDs = [][]byte{ []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xccYK\x8f\x1b\xb9\x11\xbe\xebW\x14v\x0f{ٖ\xec\x04\t\x02\xdd\xc6r\x02\x18\x19\xc7\x03k2\xb9.EVK\\\xb1\xc9\x0e\x1f\x92\x95\xc7\x7f\x0f\x8a\x0f\xa9\xd5\x0fK\xe3\x04\x9b\xe5eF|\x14\xeb\xf9U\x15\xbb\xaa\xaa\x19k\xe5\vZ'\x8d^\x02k%~\xf1\xa8闛\xef\xff\xe0\xe6\xd2,\x0eog{\xa9\xc5\x12V\xc1y\xd3|Fg\x82\xe5\xf8\x1ek\xa9\xa5\x97F\xcf\x1a\xf4L0ϖ3\x00\xa6\xb5\xf1\x8c\xa6\x1d\xfd\x04\xe0F{k\x94B[mQ\xcf\xf7a\x83\x9b \x95@\x1b\x89\x97\xab\x0fo\xe6o\x7f?\xff\xdd\f@\xb3\x06\x97\xb0a|\x1fZ\xe7\x8de[T\x86'\x92\xf3\x03*\xb4f.\xcd̵\xc8醭5\xa1]\xc2e!Qȷ'\xce\xdfEb\xebD\xec1\x13\x8b\xebJ:\xff\xe7\xe9=\x8f\xd2\xf9\xb8\xafU\xc125\xc5V\xdc\xe2v\xc6\xfa\xbf\\\xae\xae`\xe3TZ\x91z\x1b\x14\xb3\x13\xc7g\x00\x8e\x9b\x16\x97\x10O\xb7\x8c\xa3\x98\x01d\xd5Dj\x150!\xa2\xb2\x99z\xb2R{\xb4+\xa3B\xa3\xcfw\tt\xdc\xca\xd6Ge&Y \v\x03E\x1ap\x9e\xf9\xe0\xc0\x05\xbe\x03\xe6\xe0\xe1\xc0\xa4b\x1b\x85\x8b\xbfjV\xfe\x8f\xf4\x00~vF?1\xbf[\xc2<\x9d\x9a\xb7;\xe6\xcaj\xb2\xd1SgƟH\x00\xe7\xad\xd4\xdb1\x96\x1e\x99\xf3/LI\x119y\x96\r\x82t\xe0w\b\x8a9\x0f\x9e&\xe8W\xd2\x10\x90\x8a\x10\x8a\x86\xe0\xc8\\\xbe\a\xe0\x90\xa8D\x1d\x8ds\xaa\x06w]\xb1M\xac\xc0K\x8fJ\xe2\x9ff2\xf7\x1d\xb2ſ\xe7\xdc♤\xf3\xaci\xaf\xe8>lq\x8aؕ*\xdec͂\xf2]Q\xc9J\xaa\xeb\x97\xd7b\xb5\xc8\xe7\"\x9d\xba\xba\xf1\xfd\xd5\\\xbauc\x8cB\x96\xa8\xa4]\x87\xb7\xc9\v\xf9\x0e\x1b\xb6̛M\x8b\xfa\xe1\xe9\xc3\xcbo\xd7W\xd30\xe6H\xbd\xa0 ñ\x8emvh\x11^b\xfc%\xbb\xb9,ڙ&\x80\xd9\xfc\x8c\xdc_\x8c\xd8ZӢ\xf5\xb2\x04K\x1a\x1d,\xea\xcc\xf6x\xfaWu\xb5\x06@b\xa4S \b\x940\xf9U\x8e\x1f\x14Yr05\xf8\x9dt`\xb1\xb5\xe8P'\x98\xa2i\xa63\x83\xf3\x1e\xe95Z\"C\xb1\x1d\x94 ,;\xa0\xf5`\x91\x9b\xad\x96\xff8\xd3v\xe0Mvf\x8f\xceC\x8cP\xcd\x149k\xc0\x1f\x81iѣܰ\x13X\xa4;!\xe8\x0e\xbdx\xc0\xf5\xf9\xf8H\xd1 um\x96\xb0\xf3\xbeu\xcb\xc5b+}Ahn\x9a&h\xe9O\x8b\b\xb6r\x13\xbc\xb1n!\xf0\x80j\xe1\xe4\xb6b\x96\xef\xa4G\xee\x83\xc5\x05ke\x15\x05\xd1\tR\x1b\xf1\xbd͘\uebae\x1d\x84t\x1a\x11R_a\x1e\x82\xd7\xe42\x89T\x12\xf1b\x05\x9a\"\xd5}\xfe\xe3\xfa\x19\n'\xc9R\xc9(\x97\xad\x03\xbd\x14\xfb\x906\xa5\xaeѦs\xb55M\xa4\x89Z\xb4Fj\x1f\x7fp%Q{pa\xd3HOn\xf0\xf7\x80Γ\xe9\xfadW1\x8b\xc1\x06!\xb4\x11$\xfa\x1b>hX\xb1\x06Պ9\xfc\x85mEVq\x15\x19\xe1.kuss\x7fsRog\xa1\xe4\xd4\tӎ\xa2\xc1\xbaE~\x15w\x02\x9d\xb4\x14\x19\x9ey\x8c\xd1\xd5SP\x86\x8a\xe9\xa4\\\xc68H\xd0`\x9c\xa3s\x1f\x8d\xc0\xfeJ\x8f\xe5\x87\xf3\xc6+\x1e[\xb4\x8dt1\xbdBml?\xf3\xb03\x92wGA\xbc\xbe\xc1\x01P\x87f\xc8H\x05\x9f\x91\x89OZ\x9d&\x96\xfef\xa5\x1f^4aH\x1a\x89\xc5\xf5I\xf3'\xb4҈\x1b¿\xebm?\xab`g\x8ePG\xff\xd7^\x9d\b\xbb\xdcI\xf3!j\x97\xf1\xf0\xf4\xa1 x\x8a\xad\x1c\x98YWsx\xc8Amjx\x03B:*$\\$:T\x96\x0e*\x16\x1aK\xf06\xbcJ|nt-\xb7C\xa1\xbb\xb5є\xc7\xdc \xdd\xd3\xdc*\xdeD\xa8E\xde\xd1Zs\x90\x02mE\xf1!k\xc93'\xc1\xa6\fRKTb\x80M\x93Q\x16E\xb1((\xa8\x99\xbaa\xc3\xd5yc\xac\xa4\x99\xd4Ƀ/\x04\"\xd6\xd8&\xa7f\xedQ\v\xecg\x9bȍ\x89\x80\xe6P\xc0Q\xfa]BJ5\x16w\xf0\xd5أ\xb1\xc7\xd3\xd8t\x8f\xf7\xe7\x1d\xd2Δx\x11\x1cr\x8b>z\x1b*r\x1fr\xa59\xc0\xc7\xe0\"\xd6\xf6q\xa2\x8cX\xf0\x95\xd3{<\r\x15\r\xb7\x8c\x9bK\xa1\t\x96c\x11\xb5\x84ᄏ-\xd2 \xbb\x95A\xa5{\x11\xd4b\x8d\x16\xf5\xa0\x9a(\xe39\xe6(r\x1a\xf20\xack\xe4^\x1eP\x9dbN\"\xf0\xfc\x116\xc1\x83\b\x18\xad\xc6\xf8\xfeȬp\xc0M\xd32/7RI\x7f\x02\xe9&\xe83\xa5\xcc\x11E\xb686\xad?\xcd\xe1\x83v\x9ei\x8e\xee\\\a\x91ƒ+0\x9dv\xe5(\x8e\x05\x1d\xb3c\x18\x98\xc87\xc6y\xe0h\xc9\x1d\xd5\t\x8e\xd6\xe8픰#\xe9\x90z@\xab\xd1c̈\xc2pGɐc\xeb\xdd\xc2\x1c\xd0\x1e$\x1e\x17Gc\xf7Ro+b\xb0\xcaೈ\x9d\xdd\xe2\xfb\xf8\xe7[\xbc\xc0\xb4\t'\xeep\xdeu\x8c\xf5\x13\x95\xb7~\x87)E\xac\x93\x0f\x1a\vT@\x90k7\xd9w\x13\xb2\x8e\x85\xddX]\xde\x1d\xc5\xe4c\xf9c\x8f\xc3\xd4\xf1\x15P\x01\xf8R]t[5\xac\xad\xd2n\xe6M#\xf9\xac/m\xf2\xfb\xaf\xe3OiV\xa4\x16\x92Sq{\x8d\x1b\xa5\x89\x13W=͈\x1a\xfa]\xce\x14Z\x8e\xab)\x89\x9bk\x85\x1b\x1c\x7f\xea\uef74\xbe\t\xbas\xfew\xe8\xa9\xeet\xa0\x91\xea\x03f\x87z\x8e\x80ɍքT\xde\x00;\xa7\x81\x1f\\?\xff\xbd\x12=7\x81\xefqD\xf1\x03Q\xdeōE\xc7\xe9\x18\xf1\x12\x1c\xc6\xc4t\x8b\r\xb8\x1d\x11\x9c\xad\xd0\xde\xc3\xcb\xea\x816\x9eK\b\x06\xab\a\xd8\x04-\x14\x16\x8e\x8e;\xd4\xd4u\xc9\xfa4~\x17\x8d\xe7\xc7u\xd1j\xac\xber\xdfTt;.C\xcaoK\u061cF\xea\xa5;\x84l-\xd6\xf2\xcb\x1dB>ōE\xe1-\xf3;\x90\xdaI\x81\xc0Fԟ\n\xd9\tAϵѧ\x8c9\xdf`\x9e\xafaCb\xe75\xf0Pt|#~\x9e\xf2\xb6\xb3\x16\xca\xef\x9cݮ\xeb\xe4\xa98\x1e\x95\xe8p~\x94\xf9S\xaa>\xf9H\x19q\xc5\xcc\xcb\xf0\xc4W\xaa\xd8\xf244\x16\xccT3\x19kѵF\v\xea9\xef\xaba/,\xff\xef*\xd9q\xb3V\xd7(\xd7[+V\xb8\xab\x8d\x8b\xcf`\xafn\xe4\xd2\xe3`\xb7M2\x1bG\r\xf6\xa5\x97\xeb\xc9\xf8\x8b\xb4p\xa3%W\xa7\xaf\x93\x8eꗠce\x1b\xab\xaa\xf9l\xe4\xc4{l-R\x06\x13K\x92\xcdƃ\xda\x1c\xe9p\x87Z*ˌN\xf9\x9ez[\xa6E~U\xa0\xa5\x11\xcaG\xa9\x14\xd5\x00\x16\x1bCʢ\xb2\xdcR5\xc7b\xadu\xf8\xcd\xfc\xcd\xff\xafeT\xccy\xea\x00Q|ƃ\x1c>\xadݧ\xee\xc7\x01\x95\x82\x0e瘡\x1f?\x95׆\x85\xcd\xdb~\x82Z*\xaa\xff:\xd0qGu0\xf20\xfcn\xfd\xf8\x83\x8b=\x10j\xef\xe0H\x16t\x91%jzL~\xe1\t\xceS\x12\xb9i\xffn\x01\xae\r(\xa3\xb7h\xcbk\x0f\x15xɛ\x8c\x05\x81\x9er\x95\xde\x02\xdf1\xbd\xa5\xc8\x18\x83\xfc\xc8p\xe6\xbe\xcb'yϤ\x83H=\xe1\x1dw\x19\xf4Y\x8e\xb54\xaf1\xe6\xf43\xfc\x99\xffl\xd9\xcbkoO\xefSP[,\xd1_,\xa9\x9c\x14]\xf9\xcb\xd3\xfce|\xfb\xfb\xc0\xf0\xdd\xff[\xd5\xf3_}\xa9\x18|\xa1\xf8U(\xa7\xa1:\xf7f\xf1\xfc1\xedJ\xef\xb5\xf9\b\xb0\x8d\t~$\xf7w\x1c~4\xa6\xe3ǘ\xd7\xf0\x18?1\xdd*OhO\xb1\b\x0f\xd6\xc67\xdd\xf2\xd6\x18\x91b,+ݏ\xc0\x0f\xbd/aݵ\xe1w\xb2;\xe4\x1a\xcd҃ɔi;v\xcdJ\xee΄\xcd\xf9\xa5~\t\xff\xfc\xf7\xec?\x01\x00\x00\xff\xff\x03f\x86Y\xc0\x1d\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcVMo\x1b7\x10\xbd\xebW\f\xd0kwU\xa3hQ\xec\xadqr0\xda\x06\x82\x1d\xe4N\x91#-c.\xc9\xce\f\xe5\xba\x1f\xff\xbd \xb9+K\xab\x95\x93\\\xb27\x91Ù\xc7\xf7f\x1e\xd54\xcdJE\xfb\x11\x89m\xf0\x1d\xa8h\xf1/A\x9f\x7fq\xfb\xf8\v\xb76\xac\x0f7\xabG\xebM\a\xb7\x89%\f\xf7\xc8!\x91Ʒ\xb8\xb3ފ\r~5\xa0(\xa3Du+\x00\xe5}\x10\x95\x979\xff\x04\xd0\xc1\v\x05琚=\xfa\xf61mq\x9b\xac3H%\xf9T\xfa\xf0C{\xf3s\xfb\xd3\n\xc0\xab\x01;0\xe8Pp\xab\xf4c\x8a\x84\x7f&d\xe1\xf6\x80\x0e)\xb46\xac8\xa2\xce\xf9\xf7\x14R\xec\xe0e\xa3\x9e\x1fkW\xdcoK\xaa7%\xd5}MUv\x9de\xf9\xedZ\xc4\xefv\x8c\x8a.\x91rˀJ\x00[\xbfON\xd1b\xc8\n\x80u\x88\xd8\xc1\xfb\f+*\x8df\x050^\xbb\xc0l@\x19S\x88TnC\xd6\v\xd2mpi\x98\bl\xc0 k\xb2Q\nQ\x1fz,W\x84\xb0\x03\xe9\x11j9\x90\x00[\x1c\x11\x98r\x0e\xe0\x13\a\xbfQ\xd2w\xd0f\xbe\xda\x1a\x9a\x81\x8c\x01\x95\xea7\xf3ey\u0380Y\xc8\xfa\xfd5\b,J\x12O J]\x1b<\xd0\t\xbf\xe7\x00J|\x1b{\xc5\xe7\xd5\x1f\xcaƵ\xca5\xe6pS\x99\xd6=\x0e\xaa\x1bcCD\xff\xeb\xe6\xee\xe3\x8f\x0fg\xcbp\x8euAZ\xb0\fjB\x9a\x89\xab\xacA\xf0\b\x81`\b4\xb1\xca\xed1i\xa4\x10\x91\xc4N\xadU\xbf\x93\xe19Y\x9dA\xf8\xb79\xdb\x03Ȩ\xeb)0y\x8a\x90\v\x89cS\xa0\x19/Zɵ\f\x84\x91\x90\xd1\u05f9\xca\xcb\xcaC\xd8~B-\xed,\xf5\x03RN\x03܇\xe4L\x1e\xbe\x03\x92\x00\xa1\x0e{o\xff>\xe6\xe6|\xef\\\xd4))\x94\xe4\xb6\xf3\xca\xc1A\xb9\x84߃\xf2f\x96yP\xcf@\x98kB\xf2'\xf9\xca\x01\x9e\xe3\xf8#\x93h\xfd.tЋD\xee\xd6뽕\xc9Rt\x18\x86\xe4\xad<\xaf\x8b;\xd8m\x92@\xbc6x@\xb7f\xbbo\x14\xe9\xde\njI\x84k\x15mS.⋭\xb4\x83\xf9\x8eF\x13Ⳳ\x17\xddS\xbf\xe2\x02_!O\xf6\x84\xda#5U\xbd\xe2\x8b\ny)Sw\xff\xee\xe1\x03LH\xaaRU\x94\x97\xd0\v^&}2\x9b\xd6\xef\x90\xea\xb9\x1d\x85\xa1\xe4Dob\xb0^\xca\x0f\xed,z\x01N\xdb\xc1\nO\x1d\x9b\xa5\x9b\xa7\xbd-\xb6\x9b\x1d E\xa3\x04\xcd<\xe0\xceí\x1a\xd0\xdd*\xc6o\xacUV\x85\x9b,\xc2\x17\xa9u\xfa\x98̃+\xbd'\x1b\xd33pEڅ\xe1\x7f\x88\xa8\xb3\xb8\x99\xdf|\xda\ueb2ec\xb5\v\x04O\xbd\xd5\xfd4\xfc3\x9a\x8eFq\xce߲1\xe4\xef\xc5n\xe7;W/\x0fEdK8k\xd8\x06.\xbc\xfbu^\x8a\xa9~%3\xd5\xd1Gnt\"*\xcdw\xf4y\xb5t\xe8K\xb9@\xa2@\x17\xab3P\xefJP\xf9Ǡ\xacgP\xfey<\b\xd2+\x81'\xa4\r\x97\x95\x1ax\x8fO\v\xabw~CaO\xc8\xf3\x96ϛ\x9b\xca\x1e\xce߃WXZlʋE\xceVhNXd\t\xa4\xf6\xa7\xbcr\xda\x1e\x9d\xbe\x83\x7f\xfe[\xfd\x1f\x00\x00\xff\xff\xbeM\x1a\xea\xb1\n\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcWMo\xe36\x10\xbd\xfbW\f\xd0K\v\xac\xe4\x06E\x8b·\xd6\xd9C\xb0\xe96\x88\xb7\xb9S\xd4HbC\x91,9t6E\x7f|1\xa4\xe4\x0fYv\x9c\xcb\xea\xe6\xe1p\xf8\xe6\xcd\xcc#]\x14\xc5B8\xf5\x84>(kV \x9c¯\x84\x86\x7f\x85\xf2\xf9\xd7P*\xbb\xdc\xde,\x9e\x95\xa9W\xb0\x8e\x81l\xff\x88\xc1F/\xf1\x16\x1be\x14)k\x16=\x92\xa8\x05\x89\xd5\x02@\x18cI\xb09\xf0O\x00i\ry\xab5\xfa\xa2ES>\xc7\n\xab\xa8t\x8d>\x05\x1f\x8f\xde\xfeX\xde\xfcR\xfe\xbc\x000\xa2\xc7\x15\xd4\xf6\xc5h+j\x8f\xffD\f\x14\xca-j\xf4\xb6Tv\x11\x1cJ\x8e\xddz\x1b\xdd\n\xf6\vy\xefpn\xc6|;\x84y\xccaҊV\x81>ͭޫ\xc1\xc3\xe9\xe8\x85>\x05\x91\x16\x832m\xd4\u009f,/\x00\x82\xb4\x0eW\xf0\x99a8!\xb1^\x00\f)&XŐ\xdd\xf6&\x87\x92\x1d\xf6\"\xe3\x05\xb0\x0e\xcdo\x0fwO?m\x8e\xcc\x005\x06镣D\xd4\x7f\xc5\xce\x0e\xd3\x04@\x05\x100\xc0\x01\xb2;\x84 \f\bO\xaa\x11\x92\xa0\xf1\xb6\x87J\xc8\xe7\xe8\xc0V\x7f\xa3$\bd\xbdh\xf1\x03\x84(;\x10\x1c%;\x1c\x9c\xa5m\v\x8d\xd2X\xeel\xce[\x87\x9e\xd4Hy\xfe\x0e\x1a\xea\xc0z)\v\xfe8\xf1\xbc\vj\xee,\f@\x1d\x8e\xe4a=p\x05\xb6\x01\xeaT\x00\x8f\xcec@\x93{\x8d\xcd\xc2\fٔ\x93\xd0\x1b\xf4\x1c\x06Bg\xa3\xae\xb9!\xb7\xe8\t\x1aE\xaf\xcb41\xaa\x8ad}XָE\xbd\f\xaa-\x84\x97\x9d\"\x94\x14=.\x85SEJĤQ+\xfb\xfa;?\ff8:\x96^\xb9!\x03yeڃ\x854\x1d\xef(\x0f\xcfK\xee\xae\x1c*\xa7\xb8\xaf\x02\x9b\x98\xbaǏ\x9b/0\"ɕ\x1aZl\xe7z\xc2\xcbX\x1ffS\x99\x06}ޗڔc\xa2\xa9\x9dU\x86\xd2\x0f\xa9\x15\x1a\x82\x10\xab^Q\x18{\x9dK7\r\xbbNR\x04\x15Bt\xb5 \xac\xa7\x0ew\x06֢G\xbd\x16\x01\xbfq\xad\xb8*\xa1\xe0\"\\U\xadC\x81\x9d:gz\x0f\x16Fy&j^\x01\x128\xe1[\xa4\xa9u\x82\xe5Kr\xe2\xe3_:q,X\xdfcٖ\xac9a\x00\x92\xf5\xe8\x87i\xa1.a\x80\xd9F\x9fE2\xf67\xd3\xc0\xbc\xb2\xa0\xb0\xd8\x1db:=\x9a?4\xb1\x9f?\xa0\x80\xdf\x13\xe6{\xdb^\\_[C<\x17\x17\x9d\x9e\xac\x8e=n\x8cp\xa1\xb3o\xf8\xde\x11\xf6\x7f:\xf4\xf9\x1a\xbe\xe8:\xde滫\xef\x82c\xd4g\xcf}D\xbeA\xf0|\xa6\x83\xc3UQ\xae\xc04x^\x95\xe8zs\xf7\x1e\nϸ\xbf\xa3Hw\xa6\xb1o\xa4\xb8w\x9c\xf5;#\x03\xe3\x97\xde\x10o\xf74\xbfBƞ\xe6-\xf9\xeeD\xf8\x14+\xf4\x06\t\xc3^\xa9_\x14u\xb3\x11\x01^:%\xbb\xb41\r\x04_\x02!X\xa9\xe6$\xf5\n\xf8\xac#\xca\xe3\xccP\x16iXg\xcc\f\xfe\xc4|F\xfd\xce\x1dP\f\x8at\x95\x82\x92\xa0\x18ޡ\xa1\xc9\x7f\xa4ZF\xef\xd3\x15\x95\xad\xfc2\x99n\xb8VDG\xe5\xf9\xeb\xf1\xfe\r%\xbd\xdd{\xa6\x17\xb7P&\xa3q\x1e\x8b\xa0Z~A\xf1\x1akiҸS2\xf2w\xfc\xc2;&j\xb6\xa2\xf8թ<\x80o@\xfc\xb8ŝ\x8f&\xdf\xf3\xd37l\n\x88\x81\x9f[ \x85\x99\xc1X!Ԩ\x91\xb0\x86\xea5\xdf\\\xaf\x81\xb0?\xc5\xddX\xdf\vZ\x01\xdf\xff\x05\xa9\x9962QkQi\\\x01\xf9x\xae\xcbf\x13w\x9d\b3cx\x94\xf3\x03\xfb\xcc5\xc6n\x18/v\x06\x9c\xbd_\n\xf8\x8c/3\xd6\ao%\x86\x80\xa7ct6\x93\xd9!81\x06~\xa4\xd5\a,\r\x7f\x19\x06\xcb\xff\x01\x00\x00\xff\xffx\xae@\xbaJ\x0e\x00\x00"), - []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4ZK\x93\x1b\xb7\x11\xbe\xef\xaf\xe8Z\x1flWi\xc8HI\\)ޤU\x9c\xda\xc4V\xb6ĕ..\x1f\xc0A\x93\x03\xef\f\x80\x00\x18R\xb4\xe3\xff\x9ej<\x86\xf3\x00\xc9]*\xf2\xcee\x97x\xf44\xbe~7\xa6(\x8a+\xa6\xc5G4V(\xb9\x00\xa6\x05~r(闝=\xfc\xcd΄\x9ao_^=\b\xc9\x17p\xd3Z\xa7\x9a\xf7hUkJ|\x8bk!\x85\x13J^5\xe8\x18g\x8e-\xae\x00\x98\x94\xca1\x1a\xb6\xf4\x13\xa0T\xd2\x19U\xd7h\x8a\r\xca\xd9C\xbb\xc2U+j\x8e\xc6\x13O\xaf\xde\xfei\xf6\xf2\xbb\xd9_\xaf\x00$kp\x01Z\xf1\xad\xaa\xdb\x06W\xac|h\xb5\x9dm\xb1F\xa3fB]Y\x8d%\xd1\xde\x18\xd5\xea\x05\x1c&\xc2\xde\xf8\xde\xc0\xf3\x9d\xe2\x1f=\x997\x9e\x8c\x9f\xa9\x85u\xff\xca\xcd\xfe \xac\xf3+t\xdd\x1aVO\x99\xf0\x93V\xc8M[33\x99\xbe\x02\xb0\xa5Ҹ\x80wĆf%\xf2+\x80xD\xcfV\x01\x8cs\x0f\x1a\xab\uf310\x0e\xcd\rQH`\x15\xc0іFh\xe7A\x19\xf1\a\xd61\xd7Z\xb0mY\x01\xb3\xf0\x0ew\xf3[yg\xd4Ơ\r\xcc\x01\xfcb\x95\xbcc\xaeZ\xc0,,\x9f\xe9\x8aY\x8c\xb3\x01ܥ\x9f\x88CnO,[g\x84\xdc䘸\x17\r\x02o\x8d\x17*\x9d\xbeDp\x95\xb0\x13\xeev\xcc\x12\x87\xc6\xf9c\xe7y\xf1\xf3D\xd1:\xd6\xe81S\xbd\xad\x81+\xce\x1c\xe6x\xbaQ\x8d\xae\xd1!\x87\xd5\xdea:\xc9Z\x99\x86\xb9\x05\b\xe9\xbe\xfb\xcbq8\"^3\xbf\xf5\xad\x92Cl\xde\xd0(\xf4\x86\x03'$\xab\r\x9a,@ʱ\xfas\x18qD\xe0Mo\x7f\xe0$\xd0폟e\x85\x14\x0f\xd4\x1a\\\x85\x10\xa5\xb2tʰ\r\xc2\x0f\xaa\f\x12\xdcUh\xa2\x04WQ\xad*\xd5\xd6\x1cV\xe9\xc4\x00\xd6)\x93\x95\xa2\xc6r\x16vE\xba\x89\xecH\x94\xc3w~\tM+\r\xb2\xac\xa6%o4\xf3+\x84\x92yu{\xbd\xc1G\xa9Z\x1fR\xa98v\xf8\xe1\x84-aA\x1bU\xa2\xb5',\x80h\f\x18yw\x188\vP\x85~M\xe2\xa7յb\x1c\r8\x05\x15\x93\xbcF:\x06\x03g\x98\xb4\xeb\xa8\"S\x01\xa6m\xf7{=d\xe5C\x9c8\xc6NX\xb5}\x19\xfc`Ya\xc3\x16q\xad\xd2(_\xdf\xdd~\xfc\xf3r0\f\x84\x88F\xe3D\xf2\xcb\xe1\xe9E\x9d\xde(\f\x8f\xfb\xdfb0\a@/\b\xbb\x80S\xf8A\xeba\x88\x1e\x16y\xe4)\xc0#,\x18\xd4\x06-\xca\x10\x90h\x98IP\xab_\xb0t\xb3\x11\xe9%\x1a\"\x93l\xa1Tr\x8bƁ\xc1Rm\xa4\xf8\xb5\xa3m\tkzi\xcd\x1cZ\xe7\x8d\xd1HVÖ\xd5-\xbe\x00&\xf9\x88r\xc3\xf6`\x90\xde\t\xad\xec\xd1\xf3\x1b옏\x1f\x95A\x10r\xad\x16P9\xa7\xedb>\xdf\b\x97bq\xa9\x9a\xa6\x95\xc2\xed\xe7>\xac\x8aU딱s\x8e[\xac\xe7Vl\nf\xcaJ8,]kpδ(\xfcA\xa4\x8fdz\x86\x7feb\xf4\xb6\x83\xd7N\x04\x1d\x1e\x1fB\x9f \x1e\n\xaad\x04,\x92\nGI\x1cZ\xf13|\xc5720\xb8F\x83>\x1b\t\xbe_+\x1f!\x1c\x132\xf9\xb4P\b\x80S\x19\xceVA\x89\x90\xc3\xd86\xe0\xa4}\xc0\x89@\x99\xe5\xf8\xf5\xddm\n\x86\t\xc4\xc8\xfb$ޝŇ\x9e\xb5\xc0\x9a\xfb\xcc\xe1\xfc\xbb\xb3\x9aK\xcf\xed:0\xe1#\x82S\xc0@\v,q\x10\x8dAH\xeb\x90\xf18HN\xd0`\x9c{\x11<\xfdQ&\xe99Dm\x92\t0\x8a<\x82\xc3?\x97\xff~7\xff\x87\n\xe7\x00VRj\xe6\x8b(lP\xba\x17]!\xc5\xd1\n\x83\x9c\xca\"\x9c5L\x8a5Z7\x8b\xd4\xd0؟^\xfd\x9c\xc7\x0f\xe0{e\x00?1*G^\x80\b\x98w\xc1,\xa9\x8d\xb0\xe1\xe0\x1dE\xd8\tWyF\xb5\xe2\xf1\x80;\x7f\x04\xc7\x1eȒ\xc3\x11Z\x84Z\x9b;\xb0\xf9\x1bY\xcf\xef\xd7\xf0Mp^\xd7\xf4\xf3:\xb0ѥ-}\x03;\xb0\x13\xac̈\xcd\x06\x0fy\xffDY(\xccR\x80\xfa\x16\x94\xa1\xb3J\xd5#\xe1\t\x93\x9cB|@>a\xef\xa7W?_\xc37C\f\x8e\xbcJH\x8e\x9f\xe0\x15y\x1f\x8f\x8dV\xfc\xdb\x19\xdc{=\xd8K\xc7>ћ\xcaJY\x94\xa0d\xbd\x0f\t\xf0\x16\xc1\xaa\x06a\x87u]\x84\x04\x91Î\xedA\xad\x8f\xbc'\x89\x88T\x93\x81fƝL\x12#\x0e\xa7\x8df\x9a5\xa5\xe7q\xf6⳨GY\xef\xb3e \x8fD\u0097\v\x9f\x81D\xbf\xf4\xba\x00\x89\x87v\x85F\xa2C\x0f\x06W\xa5%\x1cJ\xd4\xce\xce\xd5\x16\xcdV\xe0n\xbeS\xe6A\xc8MA\xcaX\x04\xa9۹o#Ϳ\xf2\x7f.=\xb8\xef\xff|\xee\xe9=\x91烀\xden\xe7\x97 \x90\xb2\xfb\xc7Ǯ\xa38,c\xc29\xa6I6\xbf\xabDY\xa5Z\xaf\xe7m\x1bƃ;fr\xffL\xb6C8\xb7\x868\xda\x17\xb1\aZ0\xc9\xe9\x7f+\xac\xa3\xf1K\x80m\xc5g9\x97\x0f\xb7o\x9fӢZq\x89'9RÄ\xe7Sq\xe0\xaah\x98.\xc2j\xe6T#\xca\xd1j\xca\xe1o9\ti-МI\xff\xde\x0f\x16\xa7\x045S\rtk\x9e\x94\x7f:\xb6\xc9$|\xfd\xf6\xf0\xa9\xb4\xf0$^\xe7U\xe1\x9em,0\x83\xc0\xa0a\x9a4\xe2\x01\xf7E\xc884\x13\x94.PF\xd05\x06\x81i]SL\x0fYD\x86b\xcc\x7f#<\xcc\xfa\xf3\x1d\x03$+\xcaԕZ\xa2sB>#8\x1fF\x8c\xfc\x7f\x81\xeazv\xa5\x92k\xb1\x89\xdd\xce)R\xb2\xadk\xb6\xaaq\x01δ\xc7j\xae\x93@\xdeӒ\xd3\xe7\xff\xd0[\x9a4\xfcL\x831\x7f\xaaA\xdbqz\x18\x94m3e\xa5\x80\a\xa5\x05ˌ\x1b\xb4nb\xbd4q}\xfd\x14\x1b\vJyI\xc9\x1d\xca\xe0\\U\x1a\x15=&\xf0\xa92u\xeaP\xe5e\x85\xfe\x04\xdf@\xd5=\x95#C\xbe\x8b|\xbbd\xb4\xa6\xd7]NCZ\xf1\xd1\xc8\xd0\r\x8e&\xc3\xf9\x1e\xd5C\xf2\r\xed't\x91\xc2\xedU\xc44\x04G\x97\xee\xb4(\xed\xbe\xb4\x8fD\x85\x9dvȻF\xff%\x12\x7f=&\xe2{\xbf\x86G\xa3\x10\rv\xa5\xff\xd0ׅ\xe2n\x85\xa0\rj\x96\xed\n\x81\xef\xdc[\xdf\xc2\xfc\xda\x06b\xc2Bk\x91\xfb\x0e\xda\xe4\xdd\x13\n\xe9F\x893\x87\x05\xed\xbf\xcc_\xe4\x1bS\xe12\xad\x7fSrQ\x97jJf\n!K\xa8\xf9+\x9ct\x8b\x97C\xec@\xae\xc3+PC\xee\xabP*\x92\xd7L\xd4\xc8!]\x11?\x91\xca\nה\xe2\x04\x1f\x97\xfa8\x91\xbd\xe3\xf5\xdfiIf@\x98&<_R\x98\rZ\xcb6\xe7|ޏaUho\xc5-\xc0V\xaauy%\xff\xdaF;}Z\x8b-\xdb9\x1a\xba\b\xe6\xaa\xe4\x11\xd6m]\xfb=}\xe7z\xf8|\xc0s\xb5\xc2|Z|\xa2\xbfv\x8a\xc1\x8a\xd9sP\xddњ\x9c\xd3\xea\"\xc2I\xaf\x05'\xa2\xdf;\xdceF\x933\xc8L\xddE\x0f\x93\x99\x9a|\aП\f\r\xe4\x1cri.K\xb3\xbbe\xcf\xcc}\xefM\xefI`G\xfe.\xf1-]\x03\xbaRur'\xfev\\\xb6\xcd\n\rI\xc2߿\x8f\x824\x93\xbc/\xb6\\\xa5~؟4(P\x8aݦ\xd87\xf7\xf6\xed\x14pau\xcd\xf6\xddY|}DƜ\xbfD8XTr+\x1a\x8f\xe5{\xa7\xdb\xc0ݷ\n\xf9\xe2/\xf7\xc1\xc1\xf0\x99~:0\x9a\xef\xbeA\xf82o8\x91\xafZɴ\xad\x94\xbb}{F5\x96\xdd\xc2d\x8f\x87\xda\xcb{_\x7f?\x15\x17EUȰz\xf0nOr\x16\x89\xf0R\xfcz\xceg,{K\x13\xab\xb5ڈ\x92\xd5`i,\xaai\"9\xe5\xe34ܧ\xa0\x1e~as\x89\xb1-\a\x14\xce\xc4\xf0\xf8\xc1O.R.\xc9Y\x91\x9f\xf4\x97\xb47\xe3\xaf1^t_x0\x17\x9b\xdde\xc5\xe4&\xdbrS\xd2\xd7\x04\xcaLo\xcc\xe1lP\x1e\x1e菌\xc7Y\xad\x9f\fz\xcey\x8fv\xbc\x9f쏴\xab\xee\xea~\x01\xbf\xfd~\xf5\xbf\x00\x00\x00\xff\xffXO骻'\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4ZK\x93\x1b\xb7\x11\xbe\xef\xaf\xe8Z\x1flWi\xc8HI\\)ޤU\x9c\xda\xc4V\xb6ĕ..\x1f\xc0A\x93\x03\xef\f\x80\x00\x18R\x8c\xe3\xff\x9ej<\x86\xf3\x00\xc9]\xca\xf2\xe2\xb2K<\x1a\x8d\xaf\x1b\xfd\xc2\x14EqŴ\xf8\x88\xc6\n%\x17\xc0\xb4\xc0O\x0e%\xfd\xb2\xb3\x87\xbfٙP\xf3\xed˫\a!\xf9\x02nZ\xebT\xf3\x1e\xadjM\x89oq-\xa4pBɫ\x06\x1d\xe3̱\xc5\x15\x00\x93R9Fݖ~\x02\x94J:\xa3\xea\x1aM\xb1A9{hW\xb8jE\xcd\xd1x\xe2i\xeb\xed\x9ff/\xbf\x9b\xfd\xf5\n@\xb2\x06\x17\xa0\x15ߪ\xbamp\xc5ʇV\xdb\xd9\x16k4j&ԕ\xd5X\x12\xed\x8dQ\xad^\xc0a \xac\x8d\xfb\x06\x9e\xef\x14\xff\xe8ɼ\xf1d\xfcH-\xac\xfbWn\xf4\aa\x9d\x9f\xa1\xebְzʄ\x1f\xb4Bnښ\x99\xc9\xf0\x15\x80-\x95\xc6\x05\xbc#64+\x91_\x01\xc4#z\xb6\n`\x9c{\xd0X}g\x84thn\x88B\x02\xab\x00\x8e\xb64B;\x0fʈ?\xb0\x8e\xb9ւm\xcb\n\x98\x85w\xb8\x9b\xdf\xca;\xa36\x06m`\x0e\xe0\x17\xab\xe4\x1ds\xd5\x02fa\xfaLW\xccb\x1c\r\xe0.\xfd@\xecr{b\xd9:#\xe4&\xc7Ľh\x10xk\xbcP\xe9\xf4%\x82\xab\x84\x9dp\xb7c\x9684\xce\x1f;ϋ\x1f'\x8aֱF\x8f\x99\xea-\r\\q\xe60\xc7Ӎjt\x8d\x0e9\xac\xf6\x0e\xd3I\xd6\xca4\xcc-@H\xf7\xdd_\x8e\xc3\x11\xf1\x9a\xf9\xa5o\x95\x1cb\xf3\x86z\xa1\xd7\x1d8!Ym\xd0d\x01R\x8e՟È#\x02oz\xeb\x03'\x81n\xbf\xff,+\xa4x\xa0\xd6\xe0*\x84(\x95\xa5S\x86m\x10~Pe\x90\xe0\xaeB\x13%\xb8\x8ajU\xa9\xb6\xe6\xb0J'\x06\xb0N\x99\xac\x145\x96\xb3\xb0*\xd2MdG\xa2\x1c\xee\xf9%4\xad4Ȳ\x9a\x96\xac\xd1\xcc\xcf\x10J\xe6\xd5\xed\xf5\x06\x1f\xa5j}H\xa5\xe2\xd8\xe1\x87\x13\xb6\x84\x05mT\x89֞\xb8\x01Dc\xc0ȻC\xc7Y\x80*\xf4s\x12?\xad\xae\x15\xe3h\xc0)\xa8\x98\xe45\xd21\x188ä]G\x15\x99\n0-\xbb\xdf\xeb!+\x1f\xe2\xc01v¬\xed\xcb`\a\xcb\n\x1b\xb6\x88s\x95F\xf9\xfa\xee\xf6㟗\x83n D4\x1a'\x92]\x0e\xad\xe7uz\xbd0<\xee\xff\x8a\xc1\x18\x00m\x10V\x01'\xf7\x83\xd6\xc3\x10-,\xf2\xc8S\x80GX0\xa8\rZ\x94\xc1!Q7\x93\xa0V\xbf`\xe9f#\xd2K4D&݅R\xc9-\x1a\a\x06K\xb5\x91\xe2\xbf\x1dmKXӦ5sh\x9d\xbf\x8cF\xb2\x1a\xb6\xacn\xf1\x050\xc9G\x94\x1b\xb6\a\x83\xb4'\xb4\xb2G\xcf/\xb0c>~T\x06AȵZ@圶\x8b\xf9|#\\\xf2ťj\x9aV\n\xb7\x9f{\xb7*V\xadS\xc6\xce9n\xb1\x9e[\xb1)\x98)+\xe1\xb0t\xad\xc19Ӣ\xf0\a\x91\xde\x1f\xcf\x1a\xfe\x95\x89\xde\xdb\x0e\xb6\x9d\b:4\xefB\x9f \x1er\xaat\tX$\x15\x8ex\x90\x02u\x11t\xef\xff\xbe\xbc\x87\xc4I\x90T\x10\xcaa\xea\x04\x97$\x1fBS\xc85\xe9<\xad[\x1b\xd5x\x9a(\xb9VB:\xff\xa3\xac\x05J\a\xb6]5\u0091\x1a\xfc\xa7E\xebHtc\xb27>^\x81\x15\xdd%\xb2\x00|<\xe1V\xc2\rk\xb0\xbea\x16\xff`Y\x91TlABx\x94\xb4\xfaQ\xd8xr\x80\xb77\x90b\xa8#\xa2\x1dY\xb6\xa5ƒ\x04K\xd8\xd2J\xb1\x16љ\xac\x95\x016\x9e>\xc4)o\x00\xa8e\x1d\xc9x\xd29\xa5\xa3\xf6&G(1,{\x06<9\xbc\xe8\x9f\xea\xa1\x7f귃\x95\x8fk\fje\x85SfO\x84\x83\x83\x1c+\xc4Q\xd9P+\x99,\xb1\xbe\xe4x7~%\b\xc9\tv\xec\x14\x9aLQ\xa0\xea\x19Ur\xa3芍\xa5\x01\xb7\x8e\xa6\x91\x92[t\xf9\xb3\xcac\x0eMH8\x84\x98\xd0\x0f%LJ^)U#\x1bcI\xee\xee̙\xc9\x01\xe6\x84彭\xab\x98K\xbc\xd1$\xd3J9Ŗ\x9a\x92O\x12\x87V\xfc\f_qG\x06\x06\xd7h\xd0G#\xc1\xf6k\xe5=\x84cB&\x9b\x16\x12\x01p*\xc3\xd9*(\x11r\x18\xdf\r8y?\xe0\x84\xa3\xccr\xfc\xfa\xee69\xc3\x04b\xe4}\xe2\xef\xce\xe2Cm-\xb0\xe6>r8\xbfwVs\xa9ݮ\x03\x13\xde#8\x05\f\xb4\xc0\x12\a\xde\x18\x84\xb4\x0e\x19\x8f\x9dd\x04\rƱ\x17\xc1\xd2\x1fe\x92\xda\xc1k\x93L\x80\x91\xe7\x11\x1c\xfe\xb9\xfc\xf7\xbb\xf9?T8\a\xb0\x92B3\x9fDa\x83ҽ\xe8\x12)\x8eV\x18\xe4\x94\x16\xe1\xacaR\xacѺY\xa4\x86\xc6\xfe\xf4\xea\xe7<~\x00\xdf+\x03\xf8\x89Q:\xf2\x02D\xc0\xbcsfIm\x84\r\a\xef(\xc2N\xb8\xca3\xaa\x15\x8f\a\xdc\xf9#8\xf6@79\x1c\xa1E\xa8\xc5C\xe6\xfe\x84v\xed\xa3\xb9\x03\x9b\xbf\xd2\xed\xf9\xed\x1a\xbe\t\xc6\xeb\x9a~^\a6\xba\xb0\xa5\x7f\xc1\x0e\xec\x84[f\xc4f\x83\x87\xb8\x7f\xa2,\xe4f\xc9A}\v\xca\xd0Y\xa5\xea\x91\xf0\x84IN\xc1? \x9f\xb0\xf7ӫ\x9f\xaf\xe1\x9b!\x06G\xb6\x12\x92\xe3'xE\xd6\xc7c\xa3\x15\xffv\x06\xf7^\x0f\xf6ұO\xb4SY)\x8b\x12\x94\xac\xf7!\x00\xde\"X\xd5 찮\x8b\x10 rر=\xa8\xf5\x91}\x92\x88H5\x19hf\xdc\xc9 1\xe2p\xfa\xd2L\xa3\xa6\xd4\x1ew_|\x14\xf5\xa8\xdb\xfbl\x11\xc8#\x91\xf0\xe9\xc2g \xd1O\xbd.@\xe2\xa1]\xa1\x91\xe8Ѓ\xc1Ui\t\x87\x12\xb5\xb3s\xb5E\xb3\x15\xb8\x9b\xef\x94y\x10rS\x902\x16A\xeav\xee\xcbH\xf3\xaf\xfc\x9fK\x0f\xee\xeb?\x9f{zO\xe4\xf9 \xa0\xdd\xed\xfc\x12\x04Rt\xffx\xdfu\x14\x87e\f8\xc74\xe9\xce\xef*QV)\xd7\xebYۆ\xf1`\x8e\x99\xdc?\xd3\xdd!\x9c[C\x1c\xed\x8bX\x03-\x98\xe4\xf4\xbf\x15\xd6Q\xff%\xc0\xb6Ⳍˇ۷\xcfy\xa3Zq\x89%9\x92Ä\xf6\xa98pU4L\x17a6s\xaa\x11\xe5h6\xc5\U00037704\xb4\x16h΄\x7f\xef\a\x93S\x80\x9a\xc9\x06\xba9O\x8a?\x1d\xdbd\x02\xbe~y\xf8TXx\x12\xaf\xf3\xaap\xcf6\x16\x98A`\xd00M\x1a\xf1\x80\xfb\"D\x1c\x9a\t\n\x17(\"\xe8\n\x83\xc0\xb4\xaeɧ\x87(\"C1ƿ\x11\x1ef\xfd\xf9\x8e\x01\x92\x15e\xaaJ-\xd19!\x9f\x11\x9c\x0f#F~_\xa0\xba\x9a]\xa9\xe4Zlb\xb5s\x8a\x94l뚭j\\\x803\xed\xb1\x9c\xeb$\x90\xf74\xe5\xf4\xf9?\xf4\xa6&\r?S`̟jPv\x9c\x1e\x06e\xdbLY)\xe0Ai\xc12\xfd\x06\xad\x9b\xdc^\x1a\xb8\xbe~\xca\x1d\vJyI\xca\x1d\xd2\xe0\\V\x1a\x15=\x06\xf0)3u\xea\x90\xe5e\x85\xfe\x04\xdb@\xd9=\xa5#C\xbe\x8b|\xb9d4\xa7W]N]Z\xf1Q\xcf\xd0\f\x8e\x06\xc3\xf9\x1eUC\xf2\x05\xed'T\x91\xc2\xebU\xc448G\x97\u07b4(쾴\x8eD\x89\x9dvȻB\xff%\x12\x7f=&\xe2k\xbf\x86\xc7K!\x1a\xecR\xff\xa1\xad\v\xc9\xdd\nA\x1b\xd4,[\x15\x02_\xb9\xb7\xbe\x84\xf9\xb5\rĄ\x85\xd6\"\xf7\x15\xb4\xc9\xde\x13\n\xe9E\x893\x87\x05\xad\xbf\xcc^\xe4\vS\xe11\xad\xffRrQ\x95jJf\n!K\xa8\xf9'\x9c\xf4\x8a\x97C\xec@\xae\xc3+PC\xee\xb3PJ\x92\xd7L\xd4\xc8!=\x11?\x91\xca\n\xd7\x14\xe2\x04\x1b\x97\xea8\x91\xbd\xe3\xf9\xdfiIf@\x98\x06<_R\x98\rZ\xcb6\xe7lޏaV(o\xc5%\xc0V\xaauy%\xff\xda\xc6{\xfa\xb4\x12[\xb6r44\x11\xccU\xc9\"\xacۺ\xf6k\xfa\xc6\xf5\xf0\xf9\x80\xe7j\x85\xf9\xb0\xf8D}\xed\x14\x83\x15\xb3砺\xa399\xa3\xd5y\x84\x93V\vNx\xbfw\xb8\xcb\xf4&c\x90\x19\xba\x8b\x16&34\xf9\x0e\xa0?\x18\n\xc89\xe4\xd2X\x96f\xf7ʞ\x19\xfb\xde_\xbd'\x81\x1d\xf9\xbbĶt\x05\xe8J\xd5ɜ\xf8\xd7q\xd96+4$\t\xff\xfe>r\xd2L\xf2\xbe\xd8r\x99\xfaa}Ҡ@)V\x9bb\xdd\xdc\xdfo\xa7\x80\v\xabk\xb6\xef\xce\xe2\xf3#\xba\xcc\xf9G\x84ÍJfE\xe3\xb1x\xeft\x19\xb8\xfbV!\x9f\xfc\xe5>8\x18\xb6\xe9\xa7\x03\xa3\xf1\xee\x1b\x84/\xb3Éx\xd5J\xa6m\xa5\xdc\xed\xdb3\xaa\xb1\xec&\xa6\xfbxȽ\xbc\xf5\xf5\xefSqRT\x85\f\xab\a\xeb\xf6$c1\xfct\xe5\x12-^\x0e(\x9cq\x8e\xf1K\x9a\x9c\vZ\x92\x15 \x03\xe4_?oƟ9\xbc\xe8>\x9d`.V\x91ˊ\xc9M\xb6\x96\xa5\xa4\x0f\xb6\x95\x99>E\xc3Yo7<\xd0\x1f\xe9\xe8\xb2\xea4\xe9\xf4\x9c\xf3\x1e\xed\xf8\xf0\xd7\xefiWݛ\xf8\x02~\xfd\xed\xea\xff\x01\x00\x00\xff\xff\xd9H\xdbA\x14'\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4ZO\x93۶\x15\xbf\xef\xa7x\xb39$\x991\xa5\xdam3\x1d\xdd\xecu\xd3\xd96\xd9\xeeX\xb6/\x99\x1c \xe2\x89DD\x02\b\x00J\xab\xa4\xf9\xee\x9d\a\x80\x14\xff@\xd2J\x1eǼ\xd8\v\x80\x8f?\xfc\xde_<(˲\x1b\xa6\xc5G4V(\xb9\x00\xa6\x05>9\x94\xf4\x97\x9dm\xfeagBͷ/o6B\xf2\x05\xdc5֩\xfa\x1dZ\u0558\x1c\xdf\xe2ZHᄒ75:ƙc\x8b\x1b\x00&\xa5r\x8c\x86-\xfd\t\x90+錪*4Y\x81r\xb6iV\xb8jD\xc5\xd1x\xe1\xed\xa7\xb7\x7f\x99\xbd\xfcn\xf6\xf7\x1b\x00\xc9j\\\x80V|\xab\xaa\xa6F\x83\xd6)\x83v\xb6\xc5\n\x8d\x9a\tuc5\xe6$\xbc0\xaa\xd1\v8L\x84\x97\xe3\x87\x03\xe8G\xc5?z9\xef\x82\x1c?U\t\xeb\xfe\x93\x9c\xfeAX\xe7\x97\xe8\xaa1\xacJ\xe0\xf0\xb3VȢ\xa9\x98\x99\xce\xdf\x00\xd8\\i\\\xc0\x03A\xd1,G~\x03\x10\xf7\xe9\xa1e\xc08\xf7̱\xea\xd1\b\xe9\xd0ܑ\x88\x96\xb1\f8\xda\xdc\b\xed<3c\x88`\x1ds\x8d\x05\xdb\xe4%0\v\x0f\xb8\x9b\xdf\xcbG\xa3\n\x836\xc0\x03\xf8\xc5*\xf9\xc8\\\xb9\x80YX>\xd3%\xb3\x18g\x03\xc5K?\x11\x87ܞ0[g\x84,R(ދ\x1a\x817ƫ\x96\xf6\x9f#\xb8R\xd8)\xbc\x1d\xb3\x04\xd18\xbf\xf14\x18?O\"\xadc\xb5\x1e\xa3\xea\xbd\x1a`q\xe60\x05\xeaNպB\x87\x1cV{\x87\xedV\xd6\xca\xd4\xcc-@H\xf7\xddߎ\xf3\x11\t\x9b\xf9W\xdf*9$\xe7\r\x8dBo8 !m\x15h\x92\f)ǪO\x01\xe2H\xc0\x9b\xde\xfb\x01I\x90\xdb\x1f?\v\x85L\x0f\xd4\x1a\\\x89\xf0\x86\xe5\x9bF\xc3\xd2)\xc3\n\x84\x1fT\x1eT\xb8+Ѡ_\xb1\n+ȃA\x90\xee\x94I\xaaNc>\vk\xa3\xb0V\xd6H\x7f\xc3\x0f}\x16\xfb\xca\r\xb2\xa4}\xb5\xa1h\xe6W\b%\xd3F\xf6\xba\xc0g\x19X\x9fH\xa98\xf6X\x9b\xe0\x12\x16\xb4Q9Z{\xc2\xf0I\xc8\x00\xc9\xc3a\xe0,E%\xfa5-\xa0FW\x8aq4\xe0\x14\x94L\xf2\n\x83\x0e\x9daҮ\xa3eLUؾ\xf6~\xaf\x87P>\xb4\xf2z3\x13La\xe9\xf6e\b\x83y\x895[ĵJ\xa3|\xfdx\xff\xf1\xaf\xcb\xc10\x10-\x1a\x8d\x13md\x0eO/\xf1\xf4Fa\xb8\xe7\xffe\x839\x00\xfa@x\v8e \xb4\x9e\x8b\x18_\x91GL\x81#a\xc1\xa06hQ\x86\x9cD\xc3L\x82Z\xfd\x82\xb9\x9b\x8dD/ѐ\x18\xb0\xa5j*N\x89k\x8bƁ\xc1\\\x15R\xfc\xd6ɶD8}\xb4b\x0e\xad\xf3\x8eh$\xab`˪\x06_\x00\x93|$\xb9f{0H߄F\xf6\xe4\xf9\x17\xec\x18Ǐޚ\xe4Z-\xa0tN\xdb\xc5|^\bצ\xe3\\\xd5u#\x85\xdb\xcf}f\x15\xab\xc6)c\xe7\x1c\xb7Xͭ(2f\xf2R8\xcc]cpδ\xc8\xfcF\xa4Oɳ\x9a\x7feb\x02\xb7\x83\xcfN\x14\x1d\x1e\x9fD/P\x0feU\xf2\x04\x16E\x85-\x1e\xb4@CDݻ\x7f.\xdfC\x8b$h*(\xe5\xb0t\xc2K\xab\x1fbS\xc85\x19>\xbd\xb76\xaa\xf62Qr\xad\x84t\xfe\x8f\xbc\x12(\x1d\xd8fU\vGf\xf0k\x83֑\xea\xc6b\xef|\xc9\x02+r(\x8a\x03|\xbc\xe0^\xc2\x1d\xab\xb1\xbac\x16\xffd]\x91VlFJx\x96\xb6\xfa\x85\xd8xq\xa0\xb77\xd1VQGT;\x8eoK\x8d9i\x96ȥW\xc5Z\xc4L\xb2V\x06\xd8d\xfd\x90\xa9t\b\xa0'\x99QƋΙ\x1d=oR\x82ZIJ\x17\xc8c\xbe\xb31QU\xc3D\xd5\x7f&9ҠVV8e\xf6\x87L96\x89\xa3ڡ'g2\xc7\xea\x9a\xed\xdd\xf97AHN\xbccg\xd2\x14\x8c\x82T\x0fT\xc9B\x91\x93M\xd4\x01\xf7\x8e֑\x9d[t\xe9\xcdʣ\x99MH8ԘЯ%\xc7\xdb^)U!\x1b\xb3\xa9\x15?\xb3\xe9G\x15\x03\x87\xc15\x1a\xf4\xf9?\x84Y\xad|0vL\xc86|\x84\x92\x1b\x9cJ\xeccE\xe1\xe6\x98j\x8e\xdb!\x9cHII\xc0\xaf\x1f\xef۴\xd3ZV\x84>\xc9,}~\x92fA\xcfZ`\xc5}\xa2>\xff\xed\xa4\x85\xd0s\xbf\x0e |\xecu\n\x18h\x819\x0e\xf2\x1e\bi\x1d2\x1e\a)\xdc\x18\x8cs/BL=\n\x92\x9eC~$\x95\x00\xa3\x18/8\xfc{\xf9߇\xf9\xbfT\xd8\a\xb0\x9c*!\x7fV\xc1\x1a\xa5{ѝW8Za\x90\xd3\xe9\x03g5\x93b\x8d\xd6͢44\xf6\xa7W?\xa7\xf9\x03\xf8^\x19\xc0'FE\xff\v\x10\x81\xf3.m\xb4V#l\xd8x'\x11v\u0095\x1e\xa8Vԛ[\x04\xabj\x84\x1dVU\x16J1\x0e;\xb6\a\xb5>\xf2\x9dVEd\x9a\f43\xeed9\x16y8\xed4\xd3\xfa\xa4}\x9e\xe7/\xbe^y\x96\xf7~\xb1\\\xffL&|a\xfe\tL\xf4\x8f:W0\xb1iVh$:\xf4dp\x95[\xe2!G\xed\xec\\m\xd1l\x05\xee\xe6;e6B\x16\x19\x19c\x16\xb4n\xe7\xbee3\xff\xca\xffs\xed\xc6}\x9f\xe5Sw\xef\x85|9\n\xe8\xebv~\r\x03m\x1d\xfd\xfc\xdcu\x94\x87e\xac\xec\xc62\xc9\xe7w\xa5\xc8\xcb\xf6TՋ\xb65\xe3!\x1c3\xb9\xffB\xbeC<7\x86\x10\xed\xb3\xd8p̘\xe4\xf4\x7f+\xac\xa3\xf1k\x88m\xc4'\x05\x97\x0f\xf7o\xbf\xa4G5\xe2\x9aHr\xe4\xb4\x10\x9e\xa7\xec\x80*\xab\x99\xce\xc2j\xe6T-\xf2\xd1j\xaa\x95\xef9)i-М\xa9\xfe\xde\r\x16\xb7U{\xa2\xea\xee\xd6\\Tv[ɴ-\x95\xbb\x7f{\x06Dz[\xd8b8\xe80\x16\x9d\xad,r\x89\x93\xb5\xe63\xf0,\xc5o\x89\xb0\x95DDK[L\x95*D\xce*\xb04\x16ѵ\"\xa78Rm\xc81\xca~3\xb1\aӇ\x80\x87\xe3\x01v\x88t\xb8\xba\x05\xab\x8c(\x84d\xd5!P\xfb\x13\xa3d5\xf3\x7f%L\xb4fZ\vY\\Di\xdb\xd6Z\xa2sB\x16\x89\xfa\xbe\xdfu?u\n8\xe9\x1e\xe7=\xff\xc3\b\b0\x83\xc0hO\xa4\xaa\r\xee\xb3Plj&\xa8R\xa4b0V\xd4+\x04\xa6uE\xe5\\( S!\xa9m\xd2\xe5J\xaeE\x11\x1b\xa6S\xa6dSUlU\xe1\x02\x9ci\x8e\x9dՒ^\xde\xef\x0f\x9e\xd1\xf8\x87\xde\xd2V\xddg:\x94\xe9]\r\xfa\x96\xd3͠l\xea)\x94\f6J\v\x96\x18'\x9f\x9c\xc4#\x9a\xb8\xbd\xbdĤ\x82ß\xe1 \x1c\x95S}\x86\x18/\xe2\xe9#\x9e\xacC\xd4H'\xf1K\xe3\x88\xc1_\x1b:J\r\x11f\xe9\x96\xcah\x8dV\xfcfLZ?\x04\x8f&\x0f\x01t<1t\xfa\xd1l\xa0\xe0Y\xdd(\xdf\x1f\xbf\xa4\x1f\x15n\xc1\"\xef!\xfb\xbb\xf6n\x8c\xce\x15Ww\xa4\xe8\xe8\xaa\x1d\xf2\xee\xea\xe0\x9av\xcd\xeb\xb1\x10\xdfG6<:\x89\xa8\xb1\xebmD;1\x87nK\xc8,ڠfI\x8b\x00\x7f\x17`}?\xf4k\x1b\xa4\t\v\x8dE\xeec\xeb\xe4\xe3Gs\x02g\x0e3z\xff\xba\x00\x92\xeeq\x85[\xb9\xfe\xe5\xcbU\r\xaf\xa9\x98)\x87\xac\xa3\xcd_\v\xb5\xf7\x81)\xca\x0e\xf2:\u00828\xe4\xfe\xa4\rJ\u009a\x89\n9tw\xce\x173\x9f\x00=\xad\xc1>'\xf95ZˊsA\xebǰ*4\xdc\xe2+\xc0V\xaaqG\xac\xf2k\x1b]뢜,\x15?\x87\xe4Aq\x0fC\x1e\xbfi\x9b\xa2I\xa8\xa5\x7f\xfbv\x11F\xdf\xcb<כ\xa45\xa9P\xd3A>\x1dk\xe0D\x0e{\xc0]b\xb4\xf5\xe0\xc4\xd4c\f\v\x89\xa9\xc9\xcf\x00\xfa\x93\xa1\x81\x9c\xaaiڹ\xa4\xcc\xee\x8e=1\xf7\xbdw\x97\x8b؎\xf8\xae\t\b]\xfb\xb9TU\x1b\x03\xfcݸl\xea\x15\x1aR\x85\xbf}\x1fW\xc4\xc0$\xefk.\xd5C\xe8$\xb4i8\x88\x8am\xb0\xd87\xf7^\xee\x14pau\xc5\xf6\xddf\xfc\xc1\x8d\\:}\x8bp\xf0\xab6VQ\xe69R\xb7\x9dnPw\xbfUH\x1fKOW\xfap\xa6\xda\xf7\xf3\xddo\x10>\xcf\x17Nԝ\xc3߄\\c ˁ\x84s\xc9\"\xfeF\xe5\xf2\x18?\xfc̟\x19ޓ\xecM\x06=rޓ\x1do\xba\xfa#ͪ\xbb\x06^\xc0\xef\x7f\xdc\xfc?\x00\x00\xff\xff\xbb:E#\n&\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xdc=[s\xdb8w\xef\xf9\x15\x98\xf4a\xdb\x19\xcbi\xa6\x97\xe9\xf8\xcd\xf5:\x8d\xfb}\xebx\xec4\xfb\f\x91G\">\x83\x00\x17\x00\xa5h\xdb\xfe\xf7\x0e\x0e.$%\x90\x84d˛-^2\xa6\x80\x03\xe0\xdc\xcf\xc1\x01\xb2X,\xdeц}\x03\xa5\x99\x14W\x846\f\xbe\x1b\x10\xf6/}\xf9\xfco\xfa\x92\xc9\x0f\x9b\x8f\uf799(\xaf\xc8M\xab\x8d\xac\x1fA\xcbV\x15\xf03\xac\x98`\x86I\xf1\xae\x06CKj\xe8\xd5;B\xa8\x10\xd2P\xfbY\xdb?\t)\xa40Jr\x0ej\xb1\x06q\xf9\xdc.a\xd92^\x82B\xe0a\xea\xcd?^~\xfc\xd7\xcb\x7fyG\x88\xa05\\\x11\x05\xdaH\x05\xfar\x03\x1c\x94\xbcd\xf2\x9dn\xa0\xb00\xd7J\xb6\xcd\x15\xe9~pc\xfc|n\xad\x8fn8~\xe1L\x9b\xbf\xf4\xbf\xfe\x95i\x83\xbf4\xbcU\x94w\x93\xe1G\xcdĺ\xe5T\xc5\xcf\xef\bхl\xe0\x8a\xdc\xdbi\x1aZ@\xf9\x8e\x10\xbft\x9cv\xe1W\xbd\xf9\xe8@\x14\x15\xd4ԭ\x87\x10ـ\xb8~\xb8\xfb\xf6OO\x83τ\x94\xa0\v\xc5\x1a\x83\b\xf8\x9fE\xfcN\xc2B\tӄ\x92o\xb8Q\xbb\x1aD<1\x155DA\xa3@\x830\x9a\x98\n\bm\x1a\xce\n\xc4;\x91\xab\x1e\xa40J\x93\x95\x92u\amI\x8b\xe7\xb6!F\x12J\fUk0\xe4/\xed\x12\x94\x00\x03\x9a\x14\xbc\xd5\x06\xd4e\x04\xd4(ـ2,`ٵ\x1e\xef\xf4\xbeNm\xcc6\x8b\v7\x8a\x94\x96\x89\xc0m\xc1\xe3\x13J\x8f>\"W\xc4TLw[\r\xdb#T\x10\xb9\xfc\x1b\x14\xe6r\x0f\xf4\x13(\v\x86\xe8J\xb6\xbc\xb4\xbc\xb7\x01e\x91Uȵ`\xbfG\xd8\xdan\xdcNʩ\x01m\b\x13\x06\x94\xa0\x9cl(o\xe1\x82PQ\xeeA\xae\xe9\x8e(\xb0s\x92V\xf4\xe0\xe1\x00\xbd\xbf\x8e_\x90xb%\xafHeL\xa3\xaf>|X3\x13$\xaa\x90u\xdd\nfv\x1fP8ز5R\xe9\x0f%l\x80\x7f\xd0l\xbd\xa0\xaa\xa8\x98\x81´\n>І-p#\x02\xa5\xea\xb2.\xff.\x12u0\xad\xd9Y\x1e\xd5F1\xb1\xee\xfd\x80\x02q\x04y\xac\xa88\xc6s\xa0\xdc\x16;*\xd8O\x16u\x8f\xb7O_\xfbLɴ'J\x8f7\xc7\xe8c\xb1\xc9\xc4\n\x94\x1b\x87\xacia\x82(\x1bɄ\xc1?\n\xce@\x18\xa2\xdbe͌e\x83\xdfZЖ\xdf\xe5>\xd8\x1b\xd4:d\t\xa4mJj\xa0\xdc\xefp'\xc8\r\xad\x81\xdfP\roL+K\x15\xbd\xb0DȢV_\x97\xeewv\xe8\xed\xfd\x104\xe2\bi\xbd\x16yj\xa0\x18H\x9a\x1d\xc6VA]\xac\xa4\x1a(\x19;d\x88\xa3\xb4\xf0\xdb洈U\x8b\xfb\xbf\xccq\x99m\xff\x1eG[~\xb3+k\x05\xfb\xad\x05T\xa6N\xfc\xe1P_\xa9\x9ej\x1f6\xcbF\xfb\xd4\x1dE\xb4m\xf0\xbd\xe0m\te\xd4\xeb\a\x1b\xcc\xd9\xc6\xed\x01\x144z\x94\t+D\xd6\xfaؽ\x88\xeeWT\xe0T\x01\x11\xd2$\xe01\xe1\xe0\x11&\x10\x03I\x9a`G\x03ubœ[&D\xb4\x9c\xd3%\x87+bT{\x88F7\x96*Ew#\xd8\n\x1e\xc0\x8b\x90\x15\x81xU\xc3Y\x81$\x8f\n\x05\xf1\xf5\xe7E\x15\xd3VQ\x86]>HΊ\xdd\f\xben\x93\x83\x82\xb4z\xd9\xf5;$K\xa8\xe8\x86I\x95\x12\x03\xa9\xb0kϞwjZZ-\xe9\x81\xec۸\xcc\r'\x91UI\xf9<\xc7\x10\x9fm\x9f\xce:\x90\x02\x1dʸ\x15Omo\xbb\x97@\xe0;\x14\xadI,\x93\x90\xb2E\xd3$\x15i\xa46\xe3t\x1fW]\xa4\xef\x1c\xa5~\x9c`\x9a\x83\x9d%Y\xdd5\xaf\x84\x03Q-\x0e\x06\nY\n\xb0ۨ-Q\xbb\xbeJ\xb6\xae\xef(RȒj(\x89\x14\xa33#\xbb\xb4\x1c\xb4\x9f\xabD\xce\xe8\xf4\xd0E\xb7\x7f\xf4x\b\xa7K\xe0D\x03\x87\xc2Hu\x88\xcc\x1c\x94\xba\x96\xa3XGP\x99ЦC\t\xe860\x01\x92XN\xdfV\xac\xa8\x9c\x87a\xd9\x13\xe1\x90R\x82\xb6\xda\x04]\xe6\xdd\xd8&\xc9\x1c\xf9\xfd$Sڣk3b\xb5\x0f/\xa5Q\xba\x96\xa1\x86\xbb\x96Dm\xa7{\x0ft\x8b\xffn\xe4\xe4\xb6\xff\x7f\"6\x18\x93\x13\x98vB\xfe\t\xba\x9f\xd9<=ʷ\x18ၾ$w+\x02ucv\x17\x84\x99\xf0uN\x12(\xe7\xbd9\xfeĴ9\x9e\xe93I\x93#\x13g\"L\x9c\xe2OH\x174\x19O\xdebd\xd3\xe4\xaf\xfdQ\x17\x84\xad\"\xd2\xcb\v\xb2b܀\xda\xc3\xfeI\xaa>P\xe65\x90\x91c\xf5\b\xe6\tLQ\xdd~\xb7.\x8e\xee\x92`\x99x\xd9\x1f\xec|\xe3\x10A\f\xcd\xf3\f\\\x82\xf12SPc\x1cN\xbe\"6\xbb/\xe8T_\xdf\xff|\x18+\xef\xb7\f\xce;\xd8Ȍйv\xbd\xb7\xa3\xfe\xfa|T\x10~A\x1f(\x06U.\xe7rA(y\x86\x9ds]\xa8 \x96>4tΘ^\x01&\x7f\x90Ϟa\x87`\xd2ٜÖ\xcb\r\xae=C\xc2\xf5O\xb5\x01\x0e\xed\x9a|X\xec\xf0d? \"0\x86\xcfe\x03\u05fc($r'閩KB\v\xb8?a\x9bY\xacҟ\xa3\x9f\xfaD\x0e\xf8I;ZZ\x89\xa9\x98\xcfij@\x99\xc9%\xa8k\xdf(ge\x9c\xc8\xc9ȝ\xb8 \xf7\xd2\xd8\x7f0@\xd3\xc8(?K\xd0\xf7\xd2\xe0\x97\xb3`\xd4-\xfc\x9c\xf8t3\xa0\xa0\t\xa7\xe5-\xc2\xfa9?g\xd3,\xb7E\xdc3M\ue10dW\x1cJ2\xa7\xc2\xf4\xae\x9b\xceMT\xb7\x1a\xd3uB\x8a\x05\xda\xcc\xe4L\x1e\xdfR\r\xd0\xfd\xe2I\xfd\x84_\xad\xb1p\xbf\xb8$3\xa7\x05\x94!\xb2\xc4\xec'5\xb0fE\xe6|5\xa85\x90ƪ\xf0<\x8e\xc8T\xac~7DZO\x9e\xf5\xee\xb7\xef\x8b\xe7\x98/XX\x93\xb3\xf0\x10\x8c\xac3p\xe0uw9\xbf\x9f\x85\x95ٌ^\x81\x13f\xbb\x8e$Gǻ\xe6 \xe5\x05\xe8@+\x8e.\xce,uiY\xe2\x11\x1a\xe5\x0fGX\x94#x\xe1X\xd5\xd0[\xbb3\xc15m\xacZ\xf8okiQ\x9a\xfe\x974\x94)}I\xae\xf1\xa4\x8c\xc3\xe07\x9f\x87\xeb\x81ɘ\xb2\xb1SY\xfe\xd9Pnm\xbfU\xe0\x82\x00w\x9e\x80\\\x1d\xf8E\x17d[I\xed\xcc\xf6\x8a\x01\xc7\xf3\x8a\xf7ϰ{\x7fa\xa7\x9f\x9d\xb2\xafd\xde߉\xf7·8P\x18\xd1ᐂ\xef\xc8{\xfc\xed\xfdK\\\xa9LN\xcd\xec6`њ6y\x1c*\x92\xc9\xfa\xae\r8\xa6\x9f\x9b\xef\x92\xf2\xdeɞ\xdam\x16\x8b6R\x9b\xcf\xe9\xbc\xe1\xc8z\x1e\u0088\xa1g\x9cȱ\xcdF\f>\x8f\x16\xf5\xbdu\"W\x06\x94\xcf%:\x1b\x10\xe2\x8f\x17Ff\xa9S\x99\xfebc2\x90\xc6\xfc\xaeE\xf0\f7\xb9\x83\x9b\x9c%\x1e\xe3\xb0Z\xbc\x1c\xe9\xed\xdf~\xef\xe53\xad\xe4ڿ\xfb\x1bym\x87\xba\x90uM\xf7O5\xb3\x96z\xe3F\x06\x9e\xf6\x80\x1c\xf5պEyε\xc8\x1d\x0f\xe1\xf9喙\x8a\tB\x83\xda\x00\xe5\x19\x8a\x92F\xa6rةVQM\x96\x00\"\xa6\xe8\x7f\x04W\xa2f\xe2\x0e' \x1f\xcf\xe0zDt\x9d\xd3ٽ\x894\x89\x94\x8f\x1f\x9c\xc9jdI\xb6\x15(\x180\xc6a\xde\x1d=U!M/eq\x84C\xda\xc8\xf2'MVLi\xd3_\x82&\xadΥ\xf5\x91\xe4\xb3\xeb\xfe\xcaj\x90\xad9'\x82o\xbbi\x06g\xcd5\xfd\xce\xea\xb6&\xb4\x96\xad3\xe6\x86\xd5\xf1TףwK\x99\x89\xc7V\x98\xbf1Ғ\xa0\xe1`\x80,a\x95>\xefM\xb5B\n\xcdJP\xa1J\xc1\x91\x8dI+\x98+\xcax\x9b:%J\xb5c#`q\xab\xd4I\x01\xf0\x177\xb2\x97w\xac\xe4v\x88\xa0̽\xe3A\x1a\x10\xb6\"\xcc\x10\x10\x85\xc58(\xa7\x92q\n\x8f\fD\r\xcb\xd5sy\n\xdc6\x10m\x9d\x87\x80\x05\n$\x13\x93)\xb7~\xf7O\x94\xf1s\x90\xcdr\xde'\xa9\x1e\x81\x96\xa7\xe4h~\xed\r' t\xab\xf0\xf0\xdf\xe9\x8e-\xe3yk\xb6\x94#\x9c\xb6\xa2\xa8\x00\x95\x90\x18\xea\x06\a\x9e\tm\x80\xe6\xf2\x82\xf5\x8aZ!\x98X\xe7\xd1.;\x11\xda5\x87\ua954\x1c\xe8\xf8)d\xd7,\xae\xdf@\x13\xfd\xdaM\xf3BM\xd4\x11\xc1\x1d\x9b#\x1d\xb2)j\x95\x16\xa1\xc6@\xdd8\x91\x93D\xb5\xa2o]Π\x88\x8e\t\xc3\xfd*^3\xbef\x82e\xd0v@\xd7;\xc1L\xdfy\xb4 \xce\xea<\xda\t\xa2;pJ\x86\xedn\x00\xc0\nh\x88Cp\xed\x91k\x8ep$\x97@hYB\xe9r\x97\xd6\x15\xf1a\x89+|\x1b)nH\xee\xeexO0\x8b\xb2\xa1\r\x82N\xccê\r,Z\xf1,\xe4V,0\x18\xd7G\xeb\x90\x13\xb3T/\x9dޜ\xac\x8c\xe6\xf5K\xbe\x9a\x9e\xd3BC~\xcd\xe7\xa9\xe0?\x9dA\xcbd\xf3\xcdQ\t\x8f).\x98\xd3k\xae\x00{\xe4\xc7\xd9UL\xcd?1\xd8\x1fJ߸b\xe9\x17\x95\xc5ݥA\xf5\x9c\xc2m\x05\xa6\x02\x15J\xb3\x17X\x92^N\x9e\x90v\xc1K\xac\x93\xb3L\x15\\dW\xfe\xb9W9\x87\xd1M\xcb\xf9\x85\xe5m\xda\xf2d8l$\x8a\xd8!geՏ\xa5=\x86\x9c\xea\x8bl<\xf6+-\x86\xf5\x85\xb1\n\"\x14\x18\xca0\xb3\xa7qj\xbfXX\xda;\xdf\x1f\x96S`\xfe/,\xff\x0f/=̨\x94\xc8Gcn\x95fDb\x02V\x82\xc1zh\xec\xea+|?_\xe8\xfbc\xe1\xd4@\xfd\xa5\xf1\x123\xea\xc2f\xa05\x01g\xaf\xde\x04\xadA\xab\x9d+\x10\xed\x80\xcf\x19\xda\xf1ׅ\xbb\x05\x11\xc0\xa4\xf8\xf5k\x05A|}\xf5>\xd3\xe4\x9fI%\xdbDU\xdf\x04\xcaf\xaa;\xe67<(\xf4\xf0\a\n`\xe8\xe6\xe3\xe5\xf0\x17#}\xd9\af\xd1\x12\x800(\xea2\xb3L\x94l\xc3ʖ\xf2 \xb5\xdd\x1d\x02\xc7@\x1d\x9f%\xa0IE\x04\xe3\x8e\x01\xc3\xf8\x01Ñ/\x8d;\x969Z\xc5M\xfb\xa2y\xd5!'ׄ\fk>F\xac\xe1\xb1\xc7\x17\xafR\x05\xfb\x87\xd4z\x1c_\xe1\x91\x13I\xccTs\x9cPÑY,\xf6\xe2\xf3\x96\x9c*\x8dcb\xee\xb3Ud\xbc~\x1dF\x16~\xe6k.\x8e\xc1\xce\xd9\xeb+ް\xaa\xe2mj)2+(^\xaf\x142/\xfa<\xa9\x14`>`\x19\xaf\x82\x98\xad}xQ@sҖfk\x1a\x8e\xa9d\x98\xa5N\x9e\x98\xbdY\xad\u009bU(\xbcm]\xc2$\x17M\xfexL\xe5A\x8c\x93~\xa1M\xc3\xc4\xfa\x90)rYg\x92m\xe6Y\xe6~o!\x03\x9e\xe9\x873]t8\x12\xfa\xba\xeb҉H2\xa4-\x990\xf2\x92\\\x8b\x9d\x87\x9b\x80\xd3\v\x1f\x854\a\x17\xd9첶\x8c\xf3\xfem-\x04;\r\xcaߙԴv\xab\x1a\xf3\xf6\x93t\x95j\xe0\x94\x9f\x148~ك\xd1ώ\xbe\xa5\xe7_\xb7ܰ\x86\x83\xf5\xe86\xacL\xde!3\x15\xec\"\x92\xff&\xf1\x86\xd4r\x87\x90\xbe]\xf4\x9eQ\xec\x9eq\x926\xbf\xc9\x13\xb6\x97Q\xcc~\\\x11{\x06\xcdrE\xf1\r\x8b\xd5߰H\xfd\xad\x8b\xd3g8k\xe6\xe7\xe3\x8a\xd0O>\x81\tG\xfd\xf7\xb2\x84\a\xa9\xcc\\p\xf2\xb0\xdf?q\x92\xda\v\xd8$/\x89\b]\x13\xbb\xc4\x10Ç\x17\xa7m*}\xe8\x19\xdc\xe9_di\xd76w\xc6\xf2\xb8\xd7\xfd\xe0\xae\xf2\n\x14\b\xf7\xcc\xc7\x7f>}\xb9\x8f\xf0S>\xaf\xf7\x8c\xf7\x9e\x97p\x1eL\xe9\x91\xe3\x8f\xe6|1\x93\xc3\x16\xfa\x00\xaf|.B\x1b\xf6\x1f\xf8\xaa\xdb\v\xd2A\xd7\x0fw\b#\xf8i\xf8L\\\xac\xa2\x88'\x96K\xb0\x16+\xa2jT,\xeeV\x03\x88Ê\xdf\xfe3JP\xba'\xb3\x82\xc5d\xa1\xc6\xcb\n\xdeÝ[\xc7\xd8,\x9f\xac\xd3(vD:\x8e\xac\x98*\x17\rUf\x87l\xa3/\x06k\bff*\x9d3\xaaX\x0f\x9f\x01K\xa27\xbc\xfe\x85g\x91\xbbfxڻ\x8f\xbbS\xd61~\xffd\xf6\xe6\xc9+\xaec\xdcb/\x10S\x89\xcf\xc9\x02\x93WK\x93yM\xf4\xf0\xed\xa4\xb4\xcbc\x1c=\xad\xe7l\x14\x1dRM\t0v<\xaa:-h\xa3\xabēK/\xd3u\xf8\x1a\x99\xa1\xa6}\xc9&\x1d\x80\xc1>YQ\xf5\xb4\xd5\x16\x82>\v\xdbFi\xc5a)\xddnm\xb3\xab{a\xfc\xa2\x97)x\x9b#\xe1\xcc\xe7\\N~\xc8šgD\xfd`\xf6˪\xb6CL\x9dp\x18<\xeb\xdae\x14\x19O;\xb1\x99π\xe4\x19\x8c\x13\x9e\xfe@|\xe5\xe2\x8a$_\x04\xc9|\xf5\xe3\x0fE\xf4\x84V\xd3E\x05e\xcb\xe1\xd47\xff\x9ez\xe3\xe7_\xfd\v\xb3e\xbc\xfbg\x91\xdd3\xd0\xd6g\x1e\xbe/\xe8)\xe1!\xf7)9\xe6\xf0ap\xe0\x9e\x17+\xdcK\x94E\x01Z\xafZ\x1e\xaa\x94\n\x05\xd4@\x19\xba3\x1dW|T\x9dM\xdbpIKP7R\xacX\xe2\x84d\x80\xd6\xff\x1at\xde\xe3\xd9\x02?\xb6\xaa{\xdaq\xf2Y\xbc\x17i\xae\x86*\xca9\xf0O\x8c\x83\xfeYn\x85]W\x86@>\xa4\xc6\xf5\xeee\x15\xad\xb2f}GD[/\xad\x93\vƌ\a\x8b+\xa9\xa6+\xa4\x1dޙ0\xb0\x86T|\xbdU\xcc\xc0SC\x95\x06\\Q\xc6\x0e~\xdd\x1b\xe2\xa2\xcf\x15\xa7kW\nW\xb2\x82\x1a\x88\x06\x18g\x18[>\x8e\xd7\b\x8b\xef\xb02I\x8e$\xbd\xb2\x85z\xecJƨX\x8f=/\x9a0\xd5\xc9\aF\x9dE.hc\xf0\x02\f\xd2\x11\x89h<\f|\xb4w\xef\x8d\xd1\x01\xd8qN\xf3e̾`N\x1bZ'\xa2\x84y\xbdss\b\x06\x9f\x05Ve\xaf\xee\xae\xff\xc0b,\xb0#[\xaac1u\xd2\xf7\xee`;0\xe8\xaa[\xd0P\x12\u0600 V\x14)\xe3PNq\xeaWL$\xab\r\xa8\x9ft\x84\x83\x95\x80\x96ş\fU&.\xfdЏYIUSsEJj`aG\x9f溥\x9fIU\xea\xc4\xe3@\xbc\xd9\xe6ţ\b\xd7n\xac\xf5s\xf7\xd1jК\xaeC\x10\xba\x05\x05d\r\xc2\xe2=\xe6\x16\x93\x1eS\xb8\xd2\xe7\x8dE,-\xb5(\xa4\x85i\xa9\x9f\xc0\xb9p\xf1\xf44\xbcO\x8cQ\xeczTE\xa7U\x85\xbf<\xf8\bT\xef?w}\x80\x8bO\xfd\xbe>I\xecv\xec\xceF\xa8+\xf0\xc4\a\x8f\r\x8b\x91uJ\xa6\x8dę\x8f2'\x95\x94\xcfYn\xf6\xe7رK'1\xe1X\t\xafL.ekz~\x8eGxb\x99\xf8\xfc\xe7+\xdb\x17\x84y\xed.P\x8d\xe5V\xf3<\xbd\xcf\x03H1\xbc\x95\x86\xf2`d,_\xc6\x0e\xd5\xc4\x03\x02O\xe1\xf1d\xcew\x17\xfb\x90\xf7^e\xef`W\xddS\x9e^\x13t\xd7\xc7\xc7Ҫ>\xeb\x97\x04\x12_\x01\xed|\x92\xb17\x17\xe7\xec\x1fB\xfd\x84\x8b\xca\xc0\xf1\xe7\xae\xf7\x18\x1e\xdd2\x9d\xc3\f\"\x1di\x12\f>L\x15%ㄥOx\xa9ME\xf5\x9c{\xfa`\xfbD\xb7\xa3g\xae\xa2\x13\xfa8\"\x95\xe9{\xae\vr\x0f\xdb\xc4W\x87,<\xfdB\xa9Jt\xb9\x13\x0fJ\xae\x15\xe8C\xa6[\xe0}F&֟\xa4z\xe0횉/\xe3\x95\xdfS\x9d\x1f\xa82\xcc2\xad[Ob\xecM\xb0q\x89\xdf\xe6G\x8f\xff\xc0\x04\xe5\xec\xf7\x94.\xef\xff87Ä\xbek<\xf2N\xb1P\x01\xf1s\n\xd0k\xe8\x9ft\xcf\xfc\x84y/ɽL\x8a\xb1? fC\xa0L\x93%h\xb3\x80\xd5J*\xe3\xf2\xf7\x8b\x05a\xab\xe0 Y\r\x81q\xa2{͞\xb0T\xe2=\x1e\xbd\x05\x87e\xe5S\x89\n\xad\x0e\x86\x9c5ݹ\x8c$-\n\x1b\x13\xc0\amh*6y\x91\x9e\xc6P\xd5\xcbJ\x8e\n\xb9\xeb\xf7\x8f9\xbe\xa8>\x10\x9cC\x1d^gw\x06\x9d\x8f\x9di\r^\xcb \xdab\xef\x14eB\x9c\x1a\xbb\x1b\x0f\xbb\xf3L\xcd\xd7\beL=\xfa\xfd\r\x1e\xe2\xf6\a\xac\xbe\x93%[QQ\xb1\x1e\xbd\xd0V)ٮ\xab\xc0\x9bc\x0e\x11)[\x8c\x9c\x1bT\x05:\xfc\xc7!\xa6U\xa2wh\xe7k,ƴt\\\uee0f\xf2\x02E\xad\xba\x8b-\x9d\xaa\x9a\xb0\xf9\xd9Y\xc2\x11\x88\xb3\xb6?\x01\x91\xea\x9d(&\xaf\xe0\xf8@\x9bM\xdc՝\xc2P\x12\tQ\x1b\xbf\x1a\x12\"\xc41$\xf4}\x89.\xe2\xf9a02棜\x88\x8ei'\x06\xb78\rj~\xd3}'h\xe8\xee\x1c\x87\x0e=\b\xfeNJ\xbb\r \x1c\x13\xf9\xe2\xdc\xe9\xb8\xf7ǍX7\xd1ۺ=9v\xfd\xb6\ac\xef\n\xa4\x8db\xbbiB\xbc\xf9\xf7l\x95\x92\x17\xf7\xbf3-9\xfc\xc3\xc1\xafo|\x95qK\x95`b}\x12F~\xf5c\x13\xf1\xbc\a{Έ>\xac\xfc\xd5b\xfa\xa4Y:\xf8\x88\f^\xf6\xf0\xecg\xf2_\xfe/\x00\x00\xff\xffP\a\xb5\x16Cm\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec=]s\x1c)\x92\xef\xfa\x15\x84\xeea?B\xdd^\xc7}ą\xde|\xb2gO\xb1\x1e[ai\xf4\xbctU\xb6\x9aQ\x15\xd4\x00\xd5r\xdf\xde\xfe\xf7\x8dL\xa0\xbe\xba\xe8\xa2Z-ygǼت\x86$\xc9L\xf2\x03\x12X,\x16g\xbc\x12\xf7\xa0\x8dP\xf2\x92\xf1J\xc0W\v\x12\xff2\xcb\xc7\xff6K\xa1\xdelߞ=\n\x99_\xb2\xab\xdaXU~\x01\xa3j\x9d\xc1{X\v)\xacP\xf2\xac\x04\xcbsn\xf9\xe5\x19c\\Je9~6\xf8'c\x99\x92V\xab\xa2\x00\xbdx\x00\xb9|\xacW\xb0\xaaE\x91\x83&\xe0\xa1\xebퟖo\xffk\xf9\x9fg\x8cI^\xc2%3\xd9\x06\xf2\xba\x00\xb3\xdcB\x01Z-\x85:3\x15d\b\xf4A\xab\xba\xbad\xed\x0f\xae\x91\xef\xd0!{\xeb\xdbӧB\x18\xfb\x97\xde\xe7\x8f\xc2X\xfa\xa9*j͋N\x7f\xf4\xd5\b\xf9P\x17\\\xb7\xdf\xcf\x183\x99\xaa\xe0\x92}®*\x9eA~Ƙǟ\xba^0\x9e\xe7D\x11^\xdch!-\xe8+U\xd4e\xa0Ă\xe5`2-*K#\xbe\xb5\xdcֆ\xa95\xb3\x1b\xe8\xf6\x83\xe5g\xa3\xe4\r\xb7\x9bK\xb64ToYm\xb8\t\xbf:\x129\x00\xfe\x93\xdd!n\xc6j!\x1f\xc6z{Ǯ\xb4\x92\f\xbeV\x1a\f\xa2\xccrb\xa0|`O\x1b\x90\xcc*\xa6kI\xa8\xfc\x0f\xcf\x1e\xebj\x04\x91\n\xb2\xe5\x00O\x8fI\xff\xe3\x14.w\x1b`\x057\x96YQ\x02\xe3\xbeC\xf6\xc4\r\xe1\xb0V\x9aٍ0\xd34A =l\x1d:\x1f\x87\x9f\x1dB9\xb7\xe0\xd1\xe9\x80\n»\xcc4\x90\xdcމ\x12\x8c\xe5e\x1f\xe6\xbb\aH\x00F$\xaaxmH8\xda\xd67\xddO\x0e\xc0J\xa9\x02\xb8\x80vX4\xb6\nu%\xa0\x80\xe6\f\xddN\x8d\x16FH\xb6\xae\xd1#]2\xd4\x12Q\x19\x11\xd2X\xe0\x11a>\x01\xef\xe0kV\xd49\xe4WEm,\xe8\xdbLU\x90\x87E\xa6Q͜\xca\xc3\x0f\a!\xfb\xf8\xa5\x10\x19 \x1f2WiA\x8b<1\xd1nC\x99]\x05n\xcd\tY\xed\x87\xd0\xc6(\x93\xbaŀņ\xe7\x7f<\xbf \t\xe8\xf7\xde\xef\xc70\xae\xa1!\xd3,\xddL\x16\x7f\xbc\x85\xb0PF\xa8;\xa9\xa3f\xf0\x9dk\xcdw\a\xb8\xde,\xa6\xbd\x00\xdfc\xb0\a\x9c\x97\xa1\xda7\xe2\xfd\xb0\xff\xdf\"\xf7O\xcboC\x8b\xce\\H\xe4s!\x8c\xed\xb1ٸU,$\xebX\b\xe9\t$\x1dLT\x93S\\\xfd'!\xe6I\xe7Nl\xb24\xb2\xe9'\xc0\xbf\x14%7J=\xa6P\xef\x7f\xb1^\xbb\x84\xc52\xda\x18a+\xd8\xf0\xadP\xda\f\x97I\xe1+d\xb5\x8dj\x16nY.\xd6k\xd0\b\x8b\x96\xf9\x9b]\x81C\xc4:\x1c\xbe\xb0\x8eʊV\x18\x8c\xabe:\xb2\x94\xa8\x11\x1b\n\x05\xa8Q\xa8\xce\xc1\xc1Ђ\x1c\x88\\lE^\xf3\x82|\t.37>\xde\xe0\x17\xd3j\x13\x02\xb1\x87\x7fT\xaa]q\x0eM\x18$2\xb1\xb7\xea\xa5$\xa0\x8f_bl\xb4_5N\x89\xb0\x94p\xb0od\xa6\xae\v0\xbe\xbb\x9c\xdc\xe4V']\xb4\xccrk\f\x05_A\xc1\f\x14\x90Y\xa5\xe3\x14J\x91\x03WR\x95n\x84\xb8#Z\xb6\x1fm\xb5\x83\x99\x00\xcb(\xc4݈l\xe3\xdcW\x144\x82\xc5r\x05\x86VExU\x15\x11\xd3ՖI\xe1\xf0\x9dM鍶$h\x90!ܘ.iK\xa2~n\xcb(\xd9۹٧\xfa\xf8:\xff(\xbe\xbf%\xa2\a\xabs\xa4\xb0Oh\x12F\xfb\x05\xc9\xf3!Jz\xa4\xb8\x00\xb3\xec\xac\xce\t\x1b\xbe\xa60\xb4\xe7?\xeem\xa5\xec\x11\xe5\xd7Ż\xe3&\xcc\f\xd6MΩ\x97e\\\xd3Ϳ\b\xdf\xc8d\xddz\x8b5\x8bg\x1f\xbb-/hW\xc03$\xbf`kQX \xa7j\nQ6\x83s\xa7$P\xaa\x05f\xb4Il\xb3͇f\xef(\xa1ŀVC\x00\xceA\x0fQ\x0e\xf1 \x01$k\\\v\xda4\x15\x1aJڌ\xa5H\xb2\xfb\x85\\\xc1w\x9f\xde\xc7c\xcfnI\x94ԽA%LZW\xde\r\x1c\xa3.\xae>T\t\xbf\x90\xbf\xd6\x04\x82n\x13\xfe\x82q\xf6\b;\xe7bqɐo)\x8b\xff|\xf8*\fv,s\xf6^\x81\xf9\xa4,}yQ*\xbbA\xbc\x06\x8d]O4A\xa5\xb3$H\xc4n\U00088ce5(\xa8\r?\x84a\xd7\x12C2G\xa2\x19\xddQ\xae\x90\xeb\xd2uVֆ\xb6Z\xa5\x92\v\xb7,6֛\xe7\x81\xd2=\x16\x9c\xa4c\xdf\xe9\x1d\x1a#\xf7\x8b\xcbZ*x\x06yآ\xa3t\x1an\xe1Ad3\xfa,A?\x00\xab\xd0,\xa4K\xcb\fE\xedG6_\xbc\xd2=\x87n\xf9\xbax\xacW\xa0%X0\v4k\v\x0fŪ2\x91.\xde&\x8c䜌\x95\x05\xce\xf5ĚAZ\x92\xaaG2r\x0eWO%\xd63\xc9D^\x04\xb9]IR\xd0Ml\x9dg\xbdf\xca\xcd1*\xa63\x16\xe7\x02\x94\x9c\xb6\xd6\xfe\x86\x96\x9ef\xe3\xdfYŅ6K\xf6\x8e2{\v\xe8\xfd\xe6\x17&;`\x12\xbb\xadh\x95\xfd\x97Zly\x81\xfe\a\x1a\bɠpވZ\xef\xf9j\x17\xeci\xa3\x8cs\x1b\x9aM\xbb\xf3Gع\x1d\xe5\xa4n\xbb\n\xeb\xfcZ\x9e;_fO\xf14\x8e\x8f\x92Ŏ\x9d\xd3o\xe7\xcfu\xeffH\xf4\x8c\xaa=Q.y\x95.ɔ7;'\xd0\xc0`=8DظI \xc5\x00a\x8a\x02ɢ\\)\x13I\x16\x89\xa0\x95 \xe87\xcaX\xb7\x0e\xd9\xf3\xf7G\x17*UX\x9cd|mA3c\x95\x0e)\x99\xa8\xf8S\x96\xe2\xbb\xe5n\x03\x06\xfc>\x94_\xf4t\x801\x8a=ou\x83\xb3*\xe7n/\x8c:\xe2\x19yOԶ\xd2*\x03\x13͋hK\xa2m\xeaQp\x9f\x0eͺ.w\xd1\xdf:Ik\xa7,J\x872ϑG\xd2\x1d\x11\x19}\xf8\xdaY\xa2F\xed\x82\x7f\xa7H\xeb182:\xafQ\x96|\x98\x0e\x9c\x8c\xee\x95k\x1d\xe6\x98\a\xe6\xc2-\xfdP\x93Ι\xe3u4\xa2\xfc\xcf\xe6ڔB^SG\xec\xed\v\xbaC^\x8b\xc7ң\xc6\xca\xf1N\xfaU\xe8\xac\xe5^\xf3\xc1\xe7\xd4)\xda\xf8\xd1\xd0c\xee\xfe\x9e\by\xd7R\xd9\xce2\xceL'\xbaR\xf9\xef\f[\vml\x17\rs \xb1j\x14\xd4\x11\xa1\xa7\xfc\xa0\xf5ё\xe7g\u05fa\xb3\xa0\xb8QO>qzN\xbc\x1dH\xba\xe1[\xf0\x99\xab 3UKZ\nC=\x80\xdd̀\xe8X\xe3\xac@\xa2\xbd\xeb4\x96u\x99N\x90\x05I\x92\x90\x93\xebf\xdd&?p\x91\xb6nŎc\xab=\x94\xc39V\x8e\x9fG!\xc1\xb3\x9bN_\U000af8acK\xc6K\xe4!\xb9\x1d\xa2\x84&\xa3ޱ\xbbI\xfb\xc4\x16d\xb4\xac\xc2YV\x15`\xc1\xa7m\xce\xc0#S҈\x1c\x1a\xd3\xefE@I\xc6ٚ\x8b\xa2\xd63\xb4\xeal\x92\xcf\r¼69}d\x95\x8eȂH\x94\xb8\xce>\xc3\v\x9e\xd6\xf8\x95\x9e\xe7Ǧ8\x8c\x1a\xe6\xfb\x8b\x95\x16\xca\x1d\x068\xbd\xcb\xe8ӎ\xb9\xdc}\xf7\x19\xbf\xfb\x8c\xdf}\xc69\x1d}\xf7\x19'\xcaw\x9f\xf1\xbb\xcfx\xb8|\xf7\x19S\xcaw\x9fq&\"\xdf\xcagL\xc1pAk\x9c\a*$a\x95\x98\n1\x85\xf6D_>\xe9ǟ\xd58I.\xf3\xf58ȑC<\x91\xe3\x171\xaf\xa35^Mr3\xce\xc00w\xdc)\xca\x04\x87\xf9\x04\xa7g\x02\x02\xa7?=s}\x10\xf2\tO\xcf\xf8!\xa4E\x18G\x9d\x9d\tD\x9a\x7fz\xe2\xc2'\x11\x95\xc0\xc3V\x8aK\xff\x88\x8d1&I\tx|\xe3\xe4\xf7\xbd\x8c\xc9\x17\x90\xa5W9\x913K\x9eFY\x7f\xfe\xc7\xf3_\a\x8bN˔(\x1b\xf6i\xeb\xd4xL?b,\xdfM\x8d\xecg\xa9\xfez\xa6\xc2Ie?\xf5DMC\xe4\b\xbc\xbeX\x0f\xa8\xfck\xd27\x16\xcaϕ\xb7\x96'8a\x7f=\x02/\xe9\x8c=7;\x99m\xb4\x92\xaa6~M\ba\xbd\xcbܽ\x03\x01dL\xd8G5\xc8\x7f\xb0\x8d\xaa#\xa76&H\x9b\x90E\x9bF\x90^R\xadO\x8c\x00˷o\x97\xfd_\xac\xf2)\xb6\xecI\xd8M\x04\x18\xddG\xc1\xf3\x1c\xe3\x82\u0381\x1e\xaf\a\xc2UIC\xa1\x8c\x00S\x9aIQ8\x89\r\x10z\xf2\xca>Wnu\xf0h\xbfiz\r+=\x11wn\xfam\x93-9\xed\xbe?#\xe9\xf6\xa4G\xa3\xbeYZ\xedqɴ\xa9+\x94\t\x89\xb3\xe9\xe9\xb2)lu%=I69BNM\x88\x9d\xbb\x02\xf1\xa2ɯ/\x93\xf2\x9aL\xb3\xb4\xf4ֹ\x14{\x95T\xd6WN`}\xbd\xb4\xd5\x19ɪ\xa7?\xf5\x92\xbe\x96~tveڲ\xcc\xe1\x84Ӥ4Ӥ\xa5\x9b\x94\x01\x1f5Ԥ\xf4ѹI\xa3I\x9cL\x9f\xae\xaf\x9a\x16\xfa\xaaɠ\xaf\x9f\x02:)m\x93\x15\xe6&y\x8e_r\x18ʴ\x03P|\v\xe1|.\x99\x94\xee\xb9\xe6ϊ;?\x0f`\xa1\xb0\x047\xf5\x15〲.\xac\xa8\x8a\xf6>\xb6X\xc0\xb9\x81]sY\xd1ϊ\x8e\xc8\xfb\x9b\xba>\x7fi$~9\x88j\xb8aOP\x14\x8c\xc7\xe6\xe6\x1e\x152w\x0fh\xa6\x16\x80\xb6\x11g\xb9\xbf\x8c\xc9_\x1ez\xe1\xa6\v\xdd\x06@\x16\xb6\x8c-\xf5qy\xf8\xa6\xaf\x83\x06,U\x8f\xedy\xe6.ޠo\xbfԠw\x8c\xee\x1dk|\xb3\xf6P\xa9\x9f\xe8\x06\x03Ӡ~\xbc:<\xb4g\xb2\x17\xe0\xb4ꁽ\x93\xce#\x18\xe2DmP\xef\xb4\x01\x1d*U\x8cӢ\xfdD@H\xd5@\x884Mq\xfe眲|\x89\xf0\xee\x14\x01^\x92\a4\xcf{\xfd\x86\xa7'\x8f=5\x99\x9e\x8c\x92tJ\xf2%½9\x01\xdf,\x7f5\xfd\x14\xe4\xfc\x8d\xe7\x17>\xf5\xf8R\xa7\x1dgP/\xf5t\xe3|ڽ\xd2i\xc6W?\xc5\xf8\x9a\xa7\x17g\x9dZLNϚ\x95q0'\xb5\xea\x19\xc7\xed\xd2r\t\xa6O!&\x9e>L\xcc4H\x1b\xfc\x91\xc3N<]8\xffTa\"\x7f\xe7L\xe9W>=\xf8ʧ\x06\xbf\xc5i\xc1\x04\tL\xa82\xffT\u0cf7\xa4\x94\xceAOn\xfb͑\xdaIyM\x8d\xe5\xfa\x88\r\xf6\xb5\xc2m\xb2X\xab\x17\x03\x90Y\xf2\x17\xf9ӣ\r\x87\xb6\xc1Q2;\x1eQo_\xb2u\xd7\xfa\x0e\xb1\x7f\xcd\xc1m]\x1a\xa88\x1a\x00\n\xdc(5+\xea*|\xe0\xd9f\xd0Æ\x1b\xb6V\xba䖝7\x9b\xc5o\\\a\xf8\xf7\xf9\x92\xb1\x1fT\x93\xabӽ/͈\xb2*v\x18\x89\xb1\xf3n\x83\xe7IIT:C\xcf7\xaa\x10Y\xc4\xe7\x1c\xbdW\xcf5ػl\x88n\xfe\xcb:\xd9\"\xb1\xc0\a\x9b\x8bp\xebb\xffJfw\x9f\xfb\x91k%\xbc\x12\x7f\xa6'\x95N\xb0\xea\xf6\xee\xe6\x9a`\x051\xa2\xb7\x9a\x9a\x04ņ\xe5+@\x97\xa1\x1d\xfb!}r\xbd\xeeA\xed\xe7\bw\x1f\xab\x80ܽL\x12\xdc\x16\xaf\x9a3\x85Z\xeb\xe6\xda\xe1r\xa8'\x94/.wL\xf9\xa7'\x84\xce\x17\x15\xd7v璉.zx\x04\xbb>\xb5jv\xd0Z\xed\xbf\xbc\xd2-=\xb2\x87GWh'{W\xf5\x93\a\x86\xf4|\x0eN\x87OUO\x9e\xa7~\x01\x9c\x0e\xbbP\v\xa2b\xe4\xa7h\x06\xe4\xc9W,\x8d\xbf\xa1\xffG\xb5\x85\xf7ѕ\xcb\xfe\xeb+\x83&#\xa9\x89\x01*]2\x1f\xa1`\x9b\x8fHw|?O\xed\xc5s\r\x03*\xfe\x8e\xf0\xe7,N\xde\xf6A\x8d?HB7\xa8\x87Nc^\x15=\xf5\xb4c7\xf7\x14\xb76\xaa\xd4O}\x1f\xb7\x86\xe5ɐ`\x10\x81%\xe4\xc17ZNEF\xab4\x7f\x80\x8fʽ\xad\x93\"&\xfd\x16\xbd\x97\x97\xbc\xe7\x16\xf2\xb5\xfd$\x8c)z?\xb6!\xc0\xf6|\xc6\xdeE\xff\x88\xed\x91O\x19X[\xba\x91ғ&\xef\xfd\xeb$\xa8\x8f\r \v\x02\x05\x1c\xb4\x15\xfew\xa3\x9e\xe8\x02\xfc\xf8\x1asx@\xa4\xf3\x86\x19\xd0A\x11J\xe1=j\x98uU(\x9e\x83\xbe\xa2GT\x12F\xfcS\xaf\xc1\xc0\x1d\xe8?\xc5\xe2\xedfd<\xa1\xe7\x17̒A\x8f\xae(\xa0\xf8A\x14`\x1c≦\xe1f\xbfec)\xear\xe5<\xd55\xfe\xd8tr\xc02\xbb\xa1\xd2\x06C\x05\x1a\xfdD\xb7\x15Q\x9b \xf9\x87\x89\xc1\x1a>\ni\xe1\x01\xc6c\xe8\t\x9b\xe0\xdeh \a (0\x8a\xf8\xfe\x12[y\xec\x11\xe4>\xdez \x03\xcdbdL\x8e\x95w\xabn\xee\xaf\f\xabeN\x1b\x00\xf7\x7f\xbe=J~\xb7\xbd\xf7e\x82NHQ\xef\xf7\xe3-;!BG;\x91O\x1fW\xe21X\xdc\x18\x95\t\x8a*\x9e\x84\xf5\xd79\xbe\xdc\x1d\xe2\x87\x02\xc4\x03\xd2Q\x1b\xf8\xfc$A\x7f\t\x16\xc8\\\xcbػ-\xd3\xda\xef\xa7=h\xd1\xf7Z\xac¾G`\f\x000\x15\xf6\xb9\x8c{\t(l\xaf\t\xd3H\x1c\xc4>\x01\xdcyG\xc8ik\x85\xb4\xe3\x9c!n\x9bVt\xd8tDCN\x8b\xed\xfd\x00\xc6 \x93\x9d\x1e}j\xaa\xb8Ӧ\x86\xfd^\x8cy\xa3\xb4c\x96\xe1@\xff\xb0\xf7kT\x83\x1f\xd4\xde1\xcd=\xaaF\xf6>\xd2CxyGr\xbc\x97\xde\xfdR\xaf\xda\a\x15\xd8\xdf\xfe~\xf6\x8f\x00\x00\x00\xff\xff)\x00\x87w>{\x00\x00"), diff --git a/config/crd/v2alpha1/bases/velero.io_datauploads.yaml b/config/crd/v2alpha1/bases/velero.io_datauploads.yaml index dff364ea2..be2bb0861 100644 --- a/config/crd/v2alpha1/bases/velero.io_datauploads.yaml +++ b/config/crd/v2alpha1/bases/velero.io_datauploads.yaml @@ -219,10 +219,6 @@ spec: description: SnapshotID is the identifier for the snapshot in the backup repository. type: string - snapshotSize: - description: SnapshotSize is the logical size of the snapshot. - format: int64 - type: integer startTimestamp: description: |- StartTimestamp records the time a backup was started. diff --git a/config/crd/v2alpha1/crds/crds.go b/config/crd/v2alpha1/crds/crds.go index f00338a71..7bfa0b6cf 100644 --- a/config/crd/v2alpha1/crds/crds.go +++ b/config/crd/v2alpha1/crds/crds.go @@ -30,7 +30,7 @@ import ( var rawCRDs = [][]byte{ []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcYK\x93\xe3\xb8\r\xbe\xf7\xaf@M\x0es\x19\xbb3yl\xa5|\x9bq'U]\xd9\xe9q\xad;}\xa7$X\xe6\x0eE2|\xd8\xebM\xf2\xdfS %\x99\x92\xe8\xe7>|3\t\x82\x1f\x01\x10\xf8@\xcdf\xb3\a\xa6\xf9\x1b\x1a˕\\\x00\xd3\x1c\x7fr(韝\x7f\xfb\x9b\x9ds\xf5\xb8\xfb\xf8\xf0\x8d\xcbj\x01Ko\x9dj~@\xab\xbc)\xf1\t7\\rǕ|hб\x8a9\xb6x\x00`R*\xc7h\xd8\xd2_\x80RIg\x94\x10hf5\xca\xf97_`Ṩ\xd0\x04\xe5\xddֻ?\xce?~7\xff\xeb\x03\x80d\r.\x80\xf4Uj/\x85b\x95\x9d\xefP\xa0Qs\xae\x1e\xacƒ\x14\xd7Fy\xbd\x80\xe3D\\\xd8n\x1a\x01?1ǞZ\x1daXp\xeb\xfe9\x99\xfa\x9e[\x17\xa6\xb5\xf0\x86\x89\xd1\xdea\xc6rY{\xc1\xccp\xee\x01\xc0\x96J\xe3\x02^hk\xcdJ\xa4\xb1\xf6L\x01\xca\fXU\x05+1\xb12\\:4K%|\xd3Yg\x06\x15\xda\xd2p\xed\x82\x15RX`\x1dsނ\xf5\xe5\x16\x98\x85\x17\xdc?>˕Q\xb5A\x1ba\x01\xfch\x95\\1\xb7]\xc0<\x8a\xcf\xf5\x96Ylg\xa3)\xd7a\xa2\x1dr\a\xc2k\x9d\xe1\xb2\xce!x\xe5\rB\xe5Mp!\x9d\xbbDp[n\x87\xd0\xf6\xcc\x12<\xe3\xb0:\t$̓:\xebX\xa3Lj\x92\xa5\x11R\xc5\x1c\xe6\x00-U\xa3\x05:\xac\xa088쎱Q\xa6an\x01\\\xba\xef\xfer\xda\x16\xad\xb1\xe6a铒C\xc3|\xa6QH\x86#\x12\xf2R\x8d&k\x1d\xe5\x98\xf8%@\x1c)\xf8\x9c\xac\x8fH\xa2\xdet\xfc\"\x14\n9P\x1bp[\x84Ϭ\xfc\xe65\xac\x9d2\xacF\xf8^\x95\xd1}\xfb-\x1a\f\x12E\x94\xa0\xe8\x05N\xbeS&\xeb:\x8d\xe5<ʶ\xca:]#\xff\r7\xfa\xd5c\xab4Ȳ\xb1ե\x9ay\x90\xe0J\xe6\x03\xecS\x8dW\x05WjD\xa9*L,6\xc0\xc4-h\xa3J\xb4\xf6L\xc0\x93\x82\x01\x8a\x97\xe3\xc0\xc44Qb\xf7'&\xf4\x96}\x8cI\xa6\xdcb\xc3\x16\xed\n\xa5Q~Z=\xbf\xfdy=\x18\x863\t\x83\x95\xceR\xa6 \xf8\xda(\xa7J%\xa0@\xb7G\x94\xd1\xf5\x8dڡ\xa1\x9a\x8d\x93\x06C\xf4\x10@\x93z\x1fhO\x8d\xc6\xf1.\v\xb7\xba\x8f\x05&\x19\x1d\x9d㿳\xc1\x1c\x00\x1d=\xae\x82\x8a*\r\xc6c\xb5\xb9\x15\xab\xd6Z\xd1y܂AmТ\x8c\xb5\x87\x86\x99\x04U\xfc\x88\xa5\x9b\x8fT\xafѐ\x1a\xb0[\xe5EE\x87ݡq`\xb0T\xb5\xe4?\xf7\xba-8\x156\x15̡u\xe12\x1a\xc9\x04\xec\x98\xf0\xf8\x81\x8c6\xd2ܰ\x03\x18\xa4=\xc1\xcbD_X`\xc78\xbe\x90\x15\xb9ܨ\x05l\x9d\xd3v\xf1\xf8Xsו\xddR5\x8d\x97\xdc\x1d\x1e\x837x\xe1\x9d2\xf6\xb1\xc2\x1d\x8aG\xcb\xeb\x193\xe5\x96;,\x9d7\xf8\xc84\x9f\x85\x83\xc8Pz\xe7M\xf5\a\xd3\x16j;\xd8v\x12\x88\xf1\x17\n\xe6\r\xee\xa1*J\xb7\x82\xb5\xaa\xe2\x11\x8f^\xa0!2\xdd\x0f\x7f_\xbfB\x87$z*:\xe5(:\xb1K\xe7\x1f\xb2&\x97\x1b4q\xddƨ&\xe8DYiť\v\x7fJ\xc1Q:\xb0\xbeh\xb8\xa30\xf8\xb7G\xeb\xc8uc\xb5\xcb@M\xa0@\xf0\x9a\xf2A5\x16x\x96\xb0d\r\x8a%\xb3\xf8;\xfb\x8a\xbcbg䄫\xbc\x95\x12\xae\xb1p4o2\xd11\xa6\x13\xaeM3\xc8ZcI^%\xc3\xd22\xbe\xe1m%\xa14\xc0\x06\xb2C\v\xe5\xaf>\xfd\xb2\xd5d,t)\xdc\xe8\xf79\xa7\xa8C+\x93D\xde\xd6:\xdb\x16)1,R\xe9oR\x1f\rje\xb9S\xe6p\xac\x92\xe3P8\xe9\x15\xfa\x95L\x96(\xee9\xde2\xac\x04.+\xb29\xf6\xa1LI(j\r@\x95\xac\x15]\xae\x81+\xe0ّ\fŶE\x97?\xa8\xccV5.\xe1\xc8)!\xe5\x8e\xe3\xe3\x16J\tdc+R\x14~\xa1\xb2\xb0Tr\xc3\xeb\xe9\xc1S\xfa{*D.\xd84\x13\xb0ɖt\n\x8aNB2\v\x15jօ.\xa5\xf6\r\xaf\xbd9\xe5\xff\rGQM\xf2\xcfɛ\xd4\x1d8\xecr\x8f\x8f{\xe8\xdd\xedj\xabZRz\x9d\n\x19\xca\x06\xbe\x9b\x84\xe6\x14$\xc0\xf3&\xd1\xc8-\xbc{\a\xca\xc0\xbb\xd8\x13\xbd\xfb\x10W{.܌\x0f\xea\xff\x9e\v\xd1\xedrSt\x13\xc3\xf9\xba\xbep\xf2\x97 Dx\xbe\xaeo\xe5VS4(}3\xddp\x06\xcc;\x95\x19\x16\\\xfa\x9f2\xe3{.+\xb5\xb7\xb7\x1c\xb6\xe77D1\x95w\xf78\xfc\xebH\xc7\xc8\xef\x8e\bq\xf0\xb5S\xb0g<\xe1\x18\xfd\xee\xf6CFo\x81\x1b*H\x06\x9d7\x92\xd2\x01\x1aC\x19\xda\x06\x95\xcaO8\xcfٓZɴ\xdd*\xf7\xfct\xe1\x8c\xeb^\xb0˻\xcfO\x9d\x8b\xdfB\xd4\xf5ɷ\x95\x84\x8c\x97\b~\xc7\"\xabP\xd6\xefB\xbb\xe6?\xe3\x95xI\xb4C,T\xcdK&\xc0\xd2X\x8b\xbdS9ők\xef\xc6(\xd3&-\x81\x19(O\xff0pO\xf4\xac\x87*\xba\x13(\xc3kN1\"\xfb\x99\xe3\xd5\xda)\xe1\x9b J\x9e\xc0\n\xbc>ab\xa0\xaaA\x1c\xab@\xa8\xf8f\x83\x86\x88T`Yq\xe3\xd5\xdb\xf2\xbdM6\xe1\x9b\xf4\x0f\x15\xa8\x86i\x8d\x15\xb5t\x14\x83\xadKor\xa6c\xa6F\xf7\x16@_0\xd1k\"ڙ\x82\x18\x199\xa8\xa5\xfc\xe1N\x051X\xbd-3\x04\x9d~\xab\xb7)\xc2\xd3\xf4\x05\xda^\xed\x84\x13'('\xdej\xf1\xf4:\xb2*\xceV?\x00\xbd\xbbb\xe7\xd5[\x8e\f\xf5\xe6\x00\xb7e\x8e$\xda\xde\x1a\x8aCV't7\xb9u\xe7}x˫\x00/\xcf\"^\x8e!\x9f\xc0[\x1c~1d\xe2Z\xdc`\x95\xab4\xa7=7\x03\xbd\xcb\x0e\x96\xd73\x8a\xfcγokf\xb0\x9b\r\xea[\xf9\x89nȾ\x13\xb7\xc6j.\xab\xdc\xf9/\xbcA(\x9d\xf6f#\x99\v\x04[s\x932\xb6c\x86\x98\xd3\x16˃l\xf8y\"f,k\xda1?\xc9\xd6\xc0P\xc9,\xe6\xd8Y\xaa\xa6\x15h\xb1\x84\xf5\xbb\xc5(\xc4F\xe9\x86\xd9\x05pi\x7f\xfc\xcbaMt\xaa\x9a\xfb\xad\x0fJ\x0e\xd5rO\xa3\x90\f\aN\xc8B\x15\xea\xacn\x94e\xe2\xb70b\x89\xc0}\xb2?p\x12\xe8\xa6\xe3'Y!w\x03\xb5\x01[#ܳ\xe2͵\xb0\xb2J\xb3\n\xe1'U\x04\xe3\xedjԝ\xf1\xd6a\x89\xa9\x95\x13%\xac\xa3\xc4\x00\xc6*\x9d\xb5b\x8b\xc5<\xec\xea\xe8F\xb2#S\x0e\xcf\xfc\x9d\x9d\xac\xd0ȲN\x16Qf\xeeWp%\xf3\x9e\xf6\xa9³\xbc,զT%\xf6\xaaÔ#n\xa0ժ@c\x8e\xf8=m\x1f\xf0\xf0\xb4\x1f\x98\xa8%\xac\xd8\xfe\x89\x89\xb6f\x1f\x03\xca\x1456l\xd1\xedP-\xcaOϏ\xaf\x7f^\r\x86\xe1 f\xb0\xc2\x1a\x02\vb\xbd\xd5ʪB\tX\xa3\xdd!J\x8f[Ш-j\x02\xb9\x8aK\x03L\x96=MH\x17졚\x9c\xdcӣ\xd90ٹ\x93jQ\xa7f\a:\xb2EmyD\xdf\xf0%a%\x19\x1d\t\xf1\xdf\xd9`\x0e\x80\xe4\x0e\xbb\xa0\xa4\xf8\x82A\xaa\x0e[\xb1\xecT\x15\xec\xc6\rhl5\x1a\x94!\xe2\xd00\x93\xa0\xd6?ca\xe7#\xd2+\xd4D&އB\xc9-j\v\x1a\vUI\xfekOۀU\xfeP\xc1,\x1a\xeb/\xa4\x96L\xc0\x96\t\x87\xb7#\xed\xd1װw\xd0Hg\x82\x93\t=\xbf\xc1\x8c\xf9\xf8\xac4\x02\x97\x1b\xb5\x80\xda\xda\xd6,\xee\xee*nc\xb0-T\xd38\xc9\xed\xfb\x9d7\x06_;\xab\xb4\xb9+q\x8b\xe2\xce\xf0j\xc6tQs\x8b\x85u\x1a\xefX\xcbg^\x10\xe9\x03\xee\xbc)\xff\xa0\xbb\xf0l\x06\xc7N\xbc0|>P^`\x1e\x8a\x9ft%XG*\x88\xb8\xb7\x02\r\x91\xea\xbe\xfe}\xf5\x02\x91\x93`\xa9`\x94\xfd҉^\xa2}H\x9b\\nP\x87}\x1b\xad\x1aO\x13e\xd9*.\xad\xffQ\b\x8e҂q\xeb\x86[r\x83\x7f;4\x96L7&\xbb\xf4\t\t\xac\x11\\KPP\x8e\x17xI\x8aR!\xfcMe\x00\x82\xee=En\xe0\xc3\aP\x1a>\x84^ˇ۰\xdbqag|P^\xec\xb8\x10\xf1\x94\x8b\"h_RPA\xa7ܩВ\xd5\xc1\x97\x11\x8d\x91*,\x15\x9f^|\xab`\xc7x\x92\xd6\xf7\xa7\x9b\xdb\f\xdd5n(\a\xd4h\x9d\x96\x14\x85QkJ\x8b\x8c'\xa9\\&\f\x1d\x91\xd4$!\xf1\x84\x94\xe3\xe8饠\xff\x8f\xb1<\x05\x80\x8c\x009\x1b\x1f\xe3Ч\xec}c\xeb\x1aS\xac\x86$\"\xf3J\xf3\x8a\x93\xc2e?\xb3O\xc6:\xac\xeb\xba\x16\x1e\xc9<\x14g\xfd\xb3GKCh\xb9'G\xd79\x1cNh\xcfd\xe9\xf3\x85~\xbe\xec\xae^\xe6\xe2\x9eT\xc8\xf3\xeb\xf2\x94\xbd\xfa\x833PNû\x9a\x17\xf5\xd0t|\n\xaa\x00\x96\xbd\xa1Ͻ/`3\x8f\xe1\xb3|&>Z3\xbe}\xa3\xe9\xd4e\xc7SCCgg\x9f_\x97gU+\xbe\x91r^\xbd\x12:\xa4\x9d\x96\v\xa7\xb5\xaf\x04è\xda\\U\xb1\xb0\xa2\xc0\xd6by\xff\xfe\xa4\xcaSN\xffi\xb0\x98\x18\x91紒2\xa6\xf6\xcd%l٥%Gd\xb7o\x80]sM?\x8d\x89\xf8V\x88.\x13\xc0\x9c\x16\x10\x01l\x0e3\r\xf0B\x0e\xeeK\xf9\x1f\x02F\xd26\x8f\xbct='\x87N(\xc4\xee*\xd5\xea3\xda\x7f]\x94͗j\xa1\xb1\x9c\xb6\x0e\xaf\xaaۦd\xa6\xbac\xb1\xc0\xf4=\xcd\xd8\xd1\xceilO\xae\xd7W\xa0\x86%\xe0\x16%P)θ\xa0\xd8\xedIf\x00\xec8\x95.\x88\x85\xe7\x8bأ\x89\xfd\xbcl\xb3\xec\xb4%3J\x98\xa2ٷ4f\x9fB~E\xe3D&i\xf8\x86)d82t\vL6\x85<^\xce2\x03\ft \xd2\xe1\xc6!\xd0:[Iټ\xb2AcXu\n\xd1>\x87U\xa1\xb3\xd7m\x01\xb6\xa64j\xc8\xda\x0f\xa6\x03ڋ\xe0J\x9e\xc6ԋ\x90tД\xbf\x98\x93/\xab3x\xf9\xb2\xa2C\xbe\xac~+/(]\x93+\xac\x98\xb3*3,\xb8t\xbfd\xc6w\\\x96j7\xbd_GDm\x99\xadO\b\xfa\xccl\x1d\xe3\xe8\xc6\t\xe1\xf7L\xf2\xcb.5[#\x01\xc7\xef\x95f\xfa\xd6\xd3)\xf6hM.\xce\xe39w\xe6\x90\xe6\x9fp\x97\x19\x8dq)3\xf5\xdc\x05\xbb\xcc\xd4\xe4e6\x9d\fݽ\x1c\xa6Ĺ,\xcd\xfe\xf133\xf7\x0f\x1f\x05.\xd2s\xc7\xdf5a\xae\xef\x13\xd6J\xc4\xc8\xe6\x1f-\xa5k֨\xc9\b\xfeYtԯ\xa0\xbc;\xb1X\x86p\xb2\xbfO\xf6=\xa59\xbc\xd4\xdc\xc4\xcef,\xd7JnZ\xc1\xde{YNak\x8f[\xe3\x17\xab\xa9\x93\x1co\t\xf6O\xc8\xf9vN\xee\x1dx\xf8M_tG\xf3\xfd\xd3\xf0\xb79\xe1H`\x88\xd7\xfb\xf1\xe1\xcc:\xf4\xf1!^E^\xa2\xb4TZ\xef_\t\xf7\x15\x8d\xef:\xe7t9\xee\xb6_U7\xaf\xf8\xaf\xe7\xd6ʹ4r,T\xc5\v&\xc0\xd0\xd8\bߦ|\x1c\xd7\xfa1\x8d\x0f\xff\xfe\xe1\xaa\xday@\xe1DV\xd9\xfd9F.w[\x11f\x11R\xfa\xe7\xb3\xe5\xf8\xc1\xfc\xb6\x7f\x7fg\xb6{\xc3+j&+\xcc\x15\xa4JR\xaa\xe2S\x9d\xcb\xd3ġ@\xdf3C\xcc:\xffd\xd0s^&\xb4\xbb\x96g:\xe2\xd6\xfd\xa3\xea\x02\xfe\xf3\xbf\x9b\xff\a\x00\x00\xff\xff\xe5\x00\x96\xae6%\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcZIs\xe3\xb8\x15\xbe\xfbW\xbc\xea\x1c\xe6b\xc9\xe9,S)\xdd\xdarR\xe5ʴ\xdb\xd5r|\x87\xc8'\x11c\x10`\xb0H\xe3,\xff}\xea\x01\x04\x05\x92\x90(i\xa6\x9b\x87\xae\x16\x96\x87\xb7\xe1{\v<\x9b\xcdnX\xc3_Q\x1b\xae\xe4\x02X\xc3\xf1\x17\x8b\x92~\x99\xf9\xdb\xdf̜\xab\xbb\xddǛ7.\xcb\x05,\x9d\xb1\xaa\xfe\x8aF9]\xe0\x03n\xb8\xe4\x96+yS\xa3e%\xb3lq\x03\xc0\xa4T\x96Ѱ\xa1\x9f\x00\x85\x92V+!P϶(\xe7on\x8dk\xc7E\x89\xda\x13\x8fG\xef\xfe8\xff\xf8\xe3\xfc\xaf7\x00\x92ո\x00\xa2\xe7\x1a\xa1Xi\xe6;\x14\xa8՜\xab\x1b\xd3`Ad\xb7Z\xb9f\x01\x87\x89\xb0\xad=2\xb0\xfb\xc0,\xfb\x97\xa7\xe0\a\x057\xf6\x9f\x83\x89\x9f\xb8\xb1~\xb2\x11N3\xd1;Տ\x1b.\xb7N0\x9d\xce\xdc\x00\x98B5\xb8\x80':\xb2a\x05\xd2X+\x89ga\x06\xac,\xbdn\x98x\xd6\\Z\xd4K%\\\x1du2\x83\x12M\xa1yc\xbd\xec\a\x86\xc0Xf\x9d\x01\xe3\x8a\n\x98\x81'\xdc\xdf=\xcag\xad\xb6\x1aM`\t\xe0g\xa3\xe43\xb3\xd5\x02\xe6a\xf9\xbc\xa9\x98\xc1v6\xa8o\xe5'\xda!\xfbN\xdc\x1a\xab\xb9\xdc\xe6\xce\x7f\xe15B\xe9\xb47\x1b\xc9\\ ؊\x9b\x94\xb1=3Ĝ\xb6X\x1ee\xc3\xcf\x131cY\xdd\f\xf9I\xb6\x06\x86Jf1\xc7\xceRՍ@\x8b%\xac\xdf-F!6J\xd7\xcc.\x80K\xfb\xe3_\x8ek\xa2U\xd5\xdco}P\xb2\xaf\x96{\x1a\x85d8pB\x16ڢ\xce\xeaFY&~\v#\x96\b\xdc'\xfb\x03'\x81n:>\xc9\n\xb9\x1b\xa8\r\xd8\n\xe1\x9e\x15o\xae\x81\x95U\x9am\x11~RE0\u07beB\xdd\x1ao\x1d\x96\x98J9Q\xc2:J\f`\xac\xd2Y+6X\xccî\x96n$;0e\xff\xcc\xdf\xd9\xc9\n\x8d,\xebd\x11e\xe6~\x05W2\xefi\x9f\xb6x\x96\x97\xa5ڔ\xaa\xc4Nu\x98r\xc4\r4Z\x15h\xcc\t\xbf\xa7\xed=\x1e\x9e\x0e\x03#\xb5\x84\x15\xbb?1\xd1T\xecc@\x99\xa2\u009a-\xda\x1d\xaaA\xf9\xe9\xf9\xf1\xf5ϫ\xde0\x1c\xc5\fVXC`A\xac7ZYU(\x01k\xb4{D\xe9q\vj\xb5CM \xb7\xe5\xd2\x00\x93eG\x13\xd2\x05\a\xa8&'\xf7\xf4h6L\xb6\xee\xa4\x1aԩف\x8elP[\x1e\xd17|IXIF\aB\xfco֛\x03 \xb9\xc3.()\xbe`\x90\xaa\xc5V,[U\x05\xbbq\x03\x1a\x1b\x8d\x06e\x8884\xcc$\xa8\xf5\xcfX\xd8\xf9\x80\xf4\n5\x91\x89\xf7\xa1Pr\x87ڂ\xc6Bm%\xffOGۀU\xfeP\xc1,\x1a\xeb/\xa4\x96L\xc0\x8e\t\x87\xb7\x03\xed\xd1W\xb3w\xd0Hg\x82\x93\t=\xbf\xc1\f\xf9\xf8\xac4\x02\x97\x1b\xb5\x80\xca\xda\xc6,\xee\xee\xb6\xdc\xc6`[\xa8\xbav\x92\xdb\xf7;o\f\xbevVisW\xe2\x0eŝ\xe1\xdb\x19\xd3E\xc5-\x16\xd6i\xbcc\r\x9fyA\xa4\x0f\xb8\xf3\xba\xfc\x83nó\xe9\x1d;\xf2\xc2\xf0\xf9@y\x81y(~ҕ`-\xa9 \xe2\xc1\n4D\xaa\xfb\xfa\xf7\xd5\vDN\x82\xa5\x82Q\x0eKGz\x89\xf6!mr\xb9A\x1d\xf6m\xb4\xaa=M\x94e\xa3\xb8\xb4\xfeG!8J\vƭkn\xc9\r\xfe\xed\xd0X2ݐ\xec\xd2'$\xb0Fp\rAA9\\\xf0(a\xc9j\x14Kf\xf0;ۊ\xacbfd\x84\xb3\xac\x95\xa6Y\xc3\xc5A\xbd\xc9D̔\x8e\x98\xf6\x00\x1f\xab\x06\v\xb2)\xa9\x956\xf1\roc\ta\x00KV\xf6\xb5\x93\xbf\xf6\xf4eC\xc8pє\xab\xd1w\x9f#\x14y\x95\t~\xc7P\xd7F&яL\xe9w\x00\xf9v\x8f\xc6F\x19n\x95~'\xc2!4\x0e\xdd\xe0\xa8E\xe8+\x98,P\\#\xde\xd2\xef\x04.K\xd28vnL\x00\x14\xa8zF\x95\xdc*\xbaX\x89!\xe0\xd1\xd2\n\xf2j\x836/\xa6̄2.\xe1\x90MB\x9a5\x0eE]+%\x90\r5X\x18\xbe\x92\xac1\x95\xb2\x13\x02?n \xae|yo\x90\x0e_\xae\x1eo\xe9\x9f8N\x1e\xb4\xe3e\v\xf1t\xcb(\xafʛ\xad\xb5\xf3r\xf5\b\xa6\xdd>6\x92tB\xb0\xb5\xc0\x05X\xedƂ\x1dwXϽ\xe6;Թ\x99\xe1\xcd\xf1\v\xa3\x17\x86m\xe0\x8c\xcfV\xfd\xd0+e\xfa\x18\xa5\\*iQ\xe6ltҫ苒.\x053Y\x9e\a\x9c\xad\xd2\xf5\xb9k\x12\tB\xe1W؊\xe5\xf9\x82\x10t\xbd\x1c\x87M\xbc\xcb\xcd`\xcfmu\x95D႞-P\xb2<+O{߃8jsB\x98\xe7ץ\x97wJ2\n7\xd7H\xb6\xeb\x19\xfd\f\xd9\xfa^\x92\x93n\xc0\xe51\xe1\x14\xa1\x00\x81\x19\x96\xe0\x9a\xcby'\xd0\xe1\x1a\xcb1ϳ\x9e\xbd2\xd3}\xa1\x8f \xc9(2A\x9bt~\xa6\xb4r\xa9\xe4\x86o\xc7g\xa7\xf5\xf3\xa9k{R\xb4Q\xc4K\x8e$\x8dS\x80#Nf>Ý\xc5\xe8G\xb9\xe1\x86o\x9d>\x86F\x1b\x8e\xa2\x1c%0\x93\x004\xa1\x0f\xcf\xc45q\xa4\x93,\xc6\xef\x16R\x93\xcc>xI\x8aR!\xfc\x8de\x00\x82\xee\x03En\xe0\xc3\aP\x1a>\x84^ˇ۰\xdbqag\xbcW^\xec\xb9\x10\xf1\x94\x8b\"hWRPA\xa7\xdcTh\xc9\xea\xe0ˀ\xc6@\x15\x96\x8aO/\xbeU\xb0g\x89ȼ\xd2|\xcbIᲛ9$c-ֵ]\v\x8fd\x1e\x8a\xb3\xfe١\xa5!\xb4<\x90\xa3\xeb\x1c\x0e'\xb4g\xb2\xf4\xf9B7_\xb6W/sq'\x15\xf2\xfc\xba\x9c\xb2Wwp\x06\xcaix_\xf1\xa2ꛎ\x8fA\x15\xc0\xb27\xf4\xb9\xf7\x05l\xe61|\x96\xcf\xc4\ak\x86\xb7o0\x9d\xba\xecp\xaao\xe8\xec\xec\xf3\xeb\xf2\xacj\xc57RΫWB\x87\xb4\xd5r\xe1\xb4\xf6\x95`\x18U\x9b\xab*\x16V\x14\xd8X,\xefߟT9\xe5\xf4\x9fz\x8b\x89\x11yN+)cj\xdf\\\u0086]ZrDv\xbb\x06\xd85\xd7\xf4Ӑ\x88o\x85\xe82\x01\xccq\x01\x11\xc0\xe68\xd3\x00/\xe4ྔ\xff!`$m\xf3\xc8K\xd7st\xe8\x88B\xec\xaeR\xad>\xa3\xfd\xd7E\xd9|\xa9\x16\x1a\xcbi\xeb\xf0\xaa\xbamLf\xac;\x16\vL\xdfӌ\x1d\xed\x9c\xc6\x0e\xe4:}\x05jX\x02\xeeP\x02\x95\xe2\x8c\v\x8aݞd\x06\xc0NSi\x83Xx\xbe\x88=\x9a\xd8\xcf\xcb6˦-\x99Q\xc2\x18;\xa51\xbb\x14\xf2+\x1a'2I\xc37L!Ñ\xa1[`\xb2)\xe4\xe9r\x96\x19`\xa0\x03\x91\x167\x8e\x81\xd6\xd9J\xca\xe6\x955\x1aöS\x88\xf69\xac\n\x9d\xbdv\v\xb05\xa5Q}\xd6~0-\xd0^\x04Wr\x1aS/B\xd2^S\xfebN\xbe\xac\xce\xe0\xe5ˊ\x0e\xf9\xb2\xfa\xad\xbc\xa0tu\xae\xb0bΪ̰\xe0\xd2\xfd\x92\x19\xdfsY\xaa\xfd\xf8~\x9d\x10\xb5a\xb6\x9a\x10\xf4\x99\xd9*\xc6э\x13\xc2\xef\x19\xe5\x97mj\xb6F\x02\x8e\xdf+\xcd\xf4\xad\xa7)\xf6hM.\xce\xe39w\xe6\x98\xe6\x9fp\x9f\x19\x8dq)3\xf5\xdc\x06\xbb\xcc\xd4\xe8e6\x9d\fݽ\x1c\xa6Ĺ,\xcd\xee\xf133\xf7\x0f\x1f\x05.\xd2s\xcb\xdf5a\xae\xeb\x13VJ\xc4\xc8\xe6\x1f-\xa5\xabר\xc9\b\xfeYtЯ\xa0\xbc;\xb1X\x86p\xb2\xbfK\xf6=\xa59\xbcT\xdc\xc4\xcef,\xd7Jn\x1a\xc1\xde;Y\xa6\xb0\xb5í\xe1\x8b\xd5\xd8IN\xb7\x04\xbb'\xe4|;'\xf7\x0e\xdc\xff\xc6/\xba\x83\xf9\xeei\xf8ۜp\"0\xc4\xeb\xfd\xf8pf\x1d\xfa\xf8\x10\xaf\"/QZ*\xad\x0f\xaf\x84\x87\x8a\xc6w\x9ds\xba\x1cv\xdb/+\xc2z\x7fXpUQڣ0\x91\xae\xb5\x7f\xe7\x90K\x8aV\x04\x06\x04A\xfe]j9|\x89\xbe\xed\x1e\xb6\x99m\x1fNJ\x8a\xc9-\xe6*=%)\a\xf09\xc4\xe5\xf9W_\xa0\xef\x99ze\xbdj4\xe89/\x13\xdam/1\x1dq\xeb\xee\xb5r\x01\xff\xfd\xffͯ\x01\x00\x00\xff\xff\xee\xe6t\xbc\x8f$\x00\x00"), } var CRDs = crds() diff --git a/pkg/apis/velero/v1/pod_volume_backup_types.go b/pkg/apis/velero/v1/pod_volume_backup_types.go index f0ea8dc38..546616c5a 100644 --- a/pkg/apis/velero/v1/pod_volume_backup_types.go +++ b/pkg/apis/velero/v1/pod_volume_backup_types.go @@ -123,10 +123,6 @@ type PodVolumeBackupStatus struct { // +optional // +nullable AcceptedTimestamp *metav1.Time `json:"acceptedTimestamp,omitempty"` - - // SnapshotSize is the logical size of the snapshot. - // +optional - SnapshotSize int64 `json:"snapshotSize,omitempty"` } // TODO(2.0) After converting all resources to use the runttime-controller client, diff --git a/pkg/apis/velero/v2alpha1/data_upload_types.go b/pkg/apis/velero/v2alpha1/data_upload_types.go index 4db59b214..3d7c95fb9 100644 --- a/pkg/apis/velero/v2alpha1/data_upload_types.go +++ b/pkg/apis/velero/v2alpha1/data_upload_types.go @@ -172,10 +172,6 @@ type DataUploadStatus struct { // +optional // +nullable AcceptedTimestamp *metav1.Time `json:"acceptedTimestamp,omitempty"` - - // SnapshotSize is the logical size of the snapshot. - // +optional - SnapshotSize int64 `json:"snapshotSize,omitempty"` } // TODO(2.0) After converting all resources to use the runttime-controller client, diff --git a/pkg/builder/data_upload_builder.go b/pkg/builder/data_upload_builder.go index f704bbaee..f6bfba68e 100644 --- a/pkg/builder/data_upload_builder.go +++ b/pkg/builder/data_upload_builder.go @@ -181,14 +181,8 @@ func (d *DataUploadBuilder) Message(msg string) *DataUploadBuilder { return d } -// SnapshotSize sets the DataUpload's SnapshotSize. -func (d *DataUploadBuilder) SnapshotSize(size int64) *DataUploadBuilder { - d.object.Status.SnapshotSize = size - return d -} - // TotalBytes sets the DataUpload's TotalBytes. func (d *DataUploadBuilder) TotalBytes(size int64) *DataUploadBuilder { - d.object.Status.SnapshotSize = size + d.object.Status.Progress.TotalBytes = size return d } diff --git a/pkg/controller/data_upload_controller.go b/pkg/controller/data_upload_controller.go index 0d8f6c0f3..46704e5b1 100644 --- a/pkg/controller/data_upload_controller.go +++ b/pkg/controller/data_upload_controller.go @@ -493,7 +493,6 @@ func (r *DataUploadReconciler) OnDataUploadCompleted(ctx context.Context, namesp du.Status.Path = result.Backup.Source.ByPath du.Status.Phase = velerov2alpha1api.DataUploadPhaseCompleted du.Status.SnapshotID = result.Backup.SnapshotID - du.Status.SnapshotSize = result.Backup.TotalBytes du.Status.CompletionTimestamp = &metav1.Time{Time: r.Clock.Now()} if result.Backup.EmptySnapshot { du.Status.Message = "volume was empty so no data was upload" diff --git a/pkg/controller/data_upload_controller_test.go b/pkg/controller/data_upload_controller_test.go index 9cfca2f50..14209052c 100644 --- a/pkg/controller/data_upload_controller_test.go +++ b/pkg/controller/data_upload_controller_test.go @@ -856,7 +856,6 @@ func TestOnDataUploadCompleted(t *testing.T) { Source: datapath.AccessPoint{ ByPath: "fake-path", }, - TotalBytes: int64(1000), }, }) updatedDu := &velerov2alpha1api.DataUpload{} @@ -865,7 +864,6 @@ func TestOnDataUploadCompleted(t *testing.T) { assert.False(t, updatedDu.Status.CompletionTimestamp.IsZero()) assert.Equal(t, "fake-id", updatedDu.Status.SnapshotID) assert.Equal(t, "fake-path", updatedDu.Status.Path) - assert.Equal(t, int64(1000), updatedDu.Status.SnapshotSize) } func TestFindDataUploadForPod(t *testing.T) { diff --git a/pkg/controller/pod_volume_backup_controller.go b/pkg/controller/pod_volume_backup_controller.go index 6073c040f..625ec8337 100644 --- a/pkg/controller/pod_volume_backup_controller.go +++ b/pkg/controller/pod_volume_backup_controller.go @@ -525,7 +525,6 @@ func (r *PodVolumeBackupReconciler) OnDataPathCompleted(ctx context.Context, nam pvb.Status.Path = result.Backup.Source.ByPath pvb.Status.Phase = velerov1api.PodVolumeBackupPhaseCompleted pvb.Status.SnapshotID = result.Backup.SnapshotID - pvb.Status.SnapshotSize = result.Backup.TotalBytes pvb.Status.CompletionTimestamp = &completionTime if result.Backup.EmptySnapshot { pvb.Status.Message = "volume was empty so no snapshot was taken" diff --git a/pkg/podvolume/util.go b/pkg/podvolume/util.go index 6af666b52..1864e9615 100644 --- a/pkg/podvolume/util.go +++ b/pkg/podvolume/util.go @@ -93,14 +93,9 @@ func getVolumeBackupInfoForPod(podVolumeBackups []*velerov1api.PodVolumeBackup, continue } - snapshotSize := pvb.Status.SnapshotSize - if snapshotSize == 0 { - snapshotSize = pvb.Status.Progress.TotalBytes - } - volumes[pvb.Spec.Volume] = volumeBackupInfo{ snapshotID: pvb.Status.SnapshotID, - snapshotSize: snapshotSize, + snapshotSize: pvb.Status.Progress.TotalBytes, uploaderType: getUploaderTypeOrDefault(pvb.Spec.UploaderType), repositoryType: getRepositoryType(pvb.Spec.UploaderType), } diff --git a/pkg/restore/actions/dataupload_retrieve_action.go b/pkg/restore/actions/dataupload_retrieve_action.go index e0be8e20f..a7efdc5f7 100644 --- a/pkg/restore/actions/dataupload_retrieve_action.go +++ b/pkg/restore/actions/dataupload_retrieve_action.go @@ -72,16 +72,11 @@ func (d *DataUploadRetrieveAction) Execute(input *velero.RestoreItemActionExecut return nil, errors.Wrapf(err, "error to get backup for restore %s", input.Restore.Name) } - snapshotSize := dataUpload.Status.SnapshotSize - if snapshotSize == 0 { - snapshotSize = dataUpload.Status.Progress.TotalBytes - } - dataUploadResult := velerov2alpha1.DataUploadResult{ BackupStorageLocation: backup.Spec.StorageLocation, DataMover: dataUpload.Spec.DataMover, SnapshotID: dataUpload.Status.SnapshotID, - SnapshotSize: snapshotSize, + SnapshotSize: dataUpload.Status.Progress.TotalBytes, SourceNamespace: dataUpload.Spec.SourceNamespace, DataMoverResult: dataUpload.Status.DataMoverResult, NodeOS: dataUpload.Status.NodeOS, diff --git a/pkg/restore/actions/dataupload_retrieve_action_test.go b/pkg/restore/actions/dataupload_retrieve_action_test.go index 68c9eacf2..64be241bf 100644 --- a/pkg/restore/actions/dataupload_retrieve_action_test.go +++ b/pkg/restore/actions/dataupload_retrieve_action_test.go @@ -58,7 +58,7 @@ func TestDataUploadRetrieveActionExectue(t *testing.T) { }, { name: "DataUploadRetrieve Action test", - dataUpload: builder.ForDataUpload("velero", "testDU").SourceNamespace("testNamespace").SourcePVC("testPVC").SnapshotID("fake-id").SnapshotSize(1000).Result(), + dataUpload: builder.ForDataUpload("velero", "testDU").SourceNamespace("testNamespace").SourcePVC("testPVC").SnapshotID("fake-id").TotalBytes(1000).Result(), restore: builder.ForRestore("velero", "testRestore").ObjectMeta(builder.WithUID("testingUID")).Backup("testBackup").Result(), runtimeScheme: scheme, veleroObjs: []runtime.Object{ @@ -76,16 +76,6 @@ func TestDataUploadRetrieveActionExectue(t *testing.T) { }, expectedDataUploadResult: builder.ForConfigMap("velero", "").ObjectMeta(builder.WithGenerateName("testDU-"), builder.WithLabels(velerov1.PVCNamespaceNameLabel, "migre209d0da-49c7-45ba-8d5a-3e59fd591ec1.kibishii-data-ki152333", velerov1.RestoreUIDLabel, "testingUID", velerov1.ResourceUsageLabel, string(velerov1.VeleroResourceUsageDataUploadResult))).Data("testingUID", `{"backupStorageLocation":"testLocation","sourceNamespace":"migre209d0da-49c7-45ba-8d5a-3e59fd591ec1"}`).Result(), }, - { - name: "snapshotSize is zero", - dataUpload: builder.ForDataUpload("velero", "testDU").SourceNamespace("testNamespace").SourcePVC("testPVC").TotalBytes(2000).Result(), - restore: builder.ForRestore("velero", "testRestore").ObjectMeta(builder.WithUID("testingUID")).Backup("testBackup").Result(), - runtimeScheme: scheme, - veleroObjs: []runtime.Object{ - builder.ForBackup("velero", "testBackup").StorageLocation("testLocation").Result(), - }, - expectedDataUploadResult: builder.ForConfigMap("velero", "").ObjectMeta(builder.WithGenerateName("testDU-"), builder.WithLabels(velerov1.PVCNamespaceNameLabel, "testNamespace.testPVC", velerov1.RestoreUIDLabel, "testingUID", velerov1.ResourceUsageLabel, string(velerov1.VeleroResourceUsageDataUploadResult))).Data("testingUID", `{"backupStorageLocation":"testLocation","sourceNamespace":"testNamespace","snapshotSize":2000}`).Result(), - }, } for _, tc := range tests { From 8d29051bbe3835a2ecfd3c596bb744c877da4681 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Wed, 22 Oct 2025 19:11:56 +0800 Subject: [PATCH 067/104] expose supports cache volume Signed-off-by: Lyndon-Li --- pkg/exposer/cache_volume.go | 99 ++++++++++++++++++++ pkg/exposer/generic_restore.go | 81 +++++++++++++++- pkg/exposer/generic_restore_priority_test.go | 2 + pkg/exposer/generic_restore_test.go | 1 + pkg/exposer/pod_volume.go | 84 ++++++++++++++++- 5 files changed, 263 insertions(+), 4 deletions(-) create mode 100644 pkg/exposer/cache_volume.go diff --git a/pkg/exposer/cache_volume.go b/pkg/exposer/cache_volume.go new file mode 100644 index 000000000..85571c243 --- /dev/null +++ b/pkg/exposer/cache_volume.go @@ -0,0 +1,99 @@ +/* +Copyright 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 exposer + +import ( + "context" + + corev1api "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + + "github.com/vmware-tanzu/velero/pkg/util/boolptr" + "github.com/vmware-tanzu/velero/pkg/util/kube" +) + +type CacheConfigs struct { + Limit int64 + StorageClass string + ResidentThreshold int64 +} + +const ( + cacheVolumeName = "cachedir" + cacheVolumeDirSuffix = "-cache" +) + +func createCachePVC(ctx context.Context, pvcClient corev1client.CoreV1Interface, ownerObject corev1api.ObjectReference, sc string, size int64, selectedNode string) (*corev1api.PersistentVolumeClaim, error) { + cachePVCName := getCachePVCName(ownerObject) + + volumeMode := corev1api.PersistentVolumeFilesystem + + pvcObj := &corev1api.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ownerObject.Namespace, + Name: cachePVCName, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: ownerObject.APIVersion, + Kind: ownerObject.Kind, + Name: ownerObject.Name, + UID: ownerObject.UID, + Controller: boolptr.True(), + }, + }, + }, + Spec: corev1api.PersistentVolumeClaimSpec{ + AccessModes: []corev1api.PersistentVolumeAccessMode{corev1api.ReadWriteOnce}, + StorageClassName: &sc, + VolumeMode: &volumeMode, + Resources: corev1api.VolumeResourceRequirements{ + Requests: corev1api.ResourceList{ + corev1api.ResourceStorage: *resource.NewQuantity(size, resource.BinarySI), + }, + }, + }, + } + + if selectedNode != "" { + pvcObj.Annotations = map[string]string{ + kube.KubeAnnSelectedNode: selectedNode, + } + } + + return pvcClient.PersistentVolumeClaims(pvcObj.Namespace).Create(ctx, pvcObj, metav1.CreateOptions{}) +} + +func getCachePVCName(ownerObject corev1api.ObjectReference) string { + return ownerObject.Name + cacheVolumeDirSuffix +} + +func getCacheVolumeSize(dataSize int64, info *CacheConfigs) int64 { + if info == nil { + return 0 + } + + if dataSize != 0 && dataSize < info.ResidentThreshold { + return 0 + } + + // 20% inflate and round up to GB + volumeSize := (info.Limit*12/10 + (1 << 30) - 1) / (1 << 30) * (1 << 30) + + return volumeSize +} diff --git a/pkg/exposer/generic_restore.go b/pkg/exposer/generic_restore.go index 8691eedfc..a2d4ab020 100644 --- a/pkg/exposer/generic_restore.go +++ b/pkg/exposer/generic_restore.go @@ -73,6 +73,12 @@ type GenericRestoreExposeParam struct { // PriorityClassName is the priority class name for the data mover pod PriorityClassName string + + // RestoreSize specifies the data size for the volume to be restored + RestoreSize int64 + + // CacheVolume specifies the info for cache volumes + CacheVolume *CacheConfigs } // GenericRestoreExposer is the interfaces for a generic restore exposer @@ -148,6 +154,28 @@ func (e *genericRestoreExposer) Expose(ctx context.Context, ownerObject corev1ap affinity := kube.GetLoadAffinityByStorageClass(param.LoadAffinity, storageClassName, curLog) + var cachePVC *corev1api.PersistentVolumeClaim + if param.CacheVolume != nil { + cacheVolumeSize := getCacheVolumeSize(param.RestoreSize, param.CacheVolume) + if cacheVolumeSize > 0 { + curLog.Infof("Creating cache PVC with size %v", cacheVolumeSize) + + if pvc, err := createCachePVC(ctx, e.kubeClient.CoreV1(), ownerObject, param.CacheVolume.StorageClass, cacheVolumeSize, selectedNode); err != nil { + return errors.Wrap(err, "error to create cache pvc") + } else { + cachePVC = pvc + } + + defer func() { + if err != nil { + kube.DeletePVAndPVCIfAny(ctx, e.kubeClient.CoreV1(), cachePVC.Name, cachePVC.Namespace, 0, curLog) + } + }() + } else { + curLog.Infof("Don't need to create cache volume, restore size %v, cache info %v", param.RestoreSize, param.CacheVolume) + } + } + restorePod, err := e.createRestorePod( ctx, ownerObject, @@ -161,6 +189,7 @@ func (e *genericRestoreExposer) Expose(ctx context.Context, ownerObject corev1ap param.NodeOS, affinity, param.PriorityClassName, + cachePVC, ) if err != nil { return errors.Wrapf(err, "error to create restore pod") @@ -287,6 +316,22 @@ func (e *genericRestoreExposer) DiagnoseExpose(ctx context.Context, ownerObject diag += fmt.Sprintf("error getting restore pvc %s, err: %v\n", restorePVCName, err) } + var cachePVC *corev1api.PersistentVolumeClaim + if pod.Spec.Volumes != nil { + for _, v := range pod.Spec.Volumes { + if v.Name == cacheVolumeName { + cachePVC, err = e.kubeClient.CoreV1().PersistentVolumeClaims(ownerObject.Namespace).Get(ctx, getCachePVCName(ownerObject), metav1.GetOptions{}) + if err != nil { + cachePVC = nil + diag += fmt.Sprintf("error getting cache pvc %s, err: %v\n", getCachePVCName(ownerObject), err) + } + + break + } + + } + } + events, err := e.kubeClient.CoreV1().Events(ownerObject.Namespace).List(ctx, metav1.ListOptions{}) if err != nil { diag += fmt.Sprintf("error listing events, err: %v\n", err) @@ -314,6 +359,18 @@ func (e *genericRestoreExposer) DiagnoseExpose(ctx context.Context, ownerObject } } + if cachePVC != nil { + diag += kube.DiagnosePVC(cachePVC, events) + + if cachePVC.Spec.VolumeName != "" { + if pv, err := e.kubeClient.CoreV1().PersistentVolumes().Get(ctx, cachePVC.Spec.VolumeName, metav1.GetOptions{}); err != nil { + diag += fmt.Sprintf("error getting cache pv %s, err: %v\n", cachePVC.Spec.VolumeName, err) + } else { + diag += kube.DiagnosePV(pv) + } + } + } + diag += "end diagnose restore exposer" return diag @@ -322,9 +379,11 @@ func (e *genericRestoreExposer) DiagnoseExpose(ctx context.Context, ownerObject func (e *genericRestoreExposer) CleanUp(ctx context.Context, ownerObject corev1api.ObjectReference) { restorePodName := ownerObject.Name restorePVCName := ownerObject.Name + cachePVCName := getCachePVCName(ownerObject) kube.DeletePodIfAny(ctx, e.kubeClient.CoreV1(), restorePodName, ownerObject.Namespace, e.log) kube.DeletePVAndPVCIfAny(ctx, e.kubeClient.CoreV1(), restorePVCName, ownerObject.Namespace, 0, e.log) + kube.DeletePVAndPVCIfAny(ctx, e.kubeClient.CoreV1(), cachePVCName, ownerObject.Namespace, 0, e.log) } func (e *genericRestoreExposer) RebindVolume(ctx context.Context, ownerObject corev1api.ObjectReference, targetPVCName string, targetNamespace string, timeout time.Duration) error { @@ -433,6 +492,7 @@ func (e *genericRestoreExposer) createRestorePod( nodeOS string, affinity *kube.LoadAffinity, priorityClassName string, + cachePVC *corev1api.PersistentVolumeClaim, ) (*corev1api.Pod, error) { restorePodName := ownerObject.Name restorePVCName := ownerObject.Name @@ -461,7 +521,6 @@ func (e *genericRestoreExposer) createRestorePod( var gracePeriod int64 volumeMounts, volumeDevices, volumePath := kube.MakePodPVCAttachment(volumeName, targetPVC.Spec.VolumeMode, false) - volumeMounts = append(volumeMounts, podInfo.volumeMounts...) volumes := []corev1api.Volume{{ Name: volumeName, @@ -471,6 +530,25 @@ func (e *genericRestoreExposer) createRestorePod( }, }, }} + + cacheVolumePath := "" + if cachePVC != nil { + mnt, _, path := kube.MakePodPVCAttachment(cacheVolumeName, nil, false) + volumeMounts = append(volumeMounts, mnt...) + + volumes = append(volumes, corev1api.Volume{ + Name: cacheVolumeName, + VolumeSource: corev1api.VolumeSource{ + PersistentVolumeClaim: &corev1api.PersistentVolumeClaimVolumeSource{ + ClaimName: cachePVC.Name, + }, + }, + }) + + cacheVolumePath = path + } + + volumeMounts = append(volumeMounts, podInfo.volumeMounts...) volumes = append(volumes, podInfo.volumes...) if label == nil { @@ -488,6 +566,7 @@ func (e *genericRestoreExposer) createRestorePod( fmt.Sprintf("--volume-mode=%s", volumeMode), fmt.Sprintf("--data-download=%s", ownerObject.Name), fmt.Sprintf("--resource-timeout=%s", operationTimeout.String()), + fmt.Sprintf("--cache-volume-path=%s", cacheVolumePath), } args = append(args, podInfo.logFormatArgs...) diff --git a/pkg/exposer/generic_restore_priority_test.go b/pkg/exposer/generic_restore_priority_test.go index b67652b93..642e0cc43 100644 --- a/pkg/exposer/generic_restore_priority_test.go +++ b/pkg/exposer/generic_restore_priority_test.go @@ -148,6 +148,7 @@ func TestCreateRestorePodWithPriorityClass(t *testing.T) { kube.NodeOSLinux, nil, // affinity tc.expectedPriorityClass, + nil, ) require.NoError(t, err, tc.description) @@ -227,6 +228,7 @@ func TestCreateRestorePodWithMissingConfigMap(t *testing.T) { kube.NodeOSLinux, nil, // affinity "", // empty priority class since config map is missing + nil, ) // Should succeed even when config map is missing diff --git a/pkg/exposer/generic_restore_test.go b/pkg/exposer/generic_restore_test.go index 2e528d6a2..271e4e7d6 100644 --- a/pkg/exposer/generic_restore_test.go +++ b/pkg/exposer/generic_restore_test.go @@ -973,6 +973,7 @@ func TestCreateRestorePod(t *testing.T) { test.nodeOS, test.affinity, "", // priority class name + nil, ) require.NoError(t, err) diff --git a/pkg/exposer/pod_volume.go b/pkg/exposer/pod_volume.go index 591600eb3..1702fb0f5 100644 --- a/pkg/exposer/pod_volume.go +++ b/pkg/exposer/pod_volume.go @@ -76,6 +76,12 @@ type PodVolumeExposeParam struct { // Privileged indicates whether to create the pod with a privileged container Privileged bool + + // RestoreSize specifies the data size for the volume to be restored, for restore only + RestoreSize int64 + + // CacheVolume specifies the info for cache volumes, for restore only + CacheVolume *CacheConfigs } // PodVolumeExposer is the interfaces for a pod volume exposer @@ -156,7 +162,29 @@ func (e *podVolumeExposer) Expose(ctx context.Context, ownerObject corev1api.Obj curLog.WithField("path", path).Infof("Host path is retrieved for pod %s, volume %s", param.ClientPodName, param.ClientPodVolume) - hostingPod, err := e.createHostingPod(ctx, ownerObject, param.Type, path.ByPath, param.OperationTimeout, param.HostingPodLabels, param.HostingPodAnnotations, param.HostingPodTolerations, pod.Spec.NodeName, param.Resources, nodeOS, param.PriorityClassName, param.Privileged) + var cachePVC *corev1api.PersistentVolumeClaim + if param.CacheVolume != nil { + cacheVolumeSize := getCacheVolumeSize(param.RestoreSize, param.CacheVolume) + if cacheVolumeSize > 0 { + curLog.Infof("Creating cache PVC with size %v", cacheVolumeSize) + + if pvc, err := createCachePVC(ctx, e.kubeClient.CoreV1(), ownerObject, param.CacheVolume.StorageClass, cacheVolumeSize, pod.Spec.NodeName); err != nil { + return errors.Wrap(err, "error to create cache pvc") + } else { + cachePVC = pvc + } + + defer func() { + if err != nil { + kube.DeletePVAndPVCIfAny(ctx, e.kubeClient.CoreV1(), cachePVC.Name, cachePVC.Namespace, 0, curLog) + } + }() + } else { + curLog.Infof("Don't need to create cache volume, restore size %v, cache info %v", param.RestoreSize, param.CacheVolume) + } + } + + hostingPod, err := e.createHostingPod(ctx, ownerObject, param.Type, path.ByPath, param.OperationTimeout, param.HostingPodLabels, param.HostingPodAnnotations, param.HostingPodTolerations, pod.Spec.NodeName, param.Resources, nodeOS, param.PriorityClassName, param.Privileged, cachePVC) if err != nil { return errors.Wrapf(err, "error to create hosting pod") } @@ -251,6 +279,22 @@ func (e *podVolumeExposer) DiagnoseExpose(ctx context.Context, ownerObject corev diag += fmt.Sprintf("error getting hosting pod %s, err: %v\n", hostingPodName, err) } + var cachePVC *corev1api.PersistentVolumeClaim + if pod.Spec.Volumes != nil { + for _, v := range pod.Spec.Volumes { + if v.Name == cacheVolumeName { + cachePVC, err = e.kubeClient.CoreV1().PersistentVolumeClaims(ownerObject.Namespace).Get(ctx, getCachePVCName(ownerObject), metav1.GetOptions{}) + if err != nil { + cachePVC = nil + diag += fmt.Sprintf("error getting cache pvc %s, err: %v\n", getCachePVCName(ownerObject), err) + } + + break + } + + } + } + events, err := e.kubeClient.CoreV1().Events(ownerObject.Namespace).List(ctx, metav1.ListOptions{}) if err != nil { diag += fmt.Sprintf("error listing events, err: %v\n", err) @@ -266,6 +310,18 @@ func (e *podVolumeExposer) DiagnoseExpose(ctx context.Context, ownerObject corev } } + if cachePVC != nil { + diag += kube.DiagnosePVC(cachePVC, events) + + if cachePVC.Spec.VolumeName != "" { + if pv, err := e.kubeClient.CoreV1().PersistentVolumes().Get(ctx, cachePVC.Spec.VolumeName, metav1.GetOptions{}); err != nil { + diag += fmt.Sprintf("error getting cache pv %s, err: %v\n", cachePVC.Spec.VolumeName, err) + } else { + diag += kube.DiagnosePV(pv) + } + } + } + diag += "end diagnose pod volume exposer" return diag @@ -273,11 +329,14 @@ func (e *podVolumeExposer) DiagnoseExpose(ctx context.Context, ownerObject corev func (e *podVolumeExposer) CleanUp(ctx context.Context, ownerObject corev1api.ObjectReference) { restorePodName := ownerObject.Name + cachePVCName := getCachePVCName(ownerObject) + kube.DeletePodIfAny(ctx, e.kubeClient.CoreV1(), restorePodName, ownerObject.Namespace, e.log) + kube.DeletePVAndPVCIfAny(ctx, e.kubeClient.CoreV1(), cachePVCName, ownerObject.Namespace, 0, e.log) } func (e *podVolumeExposer) createHostingPod(ctx context.Context, ownerObject corev1api.ObjectReference, exposeType string, hostPath string, - operationTimeout time.Duration, label map[string]string, annotation map[string]string, toleration []corev1api.Toleration, selectedNode string, resources corev1api.ResourceRequirements, nodeOS string, priorityClassName string, privileged bool) (*corev1api.Pod, error) { + operationTimeout time.Duration, label map[string]string, annotation map[string]string, toleration []corev1api.Toleration, selectedNode string, resources corev1api.ResourceRequirements, nodeOS string, priorityClassName string, privileged bool, cachePVC *corev1api.PersistentVolumeClaim) (*corev1api.Pod, error) { hostingPodName := ownerObject.Name containerName := string(ownerObject.UID) @@ -301,7 +360,6 @@ func (e *podVolumeExposer) createHostingPod(ctx context.Context, ownerObject cor MountPath: clientVolumePath, MountPropagation: &mountPropagation, }} - volumeMounts = append(volumeMounts, podInfo.volumeMounts...) volumes := []corev1api.Volume{{ Name: clientVolumeName, @@ -311,6 +369,25 @@ func (e *podVolumeExposer) createHostingPod(ctx context.Context, ownerObject cor }, }, }} + + cacheVolumePath := "" + if cachePVC != nil { + mnt, _, path := kube.MakePodPVCAttachment(cacheVolumeName, nil, false) + volumeMounts = append(volumeMounts, mnt...) + + volumes = append(volumes, corev1api.Volume{ + Name: cacheVolumeName, + VolumeSource: corev1api.VolumeSource{ + PersistentVolumeClaim: &corev1api.PersistentVolumeClaimVolumeSource{ + ClaimName: cachePVC.Name, + }, + }, + }) + + cacheVolumePath = path + } + + volumeMounts = append(volumeMounts, podInfo.volumeMounts...) volumes = append(volumes, podInfo.volumes...) args := []string{ @@ -328,6 +405,7 @@ func (e *podVolumeExposer) createHostingPod(ctx context.Context, ownerObject cor command = append(command, "backup") } else { args = append(args, fmt.Sprintf("--pod-volume-restore=%s", ownerObject.Name)) + args = append(args, fmt.Sprintf("--cache-volume-path=%s", cacheVolumePath)) command = append(command, "restore") } From 2e3f41be227c75bfb632d3ca8e7f1fabed127bfd Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Thu, 23 Oct 2025 14:58:23 +0800 Subject: [PATCH 068/104] backup repo cache design Signed-off-by: Lyndon-Li --- design/backup-repo-cache-volume.md | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/design/backup-repo-cache-volume.md b/design/backup-repo-cache-volume.md index bff839853..214812d99 100644 --- a/design/backup-repo-cache-volume.md +++ b/design/backup-repo-cache-volume.md @@ -58,7 +58,7 @@ For other scenarios, we can add them regarded to the future changes/requirements If available, one cache volume is dedicately assigned to one data mover pod. That is, the cached data is destroyed when the data mover pod completes. Then the backup repository instance also closes. Cache data are fully managed by the specific backup repository. So the backup repository may also have its own way to GC the cache data. -That is to say, cache data GC may be launched by the backup repository instance during the running of the data mover pod; then the left data are automatically destroyed when the data mover pod and the cache PVC are destroyed. So no specially logics are needed for cache data GC. +That is to say, cache data GC may be launched by the backup repository instance during the running of the data mover pod; then the left data are automatically destroyed when the data mover pod and the cache PVC are destroyed (cache PVC's `reclaimPolicy` is always `Deleted`, so once the cache PVC is destroyed, the volume will also be destroyed). So no specially logics are needed for cache data GC. ### Data Size @@ -70,19 +70,22 @@ Cache volumes take storage space and cluster resources (PVC, PV), therefore, cac The cache volume size is calculated from below factors (for Restore scenarios): - **Limit**: The limit of the cache data, that is represented by `cacheLimitMB`, the default value is 5GB -- **backupSize**: The size of the backup as a reference to evaluate whether to create a cache volume. It doesn't mean the backup data really decides the cache data all the time, it is just a reference to evaluate the scale of the backup, small scale backups may need small cache data. Sometimes, backupSize is not applicable/available or is irrelevant to the size of cache data, in this case, Limit will be used directly. +- **backupSize**: The size of the backup as a reference to evaluate whether to create a cache volume. It doesn't mean the backup data really decides the cache data all the time, it is just a reference to evaluate the scale of the backup, small scale backups may need small cache data. Sometimes, backupSize is not irrelevant to the size of cache data, in this case, ResidentThreshold should not be set, Limit will be used directly. It is unlikely that backupSize is unavailable, but once that happens, ResidentThreshold is ignored, Limit will be used directly. - **ResidentThreshold**: The minimum backup size that a cache volume is created -- **InflationPercentage**: Considering the overhead of the file system and the possible delay of the cache cleanup, there should be an inflation for the final volume size vs. the logical size, otherwise, the cache volume may be overrun. This inflation percentage is hardcoded, e.g., 20% +- **InflationPercentage**: Considering the overhead of the file system and the possible delay of the cache cleanup, there should be an inflation for the final volume size vs. the logical size, otherwise, the cache volume may be overrun. This inflation percentage is hardcoded, e.g., 20%. A formula is as below: ``` -cacheVolumeSize = (backupSize != 0 ? (backupSize > residentThreshold ? limit : 0) : limit) * inflationPercentage +cacheVolumeSize = ((backupSize != 0 ? (backupSize > residentThreshold ? limit : 0) : limit) * (100 + inflationPercentage)) / 100 ``` Finally, the `cacheVolumeSize` will be rounded up to GiB considering the UX friendliness, storage friendliness and management friendliness. ### PVC/PV The PVC for a cache volume is created in Velero namespace and a storage class is required for the cache PVC. The PVC's accessMode is `ReadWriteOnce` and volumeMode is `FileSystem`, so the storage class provided should support this specification. Otherwise, if the storageclass doesn't support either of the specifications, the data mover pod may be hang in `Pending` state until a timeout setting with the data movement (e.g. `prepareTimeout`) and the data movement will finally fail. +It is not expected that the cache volume is retained after data mover pod is deleted, so the `reclaimPolicy` for the storageclass must be `Delete`. + +To detect the problems in the storageclass and fail earlier, a validation is applied to the storageclass and once the validation fails, the cache configuration will be ignored, so the data mover pod will be created without a cache volume. ### Cache Volume Configurations @@ -139,20 +142,7 @@ The cache volume configurations will be visited by node-agent server, so they al ### Backup and Restore -The restore needs to know the backup size so as to calculate the cache volume size, some new fields are added to the DataUpload, DataDownload, PodVolumeBackup and PodVolumeRestore CRDs. - -`snapshotSize` field is added to DataUpload and PodVolumeBackup's `status`: -```yaml - status: - snapshotID: - description: SnapshotID is the identifier for the snapshot in the - backup repository. - type: string - snapshotSize: - description: SnapshotSize is the logical size of the snapshot. - format: int64 - type: integer -``` +The restore needs to know the backup size so as to calculate the cache volume size, some new fields are added to the DataDownload and PodVolumeRestore CRDs. `snapshotSize` field is also added to DataDownload and PodVolumeRestore's `spec`: ```yaml @@ -167,9 +157,9 @@ The restore needs to know the backup size so as to calculate the cache volume si type: integer ``` -`snapshotSize` represents the total size of the backup; during restore, the value is transferred from DataUpload/PodVolumeBackup to DataDownload/PodVolumeRestore. +`snapshotSize` represents the total size of the backup; during restore, the value is transferred from DataUpload/PodVolumeBackup's `Status.Progress.TotalBytes` to DataDownload/PodVolumeRestore. -When restoring from backups created by previous versions, `snapshotSize` is not available, according to the above formula, `residentThresholdMB` is ignored, cache volume size is calculated directly from cache limit for the corresponding backup repository. +It is unlikely that `Status.Progress.TotalBytes` from DataUpload/PodVolumeBackup is unavailable, but once it happens, according to the above formula, `residentThresholdMB` is ignored, cache volume size is calculated directly from cache limit for the corresponding backup repository. ### Exposer From d4147e406bdf6a6fb286cfaecbe3fe93772fafb1 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Mon, 27 Oct 2025 12:38:30 +0800 Subject: [PATCH 069/104] snapshot size in restore CRs Signed-off-by: Lyndon-Li --- config/crd/v1/bases/velero.io_podvolumerestores.yaml | 2 +- config/crd/v1/crds/crds.go | 2 +- config/crd/v2alpha1/bases/velero.io_datadownloads.yaml | 2 +- config/crd/v2alpha1/crds/crds.go | 2 +- pkg/apis/velero/v1/pod_volume_restore_type.go | 2 +- pkg/apis/velero/v2alpha1/data_download_types.go | 2 +- pkg/apis/velero/v2alpha1/data_upload_types.go | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/config/crd/v1/bases/velero.io_podvolumerestores.yaml b/config/crd/v1/bases/velero.io_podvolumerestores.yaml index 9603e8520..e2917ead2 100644 --- a/config/crd/v1/bases/velero.io_podvolumerestores.yaml +++ b/config/crd/v1/bases/velero.io_podvolumerestores.yaml @@ -134,7 +134,7 @@ spec: description: SnapshotID is the ID of the volume snapshot to be restored. type: string snapshotSize: - description: SnapshotSize is the logical size of the snapshot. + description: SnapshotSize is the logical size in Bytes of the snapshot. format: int64 type: integer sourceNamespace: diff --git a/config/crd/v1/crds/crds.go b/config/crd/v1/crds/crds.go index bc688fad2..a600bae3c 100644 --- a/config/crd/v1/crds/crds.go +++ b/config/crd/v1/crds/crds.go @@ -35,7 +35,7 @@ var rawCRDs = [][]byte{ []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcVMo\x1b7\x10\xbd\xebW\f\xd0kwU\xa3hQ\xec\xadqr0\xda\x06\x82\x1d\xe4N\x91#-c.\xc9\xce\f\xe5\xba\x1f\xff\xbd \xb9+K\xab\x95\x93\\\xb27\x91Ù\xc7\xf7f\x1e\xd54\xcdJE\xfb\x11\x89m\xf0\x1d\xa8h\xf1/A\x9f\x7fq\xfb\xf8\v\xb76\xac\x0f7\xabG\xebM\a\xb7\x89%\f\xf7\xc8!\x91Ʒ\xb8\xb3ފ\r~5\xa0(\xa3Du+\x00\xe5}\x10\x95\x979\xff\x04\xd0\xc1\v\x05琚=\xfa\xf61mq\x9b\xac3H%\xf9T\xfa\xf0C{\xf3s\xfb\xd3\n\xc0\xab\x01;0\xe8Pp\xab\xf4c\x8a\x84\x7f&d\xe1\xf6\x80\x0e)\xb46\xac8\xa2\xce\xf9\xf7\x14R\xec\xe0e\xa3\x9e\x1fkW\xdcoK\xaa7%\xd5}MUv\x9de\xf9\xedZ\xc4\xefv\x8c\x8a.\x91rˀJ\x00[\xbfON\xd1b\xc8\n\x80u\x88\xd8\xc1\xfb\f+*\x8df\x050^\xbb\xc0l@\x19S\x88TnC\xd6\v\xd2mpi\x98\bl\xc0 k\xb2Q\nQ\x1fz,W\x84\xb0\x03\xe9\x11j9\x90\x00[\x1c\x11\x98r\x0e\xe0\x13\a\xbfQ\xd2w\xd0f\xbe\xda\x1a\x9a\x81\x8c\x01\x95\xea7\xf3ey\u0380Y\xc8\xfa\xfd5\b,J\x12O J]\x1b<\xd0\t\xbf\xe7\x00J|\x1b{\xc5\xe7\xd5\x1f\xcaƵ\xca5\xe6pS\x99\xd6=\x0e\xaa\x1bcCD\xff\xeb\xe6\xee\xe3\x8f\x0fg\xcbp\x8euAZ\xb0\fjB\x9a\x89\xab\xacA\xf0\b\x81`\b4\xb1\xca\xed1i\xa4\x10\x91\xc4N\xadU\xbf\x93\xe19Y\x9dA\xf8\xb79\xdb\x03Ȩ\xeb)0y\x8a\x90\v\x89cS\xa0\x19/Zɵ\f\x84\x91\x90\xd1\u05f9\xca\xcb\xcaC\xd8~B-\xed,\xf5\x03RN\x03܇\xe4L\x1e\xbe\x03\x92\x00\xa1\x0e{o\xff>\xe6\xe6|\xef\\\xd4))\x94\xe4\xb6\xf3\xca\xc1A\xb9\x84߃\xf2f\x96yP\xcf@\x98kB\xf2'\xf9\xca\x01\x9e\xe3\xf8#\x93h\xfd.tЋD\xee\xd6뽕\xc9Rt\x18\x86\xe4\xad<\xaf\x8b;\xd8m\x92@\xbc6x@\xb7f\xbbo\x14\xe9\xde\njI\x84k\x15mS.⋭\xb4\x83\xf9\x8eF\x13Ⳳ\x17\xddS\xbf\xe2\x02_!O\xf6\x84\xda#5U\xbd\xe2\x8b\ny)Sw\xff\xee\xe1\x03LH\xaaRU\x94\x97\xd0\v^&}2\x9b\xd6\xef\x90\xea\xb9\x1d\x85\xa1\xe4Dob\xb0^\xca\x0f\xed,z\x01N\xdb\xc1\nO\x1d\x9b\xa5\x9b\xa7\xbd-\xb6\x9b\x1d E\xa3\x04\xcd<\xe0\xceí\x1a\xd0\xdd*\xc6o\xacUV\x85\x9b,\xc2\x17\xa9u\xfa\x98̃+\xbd'\x1b\xd33pEڅ\xe1\x7f\x88\xa8\xb3\xb8\x99\xdf|\xda\ueb2ec\xb5\v\x04O\xbd\xd5\xfd4\xfc3\x9a\x8eFq\xce߲1\xe4\xef\xc5n\xe7;W/\x0fEdK8k\xd8\x06.\xbc\xfbu^\x8a\xa9~%3\xd5\xd1Gnt\"*\xcdw\xf4y\xb5t\xe8K\xb9@\xa2@\x17\xab3P\xefJP\xf9Ǡ\xacgP\xfey<\b\xd2+\x81'\xa4\r\x97\x95\x1ax\x8fO\v\xabw~CaO\xc8\xf3\x96ϛ\x9b\xca\x1e\xce߃WXZlʋE\xceVhNXd\t\xa4\xf6\xa7\xbcr\xda\x1e\x9d\xbe\x83\x7f\xfe[\xfd\x1f\x00\x00\xff\xff\xbeM\x1a\xea\xb1\n\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcWMo\xe36\x10\xbd\xfbW\f\xd0K\v\xac\xe4\x06E\x8b·\xd6\xd9C\xb0\xe96\x88\xb7\xb9S\xd4HbC\x91,9t6E\x7f|1\xa4\xe4\x0fYv\x9c\xcb\xea\xe6\xe1p\xf8\xe6\xcd\xcc#]\x14\xc5B8\xf5\x84>(kV \x9c¯\x84\x86\x7f\x85\xf2\xf9\xd7P*\xbb\xdc\xde,\x9e\x95\xa9W\xb0\x8e\x81l\xff\x88\xc1F/\xf1\x16\x1be\x14)k\x16=\x92\xa8\x05\x89\xd5\x02@\x18cI\xb09\xf0O\x00i\ry\xab5\xfa\xa2ES>\xc7\n\xab\xa8t\x8d>\x05\x1f\x8f\xde\xfeX\xde\xfcR\xfe\xbc\x000\xa2\xc7\x15\xd4\xf6\xc5h+j\x8f\xffD\f\x14\xca-j\xf4\xb6Tv\x11\x1cJ\x8e\xddz\x1b\xdd\n\xf6\vy\xefpn\xc6|;\x84y\xccaҊV\x81>ͭޫ\xc1\xc3\xe9\xe8\x85>\x05\x91\x16\x832m\xd4\u009f,/\x00\x82\xb4\x0eW\xf0\x99a8!\xb1^\x00\f)&XŐ\xdd\xf6&\x87\x92\x1d\xf6\"\xe3\x05\xb0\x0e\xcdo\x0fwO?m\x8e\xcc\x005\x06镣D\xd4\x7f\xc5\xce\x0e\xd3\x04@\x05\x100\xc0\x01\xb2;\x84 \f\bO\xaa\x11\x92\xa0\xf1\xb6\x87J\xc8\xe7\xe8\xc0V\x7f\xa3$\bd\xbdh\xf1\x03\x84(;\x10\x1c%;\x1c\x9c\xa5m\v\x8d\xd2X\xeel\xce[\x87\x9e\xd4Hy\xfe\x0e\x1a\xea\xc0z)\v\xfe8\xf1\xbc\vj\xee,\f@\x1d\x8e\xe4a=p\x05\xb6\x01\xeaT\x00\x8f\xcec@\x93{\x8d\xcd\xc2\fٔ\x93\xd0\x1b\xf4\x1c\x06Bg\xa3\xae\xb9!\xb7\xe8\t\x1aE\xaf\xcb41\xaa\x8ad}XָE\xbd\f\xaa-\x84\x97\x9d\"\x94\x14=.\x85SEJĤQ+\xfb\xfa;?\ff8:\x96^\xb9!\x03yeڃ\x854\x1d\xef(\x0f\xcfK\xee\xae\x1c*\xa7\xb8\xaf\x02\x9b\x98\xbaǏ\x9b/0\"ɕ\x1aZl\xe7z\xc2\xcbX\x1ffS\x99\x06}ޗڔc\xa2\xa9\x9dU\x86\xd2\x0f\xa9\x15\x1a\x82\x10\xab^Q\x18{\x9dK7\r\xbbNR\x04\x15Bt\xb5 \xac\xa7\x0ew\x06֢G\xbd\x16\x01\xbfq\xad\xb8*\xa1\xe0\"\\U\xadC\x81\x9d:gz\x0f\x16Fy&j^\x01\x128\xe1[\xa4\xa9u\x82\xe5Kr\xe2\xe3_:q,X\xdfcٖ\xac9a\x00\x92\xf5\xe8\x87i\xa1.a\x80\xd9F\x9fE2\xf67\xd3\xc0\xbc\xb2\xa0\xb0\xd8\x1db:=\x9a?4\xb1\x9f?\xa0\x80\xdf\x13\xe6{\xdb^\\_[C<\x17\x17\x9d\x9e\xac\x8e=n\x8cp\xa1\xb3o\xf8\xde\x11\xf6\x7f:\xf4\xf9\x1a\xbe\xe8:\xde滫\xef\x82c\xd4g\xcf}D\xbeA\xf0|\xa6\x83\xc3UQ\xae\xc04x^\x95\xe8zs\xf7\x1e\nϸ\xbf\xa3Hw\xa6\xb1o\xa4\xb8w\x9c\xf5;#\x03\xe3\x97\xde\x10o\xf74\xbfBƞ\xe6-\xf9\xeeD\xf8\x14+\xf4\x06\t\xc3^\xa9_\x14u\xb3\x11\x01^:%\xbb\xb41\r\x04_\x02!X\xa9\xe6$\xf5\n\xf8\xac#\xca\xe3\xccP\x16iXg\xcc\f\xfe\xc4|F\xfd\xce\x1dP\f\x8at\x95\x82\x92\xa0\x18ޡ\xa1\xc9\x7f\xa4ZF\xef\xd3\x15\x95\xad\xfc2\x99n\xb8VDG\xe5\xf9\xeb\xf1\xfe\r%\xbd\xdd{\xa6\x17\xb7P&\xa3q\x1e\x8b\xa0Z~A\xf1\x1akiҸS2\xf2w\xfc\xc2;&j\xb6\xa2\xf8թ<\x80o@\xfc\xb8ŝ\x8f&\xdf\xf3\xd37l\n\x88\x81\x9f[ \x85\x99\xc1X!Ԩ\x91\xb0\x86\xea5\xdf\\\xaf\x81\xb0?\xc5\xddX\xdf\vZ\x01\xdf\xff\x05\xa9\x9962QkQi\\\x01\xf9x\xae\xcbf\x13w\x9d\b3cx\x94\xf3\x03\xfb\xcc5\xc6n\x18/v\x06\x9c\xbd_\n\xf8\x8c/3\xd6\ao%\x86\x80\xa7ct6\x93\xd9!81\x06~\xa4\xd5\a,\r\x7f\x19\x06\xcb\xff\x01\x00\x00\xff\xffx\xae@\xbaJ\x0e\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4ZK\x93\x1b\xb7\x11\xbe\xef\xaf\xe8Z\x1flWi\xc8HI\\)ޤU\x9c\xda\xc4V\xb6ĕ..\x1f\xc0A\x93\x03\xef\f\x80\x00\x18R\x8c\xe3\xff\x9ej<\x86\xf3\x00\xc9]\xca\xf2\xe2\xb2K<\x1a\x8d\xaf\x1b\xfd\xc2\x14EqŴ\xf8\x88\xc6\n%\x17\xc0\xb4\xc0O\x0e%\xfd\xb2\xb3\x87\xbfٙP\xf3\xed˫\a!\xf9\x02nZ\xebT\xf3\x1e\xadjM\x89oq-\xa4pBɫ\x06\x1d\xe3̱\xc5\x15\x00\x93R9Fݖ~\x02\x94J:\xa3\xea\x1aM\xb1A9{hW\xb8jE\xcd\xd1x\xe2i\xeb\xed\x9ff/\xbf\x9b\xfd\xf5\n@\xb2\x06\x17\xa0\x15ߪ\xbamp\xc5ʇV\xdb\xd9\x16k4j&ԕ\xd5X\x12\xed\x8dQ\xad^\xc0a \xac\x8d\xfb\x06\x9e\xef\x14\xff\xe8ɼ\xf1d\xfcH-\xac\xfbWn\xf4\aa\x9d\x9f\xa1\xebְzʄ\x1f\xb4Bnښ\x99\xc9\xf0\x15\x80-\x95\xc6\x05\xbc#64+\x91_\x01\xc4#z\xb6\n`\x9c{\xd0X}g\x84thn\x88B\x02\xab\x00\x8e\xb64B;\x0fʈ?\xb0\x8e\xb9ւm\xcb\n\x98\x85w\xb8\x9b\xdf\xca;\xa36\x06m`\x0e\xe0\x17\xab\xe4\x1ds\xd5\x02fa\xfaLW\xccb\x1c\r\xe0.\xfd@\xecr{b\xd9:#\xe4&\xc7Ľh\x10xk\xbcP\xe9\xf4%\x82\xab\x84\x9dp\xb7c\x9684\xce\x1f;ϋ\x1f'\x8aֱF\x8f\x99\xea-\r\\q\xe60\xc7Ӎjt\x8d\x0e9\xac\xf6\x0e\xd3I\xd6\xca4\xcc-@H\xf7\xdd_\x8e\xc3\x11\xf1\x9a\xf9\xa5o\x95\x1cb\xf3\x86z\xa1\xd7\x1d8!Ym\xd0d\x01R\x8e՟È#\x02oz\xeb\x03'\x81n\xbf\xff,+\xa4x\xa0\xd6\xe0*\x84(\x95\xa5S\x86m\x10~Pe\x90\xe0\xaeB\x13%\xb8\x8ajU\xa9\xb6\xe6\xb0J'\x06\xb0N\x99\xac\x145\x96\xb3\xb0*\xd2MdG\xa2\x1c\xee\xf9%4\xad4Ȳ\x9a\x96\xac\xd1\xcc\xcf\x10J\xe6\xd5\xed\xf5\x06\x1f\xa5j}H\xa5\xe2\xd8\xe1\x87\x13\xb6\x84\x05mT\x89֞\xb8\x01Dc\xc0ȻC\xc7Y\x80*\xf4s\x12?\xad\xae\x15\xe3h\xc0)\xa8\x98\xe45\xd21\x188ä]G\x15\x99\n0-\xbb\xdf\xeb!+\x1f\xe2\xc01v¬\xed\xcb`\a\xcb\n\x1b\xb6\x88s\x95F\xf9\xfa\xee\xf6㟗\x83n D4\x1a'\x92]\x0e\xad\xe7uz\xbd0<\xee\xff\x8a\xc1\x18\x00m\x10V\x01'\xf7\x83\xd6\xc3\x10-,\xf2\xc8S\x80GX0\xa8\rZ\x94\xc1!Q7\x93\xa0V\xbf`\xe9f#\xd2K4D&݅R\xc9-\x1a\a\x06K\xb5\x91\xe2\xbf\x1dmKXӦ5sh\x9d\xbf\x8cF\xb2\x1a\xb6\xacn\xf1\x050\xc9G\x94\x1b\xb6\a\x83\xb4'\xb4\xb2G\xcf/\xb0c>~T\x06AȵZ@圶\x8b\xf9|#\\\xf2ťj\x9aV\n\xb7\x9f{\xb7*V\xadS\xc6\xce9n\xb1\x9e[\xb1)\x98)+\xe1\xb0t\xad\xc19Ӣ\xf0\a\x91\xde\x1f\xcf\x1a\xfe\x95\x89\xde\xdb\x0e\xb6\x9d\b:4\xefB\x9f \x1er\xaat\tX$\x15\x8ex\x90\x02u\x11t\xef\xff\xbe\xbc\x87\xc4I\x90T\x10\xcaa\xea\x04\x97$\x1fBS\xc85\xe9<\xad[\x1b\xd5x\x9a(\xb9VB:\xff\xa3\xac\x05J\a\xb6]5\u0091\x1a\xfc\xa7E\xebHtc\xb27>^\x81\x15\xdd%\xb2\x00|<\xe1V\xc2\rk\xb0\xbea\x16\xff`Y\x91TlABx\x94\xb4\xfaQ\xd8xr\x80\xb77\x90b\xa8#\xa2\x1dY\xb6\xa5ƒ\x04K\xd8\xd2J\xb1\x16љ\xac\x95\x016\x9e>\xc4)o\x00\xa8e\x1d\xc9x\xd29\xa5\xa3\xf6&G(1,{\x06<9\xbc\xe8\x9f\xea\xa1\x7f귃\x95\x8fk\fje\x85SfO\x84\x83\x83\x1c+\xc4Q\xd9P+\x99,\xb1\xbe\xe4x7~%\b\xc9\tv\xec\x14\x9aLQ\xa0\xea\x19Ur\xa3芍\xa5\x01\xb7\x8e\xa6\x91\x92[t\xf9\xb3\xcac\x0eMH8\x84\x98\xd0\x0f%LJ^)U#\x1bcI\xee\xee̙\xc9\x01\xe6\x84彭\xab\x98K\xbc\xd1$\xd3J9Ŗ\x9a\x92O\x12\x87V\xfc\f_qG\x06\x06\xd7h\xd0G#\xc1\xf6k\xe5=\x84cB&\x9b\x16\x12\x01p*\xc3\xd9*(\x11r\x18\xdf\r8y?\xe0\x84\xa3\xccr\xfc\xfa\xee69\xc3\x04b\xe4}\xe2\xef\xce\xe2Cm-\xb0\xe6>r8\xbfwVs\xa9ݮ\x03\x13\xde#8\x05\f\xb4\xc0\x12\a\xde\x18\x84\xb4\x0e\x19\x8f\x9dd\x04\rƱ\x17\xc1\xd2\x1fe\x92\xda\xc1k\x93L\x80\x91\xe7\x11\x1c\xfe\xb9\xfc\xf7\xbb\xf9?T8\a\xb0\x92B3\x9fDa\x83ҽ\xe8\x12)\x8eV\x18\xe4\x94\x16\xe1\xacaR\xacѺY\xa4\x86\xc6\xfe\xf4\xea\xe7<~\x00\xdf+\x03\xf8\x89Q:\xf2\x02D\xc0\xbcsfIm\x84\r\a\xef(\xc2N\xb8\xca3\xaa\x15\x8f\a\xdc\xf9#8\xf6@79\x1c\xa1E\xa8\xc5C\xe6\xfe\x84v\xed\xa3\xb9\x03\x9b\xbf\xd2\xed\xf9\xed\x1a\xbe\t\xc6\xeb\x9a~^\a6\xba\xb0\xa5\x7f\xc1\x0e\xec\x84[f\xc4f\x83\x87\xb8\x7f\xa2,\xe4f\xc9A}\v\xca\xd0Y\xa5\xea\x91\xf0\x84IN\xc1? \x9f\xb0\xf7ӫ\x9f\xaf\xe1\x9b!\x06G\xb6\x12\x92\xe3'xE\xd6\xc7c\xa3\x15\xffv\x06\xf7^\x0f\xf6ұO\xb4SY)\x8b\x12\x94\xac\xf7!\x00\xde\"X\xd5 찮\x8b\x10 rر=\xa8\xf5\x91}\x92\x88H5\x19hf\xdc\xc9 1\xe2p\xfa\xd2L\xa3\xa6\xd4\x1ew_|\x14\xf5\xa8\xdb\xfbl\x11\xc8#\x91\xf0\xe9\xc2g \xd1O\xbd.@\xe2\xa1]\xa1\x91\xe8Ѓ\xc1Ui\t\x87\x12\xb5\xb3s\xb5E\xb3\x15\xb8\x9b\xef\x94y\x10rS\x902\x16A\xeav\xee\xcbH\xf3\xaf\xfc\x9fK\x0f\xee\xeb?\x9f{zO\xe4\xf9 \xa0\xdd\xed\xfc\x12\x04Rt\xffx\xdfu\x14\x87e\f8\xc74\xe9\xce\xef*QV)\xd7\xebYۆ\xf1`\x8e\x99\xdc?\xd3\xdd!\x9c[C\x1c\xed\x8bX\x03-\x98\xe4\xf4\xbf\x15\xd6Q\xff%\xc0\xb6Ⳍˇ۷\xcfy\xa3Zq\x89%9\x92Ä\xf6\xa98pU4L\x17a6s\xaa\x11\xe5h6\xc5\U00037704\xb4\x16h΄\x7f\xef\a\x93S\x80\x9a\xc9\x06\xba9O\x8a?\x1d\xdbd\x02\xbe~y\xf8TXx\x12\xaf\xf3\xaap\xcf6\x16\x98A`\xd00M\x1a\xf1\x80\xfb\"D\x1c\x9a\t\n\x17(\"\xe8\n\x83\xc0\xb4\xaeɧ\x87(\"C1ƿ\x11\x1ef\xfd\xf9\x8e\x01\x92\x15e\xaaJ-\xd19!\x9f\x11\x9c\x0f#F~_\xa0\xba\x9a]\xa9\xe4Zlb\xb5s\x8a\x94l뚭j\\\x803\xed\xb1\x9c\xeb$\x90\xf74\xe5\xf4\xf9?\xf4\xa6&\r?S`̟jPv\x9c\x1e\x06e\xdbLY)\xe0Ai\xc12\xfd\x06\xad\x9b\xdc^\x1a\xb8\xbe~\xca\x1d\vJyI\xca\x1d\xd2\xe0\\V\x1a\x15=\x06\xf0)3u\xea\x90\xe5e\x85\xfe\x04\xdb@\xd9=\xa5#C\xbe\x8b|\xb9d4\xa7W]N]Z\xf1Q\xcf\xd0\f\x8e\x06\xc3\xf9\x1eUC\xf2\x05\xed'T\x91\xc2\xebU\xc448G\x97\u07b4(쾴\x8eD\x89\x9dvȻB\xff%\x12\x7f=&\xe2k\xbf\x86\xc7K!\x1a\xecR\xff\xa1\xad\v\xc9\xdd\nA\x1b\xd4,[\x15\x02_\xb9\xb7\xbe\x84\xf9\xb5\rĄ\x85\xd6\"\xf7\x15\xb4\xc9\xde\x13\n\xe9E\x893\x87\x05\xad\xbf\xcc^\xe4\vS\xe11\xad\xffRrQ\x95jJf\n!K\xa8\xf9'\x9c\xf4\x8a\x97C\xec@\xae\xc3+PC\xee\xb3PJ\x92\xd7L\xd4\xc8!=\x11?\x91\xca\n\xd7\x14\xe2\x04\x1b\x97\xea8\x91\xbd\xe3\xf9\xdfiIf@\x98\x06<_R\x98\rZ\xcb6\xe7lޏaV(o\xc5%\xc0V\xaauy%\xff\xda\xc6{\xfa\xb4\x12[\xb6r44\x11\xccU\xc9\"\xacۺ\xf6k\xfa\xc6\xf5\xf0\xf9\x80\xe7j\x85\xf9\xb0\xf8D}\xed\x14\x83\x15\xb3砺\xa399\xa3\xd5y\x84\x93V\vNx\xbfw\xb8\xcb\xf4&c\x90\x19\xba\x8b\x16&34\xf9\x0e\xa0?\x18\n\xc89\xe4\xd2X\x96f\xf7ʞ\x19\xfb\xde_\xbd'\x81\x1d\xf9\xbbĶt\x05\xe8J\xd5ɜ\xf8\xd7q\xd96+4$\t\xff\xfe>r\xd2L\xf2\xbe\xd8r\x99\xfaa}Ҡ@)V\x9bb\xdd\xdc\xdfo\xa7\x80\v\xabk\xb6\xef\xce\xe2\xf3#\xba\xcc\xf9G\x84ÍJfE\xe3\xb1x\xeft\x19\xb8\xfbV!\x9f\xfc\xe5>8\x18\xb6\xe9\xa7\x03\xa3\xf1\xee\x1b\x84/\xb3Éx\xd5J\xa6m\xa5\xdc\xed\xdb3\xaa\xb1\xec&\xa6\xfbxȽ\xbc\xf5\xf5\xefSqRT\x85\f\xab\a\xeb\xf6$c1\xfct\xe5\x12-^\x0e(\x9cq\x8e\xf1K\x9a\x9c\vZ\x92\x15 \x03\xe4_?oƟ9\xbc\xe8>\x9d`.V\x91ˊ\xc9M\xb6\x96\xa5\xa4\x0f\xb6\x95\x99>E\xc3Yo7<\xd0\x1f\xe9\xe8\xb2\xea4\xe9\xf4\x9c\xf3\x1e\xed\xf8\xf0\xd7\xefiWݛ\xf8\x02~\xfd\xed\xea\xff\x01\x00\x00\xff\xff\xd9H\xdbA\x14'\x00\x00"), - []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4ZO\x93۶\x15\xbf\xef\xa7x\xb39$\x991\xa5\xdam3\x1d\xdd\xecu\xd3\xd96\xd9\xeeX\xb6/\x99\x1c \xe2\x89DD\x02\b\x00J\xab\xa4\xf9\xee\x9d\a\x80\x14\xff@\xd2J\x1eǼ\xd8\v\x80\x8f?\xfc\xde_<(˲\x1b\xa6\xc5G4V(\xb9\x00\xa6\x05>9\x94\xf4\x97\x9dm\xfeagBͷ/o6B\xf2\x05\xdc5֩\xfa\x1dZ\u0558\x1c\xdf\xe2ZHᄒ75:ƙc\x8b\x1b\x00&\xa5r\x8c\x86-\xfd\t\x90+錪*4Y\x81r\xb6iV\xb8jD\xc5\xd1x\xe1\xed\xa7\xb7\x7f\x99\xbd\xfcn\xf6\xf7\x1b\x00\xc9j\\\x80V|\xab\xaa\xa6F\x83\xd6)\x83v\xb6\xc5\n\x8d\x9a\tuc5\xe6$\xbc0\xaa\xd1\v8L\x84\x97\xe3\x87\x03\xe8G\xc5?z9\xef\x82\x1c?U\t\xeb\xfe\x93\x9c\xfeAX\xe7\x97\xe8\xaa1\xacJ\xe0\xf0\xb3VȢ\xa9\x98\x99\xce\xdf\x00\xd8\\i\\\xc0\x03A\xd1,G~\x03\x10\xf7\xe9\xa1e\xc08\xf7̱\xea\xd1\b\xe9\xd0ܑ\x88\x96\xb1\f8\xda\xdc\b\xed<3c\x88`\x1ds\x8d\x05\xdb\xe4%0\v\x0f\xb8\x9b\xdf\xcbG\xa3\n\x836\xc0\x03\xf8\xc5*\xf9\xc8\\\xb9\x80YX>\xd3%\xb3\x18g\x03\xc5K?\x11\x87ܞ0[g\x84,R(ދ\x1a\x817ƫ\x96\xf6\x9f#\xb8R\xd8)\xbc\x1d\xb3\x04\xd18\xbf\xf14\x18?O\"\xadc\xb5\x1e\xa3\xea\xbd\x1a`q\xe60\x05\xeaNպB\x87\x1cV{\x87\xedV\xd6\xca\xd4\xcc-@H\xf7\xddߎ\xf3\x11\t\x9b\xf9W\xdf*9$\xe7\r\x8dBo8 !m\x15h\x92\f)ǪO\x01\xe2H\xc0\x9b\xde\xfb\x01I\x90\xdb\x1f?\v\x85L\x0f\xd4\x1a\\\x89\xf0\x86\xe5\x9bF\xc3\xd2)\xc3\n\x84\x1fT\x1eT\xb8+Ѡ_\xb1\n+ȃA\x90\xee\x94I\xaaNc>\vk\xa3\xb0V\xd6H\x7f\xc3\x0f}\x16\xfb\xca\r\xb2\xa4}\xb5\xa1h\xe6W\b%\xd3F\xf6\xba\xc0g\x19X\x9fH\xa98\xf6X\x9b\xe0\x12\x16\xb4Q9Z{\xc2\xf0I\xc8\x00\xc9\xc3a\xe0,E%\xfa5-\xa0FW\x8aq4\xe0\x14\x94L\xf2\n\x83\x0e\x9daҮ\xa3eLUؾ\xf6~\xaf\x87P>\xb4\xf2z3\x13La\xe9\xf6e\b\x83y\x895[ĵJ\xa3|\xfdx\xff\xf1\xaf\xcb\xc10\x10-\x1a\x8d\x13md\x0eO/\xf1\xf4Fa\xb8\xe7\xffe\x839\x00\xfa@x\v8e \xb4\x9e\x8b\x18_\x91GL\x81#a\xc1\xa06hQ\x86\x9cD\xc3L\x82Z\xfd\x82\xb9\x9b\x8dD/ѐ\x18\xb0\xa5j*N\x89k\x8bƁ\xc1\\\x15R\xfc\xd6ɶD8}\xb4b\x0e\xad\xf3\x8eh$\xab`˪\x06_\x00\x93|$\xb9f{0H߄F\xf6\xe4\xf9\x17\xec\x18Ǐޚ\xe4Z-\xa0tN\xdb\xc5|^\bצ\xe3\\\xd5u#\x85\xdb\xcf}f\x15\xab\xc6)c\xe7\x1c\xb7Xͭ(2f\xf2R8\xcc]cpδ\xc8\xfcF\xa4Oɳ\x9a\x7feb\x02\xb7\x83\xcfN\x14\x1d\x1e\x9fD/P\x0feU\xf2\x04\x16E\x85-\x1e\xb4@CDݻ\x7f.\xdfC\x8b$h*(\xe5\xb0t\xc2K\xab\x1fbS\xc85\x19>\xbd\xb76\xaa\xf62Qr\xad\x84t\xfe\x8f\xbc\x12(\x1d\xd8fU\vGf\xf0k\x83֑\xea\xc6b\xef|\xc9\x02+r(\x8a\x03|\xbc\xe0^\xc2\x1d\xab\xb1\xbac\x16\xffd]\x91VlFJx\x96\xb6\xfa\x85\xd8xq\xa0\xb77\xd1VQGT;\x8eoK\x8d9i\x96ȥW\xc5Z\xc4L\xb2V\x06\xd8d\xfd\x90\xa9t\b\xa0'\x99QƋΙ\x1d=oR\x82ZIJ\x17\xc8c\xbe\xb31QU\xc3D\xd5\x7f&9ҠVV8e\xf6\x87L96\x89\xa3ڡ'g2\xc7\xea\x9a\xed\xdd\xf97AHN\xbccg\xd2\x14\x8c\x82T\x0fT\xc9B\x91\x93M\xd4\x01\xf7\x8e֑\x9d[t\xe9\xcdʣ\x99MH8ԘЯ%\xc7\xdb^)U!\x1b\xb3\xa9\x15?\xb3\xe9G\x15\x03\x87\xc15\x1a\xf4\xf9?\x84Y\xad|0vL\xc86|\x84\x92\x1b\x9cJ\xeccE\xe1\xe6\x98j\x8e\xdb!\x9cHII\xc0\xaf\x1f\xef۴\xd3ZV\x84>\xc9,}~\x92fA\xcfZ`\xc5}\xa2>\xff\xed\xa4\x85\xd0s\xbf\x0e |\xecu\n\x18h\x819\x0e\xf2\x1e\bi\x1d2\x1e\a)\xdc\x18\x8cs/BL=\n\x92\x9eC~$\x95\x00\xa3\x18/8\xfc{\xf9߇\xf9\xbfT\xd8\a\xb0\x9c*!\x7fV\xc1\x1a\xa5{ѝW8Za\x90\xd3\xe9\x03g5\x93b\x8d\xd6͢44\xf6\xa7W?\xa7\xf9\x03\xf8^\x19\xc0'FE\xff\v\x10\x81\xf3.m\xb4V#l\xd8x'\x11v\u0095\x1e\xa8Vԛ[\x04\xabj\x84\x1dVU\x16J1\x0e;\xb6\a\xb5>\xf2\x9dVEd\x9a\f43\xeed9\x16y8\xed4\xd3\xfa\xa4}\x9e\xe7/\xbe^y\x96\xf7~\xb1\\\xffL&|a\xfe\tL\xf4\x8f:W0\xb1iVh$:\xf4dp\x95[\xe2!G\xed\xec\\m\xd1l\x05\xee\xe6;e6B\x16\x19\x19c\x16\xb4n\xe7\xbee3\xff\xca\xffs\xed\xc6}\x9f\xe5Sw\xef\x85|9\n\xe8\xebv~\r\x03m\x1d\xfd\xfc\xdcu\x94\x87e\xac\xec\xc62\xc9\xe7w\xa5\xc8\xcb\xf6TՋ\xb65\xe3!\x1c3\xb9\xffB\xbeC<7\x86\x10\xed\xb3\xd8p̘\xe4\xf4\x7f+\xac\xa3\xf1k\x88m\xc4'\x05\x97\x0f\xf7o\xbf\xa4G5\xe2\x9aHr\xe4\xb4\x10\x9e\xa7\xec\x80*\xab\x99\xce\xc2j\xe6T-\xf2\xd1j\xaa\x95\xef9)i-М\xa9\xfe\xde\r\x16\xb7U{\xa2\xea\xee\xd6\\Tv[ɴ-\x95\xbb\x7f{\x06Dz[\xd8b8\xe80\x16\x9d\xad,r\x89\x93\xb5\xe63\xf0,\xc5o\x89\xb0\x95DDK[L\x95*D\xce*\xb04\x16ѵ\"\xa78Rm\xc81\xca~3\xb1\aӇ\x80\x87\xe3\x01v\x88t\xb8\xba\x05\xab\x8c(\x84d\xd5!P\xfb\x13\xa3d5\xf3\x7f%L\xb4fZ\vY\\Di\xdb\xd6Z\xa2sB\x16\x89\xfa\xbe\xdfu?u\n8\xe9\x1e\xe7=\xff\xc3\b\b0\x83\xc0hO\xa4\xaa\r\xee\xb3Plj&\xa8R\xa4b0V\xd4+\x04\xa6uE\xe5\\( S!\xa9m\xd2\xe5J\xaeE\x11\x1b\xa6S\xa6dSUlU\xe1\x02\x9ci\x8e\x9dՒ^\xde\xef\x0f\x9e\xd1\xf8\x87\xde\xd2V\xddg:\x94\xe9]\r\xfa\x96\xd3͠l\xea)\x94\f6J\v\x96\x18'\x9f\x9c\xc4#\x9a\xb8\xbd\xbdĤ\x82ß\xe1 \x1c\x95S}\x86\x18/\xe2\xe9#\x9e\xacC\xd4H'\xf1K\xe3\x88\xc1_\x1b:J\r\x11f\xe9\x96\xcah\x8dV\xfcfLZ?\x04\x8f&\x0f\x01t<1t\xfa\xd1l\xa0\xe0Y\xdd(\xdf\x1f\xbf\xa4\x1f\x15n\xc1\"\xef!\xfb\xbb\xf6n\x8c\xce\x15Ww\xa4\xe8\xe8\xaa\x1d\xf2\xee\xea\xe0\x9av\xcd\xeb\xb1\x10\xdfG6<:\x89\xa8\xb1\xebmD;1\x87nK\xc8,ڠfI\x8b\x00\x7f\x17`}?\xf4k\x1b\xa4\t\v\x8dE\xeec\xeb\xe4\xe3Gs\x02g\x0e3z\xff\xba\x00\x92\xeeq\x85[\xb9\xfe\xe5\xcbU\r\xaf\xa9\x98)\x87\xac\xa3\xcd_\v\xb5\xf7\x81)\xca\x0e\xf2:\u00828\xe4\xfe\xa4\rJ\u009a\x89\n9tw\xce\x173\x9f\x00=\xad\xc1>'\xf95ZˊsA\xebǰ*4\xdc\xe2+\xc0V\xaaqG\xac\xf2k\x1b]뢜,\x15?\x87\xe4Aq\x0fC\x1e\xbfi\x9b\xa2I\xa8\xa5\x7f\xfbv\x11F\xdf\xcb<כ\xa45\xa9P\xd3A>\x1dk\xe0D\x0e{\xc0]b\xb4\xf5\xe0\xc4\xd4c\f\v\x89\xa9\xc9\xcf\x00\xfa\x93\xa1\x81\x9c\xaaiڹ\xa4\xcc\xee\x8e=1\xf7\xbdw\x97\x8b؎\xf8\xae\t\b]\xfb\xb9TU\x1b\x03\xfcݸl\xea\x15\x1aR\x85\xbf}\x1fW\xc4\xc0$\xefk.\xd5C\xe8$\xb4i8\x88\x8am\xb0\xd87\xf7^\xee\x14pau\xc5\xf6\xddf\xfc\xc1\x8d\\:}\x8bp\xf0\xab6VQ\xe69R\xb7\x9dnPw\xbfUH\x1fKOW\xfap\xa6\xda\xf7\xf3\xddo\x10>\xcf\x17Nԝ\xc3߄\\c ˁ\x84s\xc9\"\xfeF\xe5\xf2\x18?\xfc̟\x19ޓ\xecM\x06=rޓ\x1do\xba\xfa#ͪ\xbb\x06^\xc0\xef\x7f\xdc\xfc?\x00\x00\xff\xff\xbb:E#\n&\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4Z͒\x1b\xb7\x11\xbe\xefSt\xad\x0f\xb6\xab4d\xa4$\xae\x14o\xd2*Nmbo\xb6DI\x17\x97\x0f\xe0\xa09\x03s\x06\x80\x01\f\xb9\xb4\xe3wO5\x80\x19\xce\x0fH.\xa9\x925\x17i\xf1\xd3\xf8\xf0u\xa3\xbb\xd1`\x96e7L\x8b\x8fh\xacPr\x01L\v|r(\xe9/;\xdb\xfc\xc3΄\x9ao_\xdel\x84\xe4\v\xb8k\xacS\xf5;\xb4\xaa19\xbeŵ\x90\xc2\t%ojt\x8c3\xc7\x167\x00LJ\xe5\x185[\xfa\x13 W\xd2\x19UUh\xb2\x02\xe5lӬpՈ\x8a\xa3\xf1\xc2ۥ\xb7\x7f\x99\xbd\xfcn\xf6\xf7\x1b\x00\xc9j\\\x80V|\xab\xaa\xa6F\x83\xd6)\x83v\xb6\xc5\n\x8d\x9a\tuc5\xe6$\xbc0\xaa\xd1\v8t\x84\xc9q\xe1\x00\xfaQ\xf1\x8f^λ \xc7wUº\xff$\xbb\x7f\x10\xd6\xf9!\xbaj\f\xab\x128|\xaf\x15\xb2h*f\xa6\xfd7\x006W\x1a\x17\xf0@P4ˑ\xdf\x00\xc4}zh\x190\xce=s\xacz4B:4w$\xa2e,\x03\x8e67B;\xcf\xcc\x18\"X\xc7\\c\xc16y\t\xcc\xc2\x03\xee\xe6\xf7\xf2Ѩ\u00a0\r\xf0\x00~\xb1J>2W.`\x16\x86\xcft\xc9,\xc6\xde@\xf1\xd2w\xc4&\xb7'\xcc\xd6\x19!\x8b\x14\x8a\xf7\xa2F\xe0\x8d\xf1\xaa\xa5\xfd\xe7\b\xae\x14v\no\xc7,A4\xceo<\r\xc6\xf7\x93H\xebX\xadǨzS\x03,\xce\x1c\xa6@ݩZW\xe8\x90\xc3j\xef\xb0\xdd\xcaZ\x99\x9a\xb9\x05\b\xe9\xbe\xfb\xdbq>\"a3?\xf5\xad\x92Cr\xdeP+\xf4\x9a\x03\x12\xd2V\x81&ɐr\xac\xfa\x14 \x8e\x04\xbc\xe9\xcd\x0fH\x82\xdc~\xfbY(dz\xa0\xd6\xe0J\x847,\xdf4\x1a\x96N\x19V \xfc\xa0\xf2\xa0\xc2]\x89\x06\xfd\x88U\x18A'\x18\x04\xe9N\x99\xa4\xea4\xe6\xb306\nke\x8d\xf47\\\xe8\xb3\xd8Wn\x90%\xed\xabuE3?B(\x996\xb2\xd7\x05>\xcb\xc0\xfaDJű\xc7\xda\x04\x97\xb0\xa0\x8d\xca\xd1\xda\x13\x86OB\x06H\x1e\x0e\rg)*яi\x015\xbaR\x8c\xa3\x01\xa7\xa0d\x92W\x18t\xe8\f\x93v\x1d-c\xaa\xc2v\xda\xfb\xbd\x1eB\xf9\xd0\xca\xeb\xf5L0\x85\xa1ۗ\xc1\r\xe6%\xd6l\x11\xc7*\x8d\xf2\xf5\xe3\xfdǿ.\a\xcd@\xb4h4N\xb4\x9e9|\xbd\xc0\xd3k\x85\xe1\x9e\xff\x97\r\xfa\x00h\x810\v8E \xb4\x9e\x8b\xe8_\x91GL\x81#a\xc1\xa06hQ\x86\x98D\xcdL\x82Z\xfd\x82\xb9\x9b\x8dD/ѐ\x18\xb0\xa5j*N\x81k\x8bƁ\xc1\\\x15R\xfc\xd6ɶD8-Z1\x87\xd6\xf9\x83h$\xab`˪\x06_\x00\x93|$\xb9f{0HkB#{\xf2\xfc\x04;\xc6\xf1\xa3\xb7&\xb9V\v(\x9d\xd3v1\x9f\x17µ\xe18Wu\xddH\xe1\xf6s\x1fYŪq\xca\xd89\xc7-Vs+\x8a\x8c\x99\xbc\x14\x0es\xd7\x18\x9c3-2\xbf\x11\xe9C\xf2\xac\xe6_\x99\x18\xc0\xed`ى\xa2\xc3\xe7\x83\xe8\x05ꡨJ'\x81EQa\x8b\a-P\x13Q\xf7\xee\x9f\xcb\xf7\xd0\"\t\x9a\nJ9\f\x9d\xf0\xd2\xea\x87\xd8\x14rM\x86O\xf3\xd6F\xd5^&J\xae\x95\x90\xce\xff\x91W\x02\xa5\x03۬j\xe1\xc8\f~m\xd0:R\xddX\xec\x9dOY`E\a\x8a\xfc\x00\x1f\x0f\xb8\x97p\xc7j\xac\xee\x98\xc5?YW\xa4\x15\x9b\x91\x12\x9e\xa5\xad~\"6\x1e\x1c\xe8\xedu\xb4Y\xd4\x11Վ\xfd\xdbRcN\x9a%ri\xaaX\x8b\x18I\xd6\xca\x00\x9b\x8c\x1f2\x95v\x01\xf4%#\xcax\xd09\xb3\xa3\xefMJP\x8bX\xf6\x1cy\x8cw6\x06\xaaj\x18\xa8\xfa\xdf$F\x1a\xd4\xca\n\xa7\xcc\xfe\x10)\xc7&qT;\xf4\xe5L\xe6X]\xb3\xbd;?\x13\x84\xe4\xc4;v&M\xce(H\xf5@\x95,\x14\x1d\xb2\x89:\xe0\xde\xd18\xb2s\x8b.\xbdYy4\xb2\t\t\x87\x1c\x13\xfa\xb9\xe4x\xdb+\xa5*dc6\xb5\xe2g6\xfd\xa8\xa2\xe30\xb8F\x83>\xfe\a7\xab\x95wƎ\tٺ\x8f\x90r\x83S\x89}\xac\xc8\xdd\x1cS\xcdq;\x84\x13!)\t\xf8\xf5\xe3}\x1bvZˊ\xd0'\x91\xa5\xcfO\xd2,\xe8[\v\xac\xb8\x0f\xd4\xe7\xd7NZ\b}\xf7\xeb\x00\xc2\xfb^\xa7\x80\x81\x16\x98\xe3 \ue050\xd6!㱑܍\xc1\xd8\xf7\"\xf8ԣ \xe9;\xc4GR\t0\xf2\xf1\x82ÿ\x97\xff}\x98\xffK\x85}\x00\xcb)\x13\xf2w\x15\xacQ\xba\x17\xdd}\x85\xa3\x15\x069\xdd>pV3)\xd6h\xdd,JCc\x7fz\xf5s\x9a?\x80\xef\x95\x01|b\x94\xf4\xbf\x00\x118\xef\xc2Fk5\u0086\x8dw\x12a'\\\xe9\x81j\xc5\xe3\x06w~\v\x8em\xe8Ą-4\b\x95\xd8`\x9a}\x80[\x9f<\x1d`\xfeN.\xe5\x8f[\xf8&8\x89[\xfa\xf36\xc0\xe8\x12\x84\xbe\xd79\xc0q%s\xe0\x8c(\n<$\xda\x13c\xa1\x80F\xa1\xe0[P\x86\xf6*UO\x84\x17Lz\n\x8e\x18\xf9\x04\xdeO\xaf~\xbe\x85o\x86\x1c\x1cYJH\x8eO\xf0\x8aθ\xe7F+\xfe\xed\f\xde{;\xd8KǞh\xa5\xbcT\x16%(Y\xedC\xbe\xb9E\xb0\xaaF\xd8aUe!\x15\xe3\xb0c{P\xeb#\xeb\xb4*\"\xd3d\xa0\x99q'ӱ\xc8\xc3\xe9C3\xcdO\xda\xefy\xe7\xc5\xe7+\xcf:\xbd_,\xd6?\x93\t\x9f\x98\x7f\x02\x13\xfd\xab\xce\x15Ll\x9a\x15\x1a\x89\x0e=\x19\\\xe5\x96x\xc8Q;;W[4[\x81\xbb\xf9N\x99\x8d\x90EFƘ\x05\xad۹/\xd9̿\xf2\xff\\\xbbq_g\xf9\xd4\xdd{!_\x8e\x02Z\xddίa\xa0ͣ\x9f\x1f\xbb\x8e\U000b0319\xddX&\x9d\xf9])\xf2\xb2\xbdU\xf5\xbcm\xcdxp\xc7L\xee\xbf\xd0\xd9!\x9e\x1bC\x88\xf6Y,8fLr\xfa\xbf\x15\xd6Q\xfb5\xc46ⓜˇ\xfb\xb7_\xf2D5\xe2\x1aOr\xe4\xb6\x10\xbe\xa7\xec\x80*\xab\x99\xce\xc2h\xe6T-\xf2\xd1hʕ\xef9)i-М\xc9\xfe\xde\r\x06\xb7Y{\"\xeb\xee\xc6\\\x94v[ɴ-\x95\xbb\x7f{\x06Dz\x1b\xd8b8\xe80&\x9d\xad,:\x12's\xcdg\xe0Y\x8a\xdf\x12n+\x89\x88\x86\xb6\x98*U\x88\x9cU`}\x9b\x8c\xc5\xca\b\xb3\x95=\x05\x94\xaaG\x8e\xe1\xf6\xab\x8a=\xbc\xde\x17<\x1c\xf7\xb4C\xc8\xc3\xd1-jeD!$\xab\x0e\x1e\xdb_\x1d%\xab\x99\xff+a\xab5\xd3Z\xc8\xe2\"n\xdb\xfa\xd6\x12\x9d\x13\xb2H$\xfa\xfd\xf2\xfb\xa9\xeb\xc0\xc9sr\xde\x05|\x18\x01\x01f\x10\x18\xed\x89T\xb5\xc1}\x16\xb2N\xcd\x04\xa5\x8c\x94\x15\xc6\xd4z\x85\xc0\xb4\xae(\xaf\v\x99d\xca7\xb5պ\\ɵ(b\xe5tʔl\xaa\x8a\xad*\\\x803ͱK[\xf2\xb8\xf7\v\x85g4\xfe\xa17\xb4U\xf7\x99RezW\x83\x02\xe6t3(\x9bz\n%\x83\x8d҂%\xda\xe9pN\x1c\x13u\xdc\xde^bR\xe1\xe4\x9f\xe1 ܙS\x05\x87\xe88\xe25$^\xb1\x83\xfbHG\xf3K\x1d\x8a\xc1_\x1b\xbaS\r\x11f\xe9\xda\xcah\x8cV\xfcfLZ\xdf\x17\x8f:\x0f\x9et\xdc1<\xf4\xa3\xde@\xc1\xb3\xcaR\xbeP~Ia*<\x87E\xdeC\x1a\xe0\xdaG2\xba`\\]\x9a\xa2;\xacvȻ7\x84k\xea6\xaf\xc7B|A\xd9\xf0xHD\x8d]\x91#ډ9\x94]B\x88\xd1\x065KZ\x04\xf8G\x01\xeb\v\xa3_\xdb MXh,r\xef['\x8b\x1f\x8d\t\x9c9\xcch\xfeu\x0e$]\xec\n\xcfs\xfdW\x98\xab*_S1S\x0eYG\x9b\x7f\x1fj\x1f\x06S\x94\x1d\xe4u\x84\x05q\xc8\xfd\x95\x1b\x94\x845\x13\x15r\xe8\x1e\x9f/f>\x01z\x9a\x8c}N\xf2k\xb4\x96\x15\xe7\x9c֏aT\xa8\xbc\xc5)\xc0V\xaaqG\xac\xf2k\x1b\x8f\xd6E1Y*~\x0eɃ\xe2\x1e\x86<\xfe\xe46E\x93PK\xff\x19\xee\"\x8c\xbe\xa8y\xaeHIcR\xae\xa6\x83|\xda\xd7\xc0\x89\x18\xf6\x80\xbbDk{\x82\x13]\x8f\xd1-$\xba&\xbf\a\xe8w\x86Jr*\xa7i\xfb\x922\xbb\xc7\xf6D\xdf\xf7\xfe\xb8\\\xc4v\xc4w\x8dC\xe8\xeaХ\xaaZ\x1f\xe0\x1f\xc9eS\xafА*V\xa9\x8c\x18\x98\xe4}ͥ\x8a\t\x9d\x846\f\aQ\xb1\x1e\x16\v\xe8\xfe\x94;\x05\\X]\xb1}\xb7\x19\x7f\x83\xa3#\x9d~N8\x9c\xab\xd6WQ\xe49\x92\xb7\x9d\xaeTw?ZH\xdfOOg\xfap&\xdb\xf7\xfdݏ\x11>\xcf\n'\xf2\xce\xe1\x8fC\xae1\x90\xe5@¹`\x11\x7f\xacr\xb9\x8f\x1f.\xf3g\xba\xf7${\x93F\x8f\x9c\xf7d\xc7'\xaf~K\xb3\xeaރ\x17\xf0\xfb\x1f7\xff\x0f\x00\x00\xff\xff;\xa8N\xc3\x13&\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xdc=[s\xdb8w\xef\xf9\x15\x98\xf4a\xdb\x19\xcbi\xa6\x97\xe9\xf8\xcd\xf5:\x8d\xfb}\xebx\xec4\xfb\f\x91G\">\x83\x00\x17\x00\xa5h\xdb\xfe\xf7\x0e\x0e.$%\x90\x84d˛-^2\xa6\x80\x03\xe0\xdc\xcf\xc1\x01\xb2X,\xdeц}\x03\xa5\x99\x14W\x846\f\xbe\x1b\x10\xf6/}\xf9\xfco\xfa\x92\xc9\x0f\x9b\x8f\uf799(\xaf\xc8M\xab\x8d\xac\x1fA\xcbV\x15\xf03\xac\x98`\x86I\xf1\xae\x06CKj\xe8\xd5;B\xa8\x10\xd2P\xfbY\xdb?\t)\xa40Jr\x0ej\xb1\x06q\xf9\xdc.a\xd92^\x82B\xe0a\xea\xcd?^~\xfc\xd7\xcb\x7fyG\x88\xa05\\\x11\x05\xdaH\x05\xfar\x03\x1c\x94\xbcd\xf2\x9dn\xa0\xb00\xd7J\xb6\xcd\x15\xe9~pc\xfc|n\xad\x8fn8~\xe1L\x9b\xbf\xf4\xbf\xfe\x95i\x83\xbf4\xbcU\x94w\x93\xe1G\xcdĺ\xe5T\xc5\xcf\xef\bхl\xe0\x8a\xdc\xdbi\x1aZ@\xf9\x8e\x10\xbft\x9cv\xe1W\xbd\xf9\xe8@\x14\x15\xd4ԭ\x87\x10ـ\xb8~\xb8\xfb\xf6OO\x83τ\x94\xa0\v\xc5\x1a\x83\b\xf8\x9fE\xfcN\xc2B\tӄ\x92o\xb8Q\xbb\x1aD<1\x155DA\xa3@\x830\x9a\x98\n\bm\x1a\xce\n\xc4;\x91\xab\x1e\xa40J\x93\x95\x92u\amI\x8b\xe7\xb6!F\x12J\fUk0\xe4/\xed\x12\x94\x00\x03\x9a\x14\xbc\xd5\x06\xd4e\x04\xd4(ـ2,`ٵ\x1e\xef\xf4\xbeNm\xcc6\x8b\v7\x8a\x94\x96\x89\xc0m\xc1\xe3\x13J\x8f>\"W\xc4TLw[\r\xdb#T\x10\xb9\xfc\x1b\x14\xe6r\x0f\xf4\x13(\v\x86\xe8J\xb6\xbc\xb4\xbc\xb7\x01e\x91Uȵ`\xbfG\xd8\xdan\xdcNʩ\x01m\b\x13\x06\x94\xa0\x9cl(o\xe1\x82PQ\xeeA\xae\xe9\x8e(\xb0s\x92V\xf4\xe0\xe1\x00\xbd\xbf\x8e_\x90xb%\xafHeL\xa3\xaf>|X3\x13$\xaa\x90u\xdd\nfv\x1fP8ز5R\xe9\x0f%l\x80\x7f\xd0l\xbd\xa0\xaa\xa8\x98\x81´\n>І-p#\x02\xa5\xea\xb2.\xff.\x12u0\xad\xd9Y\x1e\xd5F1\xb1\xee\xfd\x80\x02q\x04y\xac\xa88\xc6s\xa0\xdc\x16;*\xd8O\x16u\x8f\xb7O_\xfbLɴ'J\x8f7\xc7\xe8c\xb1\xc9\xc4\n\x94\x1b\x87\xacia\x82(\x1bɄ\xc1?\n\xce@\x18\xa2\xdbe͌e\x83\xdfZЖ\xdf\xe5>\xd8\x1b\xd4:d\t\xa4mJj\xa0\xdc\xefp'\xc8\r\xad\x81\xdfP\roL+K\x15\xbd\xb0DȢV_\x97\xeewv\xe8\xed\xfd\x104\xe2\bi\xbd\x16yj\xa0\x18H\x9a\x1d\xc6VA]\xac\xa4\x1a(\x19;d\x88\xa3\xb4\xf0\xdb洈U\x8b\xfb\xbf\xccq\x99m\xff\x1eG[~\xb3+k\x05\xfb\xad\x05T\xa6N\xfc\xe1P_\xa9\x9ej\x1f6\xcbF\xfb\xd4\x1dE\xb4m\xf0\xbd\xe0m\te\xd4\xeb\a\x1b\xcc\xd9\xc6\xed\x01\x144z\x94\t+D\xd6\xfaؽ\x88\xeeWT\xe0T\x01\x11\xd2$\xe01\xe1\xe0\x11&\x10\x03I\x9a`G\x03ubœ[&D\xb4\x9c\xd3%\x87+bT{\x88F7\x96*Ew#\xd8\n\x1e\xc0\x8b\x90\x15\x81xU\xc3Y\x81$\x8f\n\x05\xf1\xf5\xe7E\x15\xd3VQ\x86]>HΊ\xdd\f\xben\x93\x83\x82\xb4z\xd9\xf5;$K\xa8\xe8\x86I\x95\x12\x03\xa9\xb0kϞwjZZ-\xe9\x81\xec۸\xcc\r'\x91UI\xf9<\xc7\x10\x9fm\x9f\xce:\x90\x02\x1dʸ\x15Omo\xbb\x97@\xe0;\x14\xadI,\x93\x90\xb2E\xd3$\x15i\xa46\xe3t\x1fW]\xa4\xef\x1c\xa5~\x9c`\x9a\x83\x9d%Y\xdd5\xaf\x84\x03Q-\x0e\x06\nY\n\xb0ۨ-Q\xbb\xbeJ\xb6\xae\xef(RȒj(\x89\x14\xa33#\xbb\xb4\x1c\xb4\x9f\xabD\xce\xe8\xf4\xd0E\xb7\x7f\xf4x\b\xa7K\xe0D\x03\x87\xc2Hu\x88\xcc\x1c\x94\xba\x96\xa3XGP\x99ЦC\t\xe860\x01\x92XN\xdfV\xac\xa8\x9c\x87a\xd9\x13\xe1\x90R\x82\xb6\xda\x04]\xe6\xdd\xd8&\xc9\x1c\xf9\xfd$Sڣk3b\xb5\x0f/\xa5Q\xba\x96\xa1\x86\xbb\x96Dm\xa7{\x0ft\x8b\xffn\xe4\xe4\xb6\xff\x7f\"6\x18\x93\x13\x98vB\xfe\t\xba\x9f\xd9<=ʷ\x18ၾ$w+\x02ucv\x17\x84\x99\xf0uN\x12(\xe7\xbd9\xfeĴ9\x9e\xe93I\x93#\x13g\"L\x9c\xe2OH\x174\x19O\xdebd\xd3\xe4\xaf\xfdQ\x17\x84\xad\"\xd2\xcb\v\xb2b܀\xda\xc3\xfeI\xaa>P\xe65\x90\x91c\xf5\b\xe6\tLQ\xdd~\xb7.\x8e\xee\x92`\x99x\xd9\x1f\xec|\xe3\x10A\f\xcd\xf3\f\\\x82\xf12SPc\x1cN\xbe\"6\xbb/\xe8T_\xdf\xff|\x18+\xef\xb7\f\xce;\xd8Ȍйv\xbd\xb7\xa3\xfe\xfa|T\x10~A\x1f(\x06U.\xe7rA(y\x86\x9ds]\xa8 \x96>4tΘ^\x01&\x7f\x90Ϟa\x87`\xd2ٜÖ\xcb\r\xae=C\xc2\xf5O\xb5\x01\x0e\xed\x9a|X\xec\xf0d? \"0\x86\xcfe\x03\u05fc($r'閩KB\v\xb8?a\x9bY\xacҟ\xa3\x9f\xfaD\x0e\xf8I;ZZ\x89\xa9\x98\xcfij@\x99\xc9%\xa8k\xdf(ge\x9c\xc8\xc9ȝ\xb8 \xf7\xd2\xd8\x7f0@\xd3\xc8(?K\xd0\xf7\xd2\xe0\x97\xb3`\xd4-\xfc\x9c\xf8t3\xa0\xa0\t\xa7\xe5-\xc2\xfa9?g\xd3,\xb7E\xdc3M\ue10dW\x1cJ2\xa7\xc2\xf4\xae\x9b\xceMT\xb7\x1a\xd3uB\x8a\x05\xda\xcc\xe4L\x1e\xdfR\r\xd0\xfd\xe2I\xfd\x84_\xad\xb1p\xbf\xb8$3\xa7\x05\x94!\xb2\xc4\xec'5\xb0fE\xe6|5\xa85\x90ƪ\xf0<\x8e\xc8T\xac~7DZO\x9e\xf5\xee\xb7\xef\x8b\xe7\x98/XX\x93\xb3\xf0\x10\x8c\xac3p\xe0uw9\xbf\x9f\x85\x95ٌ^\x81\x13f\xbb\x8e$Gǻ\xe6 \xe5\x05\xe8@+\x8e.\xce,uiY\xe2\x11\x1a\xe5\x0fGX\x94#x\xe1X\xd5\xd0[\xbb3\xc15m\xacZ\xf8okiQ\x9a\xfe\x974\x94)}I\xae\xf1\xa4\x8c\xc3\xe07\x9f\x87\xeb\x81ɘ\xb2\xb1SY\xfe\xd9Pnm\xbfU\xe0\x82\x00w\x9e\x80\\\x1d\xf8E\x17d[I\xed\xcc\xf6\x8a\x01\xc7\xf3\x8a\xf7ϰ{\x7fa\xa7\x9f\x9d\xb2\xafd\xde߉\xf7·8P\x18\xd1ᐂ\xef\xc8{\xfc\xed\xfdK\\\xa9LN\xcd\xec6`њ6y\x1c*\x92\xc9\xfa\xae\r8\xa6\x9f\x9b\xef\x92\xf2\xdeɞ\xdam\x16\x8b6R\x9b\xcf\xe9\xbc\xe1\xc8z\x1e\u0088\xa1g\x9cȱ\xcdF\f>\x8f\x16\xf5\xbdu\"W\x06\x94\xcf%:\x1b\x10\xe2\x8f\x17Ff\xa9S\x99\xfebc2\x90\xc6\xfc\xaeE\xf0\f7\xb9\x83\x9b\x9c%\x1e\xe3\xb0Z\xbc\x1c\xe9\xed\xdf~\xef\xe53\xad\xe4ڿ\xfb\x1bym\x87\xba\x90uM\xf7O5\xb3\x96z\xe3F\x06\x9e\xf6\x80\x1c\xf5պEyε\xc8\x1d\x0f\xe1\xf9喙\x8a\tB\x83\xda\x00\xe5\x19\x8a\x92F\xa6rةVQM\x96\x00\"\xa6\xe8\x7f\x04W\xa2f\xe2\x0e' \x1f\xcf\xe0zDt\x9d\xd3ٽ\x894\x89\x94\x8f\x1f\x9c\xc9jdI\xb6\x15(\x180\xc6a\xde\x1d=U!M/eq\x84C\xda\xc8\xf2'MVLi\xd3_\x82&\xadΥ\xf5\x91\xe4\xb3\xeb\xfe\xcaj\x90\xad9'\x82o\xbbi\x06g\xcd5\xfd\xce\xea\xb6&\xb4\x96\xad3\xe6\x86\xd5\xf1TףwK\x99\x89\xc7V\x98\xbf1Ғ\xa0\xe1`\x80,a\x95>\xefM\xb5B\n\xcdJP\xa1J\xc1\x91\x8dI+\x98+\xcax\x9b:%J\xb5c#`q\xab\xd4I\x01\xf0\x177\xb2\x97w\xac\xe4v\x88\xa0̽\xe3A\x1a\x10\xb6\"\xcc\x10\x10\x85\xc58(\xa7\x92q\n\x8f\fD\r\xcb\xd5sy\n\xdc6\x10m\x9d\x87\x80\x05\n$\x13\x93)\xb7~\xf7O\x94\xf1s\x90\xcdr\xde'\xa9\x1e\x81\x96\xa7\xe4h~\xed\r' t\xab\xf0\xf0\xdf\xe9\x8e-\xe3yk\xb6\x94#\x9c\xb6\xa2\xa8\x00\x95\x90\x18\xea\x06\a\x9e\tm\x80\xe6\xf2\x82\xf5\x8aZ!\x98X\xe7\xd1.;\x11\xda5\x87\ua954\x1c\xe8\xf8)d\xd7,\xae\xdf@\x13\xfd\xdaM\xf3BM\xd4\x11\xc1\x1d\x9b#\x1d\xb2)j\x95\x16\xa1\xc6@\xdd8\x91\x93D\xb5\xa2o]Π\x88\x8e\t\xc3\xfd*^3\xbef\x82e\xd0v@\xd7;\xc1L\xdfy\xb4 \xce\xea<\xda\t\xa2;pJ\x86\xedn\x00\xc0\nh\x88Cp\xed\x91k\x8ep$\x97@hYB\xe9r\x97\xd6\x15\xf1a\x89+|\x1b)nH\xee\xeexO0\x8b\xb2\xa1\r\x82N\xccê\r,Z\xf1,\xe4V,0\x18\xd7G\xeb\x90\x13\xb3T/\x9dޜ\xac\x8c\xe6\xf5K\xbe\x9a\x9e\xd3BC~\xcd\xe7\xa9\xe0?\x9dA\xcbd\xf3\xcdQ\t\x8f).\x98\xd3k\xae\x00{\xe4\xc7\xd9UL\xcd?1\xd8\x1fJ߸b\xe9\x17\x95\xc5ݥA\xf5\x9c\xc2m\x05\xa6\x02\x15J\xb3\x17X\x92^N\x9e\x90v\xc1K\xac\x93\xb3L\x15\\dW\xfe\xb9W9\x87\xd1M\xcb\xf9\x85\xe5m\xda\xf2d8l$\x8a\xd8!geՏ\xa5=\x86\x9c\xea\x8bl<\xf6+-\x86\xf5\x85\xb1\n\"\x14\x18\xca0\xb3\xa7qj\xbfXX\xda;\xdf\x1f\x96S`\xfe/,\xff\x0f/=̨\x94\xc8Gcn\x95fDb\x02V\x82\xc1zh\xec\xea+|?_\xe8\xfbc\xe1\xd4@\xfd\xa5\xf1\x123\xea\xc2f\xa05\x01g\xaf\xde\x04\xadA\xab\x9d+\x10\xed\x80\xcf\x19\xda\xf1ׅ\xbb\x05\x11\xc0\xa4\xf8\xf5k\x05A|}\xf5>\xd3\xe4\x9fI%\xdbDU\xdf\x04\xcaf\xaa;\xe67<(\xf4\xf0\a\n`\xe8\xe6\xe3\xe5\xf0\x17#}\xd9\af\xd1\x12\x800(\xea2\xb3L\x94l\xc3ʖ\xf2 \xb5\xdd\x1d\x02\xc7@\x1d\x9f%\xa0IE\x04\xe3\x8e\x01\xc3\xf8\x01Ñ/\x8d;\x969Z\xc5M\xfb\xa2y\xd5!'ׄ\fk>F\xac\xe1\xb1\xc7\x17\xafR\x05\xfb\x87\xd4z\x1c_\xe1\x91\x13I\xccTs\x9cPÑY,\xf6\xe2\xf3\x96\x9c*\x8dcb\xee\xb3Ud\xbc~\x1dF\x16~\xe6k.\x8e\xc1\xce\xd9\xeb+ް\xaa\xe2mj)2+(^\xaf\x142/\xfa<\xa9\x14`>`\x19\xaf\x82\x98\xad}xQ@sҖfk\x1a\x8e\xa9d\x98\xa5N\x9e\x98\xbdY\xad\u009bU(\xbcm]\xc2$\x17M\xfexL\xe5A\x8c\x93~\xa1M\xc3\xc4\xfa\x90)rYg\x92m\xe6Y\xe6~o!\x03\x9e\xe9\x873]t8\x12\xfa\xba\xeb҉H2\xa4-\x990\xf2\x92\\\x8b\x9d\x87\x9b\x80\xd3\v\x1f\x854\a\x17\xd9첶\x8c\xf3\xfem-\x04;\r\xcaߙԴv\xab\x1a\xf3\xf6\x93t\x95j\xe0\x94\x9f\x148~ك\xd1ώ\xbe\xa5\xe7_\xb7ܰ\x86\x83\xf5\xe86\xacL\xde!3\x15\xec\"\x92\xff&\xf1\x86\xd4r\x87\x90\xbe]\xf4\x9eQ\xec\x9eq\x926\xbf\xc9\x13\xb6\x97Q\xcc~\\\x11{\x06\xcdrE\xf1\r\x8b\xd5߰H\xfd\xad\x8b\xd3g8k\xe6\xe7\xe3\x8a\xd0O>\x81\tG\xfd\xf7\xb2\x84\a\xa9\xcc\\p\xf2\xb0\xdf?q\x92\xda\v\xd8$/\x89\b]\x13\xbb\xc4\x10Ç\x17\xa7m*}\xe8\x19\xdc\xe9_di\xd76w\xc6\xf2\xb8\xd7\xfd\xe0\xae\xf2\n\x14\b\xf7\xcc\xc7\x7f>}\xb9\x8f\xf0S>\xaf\xf7\x8c\xf7\x9e\x97p\x1eL\xe9\x91\xe3\x8f\xe6|1\x93\xc3\x16\xfa\x00\xaf|.B\x1b\xf6\x1f\xf8\xaa\xdb\v\xd2A\xd7\x0fw\b#\xf8i\xf8L\\\xac\xa2\x88'\x96K\xb0\x16+\xa2jT,\xeeV\x03\x88Ê\xdf\xfe3JP\xba'\xb3\x82\xc5d\xa1\xc6\xcb\n\xdeÝ[\xc7\xd8,\x9f\xac\xd3(vD:\x8e\xac\x98*\x17\rUf\x87l\xa3/\x06k\bff*\x9d3\xaaX\x0f\x9f\x01K\xa27\xbc\xfe\x85g\x91\xbbfxڻ\x8f\xbbS\xd61~\xffd\xf6\xe6\xc9+\xaec\xdcb/\x10S\x89\xcf\xc9\x02\x93WK\x93yM\xf4\xf0\xed\xa4\xb4\xcbc\x1c=\xad\xe7l\x14\x1dRM\t0v<\xaa:-h\xa3\xabēK/\xd3u\xf8\x1a\x99\xa1\xa6}\xc9&\x1d\x80\xc1>YQ\xf5\xb4\xd5\x16\x82>\v\xdbFi\xc5a)\xddnm\xb3\xab{a\xfc\xa2\x97)x\x9b#\xe1\xcc\xe7\\N~\xc8šgD\xfd`\xf6˪\xb6CL\x9dp\x18<\xeb\xdae\x14\x19O;\xb1\x99π\xe4\x19\x8c\x13\x9e\xfe@|\xe5\xe2\x8a$_\x04\xc9|\xf5\xe3\x0fE\xf4\x84V\xd3E\x05e\xcb\xe1\xd47\xff\x9ez\xe3\xe7_\xfd\v\xb3e\xbc\xfbg\x91\xdd3\xd0\xd6g\x1e\xbe/\xe8)\xe1!\xf7)9\xe6\xf0ap\xe0\x9e\x17+\xdcK\x94E\x01Z\xafZ\x1e\xaa\x94\n\x05\xd4@\x19\xba3\x1dW|T\x9dM\xdbpIKP7R\xacX\xe2\x84d\x80\xd6\xff\x1at\xde\xe3\xd9\x02?\xb6\xaa{\xdaq\xf2Y\xbc\x17i\xae\x86*\xca9\xf0O\x8c\x83\xfeYn\x85]W\x86@>\xa4\xc6\xf5\xeee\x15\xad\xb2f}GD[/\xad\x93\vƌ\a\x8b+\xa9\xa6+\xa4\x1dޙ0\xb0\x86T|\xbdU\xcc\xc0SC\x95\x06\\Q\xc6\x0e~\xdd\x1b\xe2\xa2\xcf\x15\xa7kW\nW\xb2\x82\x1a\x88\x06\x18g\x18[>\x8e\xd7\b\x8b\xef\xb02I\x8e$\xbd\xb2\x85z\xecJƨX\x8f=/\x9a0\xd5\xc9\aF\x9dE.hc\xf0\x02\f\xd2\x11\x89h<\f|\xb4w\xef\x8d\xd1\x01\xd8qN\xf3e̾`N\x1bZ'\xa2\x84y\xbdss\b\x06\x9f\x05Ve\xaf\xee\xae\xff\xc0b,\xb0#[\xaac1u\xd2\xf7\xee`;0\xe8\xaa[\xd0P\x12\u0600 V\x14)\xe3PNq\xeaWL$\xab\r\xa8\x9ft\x84\x83\x95\x80\x96ş\fU&.\xfdЏYIUSsEJj`aG\x9f溥\x9fIU\xea\xc4\xe3@\xbc\xd9\xe6ţ\b\xd7n\xac\xf5s\xf7\xd1jК\xaeC\x10\xba\x05\x05d\r\xc2\xe2=\xe6\x16\x93\x1eS\xb8\xd2\xe7\x8dE,-\xb5(\xa4\x85i\xa9\x9f\xc0\xb9p\xf1\xf44\xbcO\x8cQ\xeczTE\xa7U\x85\xbf<\xf8\bT\xef?w}\x80\x8bO\xfd\xbe>I\xecv\xec\xceF\xa8+\xf0\xc4\a\x8f\r\x8b\x91uJ\xa6\x8dę\x8f2'\x95\x94\xcfYn\xf6\xe7رK'1\xe1X\t\xafL.ekz~\x8eGxb\x99\xf8\xfc\xe7+\xdb\x17\x84y\xed.P\x8d\xe5V\xf3<\xbd\xcf\x03H1\xbc\x95\x86\xf2`d,_\xc6\x0e\xd5\xc4\x03\x02O\xe1\xf1d\xcew\x17\xfb\x90\xf7^e\xef`W\xddS\x9e^\x13t\xd7\xc7\xc7Ҫ>\xeb\x97\x04\x12_\x01\xed|\x92\xb17\x17\xe7\xec\x1fB\xfd\x84\x8b\xca\xc0\xf1\xe7\xae\xf7\x18\x1e\xdd2\x9d\xc3\f\"\x1di\x12\f>L\x15%ㄥOx\xa9ME\xf5\x9c{\xfa`\xfbD\xb7\xa3g\xae\xa2\x13\xfa8\"\x95\xe9{\xae\vr\x0f\xdb\xc4W\x87,<\xfdB\xa9Jt\xb9\x13\x0fJ\xae\x15\xe8C\xa6[\xe0}F&֟\xa4z\xe0횉/\xe3\x95\xdfS\x9d\x1f\xa82\xcc2\xad[Ob\xecM\xb0q\x89\xdf\xe6G\x8f\xff\xc0\x04\xe5\xec\xf7\x94.\xef\xff87Ä\xbek<\xf2N\xb1P\x01\xf1s\n\xd0k\xe8\x9ft\xcf\xfc\x84y/ɽL\x8a\xb1? fC\xa0L\x93%h\xb3\x80\xd5J*\xe3\xf2\xf7\x8b\x05a\xab\xe0 Y\r\x81q\xa2{͞\xb0T\xe2=\x1e\xbd\x05\x87e\xe5S\x89\n\xad\x0e\x86\x9c5ݹ\x8c$-\n\x1b\x13\xc0\amh*6y\x91\x9e\xc6P\xd5\xcbJ\x8e\n\xb9\xeb\xf7\x8f9\xbe\xa8>\x10\x9cC\x1d^gw\x06\x9d\x8f\x9di\r^\xcb \xdab\xef\x14eB\x9c\x1a\xbb\x1b\x0f\xbb\xf3L\xcd\xd7\beL=\xfa\xfd\r\x1e\xe2\xf6\a\xac\xbe\x93%[QQ\xb1\x1e\xbd\xd0V)ٮ\xab\xc0\x9bc\x0e\x11)[\x8c\x9c\x1bT\x05:\xfc\xc7!\xa6U\xa2wh\xe7k,ƴt\\\uee0f\xf2\x02E\xad\xba\x8b-\x9d\xaa\x9a\xb0\xf9\xd9Y\xc2\x11\x88\xb3\xb6?\x01\x91\xea\x9d(&\xaf\xe0\xf8@\x9bM\xdc՝\xc2P\x12\tQ\x1b\xbf\x1a\x12\"\xc41$\xf4}\x89.\xe2\xf9a02棜\x88\x8ei'\x06\xb78\rj~\xd3}'h\xe8\xee\x1c\x87\x0e=\b\xfeNJ\xbb\r \x1c\x13\xf9\xe2\xdc\xe9\xb8\xf7ǍX7\xd1ۺ=9v\xfd\xb6\ac\xef\n\xa4\x8db\xbbiB\xbc\xf9\xf7l\x95\x92\x17\xf7\xbf3-9\xfc\xc3\xc1\xafo|\x95qK\x95`b}\x12F~\xf5c\x13\xf1\xbc\a{Έ>\xac\xfc\xd5b\xfa\xa4Y:\xf8\x88\f^\xf6\xf0\xecg\xf2_\xfe/\x00\x00\xff\xffP\a\xb5\x16Cm\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec=]s\x1c)\x92\xef\xfa\x15\x84\xeea?B\xdd^\xc7}ą\xde|\xb2gO\xb1\x1e[ai\xf4\xbctU\xb6\x9aQ\x15\xd4\x00\xd5r\xdf\xde\xfe\xf7\x8dL\xa0\xbe\xba\xe8\xa2Z-ygǼت\x86$\xc9L\xf2\x03\x12X,\x16g\xbc\x12\xf7\xa0\x8dP\xf2\x92\xf1J\xc0W\v\x12\xff2\xcb\xc7\xff6K\xa1\xdelߞ=\n\x99_\xb2\xab\xdaXU~\x01\xa3j\x9d\xc1{X\v)\xacP\xf2\xac\x04\xcbsn\xf9\xe5\x19c\\Je9~6\xf8'c\x99\x92V\xab\xa2\x00\xbdx\x00\xb9|\xacW\xb0\xaaE\x91\x83&\xe0\xa1\xebퟖo\xffk\xf9\x9fg\x8cI^\xc2%3\xd9\x06\xf2\xba\x00\xb3\xdcB\x01Z-\x85:3\x15d\b\xf4A\xab\xba\xbad\xed\x0f\xae\x91\xef\xd0!{\xeb\xdbӧB\x18\xfb\x97\xde\xe7\x8f\xc2X\xfa\xa9*j͋N\x7f\xf4\xd5\b\xf9P\x17\\\xb7\xdf\xcf\x183\x99\xaa\xe0\x92}®*\x9eA~Ƙǟ\xba^0\x9e\xe7D\x11^\xdch!-\xe8+U\xd4e\xa0Ă\xe5`2-*K#\xbe\xb5\xdcֆ\xa95\xb3\x1b\xe8\xf6\x83\xe5g\xa3\xe4\r\xb7\x9bK\xb64ToYm\xb8\t\xbf:\x129\x00\xfe\x93\xdd!n\xc6j!\x1f\xc6z{Ǯ\xb4\x92\f\xbeV\x1a\f\xa2\xccrb\xa0|`O\x1b\x90\xcc*\xa6kI\xa8\xfc\x0f\xcf\x1e\xebj\x04\x91\n\xb2\xe5\x00O\x8fI\xff\xe3\x14.w\x1b`\x057\x96YQ\x02\xe3\xbeC\xf6\xc4\r\xe1\xb0V\x9aٍ0\xd34A =l\x1d:\x1f\x87\x9f\x1dB9\xb7\xe0\xd1\xe9\x80\n»\xcc4\x90\xdcމ\x12\x8c\xe5e\x1f\xe6\xbb\aH\x00F$\xaaxmH8\xda\xd67\xddO\x0e\xc0J\xa9\x02\xb8\x80vX4\xb6\nu%\xa0\x80\xe6\f\xddN\x8d\x16FH\xb6\xae\xd1#]2\xd4\x12Q\x19\x11\xd2X\xe0\x11a>\x01\xef\xe0kV\xd49\xe4WEm,\xe8\xdbLU\x90\x87E\xa6Q͜\xca\xc3\x0f\a!\xfb\xf8\xa5\x10\x19 \x1f2WiA\x8b<1\xd1nC\x99]\x05n\xcd\tY\xed\x87\xd0\xc6(\x93\xbaŀņ\xe7\x7f<\xbf \t\xe8\xf7\xde\xef\xc70\xae\xa1!\xd3,\xddL\x16\x7f\xbc\x85\xb0PF\xa8;\xa9\xa3f\xf0\x9dk\xcdw\a\xb8\xde,\xa6\xbd\x00\xdfc\xb0\a\x9c\x97\xa1\xda7\xe2\xfd\xb0\xff\xdf\"\xf7O\xcboC\x8b\xce\\H\xe4s!\x8c\xed\xb1ٸU,$\xebX\b\xe9\t$\x1dLT\x93S\\\xfd'!\xe6I\xe7Nl\xb24\xb2\xe9'\xc0\xbf\x14%7J=\xa6P\xef\x7f\xb1^\xbb\x84\xc52\xda\x18a+\xd8\xf0\xadP\xda\f\x97I\xe1+d\xb5\x8dj\x16nY.\xd6k\xd0\b\x8b\x96\xf9\x9b]\x81C\xc4:\x1c\xbe\xb0\x8eʊV\x18\x8c\xabe:\xb2\x94\xa8\x11\x1b\n\x05\xa8Q\xa8\xce\xc1\xc1Ђ\x1c\x88\\lE^\xf3\x82|\t.37>\xde\xe0\x17\xd3j\x13\x02\xb1\x87\x7fT\xaa]q\x0eM\x18$2\xb1\xb7\xea\xa5$\xa0\x8f_bl\xb4_5N\x89\xb0\x94p\xb0od\xa6\xae\v0\xbe\xbb\x9c\xdc\xe4V']\xb4\xccrk\f\x05_A\xc1\f\x14\x90Y\xa5\xe3\x14J\x91\x03WR\x95n\x84\xb8#Z\xb6\x1fm\xb5\x83\x99\x00\xcb(\xc4݈l\xe3\xdcW\x144\x82\xc5r\x05\x86VExU\x15\x11\xd3ՖI\xe1\xf0\x9dM鍶$h\x90!ܘ.iK\xa2~n\xcb(\xd9۹٧\xfa\xf8:\xff(\xbe\xbf%\xa2\a\xabs\xa4\xb0Oh\x12F\xfb\x05\xc9\xf3!Jz\xa4\xb8\x00\xb3\xec\xac\xce\t\x1b\xbe\xa60\xb4\xe7?\xeem\xa5\xec\x11\xe5\xd7Ż\xe3&\xcc\f\xd6MΩ\x97e\\\xd3Ϳ\b\xdf\xc8d\xddz\x8b5\x8bg\x1f\xbb-/hW\xc03$\xbf`kQX \xa7j\nQ6\x83s\xa7$P\xaa\x05f\xb4Il\xb3͇f\xef(\xa1ŀVC\x00\xceA\x0fQ\x0e\xf1 \x01$k\\\v\xda4\x15\x1aJڌ\xa5H\xb2\xfb\x85\\\xc1w\x9f\xde\xc7c\xcfnI\x94ԽA%LZW\xde\r\x1c\xa3.\xae>T\t\xbf\x90\xbf\xd6\x04\x82n\x13\xfe\x82q\xf6\b;\xe7bqɐo)\x8b\xff|\xf8*\fv,s\xf6^\x81\xf9\xa4,}yQ*\xbbA\xbc\x06\x8d]O4A\xa5\xb3$H\xc4n\U00088ce5(\xa8\r?\x84a\xd7\x12C2G\xa2\x19\xddQ\xae\x90\xeb\xd2uVֆ\xb6Z\xa5\x92\v\xb7,6֛\xe7\x81\xd2=\x16\x9c\xa4c\xdf\xe9\x1d\x1a#\xf7\x8b\xcbZ*x\x06yآ\xa3t\x1an\xe1Ad3\xfa,A?\x00\xab\xd0,\xa4K\xcb\fE\xedG6_\xbc\xd2=\x87n\xf9\xbax\xacW\xa0%X0\v4k\v\x0fŪ2\x91.\xde&\x8c䜌\x95\x05\xce\xf5ĚAZ\x92\xaaG2r\x0eWO%\xd63\xc9D^\x04\xb9]IR\xd0Ml\x9dg\xbdf\xca\xcd1*\xa63\x16\xe7\x02\x94\x9c\xb6\xd6\xfe\x86\x96\x9ef\xe3\xdfYŅ6K\xf6\x8e2{\v\xe8\xfd\xe6\x17&;`\x12\xbb\xadh\x95\xfd\x97Zly\x81\xfe\a\x1a\bɠpވZ\xef\xf9j\x17\xeci\xa3\x8cs\x1b\x9aM\xbb\xf3Gع\x1d\xe5\xa4n\xbb\n\xeb\xfcZ\x9e;_fO\xf14\x8e\x8f\x92Ŏ\x9d\xd3o\xe7\xcfu\xeffH\xf4\x8c\xaa=Q.y\x95.ɔ7;'\xd0\xc0`=8DظI \xc5\x00a\x8a\x02ɢ\\)\x13I\x16\x89\xa0\x95 \xe87\xcaX\xb7\x0e\xd9\xf3\xf7G\x17*UX\x9cd|mA3c\x95\x0e)\x99\xa8\xf8S\x96\xe2\xbb\xe5n\x03\x06\xfc>\x94_\xf4t\x801\x8a=ou\x83\xb3*\xe7n/\x8c:\xe2\x19yOԶ\xd2*\x03\x13͋hK\xa2m\xeaQp\x9f\x0eͺ.w\xd1\xdf:Ik\xa7,J\x872ϑG\xd2\x1d\x11\x19}\xf8\xdaY\xa2F\xed\x82\x7f\xa7H\xeb182:\xafQ\x96|\x98\x0e\x9c\x8c\xee\x95k\x1d\xe6\x98\a\xe6\xc2-\xfdP\x93Ι\xe3u4\xa2\xfc\xcf\xe6ڔB^SG\xec\xed\v\xbaC^\x8b\xc7ң\xc6\xca\xf1N\xfaU\xe8\xac\xe5^\xf3\xc1\xe7\xd4)\xda\xf8\xd1\xd0c\xee\xfe\x9e\by\xd7R\xd9\xce2\xceL'\xbaR\xf9\xef\f[\vml\x17\rs \xb1j\x14\xd4\x11\xa1\xa7\xfc\xa0\xf5ё\xe7g\u05fa\xb3\xa0\xb8QO>qzN\xbc\x1dH\xba\xe1[\xf0\x99\xab 3UKZ\nC=\x80\xdd̀\xe8X\xe3\xac@\xa2\xbd\xeb4\x96u\x99N\x90\x05I\x92\x90\x93\xebf\xdd&?p\x91\xb6nŎc\xab=\x94\xc39V\x8e\x9fG!\xc1\xb3\x9bN_\U000af8acK\xc6K\xe4!\xb9\x1d\xa2\x84&\xa3ޱ\xbbI\xfb\xc4\x16d\xb4\xac\xc2YV\x15`\xc1\xa7m\xce\xc0#S҈\x1c\x1a\xd3\xefE@I\xc6ٚ\x8b\xa2\xd63\xb4\xeal\x92\xcf\r¼69}d\x95\x8eȂH\x94\xb8\xce>\xc3\v\x9e\xd6\xf8\x95\x9e\xe7Ǧ8\x8c\x1a\xe6\xfb\x8b\x95\x16\xca\x1d\x068\xbd\xcb\xe8ӎ\xb9\xdc}\xf7\x19\xbf\xfb\x8c\xdf}\xc69\x1d}\xf7\x19'\xcaw\x9f\xf1\xbb\xcfx\xb8|\xf7\x19S\xcaw\x9fq&\"\xdf\xcagL\xc1pAk\x9c\a*$a\x95\x98\n1\x85\xf6D_>\xe9ǟ\xd58I.\xf3\xf58ȑC<\x91\xe3\x171\xaf\xa35^Mr3\xce\xc00w\xdc)\xca\x04\x87\xf9\x04\xa7g\x02\x02\xa7?=s}\x10\xf2\tO\xcf\xf8!\xa4E\x18G\x9d\x9d\tD\x9a\x7fz\xe2\xc2'\x11\x95\xc0\xc3V\x8aK\xff\x88\x8d1&I\tx|\xe3\xe4\xf7\xbd\x8c\xc9\x17\x90\xa5W9\x913K\x9eFY\x7f\xfe\xc7\xf3_\a\x8bN˔(\x1b\xf6i\xeb\xd4xL?b,\xdfM\x8d\xecg\xa9\xfez\xa6\xc2Ie?\xf5DMC\xe4\b\xbc\xbeX\x0f\xa8\xfck\xd27\x16\xcaϕ\xb7\x96'8a\x7f=\x02/\xe9\x8c=7;\x99m\xb4\x92\xaa6~M\ba\xbd\xcbܽ\x03\x01dL\xd8G5\xc8\x7f\xb0\x8d\xaa#\xa76&H\x9b\x90E\x9bF\x90^R\xadO\x8c\x00˷o\x97\xfd_\xac\xf2)\xb6\xecI\xd8M\x04\x18\xddG\xc1\xf3\x1c\xe3\x82\u0381\x1e\xaf\a\xc2UIC\xa1\x8c\x00S\x9aIQ8\x89\r\x10z\xf2\xca>Wnu\xf0h\xbfiz\r+=\x11wn\xfam\x93-9\xed\xbe?#\xe9\xf6\xa4G\xa3\xbeYZ\xedqɴ\xa9+\x94\t\x89\xb3\xe9\xe9\xb2)lu%=I69BNM\x88\x9d\xbb\x02\xf1\xa2ɯ/\x93\xf2\x9aL\xb3\xb4\xf4ֹ\x14{\x95T\xd6WN`}\xbd\xb4\xd5\x19ɪ\xa7?\xf5\x92\xbe\x96~tveڲ\xcc\xe1\x84Ӥ4Ӥ\xa5\x9b\x94\x01\x1f5Ԥ\xf4ѹI\xa3I\x9cL\x9f\xae\xaf\x9a\x16\xfa\xaaɠ\xaf\x9f\x02:)m\x93\x15\xe6&y\x8e_r\x18ʴ\x03P|\v\xe1|.\x99\x94\xee\xb9\xe6ϊ;?\x0f`\xa1\xb0\x047\xf5\x15〲.\xac\xa8\x8a\xf6>\xb6X\xc0\xb9\x81]sY\xd1ϊ\x8e\xc8\xfb\x9b\xba>\x7fi$~9\x88j\xb8aOP\x14\x8c\xc7\xe6\xe6\x1e\x152w\x0fh\xa6\x16\x80\xb6\x11g\xb9\xbf\x8c\xc9_\x1ez\xe1\xa6\v\xdd\x06@\x16\xb6\x8c-\xf5qy\xf8\xa6\xaf\x83\x06,U\x8f\xedy\xe6.ޠo\xbfԠw\x8c\xee\x1dk|\xb3\xf6P\xa9\x9f\xe8\x06\x03Ӡ~\xbc:<\xb4g\xb2\x17\xe0\xb4ꁽ\x93\xce#\x18\xe2DmP\xef\xb4\x01\x1d*U\x8cӢ\xfdD@H\xd5@\x884Mq\xfe眲|\x89\xf0\xee\x14\x01^\x92\a4\xcf{\xfd\x86\xa7'\x8f=5\x99\x9e\x8c\x92tJ\xf2%½9\x01\xdf,\x7f5\xfd\x14\xe4\xfc\x8d\xe7\x17>\xf5\xf8R\xa7\x1dgP/\xf5t\xe3|ڽ\xd2i\xc6W?\xc5\xf8\x9a\xa7\x17g\x9dZLNϚ\x95q0'\xb5\xea\x19\xc7\xed\xd2r\t\xa6O!&\x9e>L\xcc4H\x1b\xfc\x91\xc3N<]8\xffTa\"\x7f\xe7L\xe9W>=\xf8ʧ\x06\xbf\xc5i\xc1\x04\tL\xa82\xffT\u0cf7\xa4\x94\xceAOn\xfb͑\xdaIyM\x8d\xe5\xfa\x88\r\xf6\xb5\xc2m\xb2X\xab\x17\x03\x90Y\xf2\x17\xf9ӣ\r\x87\xb6\xc1Q2;\x1eQo_\xb2u\xd7\xfa\x0e\xb1\x7f\xcd\xc1m]\x1a\xa88\x1a\x00\n\xdc(5+\xea*|\xe0\xd9f\xd0Æ\x1b\xb6V\xba䖝7\x9b\xc5o\\\a\xf8\xf7\xf9\x92\xb1\x1fT\x93\xabӽ/͈\xb2*v\x18\x89\xb1\xf3n\x83\xe7IIT:C\xcf7\xaa\x10Y\xc4\xe7\x1c\xbdW\xcf5ػl\x88n\xfe\xcb:\xd9\"\xb1\xc0\a\x9b\x8bp\xebb\xffJfw\x9f\xfb\x91k%\xbc\x12\x7f\xa6'\x95N\xb0\xea\xf6\xee\xe6\x9a`\x051\xa2\xb7\x9a\x9a\x04ņ\xe5+@\x97\xa1\x1d\xfb!}r\xbd\xeeA\xed\xe7\bw\x1f\xab\x80ܽL\x12\xdc\x16\xaf\x9a3\x85Z\xeb\xe6\xda\xe1r\xa8'\x94/.wL\xf9\xa7'\x84\xce\x17\x15\xd7v璉.zx\x04\xbb>\xb5jv\xd0Z\xed\xbf\xbc\xd2-=\xb2\x87GWh'{W\xf5\x93\a\x86\xf4|\x0eN\x87OUO\x9e\xa7~\x01\x9c\x0e\xbbP\v\xa2b\xe4\xa7h\x06\xe4\xc9W,\x8d\xbf\xa1\xffG\xb5\x85\xf7ѕ\xcb\xfe\xeb+\x83&#\xa9\x89\x01*]2\x1f\xa1`\x9b\x8fHw|?O\xed\xc5s\r\x03*\xfe\x8e\xf0\xe7,N\xde\xf6A\x8d?HB7\xa8\x87Nc^\x15=\xf5\xb4c7\xf7\x14\xb76\xaa\xd4O}\x1f\xb7\x86\xe5ɐ`\x10\x81%\xe4\xc17ZNEF\xab4\x7f\x80\x8fʽ\xad\x93\"&\xfd\x16\xbd\x97\x97\xbc\xe7\x16\xf2\xb5\xfd$\x8c)z?\xb6!\xc0\xf6|\xc6\xdeE\xff\x88\xed\x91O\x19X[\xba\x91ғ&\xef\xfd\xeb$\xa8\x8f\r \v\x02\x05\x1c\xb4\x15\xfew\xa3\x9e\xe8\x02\xfc\xf8\x1asx@\xa4\xf3\x86\x19\xd0A\x11J\xe1=j\x98uU(\x9e\x83\xbe\xa2GT\x12F\xfcS\xaf\xc1\xc0\x1d\xe8?\xc5\xe2\xedfd<\xa1\xe7\x17̒A\x8f\xae(\xa0\xf8A\x14`\x1c≦\xe1f\xbfec)\xear\xe5<\xd55\xfe\xd8tr\xc02\xbb\xa1\xd2\x06C\x05\x1a\xfdD\xb7\x15Q\x9b \xf9\x87\x89\xc1\x1a>\ni\xe1\x01\xc6c\xe8\t\x9b\xe0\xdeh \a (0\x8a\xf8\xfe\x12[y\xec\x11\xe4>\xdez \x03\xcdbdL\x8e\x95w\xabn\xee\xaf\f\xabeN\x1b\x00\xf7\x7f\xbe=J~\xb7\xbd\xf7e\x82NHQ\xef\xf7\xe3-;!BG;\x91O\x1fW\xe21X\xdc\x18\x95\t\x8a*\x9e\x84\xf5\xd79\xbe\xdc\x1d\xe2\x87\x02\xc4\x03\xd2Q\x1b\xf8\xfc$A\x7f\t\x16\xc8\\\xcbػ-\xd3\xda\xef\xa7=h\xd1\xf7Z\xac¾G`\f\x000\x15\xf6\xb9\x8c{\t(l\xaf\t\xd3H\x1c\xc4>\x01\xdcyG\xc8ik\x85\xb4\xe3\x9c!n\x9bVt\xd8tDCN\x8b\xed\xfd\x00\xc6 \x93\x9d\x1e}j\xaa\xb8Ӧ\x86\xfd^\x8cy\xa3\xb4c\x96\xe1@\xff\xb0\xf7kT\x83\x1f\xd4\xde1\xcd=\xaaF\xf6>\xd2CxyGr\xbc\x97\xde\xfdR\xaf\xda\a\x15\xd8\xdf\xfe~\xf6\x8f\x00\x00\x00\xff\xff)\x00\x87w>{\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcV\xcfo+5\x10\xbe\xe7\xaf\x18\x89+\xbb\xa1B \x94\x1b*\x1c*\xe0\xa9j\x9ezw\xbc\x93d\xa8\xd7^f\xc6)A\xfc\xf1\xc8\xf6n\x9b\xee:\xb4\x8f\x03\xbe\xad\xed\xf9\xe6\x9bo~x\x9b\xa6Y\x99\x81\x1e\x91\x85\x82߀\x19\b\xffT\xf4\xe9Kڧ\x1f\xa4\xa5\xb0>ݬ\x9e\xc8w\x1b\xb8\x8d\xa2\xa1\x7f@\t\x91-\xfe\x84{\xf2\xa4\x14\xfc\xaaG5\x9dQ\xb3Y\x01\x18\uf0da\xb4-\xe9\x13\xc0\x06\xaf\x1c\x9cCn\x0e\xe8ۧ\xb8\xc3]$\xd7!g\xf0\xc9\xf5\xe9\x9b\xf6\xe6\xfb\xf6\xbb\x15\x807=n@\x90ә\x1a\x8d\xc2\xf8GDQiO\xe8\x90CKa%\x03ڄ\x7f\xe0\x10\x87\r\xbc\x1e\x14\xfb\xd1w\xe1\xbd\xcdP\xdb\f\xf5P\xa0\xf2\xa9#\xd1_\xae\xdd\xf8\x95\xc6[\x83\x8bl\\\x9dP\xbe \xc7\xc0\xfa\xe9\xd5i\x03\"\\N\xc8\x1f\xa23\\5^\x01\x88\r\x03n \xdb\x0e\xc6b\xb7\x02\x18\x05\xc9Xͨ\xc5\xe9\xa6\xc0\xd9#\xf6\xa68\x01\b\x03\xfa\x1f\xef\xef\x1e\xbfݾ\xd9\x06\xe8P,ӠYֿ\x9b\x97}\xa8\x85\t$``\xa4\x04\x1a\xc0X\x8b\"`#3z\x85B\x19\xc8\xef\x03\xf79\xad`v!\xea\x05\xaa\x1e\x11\x1e\xb3\xfec\x98\xed\xcb\xe1\xc0a@V\x9a\xa4)\xeb\xa2\xe2.v\xff\x8dxZ)\xd6b\x05]*=\x94\xecy\xd4\v\xbbQ\x1e\b{\xd0#\t0\x0e\x8c\x82\xbe\x14c\xda6\x1e\xc2\xeew\xb4\xdaΠ\x8b.\x922\x19]\x97*\xf6\x84\xac\xc0h\xc3\xc1\xd3_/ؒ\x04JN\x9dѬ\x9dWdo\x1c\x9c\x8c\x8b\xf85\x18\xdf͐{s\x06\xc6\xe4\x13\xa2\xbf\xc0\xcb\x062\xe7\xf1[`\xccRo\xe0\xa8:\xc8f\xbd>\x90N}hC\xdfGOz^疢]\xd4\xc0\xb2\xee\xf0\x84n-th\f\xdb#)Z\x8d\x8ck3P\x93\x03\xf1\xb9\x17۾\xfb\x8a\xc7Ε7n\xf5\x9cjP\x94\xc9\x1f.\x0er\xeb|AzR#\x95b*P%\xc4\xd7,\xa4\xad$\xdd\xc3\xcf\xdb\xcf01)\x99*Iy\xbd\xba\xd0e\xcaOR\x93\xfc\x1e\xb9\xd8\xed9\xf4\x19\x13}7\x04\xf2\x9a?\xac\xa3\\\xb8qד\xcaT\xda)us\xd8\xdb<\xab`\x87\x10\x87\xce(v\xf3\vw\x1enM\x8f\xee\xd6\b\xfeϹJY\x91&%\xe1Cٺ\x9c\xc0\xf3\xcbEދ\x83iv^ImeJl\a\xb4)\xb9I\xdfdM{\xb2\xa5\xad\xf6\x81\xc1\xd4L\xda\x0f1\xc9\x16_\xc8e\x9cH\x85\xcdlN\xa5.\x7f\x9fM},哣\x11\x9co\xce8ݧ;s\xff\x8e\xf6h\xcf\xd6a\x81(S\bߧ\x92\x16\xfa\xd8/}6\xf0\t\x9f+\xbb\xf7\x1c҄\xc6\xf9\xa8\xb9Z\x1bP\x1e\xb1\x03\xf9E\xb8\xf3\xc8ʭ\xfc0.G~\x0eh\x04\x02\x8eާ\x96\x0e~\x01Yy\x11\x16wH\xb1\xaf\xb0\xa9\xf2\xb9\xf3\xfb\x90\xff\"Lrl\xb4\xb4\x13\x8e\xc9\x1e\xfd\x14^\x15\xc0\xeb\xb9.k9\xe7>$hY\xf9y\xfeo\xc6i.\x11c\xd5w\x93YU\x0f\x92ǚ\xe2\xf5\xfe\x1aYF\xe7\xcc\xce\xe1\x06\x94\xe3Һ\xd8\x1afs\x9eW\xcdTj\x9f\xa9GQ\xd3\x0f\xef\x14\xd0\xe2UH\xeb~\x81\x92\x9a\xe7\xf9\x88\xfeZ\x8b\xc0\xb3\x91W\xe7\x15\xc8\xdd\xf9\x9a\xe9\xed\xcb\xdf\xe6\xb2\xcfJ=o \xcd\xfaF\xa9\"䇔\xaa\xa6\xb4\xd4y\xf5\xb7f\xa1\xd2\xf6\xf2\xee4H\xde\xf4\xcb\xf4W\xb3\x8c\xe1*\x85j\x05,63|w\x11\x9eh`s\x98\x02\xfe'\x00\x00\xff\xff\xef\xf8\xa6>\x10\f\x00\x00"), diff --git a/config/crd/v2alpha1/bases/velero.io_datadownloads.yaml b/config/crd/v2alpha1/bases/velero.io_datadownloads.yaml index c36fb6460..2f24f7e81 100644 --- a/config/crd/v2alpha1/bases/velero.io_datadownloads.yaml +++ b/config/crd/v2alpha1/bases/velero.io_datadownloads.yaml @@ -109,7 +109,7 @@ spec: be restored from. type: string snapshotSize: - description: SnapshotSize is the logical size of the snapshot. + description: SnapshotSize is the logical size in Bytes of the snapshot. format: int64 type: integer sourceNamespace: diff --git a/config/crd/v2alpha1/crds/crds.go b/config/crd/v2alpha1/crds/crds.go index 7bfa0b6cf..006c49754 100644 --- a/config/crd/v2alpha1/crds/crds.go +++ b/config/crd/v2alpha1/crds/crds.go @@ -29,7 +29,7 @@ import ( ) var rawCRDs = [][]byte{ - []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcYK\x93\xe3\xb8\r\xbe\xf7\xaf@M\x0es\x19\xbb3yl\xa5|\x9bq'U]\xd9\xe9q\xad;}\xa7$X\xe6\x0eE2|\xd8\xebM\xf2\xdfS %\x99\x92\xe8\xe7>|3\t\x82\x1f\x01\x10\xf8@\xcdf\xb3\a\xa6\xf9\x1b\x1a˕\\\x00\xd3\x1c\x7fr(韝\x7f\xfb\x9b\x9ds\xf5\xb8\xfb\xf8\xf0\x8d\xcbj\x01Ko\x9dj~@\xab\xbc)\xf1\t7\\rǕ|hб\x8a9\xb6x\x00`R*\xc7h\xd8\xd2_\x80RIg\x94\x10hf5\xca\xf97_`Ṩ\xd0\x04\xe5\xddֻ?\xce?~7\xff\xeb\x03\x80d\r.\x80\xf4Uj/\x85b\x95\x9d\xefP\xa0Qs\xae\x1e\xacƒ\x14\xd7Fy\xbd\x80\xe3D\\\xd8n\x1a\x01?1ǞZ\x1daXp\xeb\xfe9\x99\xfa\x9e[\x17\xa6\xb5\xf0\x86\x89\xd1\xdea\xc6rY{\xc1\xccp\xee\x01\xc0\x96J\xe3\x02^hk\xcdJ\xa4\xb1\xf6L\x01\xca\fXU\x05+1\xb12\\:4K%|\xd3Yg\x06\x15\xda\xd2p\xed\x82\x15RX`\x1dsނ\xf5\xe5\x16\x98\x85\x17\xdc?>˕Q\xb5A\x1ba\x01\xfch\x95\\1\xb7]\xc0<\x8a\xcf\xf5\x96Ylg\xa3)\xd7a\xa2\x1dr\a\xc2k\x9d\xe1\xb2\xce!x\xe5\rB\xe5Mp!\x9d\xbbDp[n\x87\xd0\xf6\xcc\x12<\xe3\xb0:\t$̓:\xebX\xa3Lj\x92\xa5\x11R\xc5\x1c\xe6\x00-U\xa3\x05:\xac\xa088쎱Q\xa6an\x01\\\xba\xef\xfer\xda\x16\xad\xb1\xe6a铒C\xc3|\xa6QH\x86#\x12\xf2R\x8d&k\x1d\xe5\x98\xf8%@\x1c)\xf8\x9c\xac\x8fH\xa2\xdet\xfc\"\x14\n9P\x1bp[\x84Ϭ\xfc\xe65\xac\x9d2\xacF\xf8^\x95\xd1}\xfb-\x1a\f\x12E\x94\xa0\xe8\x05N\xbeS&\xeb:\x8d\xe5<ʶ\xca:]#\xff\r7\xfa\xd5c\xab4Ȳ\xb1ե\x9ay\x90\xe0J\xe6\x03\xecS\x8dW\x05WjD\xa9*L,6\xc0\xc4-h\xa3J\xb4\xf6L\xc0\x93\x82\x01\x8a\x97\xe3\xc0\xc44Qb\xf7'&\xf4\x96}\x8cI\xa6\xdcb\xc3\x16\xed\n\xa5Q~Z=\xbf\xfdy=\x18\x863\t\x83\x95\xceR\xa6 \xf8\xda(\xa7J%\xa0@\xb7G\x94\xd1\xf5\x8dڡ\xa1\x9a\x8d\x93\x06C\xf4\x10@\x93z\x1fhO\x8d\xc6\xf1.\v\xb7\xba\x8f\x05&\x19\x1d\x9d㿳\xc1\x1c\x00\x1d=\xae\x82\x8a*\r\xc6c\xb5\xb9\x15\xab\xd6Z\xd1y܂AmТ\x8c\xb5\x87\x86\x99\x04U\xfc\x88\xa5\x9b\x8fT\xafѐ\x1a\xb0[\xe5EE\x87ݡq`\xb0T\xb5\xe4?\xf7\xba-8\x156\x15̡u\xe12\x1a\xc9\x04\xec\x98\xf0\xf8\x81\x8c6\xd2ܰ\x03\x18\xa4=\xc1\xcbD_X`\xc78\xbe\x90\x15\xb9ܨ\x05l\x9d\xd3v\xf1\xf8Xsו\xddR5\x8d\x97\xdc\x1d\x1e\x837x\xe1\x9d2\xf6\xb1\xc2\x1d\x8aG\xcb\xeb\x193\xe5\x96;,\x9d7\xf8\xc84\x9f\x85\x83\xc8Pz\xe7M\xf5\a\xd3\x16j;\xd8v\x12\x88\xf1\x17\n\xe6\r\xee\xa1*J\xb7\x82\xb5\xaa\xe2\x11\x8f^\xa0!2\xdd\x0f\x7f_\xbfB\x87$z*:\xe5(:\xb1K\xe7\x1f\xb2&\x97\x1b4q\xddƨ&\xe8DYiť\v\x7fJ\xc1Q:\xb0\xbeh\xb8\xa30\xf8\xb7G\xeb\xc8uc\xb5\xcb@M\xa0@\xf0\x9a\xf2A5\x16x\x96\xb0d\r\x8a%\xb3\xf8;\xfb\x8a\xbcbg䄫\xbc\x95\x12\xae\xb1p4o2\xd11\xa6\x13\xaeM3\xc8ZcI^%\xc3\xd22\xbe\xe1m%\xa14\xc0\x06\xb2C\v\xe5\xaf>\xfd\xb2\xd5d,t)\xdc\xe8\xf79\xa7\xa8C+\x93D\xde\xd6:\xdb\x16)1,R\xe9oR\x1f\rje\xb9S\xe6p\xac\x92\xe3P8\xe9\x15\xfa\x95L\x96(\xee9\xde2\xac\x04.+\xb29\xf6\xa1LI(j\r@\x95\xac\x15]\xae\x81+\xe0ّ\fŶE\x97?\xa8\xccV5.\xe1\xc8)!\xe5\x8e\xe3\xe3\x16J\tdc+R\x14~\xa1\xb2\xb0Tr\xc3\xeb\xe9\xc1S\xfa{*D.\xd84\x13\xb0ɖt\n\x8aNB2\v\x15jօ.\xa5\xf6\r\xaf\xbd9\xe5\xff\rGQM\xf2\xcfɛ\xd4\x1d8\xecr\x8f\x8f{\xe8\xdd\xedj\xabZRz\x9d\n\x19\xca\x06\xbe\x9b\x84\xe6\x14$\xc0\xf3&\xd1\xc8-\xbc{\a\xca\xc0\xbb\xd8\x13\xbd\xfb\x10W{.܌\x0f\xea\xff\x9e\v\xd1\xedrSt\x13\xc3\xf9\xba\xbep\xf2\x97 Dx\xbe\xaeo\xe5VS4(}3\xddp\x06\xcc;\x95\x19\x16\\\xfa\x9f2\xe3{.+\xb5\xb7\xb7\x1c\xb6\xe77D1\x95w\xf78\xfc\xebH\xc7\xc8\xef\x8e\bq\xf0\xb5S\xb0g<\xe1\x18\xfd\xee\xf6CFo\x81\x1b*H\x06\x9d7\x92\xd2\x01\x1aC\x19\xda\x06\x95\xcaO8\xcfٓZɴ\xdd*\xf7\xfct\xe1\x8c\xeb^\xb0˻\xcfO\x9d\x8b\xdfB\xd4\xf5ɷ\x95\x84\x8c\x97\b~\xc7\"\xabP\xd6\xefB\xbb\xe6?\xe3\x95xI\xb4C,T\xcdK&\xc0\xd2X\x8b\xbdS9ők\xef\xc6(\xd3&-\x81\x19(O\xff0pO\xf4\xac\x87*\xba\x13(\xc3kN1\"\xfb\x99\xe3\xd5\xda)\xe1\x9b J\x9e\xc0\n\xbc>ab\xa0\xaaA\x1c\xab@\xa8\xf8f\x83\x86\x88T`Yq\xe3\xd5\xdb\xf2\xbdM6\xe1\x9b\xf4\x0f\x15\xa8\x86i\x8d\x15\xb5t\x14\x83\xadKor\xa6c\xa6F\xf7\x16@_0\xd1k\"ڙ\x82\x18\x199\xa8\xa5\xfc\xe1N\x051X\xbd-3\x04\x9d~\xab\xb7)\xc2\xd3\xf4\x05\xda^\xed\x84\x13'('\xdej\xf1\xf4:\xb2*\xceV?\x00\xbd\xbbb\xe7\xd5[\x8e\f\xf5\xe6\x00\xb7e\x8e$\xda\xde\x1a\x8aCV't7\xb9u\xe7}x˫\x00/\xcf\"^\x8e!\x9f\xc0[\x1c~1d\xe2Z\xdc`\x95\xab4\xa7=7\x03\xbd\xcb\x0e\x96\xd73\x8a\xfcγ|3\t\x82\x1f\x01\x10\xf8@\xcdf\xb3\a\xa6\xf9\x1b\x1a˕\\\x00\xd3\x1c\x7fr(韝\x7f\xfb\x9b\x9ds\xf5\xb8\xfb\xf8\xf0\x8d\xcbj\x01Ko\x9dj~@\xab\xbc)\xf1\t7\\rǕ|hб\x8a9\xb6x\x00`R*\xc7h\xd8\xd2_\x80RIg\x94\x10hf5\xca\xf97_`Ṩ\xd0\x04\xe5\xddֻ?\xce?~7\xff\xeb\x03\x80d\r.\x80\xf4Uj/\x85b\x95\x9d\xefP\xa0Qs\xae\x1e\xacƒ\x14\xd7Fy\xbd\x80\xe3D\\\xd8n\x1a\x01?1ǞZ\x1daXp\xeb\xfe9\x99\xfa\x9e[\x17\xa6\xb5\xf0\x86\x89\xd1\xdea\xc6rY{\xc1\xccp\xee\x01\xc0\x96J\xe3\x02^hk\xcdJ\xa4\xb1\xf6L\x01\xca\fXU\x05+1\xb12\\:4K%|\xd3Yg\x06\x15\xda\xd2p\xed\x82\x15RX`\x1dsނ\xf5\xe5\x16\x98\x85\x17\xdc?>˕Q\xb5A\x1ba\x01\xfch\x95\\1\xb7]\xc0<\x8a\xcf\xf5\x96Ylg\xa3)\xd7a\xa2\x1dr\a\xc2k\x9d\xe1\xb2\xce!x\xe5\rB\xe5Mp!\x9d\xbbDp[n\x87\xd0\xf6\xcc\x12<\xe3\xb0:\t$̓:\xebX\xa3Lj\x92\xa5\x11R\xc5\x1c\xe6\x00-U\xa3\x05:\xac\xa088쎱Q\xa6an\x01\\\xba\xef\xfer\xda\x16\xad\xb1\xe6a铒C\xc3|\xa6QH\x86#\x12\xf2R\x8d&k\x1d\xe5\x98\xf8%@\x1c)\xf8\x9c\xac\x8fH\xa2\xdet\xfc\"\x14\n9P\x1bp[\x84Ϭ\xfc\xe65\xac\x9d2\xacF\xf8^\x95\xd1}\xfb-\x1a\f\x12E\x94\xa0\xe8\x05N\xbeS&\xeb:\x8d\xe5<ʶ\xca:]#\xff\r7\xfa\xd5c\xab4Ȳ\xb1ե\x9ay\x90\xe0J\xe6\x03\xecS\x8dW\x05WjD\xa9*L,6\xc0\xc4-h\xa3J\xb4\xf6L\xc0\x93\x82\x01\x8a\x97\xe3\xc0\xc44Qb\xf7'&\xf4\x96}\x8cI\xa6\xdcb\xc3\x16\xed\n\xa5Q~Z=\xbf\xfdy=\x18\x863\t\x83\x95\xceR\xa6 \xf8\xda(\xa7J%\xa0@\xb7G\x94\xd1\xf5\x8dڡ\xa1\x9a\x8d\x93\x06C\xf4\x10@\x93z\x1fhO\x8d\xc6\xf1.\v\xb7\xba\x8f\x05&\x19\x1d\x9d㿳\xc1\x1c\x00\x1d=\xae\x82\x8a*\r\xc6c\xb5\xb9\x15\xab\xd6Z\xd1y܂AmТ\x8c\xb5\x87\x86\x99\x04U\xfc\x88\xa5\x9b\x8fT\xafѐ\x1a\xb0[\xe5EE\x87ݡq`\xb0T\xb5\xe4?\xf7\xba-8\x156\x15̡u\xe12\x1a\xc9\x04\xec\x98\xf0\xf8\x81\x8c6\xd2ܰ\x03\x18\xa4=\xc1\xcbD_X`\xc78\xbe\x90\x15\xb9ܨ\x05l\x9d\xd3v\xf1\xf8Xsו\xddR5\x8d\x97\xdc\x1d\x1e\x837x\xe1\x9d2\xf6\xb1\xc2\x1d\x8aG\xcb\xeb\x193\xe5\x96;,\x9d7\xf8\xc84\x9f\x85\x83\xc8Pz\xe7M\xf5\a\xd3\x16j;\xd8v\x12\x88\xf1\x17\n\xe6\r\xee\xa1*J\xb7\x82\xb5\xaa\xe2\x11\x8f^\xa0!2\xdd\x0f\x7f_\xbfB\x87$z*:\xe5(:\xb1K\xe7\x1f\xb2&\x97\x1b4q\xddƨ&\xe8DYiť\v\x7fJ\xc1Q:\xb0\xbeh\xb8\xa30\xf8\xb7G\xeb\xc8uc\xb5\xcb@M\xa0@\xf0\x9a\xf2A5\x16x\x96\xb0d\r\x8a%\xb3\xf8;\xfb\x8a\xbcbg䄫\xbc\x95\x12\xae\xb1p4o2\xd11\xa6\x13\xaeM3\xc8ZcI^%\xc3\xd22\xbe\xe1m%\xa14\xc0\x06\xb2C\v\xe5\xaf>\xfd\xb2\xd5d,t)\xdc\xe8\xf79\xa7\xa8C+\x93D\xde\xd6:\xdb\x16)1,R\xe9oR\x1f\rje\xb9S\xe6p\xac\x92\xe3P8\xe9\x15\xfa\x95L\x96(\xee9\xde2\xac\x04.+\xb29\xf6\xa1LI(j\r@\x95\xac\x15]\xae\x81+\xe0ّ\fŶE\x97?\xa8\xccV5.\xe1\xc8)!\xe5\x8e\xe3\xe3\x16J\tdc+R\x14~\xa1\xb2\xb0Tr\xc3\xeb\xe9\xc1S\xfa{*D.\xd84\x13\xb0ɖt\n\x8aNB2\v\x15jօ.\xa5\xf6\r\xaf\xbd9\xe5\xff\rGQM\xf2\xcfɛ\xd4\x1d8\xecr\x8f\x8f{\xe8\xdd\xedj\xabZRz\x9d\n\x19\xca\x06\xbe\x9b\x84\xe6\x14$\xc0\xf3&\xd1\xc8-\xbc{\a\xca\xc0\xbb\xd8\x13\xbd\xfb\x10W{.܌\x0f\xea\xff\x9e\v\xd1\xedrSt\x13\xc3\xf9\xba\xbep\xf2\x97 Dx\xbe\xaeo\xe5VS4(}3\xddp\x06\xcc;\x95\x19\x16\\\xfa\x9f2\xe3{.+\xb5\xb7\xb7\x1c\xb6\xe77D1\x95w\xf78\xfc\xebH\xc7\xc8\xef\x8e\bq\xf0\xb5S\xb0g<\xe1\x18\xfd\xee\xf6CFo\x81\x1b*H\x06\x9d7\x92\xd2\x01\x1aC\x19\xda\x06\x95\xcaO8\xcfٓZɴ\xdd*\xf7\xfct\xe1\x8c\xeb^\xb0˻\xcfO\x9d\x8b\xdfB\xd4\xf5ɷ\x95\x84\x8c\x97\b~\xc7\"\xabP\xd6\xefB\xbb\xe6?\xe3\x95xI\xb4C,T\xcdK&\xc0\x861\xd96\x81\xed!:\xddS@\xb9>o\f7\xed\xd6\x12\xbc\x81\xfb\xf4/\x04\xf7\x84\xd1z\xa8\xa2;\x8a2\xbc\xe6\x14,\xb2\x9f9ޱ\x9d\x12\xbe\t\xa2\xe4\x12\xac\xc0\xeb\x13\xb6\x06*\x1fD\xb6\n\x84\x8ao6h\x88Q\x05\xba\x157^\xbd-\xdf\xdbd\x13\xbeI\xffP\xa5j\x98\xd6XQoG\xc1\xd8\xfa\xf6&\xaf:fjto\x01\xf4\x05\x13\xbd&\xa2\x9d)\x88\x9a\x91\x83Z\xee\x1f.W\x10\x83\xd5\xdb2\xc3\xd4\xe9\xb7z\x9b\"<\xcdc\xa0m\xdaN8q\x82r\xe2\xad\x16O\xaf#\xab\xe2l\x19\x04л+v^\xbd\xe5XQo\x0ep[\xe6H\xa2m\xb2\xa18duBw\xa5[wއ\xb7\xbc\n\xf0\xf2,\xe2\xe5\x18\xf2\t\xbc\xc5\xe1\x17C&\xd2\xc5\rV\xb9\x92s\xdas3л\xec`y=\xb5\xc8\xef<\xcb\xf3\xe7\x91̸T\x8d\xa6\x8f\xf9}<1\xcc+\xa3\xd9\xf4J^\xd5h\x84g\x90k[\x8d\xf8\xb8ٺ\xbd\xf4&$\x9d\xf6ɓ\xba\xf7\xbb\x9a\rV\x96\xa8\x1dV\x9f\x0f\xc4B\xae *\x04@\x9e\x7f\x04\xfa\x97>\xd2\x14\xd4\xec֎\xa0\x83\xd4?T\xddS\x00>\x8d\x95\x84\xd7\nS%4b\n7R\xc9Ӡ\x01^\xa9\xe4\x85n\xfb}d\x0e\xb4,\xf0\x11bԓMO\x16Ej\xa7g\xb4~\"!\xbd\x10\xac\x10\xb8\x00g\xfc\xa9\xd6\"\xdfI\xc5w\xdf\xf4\x89﮶j\xaafj;\xd6?j\x85\xc7\xc7\xee\xc59g\xb2\xa3\xbe\xde`Q\x1dV\x80;\x94@\xcd2\xe3\x02\xabNg\xa6\xbf\xb8d\xf9\f\xe8)u\xfd-\x8dߠ\xb5\xac\xbet\x81\xbeD\xa9\xf8\x0e\xd4.\x01V\x10\xcf\x1d\xb3\xfc\xf7\xb6\xbd\xdb7\xf7\x1b\xbf\xce%\xbe\xb2\xdb8\x83%\xf4\xc6\x17\xc0\xacH&\x97\xd3zh\xa7\x93\x1a\x9civ^p\x9f\x19\xed\xeegfj\xd5^\xfa\xcc\xd4\xe4\x13R:\x19\x1f!r\x85\xb1\x9b\xcb\xea\xec\xbf\xd1d\xe6\xfe\x11.\xc3M\x96n\xf1\xdds\xdd\xfb\xa7\x8c\xad\x12\xdd\r\x0f\xdfV\xa4o\n4\xe4\x86\"G\xf8\xc3\vx\xe2\xb5\x1c\xf9\xeb5\xf4\xbdKP5\x87\xd7-Q\x93\xf8\xfe\xd2us\x15\xb7Z\xb0C\x7f\x98\x94\xa1f\x94\x1fo\xcd\xe4y\xfdV\x92\xda\x7f\xeb\xca3\xaf\xf3\x8d\f\\hf\xc2|\xff\r\xeb\xb7\xd9\xe1\xcc\xeb\xcb\xf0\x9b\xe2]\xad\xd4@åR\xd0~\xe3\xbc=\x83\x0f\xb7\xf9=\x93w\xd6z\x93\xc1\x80\xbcJt\xb7\xaf\xa5\xe9\x88/\xfaO\b\v\xf8\xcf\xff\x1e\xfe\x1f\x00\x00\xff\xff73Hq. \x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcZIs\xe3\xb8\x15\xbe\xfbW\xbc\xea\x1c\xe6b\xc9\xe9,S)\xdd\xdarR\xe5ʴ\xdb\xd5r|\x87\xc8'\x11c\x10`\xb0H\xe3,\xff}\xea\x01\x04\x05\x92\x90(i\xa6\x9b\x87\xae\x16\x96\x87\xb7\xe1{\v<\x9b\xcdnX\xc3_Q\x1b\xae\xe4\x02X\xc3\xf1\x17\x8b\x92~\x99\xf9\xdb\xdf̜\xab\xbb\xddǛ7.\xcb\x05,\x9d\xb1\xaa\xfe\x8aF9]\xe0\x03n\xb8\xe4\x96+yS\xa3e%\xb3lq\x03\xc0\xa4T\x96Ѱ\xa1\x9f\x00\x85\x92V+!P϶(\xe7on\x8dk\xc7E\x89\xda\x13\x8fG\xef\xfe8\xff\xf8\xe3\xfc\xaf7\x00\x92ո\x00\xa2\xe7\x1a\xa1Xi\xe6;\x14\xa8՜\xab\x1b\xd3`Ad\xb7Z\xb9f\x01\x87\x89\xb0\xad=2\xb0\xfb\xc0,\xfb\x97\xa7\xe0\a\x057\xf6\x9f\x83\x89\x9f\xb8\xb1~\xb2\x11N3\xd1;Տ\x1b.\xb7N0\x9d\xce\xdc\x00\x98B5\xb8\x80':\xb2a\x05\xd2X+\x89ga\x06\xac,\xbdn\x98x\xd6\\Z\xd4K%\\\x1du2\x83\x12M\xa1yc\xbd\xec\a\x86\xc0Xf\x9d\x01\xe3\x8a\n\x98\x81'\xdc\xdf=\xcag\xad\xb6\x1aM`\t\xe0g\xa3\xe43\xb3\xd5\x02\xe6a\xf9\xbc\xa9\x98\xc1v6\xa8o\xe5'\xda!\xfbN\xdc\x1a\xab\xb9\xdc\xe6\xce\x7f\xe15B\xe9\xb47\x1b\xc9\\ ؊\x9b\x94\xb1=3Ĝ\xb6X\x1ee\xc3\xcf\x131cY\xdd\f\xf9I\xb6\x06\x86Jf1\xc7\xceRՍ@\x8b%\xac\xdf-F!6J\xd7\xcc.\x80K\xfb\xe3_\x8ek\xa2U\xd5\xdco}P\xb2\xaf\x96{\x1a\x85d8pB\x16ڢ\xce\xeaFY&~\v#\x96\b\xdc'\xfb\x03'\x81n:>\xc9\n\xb9\x1b\xa8\r\xd8\n\xe1\x9e\x15o\xae\x81\x95U\x9am\x11~RE0\u07beB\xdd\x1ao\x1d\x96\x98J9Q\xc2:J\f`\xac\xd2Y+6X\xccî\x96n$;0e\xff\xcc\xdf\xd9\xc9\n\x8d,\xebd\x11e\xe6~\x05W2\xefi\x9f\xb6x\x96\x97\xa5ڔ\xaa\xc4Nu\x98r\xc4\r4Z\x15h\xcc\t\xbf\xa7\xed=\x1e\x9e\x0e\x03#\xb5\x84\x15\xbb?1\xd1T\xecc@\x99\xa2\u009a-\xda\x1d\xaaA\xf9\xe9\xf9\xf1\xf5ϫ\xde0\x1c\xc5\fVXC`A\xac7ZYU(\x01k\xb4{D\xe9q\vj\xb5CM \xb7\xe5\xd2\x00\x93eG\x13\xd2\x05\a\xa8&'\xf7\xf4h6L\xb6\xee\xa4\x1aԩف\x8elP[\x1e\xd17|IXIF\aB\xfco֛\x03 \xb9\xc3.()\xbe`\x90\xaa\xc5V,[U\x05\xbbq\x03\x1a\x1b\x8d\x06e\x8884\xcc$\xa8\xf5\xcfX\xd8\xf9\x80\xf4\n5\x91\x89\xf7\xa1Pr\x87ڂ\xc6Bm%\xffOGۀU\xfeP\xc1,\x1a\xeb/\xa4\x96L\xc0\x8e\t\x87\xb7\x03\xed\xd1W\xb3w\xd0Hg\x82\x93\t=\xbf\xc1\f\xf9\xf8\xac4\x02\x97\x1b\xb5\x80\xca\xda\xc6,\xee\xee\xb6\xdc\xc6`[\xa8\xbav\x92\xdb\xf7;o\f\xbevVisW\xe2\x0eŝ\xe1\xdb\x19\xd3E\xc5-\x16\xd6i\xbcc\r\x9fyA\xa4\x0f\xb8\xf3\xba\xfc\x83nó\xe9\x1d;\xf2\xc2\xf0\xf9@y\x81y(~ҕ`-\xa9 \xe2\xc1\n4D\xaa\xfb\xfa\xf7\xd5\vDN\x82\xa5\x82Q\x0eKGz\x89\xf6!mr\xb9A\x1d\xf6m\xb4\xaa=M\x94e\xa3\xb8\xb4\xfeG!8J\vƭkn\xc9\r\xfe\xed\xd0X2ݐ\xec\xd2'$\xb0Fp\rAA9\\\xf0(a\xc9j\x14Kf\xf0;ۊ\xacbfd\x84\xb3\xac\x95\xa6Y\xc3\xc5A\xbd\xc9D̔\x8e\x98\xf6\x00\x1f\xab\x06\v\xb2)\xa9\x956\xf1\roc\ta\x00KV\xf6\xb5\x93\xbf\xf6\xf4eC\xc8pє\xab\xd1w\x9f#\x14y\x95\t~\xc7P\xd7F&яL\xe9w\x00\xf9v\x8f\xc6F\x19n\x95~'\xc2!4\x0e\xdd\xe0\xa8E\xe8+\x98,P\\#\xde\xd2\xef\x04.K\xd28vnL\x00\x14\xa8zF\x95\xdc*\xbaX\x89!\xe0\xd1\xd2\n\xf2j\x836/\xa6̄2.\xe1\x90MB\x9a5\x0eE]+%\x90\r5X\x18\xbe\x92\xac1\x95\xb2\x13\x02?n \xae|yo\x90\x0e_\xae\x1eo\xe9\x9f8N\x1e\xb4\xe3e\v\xf1t\xcb(\xafʛ\xad\xb5\xf3r\xf5\b\xa6\xdd>6\x92tB\xb0\xb5\xc0\x05X\xedƂ\x1dwXϽ\xe6;Թ\x99\xe1\xcd\xf1\v\xa3\x17\x86m\xe0\x8c\xcfV\xfd\xd0+e\xfa\x18\xa5\\*iQ\xe6ltҫ苒.\x053Y\x9e\a\x9c\xad\xd2\xf5\xb9k\x12\tB\xe1W؊\xe5\xf9\x82\x10t\xbd\x1c\x87M\xbc\xcb\xcd`\xcfmu\x95D႞-P\xb2<+O{߃8jsB\x98\xe7ץ\x97wJ2\n7\xd7H\xb6\xeb\x19\xfd\f\xd9\xfa^\x92\x93n\xc0\xe51\xe1\x14\xa1\x00\x81\x19\x96\xe0\x9a\xcby'\xd0\xe1\x1a\xcb1ϳ\x9e\xbd2\xd3}\xa1\x8f \xc9(2A\x9bt~\xa6\xb4r\xa9\xe4\x86o\xc7g\xa7\xf5\xf3\xa9k{R\xb4Q\xc4K\x8e$\x8dS\x80#Nf>Ý\xc5\xe8G\xb9\xe1\x86o\x9d>\x86F\x1b\x8e\xa2\x1c%0\x93\x004\xa1\x0f\xcf\xc45q\xa4\x93,\xc6\xef\x16R\x93\xcc>xI\x8aR!\xfc\x8de\x00\x82\xee\x03En\xe0\xc3\aP\x1a>\x84^ˇ۰\xdbqag\xbcW^\xec\xb9\x10\xf1\x94\x8b\"hWRPA\xa7\xdcTh\xc9\xea\xe0ˀ\xc6@\x15\x96\x8aO/\xbeU\xb0g\x89ȼ\xd2|\xcbIᲛ9$c-ֵ]\v\x8fd\x1e\x8a\xb3\xfe١\xa5!\xb4<\x90\xa3\xeb\x1c\x0e'\xb4g\xb2\xf4\xf9B7_\xb6W/sq'\x15\xf2\xfc\xba\x9c\xb2Wwp\x06\xcaix_\xf1\xa2ꛎ\x8fA\x15\xc0\xb27\xf4\xb9\xf7\x05l\xe61|\x96\xcf\xc4\ak\x86\xb7o0\x9d\xba\xecp\xaao\xe8\xec\xec\xf3\xeb\xf2\xacj\xc57RΫWB\x87\xb4\xd5r\xe1\xb4\xf6\x95`\x18U\x9b\xab*\x16V\x14\xd8X,\xefߟT9\xe5\xf4\x9fz\x8b\x89\x11yN+)cj\xdf\\\u0086]ZrDv\xbb\x06\xd85\xd7\xf4Ӑ\x88o\x85\xe82\x01\xccq\x01\x11\xc0\xe68\xd3\x00/\xe4ྔ\xff!`$m\xf3\xc8K\xd7st\xe8\x88B\xec\xaeR\xad>\xa3\xfd\xd7E\xd9|\xa9\x16\x1a\xcbi\xeb\xf0\xaa\xbamLf\xac;\x16\vL\xdfӌ\x1d\xed\x9c\xc6\x0e\xe4:}\x05jX\x02\xeeP\x02\x95\xe2\x8c\v\x8aݞd\x06\xc0NSi\x83Xx\xbe\x88=\x9a\xd8\xcf\xcb6˦-\x99Q\xc2\x18;\xa51\xbb\x14\xf2+\x1a'2I\xc37L!Ñ\xa1[`\xb2)\xe4\xe9r\x96\x19`\xa0\x03\x91\x167\x8e\x81\xd6\xd9J\xca\xe6\x955\x1aöS\x88\xf69\xac\n\x9d\xbdv\v\xb05\xa5Q}\xd6~0-\xd0^\x04Wr\x1aS/B\xd2^S\xfebN\xbe\xac\xce\xe0\xe5ˊ\x0e\xf9\xb2\xfa\xad\xbc\xa0tu\xae\xb0bΪ̰\xe0\xd2\xfd\x92\x19\xdfsY\xaa\xfd\xf8~\x9d\x10\xb5a\xb6\x9a\x10\xf4\x99\xd9*\xc6э\x13\xc2\xef\x19\xe5\x97mj\xb6F\x02\x8e\xdf+\xcd\xf4\xad\xa7)\xf6hM.\xce\xe39w\xe6\x98\xe6\x9fp\x9f\x19\x8dq)3\xf5\xdc\x06\xbb\xcc\xd4\xe8e6\x9d\fݽ\x1c\xa6Ĺ,\xcd\xee\xf133\xf7\x0f\x1f\x05.\xd2s\xcb\xdf5a\xae\xeb\x13VJ\xc4\xc8\xe6\x1f-\xa5\xabר\xc9\b\xfeYtЯ\xa0\xbc;\xb1X\x86p\xb2\xbfK\xf6=\xa59\xbcT\xdc\xc4\xcef,\xd7Jn\x1a\xc1\xde;Y\xa6\xb0\xb5í\xe1\x8b\xd5\xd8IN\xb7\x04\xbb'\xe4|;'\xf7\x0e\xdc\xff\xc6/\xba\x83\xf9\xeei\xf8ۜp\"0\xc4\xeb\xfd\xf8pf\x1d\xfa\xf8\x10\xaf\"/QZ*\xad\x0f\xaf\x84\x87\x8a\xc6w\x9ds\xba\x1cv\xdb/+\xc2z\x7fXpUQڣ0\x91\xae\xb5\x7f\xe7\x90K\x8aV\x04\x06\x04A\xfe]j9|\x89\xbe\xed\x1e\xb6\x99m\x1fNJ\x8a\xc9-\xe6*=%)\a\xf09\xc4\xe5\xf9W_\xa0\xef\x99ze\xbdj4\xe89/\x13\xdam/1\x1dq\xeb\xee\xb5r\x01\xff\xfd\xffͯ\x01\x00\x00\xff\xff\xee\xe6t\xbc\x8f$\x00\x00"), } diff --git a/pkg/apis/velero/v1/pod_volume_restore_type.go b/pkg/apis/velero/v1/pod_volume_restore_type.go index 5c4ced777..c1d75b71c 100644 --- a/pkg/apis/velero/v1/pod_volume_restore_type.go +++ b/pkg/apis/velero/v1/pod_volume_restore_type.go @@ -59,7 +59,7 @@ type PodVolumeRestoreSpec struct { // when the PodVolumeRestore is in InProgress phase Cancel bool `json:"cancel,omitempty"` - // SnapshotSize is the logical size of the snapshot. + // SnapshotSize is the logical size in Bytes of the snapshot. // +optional SnapshotSize int64 `json:"snapshotSize,omitempty"` } diff --git a/pkg/apis/velero/v2alpha1/data_download_types.go b/pkg/apis/velero/v2alpha1/data_download_types.go index 01069118b..4ea7128ec 100644 --- a/pkg/apis/velero/v2alpha1/data_download_types.go +++ b/pkg/apis/velero/v2alpha1/data_download_types.go @@ -59,7 +59,7 @@ type DataDownloadSpec struct { // +optional NodeOS NodeOS `json:"nodeOS,omitempty"` - // SnapshotSize is the logical size of the snapshot. + // SnapshotSize is the logical size in Bytes of the snapshot. // +optional SnapshotSize int64 `json:"snapshotSize,omitempty"` } diff --git a/pkg/apis/velero/v2alpha1/data_upload_types.go b/pkg/apis/velero/v2alpha1/data_upload_types.go index 3d7c95fb9..d4c5a28da 100644 --- a/pkg/apis/velero/v2alpha1/data_upload_types.go +++ b/pkg/apis/velero/v2alpha1/data_upload_types.go @@ -245,7 +245,7 @@ type DataUploadResult struct { // +optional NodeOS NodeOS `json:"nodeOS,omitempty"` - // SnapshotSize is the logical size of the snapshot. + // SnapshotSize is the logical size in Bytes of the snapshot. // +optional SnapshotSize int64 `json:"snapshotSize,omitempty"` } From 898fa13ed765b12c44f38d50a7dd646ffa78d6bc Mon Sep 17 00:00:00 2001 From: Shubham Pampattiwar Date: Mon, 27 Oct 2025 11:57:55 -0700 Subject: [PATCH 070/104] Fix managed fields patch for resources using GenerateName When restoring resources with GenerateName (where name is empty and K8s assigns the actual name), the managed fields patch was failing with error "name is required" because it was using obj.GetName() which returns empty for GenerateName resources. The fix uses createdObj.GetName() instead, which contains the actual name assigned by Kubernetes after resource creation. This affects any resource using GenerateName for restore, including: - PersistentVolumeClaims restored by kubevirt-velero-plugin - Secrets and ConfigMaps created with generateName - Any custom resources using generateName Changes: - Line 1707: Use createdObj.GetName() instead of obj.GetName() in Patch call - Lines 1702, 1709, 1713, 1716: Use createdObj in error/info messages for accuracy This is a backwards-compatible fix since: - For resources WITHOUT generateName: obj.GetName() == createdObj.GetName() - For resources WITH generateName: createdObj.GetName() has the actual name The managed fields patch was already correctly using createdObj (lines 1698-1700), only the Patch() call was incorrectly using obj. Fixes restore status showing FinalizingPartiallyFailed with "name is required" error when restoring resources with GenerateName. Signed-off-by: Shubham Pampattiwar --- pkg/restore/restore.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/restore/restore.go b/pkg/restore/restore.go index c8a9ab40a..7e0fe7f9a 100644 --- a/pkg/restore/restore.go +++ b/pkg/restore/restore.go @@ -1699,21 +1699,21 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso createdObj.SetManagedFields(obj.GetManagedFields()) patchBytes, err := generatePatch(withoutManagedFields, createdObj) if err != nil { - restoreLogger.Errorf("error generating patch for managed fields %s: %s", kube.NamespaceAndName(obj), err.Error()) + restoreLogger.Errorf("error generating patch for managed fields %s: %s", kube.NamespaceAndName(createdObj), err.Error()) errs.Add(namespace, err) return warnings, errs, itemExists } if patchBytes != nil { - if _, err = resourceClient.Patch(obj.GetName(), patchBytes); err != nil { + if _, err = resourceClient.Patch(createdObj.GetName(), patchBytes); err != nil { if !apierrors.IsNotFound(err) { - restoreLogger.Errorf("error patch for managed fields %s: %s", kube.NamespaceAndName(obj), err.Error()) + restoreLogger.Errorf("error patch for managed fields %s: %s", kube.NamespaceAndName(createdObj), err.Error()) errs.Add(namespace, err) return warnings, errs, itemExists } - restoreLogger.Warnf("item not found when patching managed fields %s: %s", kube.NamespaceAndName(obj), err.Error()) + restoreLogger.Warnf("item not found when patching managed fields %s: %s", kube.NamespaceAndName(createdObj), err.Error()) warnings.Add(namespace, err) } else { - restoreLogger.Infof("the managed fields for %s is patched", kube.NamespaceAndName(obj)) + restoreLogger.Infof("the managed fields for %s is patched", kube.NamespaceAndName(createdObj)) } } From 07f30d06b9888e4d7563c620e74312a3fecd1380 Mon Sep 17 00:00:00 2001 From: Shubham Pampattiwar Date: Mon, 27 Oct 2025 12:04:46 -0700 Subject: [PATCH 071/104] Track actual resource names for GenerateName in restore status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When restoring resources with GenerateName, Kubernetes assigns the actual name after creation, but Velero only tracked the original name from the backup in itemKey. This caused volume information collection to fail when trying to fetch PVCs using the original name instead of the actual created name. Example: - Original PVC name from backup: "test-vm-disk-1" - Actual created PVC name: "test-vm-backup-2025-10-27-test-vm-disk-1-mdjkd" - Volume info tried to fetch: "test-vm-disk-1" → Failed with "not found" This affects any plugin or workflow using GenerateName during restore: - kubevirt-velero-plugin (VMFR use case with PVC collision avoidance) - Custom restore item actions using generateName - Secrets/ConfigMaps restored with generateName Changes: 1. Add createdName field to restoredItemStatus struct (pkg/restore/request.go) 2. Capture actual name from createdObj.GetName() (pkg/restore/restore.go:1520) 3. Use createdName in RestoredResourceList() when available (pkg/restore/request.go:93-95) This fix is backwards compatible: - createdName defaults to empty string - When empty, falls back to itemKey.name (original behavior) - Only populated for GenerateName resources where needed Fixes volume information collection errors like: "Failed to get PVC" error="persistentvolumeclaims \"\" not found" Signed-off-by: Shubham Pampattiwar --- pkg/restore/request.go | 15 +++++++++++---- pkg/restore/restore.go | 6 +++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/pkg/restore/request.go b/pkg/restore/request.go index 452be4264..239d65df9 100644 --- a/pkg/restore/request.go +++ b/pkg/restore/request.go @@ -69,8 +69,9 @@ type Request struct { } type restoredItemStatus struct { - action string - itemExists bool + action string + itemExists bool + createdName string // Actual name assigned by K8s for GenerateName resources } // GetItemOperationsList returns ItemOperationsList, initializing it if necessary @@ -87,9 +88,15 @@ func (r *Request) GetItemOperationsList() *[]*itemoperation.RestoreOperation { func (r *Request) RestoredResourceList() map[string][]string { resources := map[string][]string{} for i, item := range r.RestoredItems { - entry := i.name + // Use createdName if available (GenerateName case), otherwise itemKey.name + name := i.name + if item.createdName != "" { + name = item.createdName + } + + entry := name if i.namespace != "" { - entry = fmt.Sprintf("%s/%s", i.namespace, i.name) + entry = fmt.Sprintf("%s/%s", i.namespace, name) } entry = fmt.Sprintf("%s(%s)", entry, item.action) resources[i.resource] = append(resources[i.resource], entry) diff --git a/pkg/restore/restore.go b/pkg/restore/restore.go index c8a9ab40a..52c947835 100644 --- a/pkg/restore/restore.go +++ b/pkg/restore/restore.go @@ -1514,7 +1514,11 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso createdObj, restoreErr = resourceClient.Create(obj) if restoreErr == nil { itemExists = true - ctx.restoredItems[itemKey] = restoredItemStatus{action: ItemRestoreResultCreated, itemExists: itemExists} + ctx.restoredItems[itemKey] = restoredItemStatus{ + action: ItemRestoreResultCreated, + itemExists: itemExists, + createdName: createdObj.GetName(), + } } } From 2e9998b20e9cf65c45fe84c05c0b604a27f18554 Mon Sep 17 00:00:00 2001 From: Shubham Pampattiwar Date: Mon, 27 Oct 2025 12:07:55 -0700 Subject: [PATCH 072/104] Add changelog for PR 9368 Signed-off-by: Shubham Pampattiwar --- changelogs/unreleased/9368-shubham-pampattiwar | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/unreleased/9368-shubham-pampattiwar diff --git a/changelogs/unreleased/9368-shubham-pampattiwar b/changelogs/unreleased/9368-shubham-pampattiwar new file mode 100644 index 000000000..f8262126a --- /dev/null +++ b/changelogs/unreleased/9368-shubham-pampattiwar @@ -0,0 +1 @@ +Track actual resource names for GenerateName in restore status From f9f0e48e04534787c3d7aa0e8719a747d474e451 Mon Sep 17 00:00:00 2001 From: Shubham Pampattiwar Date: Mon, 27 Oct 2025 12:11:06 -0700 Subject: [PATCH 073/104] Add changelog for PR 9367 Signed-off-by: Shubham Pampattiwar --- changelogs/unreleased/9367-shubham-pampattiwar | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/unreleased/9367-shubham-pampattiwar diff --git a/changelogs/unreleased/9367-shubham-pampattiwar b/changelogs/unreleased/9367-shubham-pampattiwar new file mode 100644 index 000000000..f9dac16f6 --- /dev/null +++ b/changelogs/unreleased/9367-shubham-pampattiwar @@ -0,0 +1 @@ +Fix managed fields patch for resources using GenerateName From 5fc76db8c0aadccc5999e1e399b004090c6c3675 Mon Sep 17 00:00:00 2001 From: Scott Seago Date: Tue, 21 Oct 2025 12:52:11 -0400 Subject: [PATCH 074/104] Add incrementalSize to DU/PVB for reporting new/changed size Signed-off-by: Scott Seago --- changelogs/unreleased/9357-sseago | 1 + .../v1/bases/velero.io_podvolumebackups.yaml | 11 +++++++++ config/crd/v1/crds/crds.go | 2 +- .../v2alpha1/bases/velero.io_datauploads.yaml | 11 +++++++++ config/crd/v2alpha1/crds/crds.go | 2 +- internal/volume/volumes_information.go | 23 ++++++++++++------- pkg/apis/velero/v1/pod_volume_backup_types.go | 5 ++++ pkg/apis/velero/v2alpha1/data_upload_types.go | 5 ++++ pkg/backup/backup.go | 1 + pkg/backup/backup_test.go | 5 ++++ pkg/builder/data_upload_builder.go | 6 +++++ pkg/cmd/util/output/backup_describer.go | 14 +++++++++-- pkg/cmd/util/output/backup_describer_test.go | 12 ++++++---- .../output/backup_structured_describer.go | 6 ++++- pkg/cmd/util/output/restore_describer.go | 2 +- pkg/controller/data_upload_controller.go | 1 + .../pod_volume_backup_controller.go | 1 + pkg/datamover/backup_micro_service_test.go | 2 +- pkg/datapath/file_system.go | 4 ++-- pkg/datapath/file_system_test.go | 2 +- pkg/datapath/types.go | 9 ++++---- pkg/podvolume/backup_micro_service_test.go | 2 +- pkg/uploader/kopia/progress.go | 4 ++++ pkg/uploader/provider/kopia.go | 15 ++++++------ pkg/uploader/provider/kopia_test.go | 2 +- pkg/uploader/provider/mocks/Provider.go | 21 +++++++++++------ pkg/uploader/provider/provider.go | 2 +- pkg/uploader/provider/restic.go | 20 ++++++++-------- pkg/uploader/provider/restic_test.go | 4 ++-- .../docs/main/csi-snapshot-data-movement.md | 7 +++++- 30 files changed, 145 insertions(+), 57 deletions(-) create mode 100644 changelogs/unreleased/9357-sseago diff --git a/changelogs/unreleased/9357-sseago b/changelogs/unreleased/9357-sseago new file mode 100644 index 000000000..9787a9024 --- /dev/null +++ b/changelogs/unreleased/9357-sseago @@ -0,0 +1 @@ +Add incrementalSize to DU/PVB for reporting new/changed size diff --git a/config/crd/v1/bases/velero.io_podvolumebackups.yaml b/config/crd/v1/bases/velero.io_podvolumebackups.yaml index f77c5df4a..2e7fe7056 100644 --- a/config/crd/v1/bases/velero.io_podvolumebackups.yaml +++ b/config/crd/v1/bases/velero.io_podvolumebackups.yaml @@ -33,6 +33,12 @@ spec: jsonPath: .status.progress.totalBytes name: Total Bytes type: integer + - description: Incremental bytes + format: int64 + jsonPath: .status.incrementalBytes + name: Incremental Bytes + priority: 10 + type: integer - description: Name of the Backup Storage Location where this backup should be stored jsonPath: .spec.backupStorageLocation @@ -189,6 +195,11 @@ spec: format: date-time nullable: true type: string + incrementalBytes: + description: IncrementalBytes holds the number of bytes new or changed + since the last backup + format: int64 + type: integer message: description: Message is a message about the pod volume backup's status. type: string diff --git a/config/crd/v1/crds/crds.go b/config/crd/v1/crds/crds.go index a600bae3c..130cae45e 100644 --- a/config/crd/v1/crds/crds.go +++ b/config/crd/v1/crds/crds.go @@ -34,7 +34,7 @@ var rawCRDs = [][]byte{ []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xccYK\x8f\x1b\xb9\x11\xbe\xebW\x14v\x0f{ٖ\xec\x04\t\x02\xdd\xc6r\x02\x18\x19\xc7\x03k2\xb9.EVK\\\xb1\xc9\x0e\x1f\x92\x95\xc7\x7f\x0f\x8a\x0f\xa9\xd5\x0fK\xe3\x04\x9b\xe5eF|\x14\xeb\xf9U\x15\xbb\xaa\xaa\x19k\xe5\vZ'\x8d^\x02k%~\xf1\xa8闛\xef\xff\xe0\xe6\xd2,\x0eog{\xa9\xc5\x12V\xc1y\xd3|Fg\x82\xe5\xf8\x1ek\xa9\xa5\x97F\xcf\x1a\xf4L0ϖ3\x00\xa6\xb5\xf1\x8c\xa6\x1d\xfd\x04\xe0F{k\x94B[mQ\xcf\xf7a\x83\x9b \x95@\x1b\x89\x97\xab\x0fo\xe6o\x7f?\xff\xdd\f@\xb3\x06\x97\xb0a|\x1fZ\xe7\x8de[T\x86'\x92\xf3\x03*\xb4f.\xcd̵\xc8醭5\xa1]\xc2e!Qȷ'\xce\xdfEb\xebD\xec1\x13\x8b\xebJ:\xff\xe7\xe9=\x8f\xd2\xf9\xb8\xafU\xc125\xc5V\xdc\xe2v\xc6\xfa\xbf\\\xae\xae`\xe3TZ\x91z\x1b\x14\xb3\x13\xc7g\x00\x8e\x9b\x16\x97\x10O\xb7\x8c\xa3\x98\x01d\xd5Dj\x150!\xa2\xb2\x99z\xb2R{\xb4+\xa3B\xa3\xcfw\tt\xdc\xca\xd6Ge&Y \v\x03E\x1ap\x9e\xf9\xe0\xc0\x05\xbe\x03\xe6\xe0\xe1\xc0\xa4b\x1b\x85\x8b\xbfjV\xfe\x8f\xf4\x00~vF?1\xbf[\xc2<\x9d\x9a\xb7;\xe6\xcaj\xb2\xd1SgƟH\x00\xe7\xad\xd4\xdb1\x96\x1e\x99\xf3/LI\x119y\x96\r\x82t\xe0w\b\x8a9\x0f\x9e&\xe8W\xd2\x10\x90\x8a\x10\x8a\x86\xe0\xc8\\\xbe\a\xe0\x90\xa8D\x1d\x8ds\xaa\x06w]\xb1M\xac\xc0K\x8fJ\xe2\x9ff2\xf7\x1d\xb2ſ\xe7\xdc♤\xf3\xaci\xaf\xe8>lq\x8aؕ*\xdec͂\xf2]Q\xc9J\xaa\xeb\x97\xd7b\xb5\xc8\xe7\"\x9d\xba\xba\xf1\xfd\xd5\\\xbauc\x8cB\x96\xa8\xa4]\x87\xb7\xc9\v\xf9\x0e\x1b\xb6̛M\x8b\xfa\xe1\xe9\xc3\xcbo\xd7W\xd30\xe6H\xbd\xa0 ñ\x8emvh\x11^b\xfc%\xbb\xb9,ڙ&\x80\xd9\xfc\x8c\xdc_\x8c\xd8ZӢ\xf5\xb2\x04K\x1a\x1d,\xea\xcc\xf6x\xfaWu\xb5\x06@b\xa4S \b\x940\xf9U\x8e\x1f\x14Yr05\xf8\x9dt`\xb1\xb5\xe8P'\x98\xa2i\xa63\x83\xf3\x1e\xe95Z\"C\xb1\x1d\x94 ,;\xa0\xf5`\x91\x9b\xad\x96\xff8\xd3v\xe0Mvf\x8f\xceC\x8cP\xcd\x149k\xc0\x1f\x81iѣܰ\x13X\xa4;!\xe8\x0e\xbdx\xc0\xf5\xf9\xf8H\xd1 um\x96\xb0\xf3\xbeu\xcb\xc5b+}Ahn\x9a&h\xe9O\x8b\b\xb6r\x13\xbc\xb1n!\xf0\x80j\xe1\xe4\xb6b\x96\xef\xa4G\xee\x83\xc5\x05ke\x15\x05\xd1\tR\x1b\xf1\xbd͘\uebae\x1d\x84t\x1a\x11R_a\x1e\x82\xd7\xe42\x89T\x12\xf1b\x05\x9a\"\xd5}\xfe\xe3\xfa\x19\n'\xc9R\xc9(\x97\xad\x03\xbd\x14\xfb\x906\xa5\xaeѦs\xb55M\xa4\x89Z\xb4Fj\x1f\x7fp%Q{pa\xd3HOn\xf0\xf7\x80Γ\xe9\xfadW1\x8b\xc1\x06!\xb4\x11$\xfa\x1b>hX\xb1\x06Պ9\xfc\x85mEVq\x15\x19\xe1.kuss\x7fsRog\xa1\xe4\xd4\tӎ\xa2\xc1\xbaE~\x15w\x02\x9d\xb4\x14\x19\x9ey\x8c\xd1\xd5SP\x86\x8a\xe9\xa4\\\xc68H\xd0`\x9c\xa3s\x1f\x8d\xc0\xfeJ\x8f\xe5\x87\xf3\xc6+\x1e[\xb4\x8dt1\xbdBml?\xf3\xb03\x92wGA\xbc\xbe\xc1\x01P\x87f\xc8H\x05\x9f\x91\x89OZ\x9d&\x96\xfef\xa5\x1f^4aH\x1a\x89\xc5\xf5I\xf3'\xb4҈\x1b¿\xebm?\xab`g\x8ePG\xff\xd7^\x9d\b\xbb\xdcI\xf3!j\x97\xf1\xf0\xf4\xa1 x\x8a\xad\x1c\x98YWsx\xc8Amjx\x03B:*$\\$:T\x96\x0e*\x16\x1aK\xf06\xbcJ|nt-\xb7C\xa1\xbb\xb5є\xc7\xdc \xdd\xd3\xdc*\xdeD\xa8E\xde\xd1Zs\x90\x02mE\xf1!k\xc93'\xc1\xa6\fRKTb\x80M\x93Q\x16E\xb1((\xa8\x99\xbaa\xc3\xd5yc\xac\xa4\x99\xd4Ƀ/\x04\"\xd6\xd8&\xa7f\xedQ\v\xecg\x9bȍ\x89\x80\xe6P\xc0Q\xfa]BJ5\x16w\xf0\xd5أ\xb1\xc7\xd3\xd8t\x8f\xf7\xe7\x1d\xd2Δx\x11\x1cr\x8b>z\x1b*r\x1fr\xa59\xc0\xc7\xe0\"\xd6\xf6q\xa2\x8cX\xf0\x95\xd3{<\r\x15\r\xb7\x8c\x9bK\xa1\t\x96c\x11\xb5\x84ᄏ-\xd2 \xbb\x95A\xa5{\x11\xd4b\x8d\x16\xf5\xa0\x9a(\xe39\xe6(r\x1a\xf20\xack\xe4^\x1eP\x9dbN\"\xf0\xfc\x116\xc1\x83\b\x18\xad\xc6\xf8\xfeȬp\xc0M\xd32/7RI\x7f\x02\xe9&\xe83\xa5\xcc\x11E\xb686\xad?\xcd\xe1\x83v\x9ei\x8e\xee\\\a\x91ƒ+0\x9dv\xe5(\x8e\x05\x1d\xb3c\x18\x98\xc87\xc6y\xe0h\xc9\x1d\xd5\t\x8e\xd6\xe8픰#\xe9\x90z@\xab\xd1c̈\xc2pGɐc\xeb\xdd\xc2\x1c\xd0\x1e$\x1e\x17Gc\xf7Ro+b\xb0\xcaೈ\x9d\xdd\xe2\xfb\xf8\xe7[\xbc\xc0\xb4\t'\xeep\xdeu\x8c\xf5\x13\x95\xb7~\x87)E\xac\x93\x0f\x1a\vT@\x90k7\xd9w\x13\xb2\x8e\x85\xddX]\xde\x1d\xc5\xe4c\xf9c\x8f\xc3\xd4\xf1\x15P\x01\xf8R]t[5\xac\xad\xd2n\xe6M#\xf9\xac/m\xf2\xfb\xaf\xe3OiV\xa4\x16\x92Sq{\x8d\x1b\xa5\x89\x13W=͈\x1a\xfa]\xce\x14Z\x8e\xab)\x89\x9bk\x85\x1b\x1c\x7f\xea\uef74\xbe\t\xbas\xfew\xe8\xa9\xeet\xa0\x91\xea\x03f\x87z\x8e\x80ɍքT\xde\x00;\xa7\x81\x1f\\?\xff\xbd\x12=7\x81\xefqD\xf1\x03Q\xdeōE\xc7\xe9\x18\xf1\x12\x1c\xc6\xc4t\x8b\r\xb8\x1d\x11\x9c\xad\xd0\xde\xc3\xcb\xea\x816\x9eK\b\x06\xab\a\xd8\x04-\x14\x16\x8e\x8e;\xd4\xd4u\xc9\xfa4~\x17\x8d\xe7\xc7u\xd1j\xac\xber\xdfTt;.C\xcaoK\u061cF\xea\xa5;\x84l-\xd6\xf2\xcb\x1dB>ōE\xe1-\xf3;\x90\xdaI\x81\xc0Fԟ\n\xd9\tAϵѧ\x8c9\xdf`\x9e\xafaCb\xe75\xf0Pt|#~\x9e\xf2\xb6\xb3\x16\xca\xef\x9cݮ\xeb\xe4\xa98\x1e\x95\xe8p~\x94\xf9S\xaa>\xf9H\x19q\xc5\xcc\xcb\xf0\xc4W\xaa\xd8\xf244\x16\xccT3\x19kѵF\v\xea9\xef\xaba/,\xff\xef*\xd9q\xb3V\xd7(\xd7[+V\xb8\xab\x8d\x8b\xcf`\xafn\xe4\xd2\xe3`\xb7M2\x1bG\r\xf6\xa5\x97\xeb\xc9\xf8\x8b\xb4p\xa3%W\xa7\xaf\x93\x8eꗠce\x1b\xab\xaa\xf9l\xe4\xc4{l-R\x06\x13K\x92\xcdƃ\xda\x1c\xe9p\x87Z*ˌN\xf9\x9ez[\xa6E~U\xa0\xa5\x11\xcaG\xa9\x14\xd5\x00\x16\x1bCʢ\xb2\xdcR5\xc7b\xadu\xf8\xcd\xfc\xcd\xff\xafeT\xccy\xea\x00Q|ƃ\x1c>\xadݧ\xee\xc7\x01\x95\x82\x0e瘡\x1f?\x95׆\x85\xcd\xdb~\x82Z*\xaa\xff:\xd0qGu0\xf20\xfcn\xfd\xf8\x83\x8b=\x10j\xef\xe0H\x16t\x91%jzL~\xe1\t\xceS\x12\xb9i\xffn\x01\xae\r(\xa3\xb7h\xcbk\x0f\x15xɛ\x8c\x05\x81\x9er\x95\xde\x02\xdf1\xbd\xa5\xc8\x18\x83\xfc\xc8p\xe6\xbe\xcb'yϤ\x83H=\xe1\x1dw\x19\xf4Y\x8e\xb54\xaf1\xe6\xf43\xfc\x99\xffl\xd9\xcbkoO\xefSP[,\xd1_,\xa9\x9c\x14]\xf9\xcb\xd3\xfce|\xfb\xfb\xc0\xf0\xdd\xff[\xd5\xf3_}\xa9\x18|\xa1\xf8U(\xa7\xa1:\xf7f\xf1\xfc1\xedJ\xef\xb5\xf9\b\xb0\x8d\t~$\xf7w\x1c~4\xa6\xe3ǘ\xd7\xf0\x18?1\xdd*OhO\xb1\b\x0f\xd6\xc67\xdd\xf2\xd6\x18\x91b,+ݏ\xc0\x0f\xbd/aݵ\xe1w\xb2;\xe4\x1a\xcd҃ɔi;v\xcdJ\xee΄\xcd\xf9\xa5~\t\xff\xfc\xf7\xec?\x01\x00\x00\xff\xff\x03f\x86Y\xc0\x1d\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcVMo\x1b7\x10\xbd\xebW\f\xd0kwU\xa3hQ\xec\xadqr0\xda\x06\x82\x1d\xe4N\x91#-c.\xc9\xce\f\xe5\xba\x1f\xff\xbd \xb9+K\xab\x95\x93\\\xb27\x91Ù\xc7\xf7f\x1e\xd54\xcdJE\xfb\x11\x89m\xf0\x1d\xa8h\xf1/A\x9f\x7fq\xfb\xf8\v\xb76\xac\x0f7\xabG\xebM\a\xb7\x89%\f\xf7\xc8!\x91Ʒ\xb8\xb3ފ\r~5\xa0(\xa3Du+\x00\xe5}\x10\x95\x979\xff\x04\xd0\xc1\v\x05琚=\xfa\xf61mq\x9b\xac3H%\xf9T\xfa\xf0C{\xf3s\xfb\xd3\n\xc0\xab\x01;0\xe8Pp\xab\xf4c\x8a\x84\x7f&d\xe1\xf6\x80\x0e)\xb46\xac8\xa2\xce\xf9\xf7\x14R\xec\xe0e\xa3\x9e\x1fkW\xdcoK\xaa7%\xd5}MUv\x9de\xf9\xedZ\xc4\xefv\x8c\x8a.\x91rˀJ\x00[\xbfON\xd1b\xc8\n\x80u\x88\xd8\xc1\xfb\f+*\x8df\x050^\xbb\xc0l@\x19S\x88TnC\xd6\v\xd2mpi\x98\bl\xc0 k\xb2Q\nQ\x1fz,W\x84\xb0\x03\xe9\x11j9\x90\x00[\x1c\x11\x98r\x0e\xe0\x13\a\xbfQ\xd2w\xd0f\xbe\xda\x1a\x9a\x81\x8c\x01\x95\xea7\xf3ey\u0380Y\xc8\xfa\xfd5\b,J\x12O J]\x1b<\xd0\t\xbf\xe7\x00J|\x1b{\xc5\xe7\xd5\x1f\xcaƵ\xca5\xe6pS\x99\xd6=\x0e\xaa\x1bcCD\xff\xeb\xe6\xee\xe3\x8f\x0fg\xcbp\x8euAZ\xb0\fjB\x9a\x89\xab\xacA\xf0\b\x81`\b4\xb1\xca\xed1i\xa4\x10\x91\xc4N\xadU\xbf\x93\xe19Y\x9dA\xf8\xb79\xdb\x03Ȩ\xeb)0y\x8a\x90\v\x89cS\xa0\x19/Zɵ\f\x84\x91\x90\xd1\u05f9\xca\xcb\xcaC\xd8~B-\xed,\xf5\x03RN\x03܇\xe4L\x1e\xbe\x03\x92\x00\xa1\x0e{o\xff>\xe6\xe6|\xef\\\xd4))\x94\xe4\xb6\xf3\xca\xc1A\xb9\x84߃\xf2f\x96yP\xcf@\x98kB\xf2'\xf9\xca\x01\x9e\xe3\xf8#\x93h\xfd.tЋD\xee\xd6뽕\xc9Rt\x18\x86\xe4\xad<\xaf\x8b;\xd8m\x92@\xbc6x@\xb7f\xbbo\x14\xe9\xde\njI\x84k\x15mS.⋭\xb4\x83\xf9\x8eF\x13Ⳳ\x17\xddS\xbf\xe2\x02_!O\xf6\x84\xda#5U\xbd\xe2\x8b\ny)Sw\xff\xee\xe1\x03LH\xaaRU\x94\x97\xd0\v^&}2\x9b\xd6\xef\x90\xea\xb9\x1d\x85\xa1\xe4Dob\xb0^\xca\x0f\xed,z\x01N\xdb\xc1\nO\x1d\x9b\xa5\x9b\xa7\xbd-\xb6\x9b\x1d E\xa3\x04\xcd<\xe0\xceí\x1a\xd0\xdd*\xc6o\xacUV\x85\x9b,\xc2\x17\xa9u\xfa\x98̃+\xbd'\x1b\xd33pEڅ\xe1\x7f\x88\xa8\xb3\xb8\x99\xdf|\xda\ueb2ec\xb5\v\x04O\xbd\xd5\xfd4\xfc3\x9a\x8eFq\xce߲1\xe4\xef\xc5n\xe7;W/\x0fEdK8k\xd8\x06.\xbc\xfbu^\x8a\xa9~%3\xd5\xd1Gnt\"*\xcdw\xf4y\xb5t\xe8K\xb9@\xa2@\x17\xab3P\xefJP\xf9Ǡ\xacgP\xfey<\b\xd2+\x81'\xa4\r\x97\x95\x1ax\x8fO\v\xabw~CaO\xc8\xf3\x96ϛ\x9b\xca\x1e\xce߃WXZlʋE\xceVhNXd\t\xa4\xf6\xa7\xbcr\xda\x1e\x9d\xbe\x83\x7f\xfe[\xfd\x1f\x00\x00\xff\xff\xbeM\x1a\xea\xb1\n\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcWMo\xe36\x10\xbd\xfbW\f\xd0K\v\xac\xe4\x06E\x8b·\xd6\xd9C\xb0\xe96\x88\xb7\xb9S\xd4HbC\x91,9t6E\x7f|1\xa4\xe4\x0fYv\x9c\xcb\xea\xe6\xe1p\xf8\xe6\xcd\xcc#]\x14\xc5B8\xf5\x84>(kV \x9c¯\x84\x86\x7f\x85\xf2\xf9\xd7P*\xbb\xdc\xde,\x9e\x95\xa9W\xb0\x8e\x81l\xff\x88\xc1F/\xf1\x16\x1be\x14)k\x16=\x92\xa8\x05\x89\xd5\x02@\x18cI\xb09\xf0O\x00i\ry\xab5\xfa\xa2ES>\xc7\n\xab\xa8t\x8d>\x05\x1f\x8f\xde\xfeX\xde\xfcR\xfe\xbc\x000\xa2\xc7\x15\xd4\xf6\xc5h+j\x8f\xffD\f\x14\xca-j\xf4\xb6Tv\x11\x1cJ\x8e\xddz\x1b\xdd\n\xf6\vy\xefpn\xc6|;\x84y\xccaҊV\x81>ͭޫ\xc1\xc3\xe9\xe8\x85>\x05\x91\x16\x832m\xd4\u009f,/\x00\x82\xb4\x0eW\xf0\x99a8!\xb1^\x00\f)&XŐ\xdd\xf6&\x87\x92\x1d\xf6\"\xe3\x05\xb0\x0e\xcdo\x0fwO?m\x8e\xcc\x005\x06镣D\xd4\x7f\xc5\xce\x0e\xd3\x04@\x05\x100\xc0\x01\xb2;\x84 \f\bO\xaa\x11\x92\xa0\xf1\xb6\x87J\xc8\xe7\xe8\xc0V\x7f\xa3$\bd\xbdh\xf1\x03\x84(;\x10\x1c%;\x1c\x9c\xa5m\v\x8d\xd2X\xeel\xce[\x87\x9e\xd4Hy\xfe\x0e\x1a\xea\xc0z)\v\xfe8\xf1\xbc\vj\xee,\f@\x1d\x8e\xe4a=p\x05\xb6\x01\xeaT\x00\x8f\xcec@\x93{\x8d\xcd\xc2\fٔ\x93\xd0\x1b\xf4\x1c\x06Bg\xa3\xae\xb9!\xb7\xe8\t\x1aE\xaf\xcb41\xaa\x8ad}XָE\xbd\f\xaa-\x84\x97\x9d\"\x94\x14=.\x85SEJĤQ+\xfb\xfa;?\ff8:\x96^\xb9!\x03yeڃ\x854\x1d\xef(\x0f\xcfK\xee\xae\x1c*\xa7\xb8\xaf\x02\x9b\x98\xbaǏ\x9b/0\"ɕ\x1aZl\xe7z\xc2\xcbX\x1ffS\x99\x06}ޗڔc\xa2\xa9\x9dU\x86\xd2\x0f\xa9\x15\x1a\x82\x10\xab^Q\x18{\x9dK7\r\xbbNR\x04\x15Bt\xb5 \xac\xa7\x0ew\x06֢G\xbd\x16\x01\xbfq\xad\xb8*\xa1\xe0\"\\U\xadC\x81\x9d:gz\x0f\x16Fy&j^\x01\x128\xe1[\xa4\xa9u\x82\xe5Kr\xe2\xe3_:q,X\xdfcٖ\xac9a\x00\x92\xf5\xe8\x87i\xa1.a\x80\xd9F\x9fE2\xf67\xd3\xc0\xbc\xb2\xa0\xb0\xd8\x1db:=\x9a?4\xb1\x9f?\xa0\x80\xdf\x13\xe6{\xdb^\\_[C<\x17\x17\x9d\x9e\xac\x8e=n\x8cp\xa1\xb3o\xf8\xde\x11\xf6\x7f:\xf4\xf9\x1a\xbe\xe8:\xde滫\xef\x82c\xd4g\xcf}D\xbeA\xf0|\xa6\x83\xc3UQ\xae\xc04x^\x95\xe8zs\xf7\x1e\nϸ\xbf\xa3Hw\xa6\xb1o\xa4\xb8w\x9c\xf5;#\x03\xe3\x97\xde\x10o\xf74\xbfBƞ\xe6-\xf9\xeeD\xf8\x14+\xf4\x06\t\xc3^\xa9_\x14u\xb3\x11\x01^:%\xbb\xb41\r\x04_\x02!X\xa9\xe6$\xf5\n\xf8\xac#\xca\xe3\xccP\x16iXg\xcc\f\xfe\xc4|F\xfd\xce\x1dP\f\x8at\x95\x82\x92\xa0\x18ޡ\xa1\xc9\x7f\xa4ZF\xef\xd3\x15\x95\xad\xfc2\x99n\xb8VDG\xe5\xf9\xeb\xf1\xfe\r%\xbd\xdd{\xa6\x17\xb7P&\xa3q\x1e\x8b\xa0Z~A\xf1\x1akiҸS2\xf2w\xfc\xc2;&j\xb6\xa2\xf8թ<\x80o@\xfc\xb8ŝ\x8f&\xdf\xf3\xd37l\n\x88\x81\x9f[ \x85\x99\xc1X!Ԩ\x91\xb0\x86\xea5\xdf\\\xaf\x81\xb0?\xc5\xddX\xdf\vZ\x01\xdf\xff\x05\xa9\x9962QkQi\\\x01\xf9x\xae\xcbf\x13w\x9d\b3cx\x94\xf3\x03\xfb\xcc5\xc6n\x18/v\x06\x9c\xbd_\n\xf8\x8c/3\xd6\ao%\x86\x80\xa7ct6\x93\xd9!81\x06~\xa4\xd5\a,\r\x7f\x19\x06\xcb\xff\x01\x00\x00\xff\xffx\xae@\xbaJ\x0e\x00\x00"), - []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4ZK\x93\x1b\xb7\x11\xbe\xef\xaf\xe8Z\x1flWi\xc8HI\\)ޤU\x9c\xda\xc4V\xb6ĕ..\x1f\xc0A\x93\x03\xef\f\x80\x00\x18R\x8c\xe3\xff\x9ej<\x86\xf3\x00\xc9]\xca\xf2\xe2\xb2K<\x1a\x8d\xaf\x1b\xfd\xc2\x14EqŴ\xf8\x88\xc6\n%\x17\xc0\xb4\xc0O\x0e%\xfd\xb2\xb3\x87\xbfٙP\xf3\xed˫\a!\xf9\x02nZ\xebT\xf3\x1e\xadjM\x89oq-\xa4pBɫ\x06\x1d\xe3̱\xc5\x15\x00\x93R9Fݖ~\x02\x94J:\xa3\xea\x1aM\xb1A9{hW\xb8jE\xcd\xd1x\xe2i\xeb\xed\x9ff/\xbf\x9b\xfd\xf5\n@\xb2\x06\x17\xa0\x15ߪ\xbamp\xc5ʇV\xdb\xd9\x16k4j&ԕ\xd5X\x12\xed\x8dQ\xad^\xc0a \xac\x8d\xfb\x06\x9e\xef\x14\xff\xe8ɼ\xf1d\xfcH-\xac\xfbWn\xf4\aa\x9d\x9f\xa1\xebְzʄ\x1f\xb4Bnښ\x99\xc9\xf0\x15\x80-\x95\xc6\x05\xbc#64+\x91_\x01\xc4#z\xb6\n`\x9c{\xd0X}g\x84thn\x88B\x02\xab\x00\x8e\xb64B;\x0fʈ?\xb0\x8e\xb9ւm\xcb\n\x98\x85w\xb8\x9b\xdf\xca;\xa36\x06m`\x0e\xe0\x17\xab\xe4\x1ds\xd5\x02fa\xfaLW\xccb\x1c\r\xe0.\xfd@\xecr{b\xd9:#\xe4&\xc7Ľh\x10xk\xbcP\xe9\xf4%\x82\xab\x84\x9dp\xb7c\x9684\xce\x1f;ϋ\x1f'\x8aֱF\x8f\x99\xea-\r\\q\xe60\xc7Ӎjt\x8d\x0e9\xac\xf6\x0e\xd3I\xd6\xca4\xcc-@H\xf7\xdd_\x8e\xc3\x11\xf1\x9a\xf9\xa5o\x95\x1cb\xf3\x86z\xa1\xd7\x1d8!Ym\xd0d\x01R\x8e՟È#\x02oz\xeb\x03'\x81n\xbf\xff,+\xa4x\xa0\xd6\xe0*\x84(\x95\xa5S\x86m\x10~Pe\x90\xe0\xaeB\x13%\xb8\x8ajU\xa9\xb6\xe6\xb0J'\x06\xb0N\x99\xac\x145\x96\xb3\xb0*\xd2MdG\xa2\x1c\xee\xf9%4\xad4Ȳ\x9a\x96\xac\xd1\xcc\xcf\x10J\xe6\xd5\xed\xf5\x06\x1f\xa5j}H\xa5\xe2\xd8\xe1\x87\x13\xb6\x84\x05mT\x89֞\xb8\x01Dc\xc0ȻC\xc7Y\x80*\xf4s\x12?\xad\xae\x15\xe3h\xc0)\xa8\x98\xe45\xd21\x188ä]G\x15\x99\n0-\xbb\xdf\xeb!+\x1f\xe2\xc01v¬\xed\xcb`\a\xcb\n\x1b\xb6\x88s\x95F\xf9\xfa\xee\xf6㟗\x83n D4\x1a'\x92]\x0e\xad\xe7uz\xbd0<\xee\xff\x8a\xc1\x18\x00m\x10V\x01'\xf7\x83\xd6\xc3\x10-,\xf2\xc8S\x80GX0\xa8\rZ\x94\xc1!Q7\x93\xa0V\xbf`\xe9f#\xd2K4D&݅R\xc9-\x1a\a\x06K\xb5\x91\xe2\xbf\x1dmKXӦ5sh\x9d\xbf\x8cF\xb2\x1a\xb6\xacn\xf1\x050\xc9G\x94\x1b\xb6\a\x83\xb4'\xb4\xb2G\xcf/\xb0c>~T\x06AȵZ@圶\x8b\xf9|#\\\xf2ťj\x9aV\n\xb7\x9f{\xb7*V\xadS\xc6\xce9n\xb1\x9e[\xb1)\x98)+\xe1\xb0t\xad\xc19Ӣ\xf0\a\x91\xde\x1f\xcf\x1a\xfe\x95\x89\xde\xdb\x0e\xb6\x9d\b:4\xefB\x9f \x1er\xaat\tX$\x15\x8ex\x90\x02u\x11t\xef\xff\xbe\xbc\x87\xc4I\x90T\x10\xcaa\xea\x04\x97$\x1fBS\xc85\xe9<\xad[\x1b\xd5x\x9a(\xb9VB:\xff\xa3\xac\x05J\a\xb6]5\u0091\x1a\xfc\xa7E\xebHtc\xb27>^\x81\x15\xdd%\xb2\x00|<\xe1V\xc2\rk\xb0\xbea\x16\xff`Y\x91TlABx\x94\xb4\xfaQ\xd8xr\x80\xb77\x90b\xa8#\xa2\x1dY\xb6\xa5ƒ\x04K\xd8\xd2J\xb1\x16љ\xac\x95\x016\x9e>\xc4)o\x00\xa8e\x1d\xc9x\xd29\xa5\xa3\xf6&G(1,{\x06<9\xbc\xe8\x9f\xea\xa1\x7f귃\x95\x8fk\fje\x85SfO\x84\x83\x83\x1c+\xc4Q\xd9P+\x99,\xb1\xbe\xe4x7~%\b\xc9\tv\xec\x14\x9aLQ\xa0\xea\x19Ur\xa3芍\xa5\x01\xb7\x8e\xa6\x91\x92[t\xf9\xb3\xcac\x0eMH8\x84\x98\xd0\x0f%LJ^)U#\x1bcI\xee\xee̙\xc9\x01\xe6\x84彭\xab\x98K\xbc\xd1$\xd3J9Ŗ\x9a\x92O\x12\x87V\xfc\f_qG\x06\x06\xd7h\xd0G#\xc1\xf6k\xe5=\x84cB&\x9b\x16\x12\x01p*\xc3\xd9*(\x11r\x18\xdf\r8y?\xe0\x84\xa3\xccr\xfc\xfa\xee69\xc3\x04b\xe4}\xe2\xef\xce\xe2Cm-\xb0\xe6>r8\xbfwVs\xa9ݮ\x03\x13\xde#8\x05\f\xb4\xc0\x12\a\xde\x18\x84\xb4\x0e\x19\x8f\x9dd\x04\rƱ\x17\xc1\xd2\x1fe\x92\xda\xc1k\x93L\x80\x91\xe7\x11\x1c\xfe\xb9\xfc\xf7\xbb\xf9?T8\a\xb0\x92B3\x9fDa\x83ҽ\xe8\x12)\x8eV\x18\xe4\x94\x16\xe1\xacaR\xacѺY\xa4\x86\xc6\xfe\xf4\xea\xe7<~\x00\xdf+\x03\xf8\x89Q:\xf2\x02D\xc0\xbcsfIm\x84\r\a\xef(\xc2N\xb8\xca3\xaa\x15\x8f\a\xdc\xf9#8\xf6@79\x1c\xa1E\xa8\xc5C\xe6\xfe\x84v\xed\xa3\xb9\x03\x9b\xbf\xd2\xed\xf9\xed\x1a\xbe\t\xc6\xeb\x9a~^\a6\xba\xb0\xa5\x7f\xc1\x0e\xec\x84[f\xc4f\x83\x87\xb8\x7f\xa2,\xe4f\xc9A}\v\xca\xd0Y\xa5\xea\x91\xf0\x84IN\xc1? \x9f\xb0\xf7ӫ\x9f\xaf\xe1\x9b!\x06G\xb6\x12\x92\xe3'xE\xd6\xc7c\xa3\x15\xffv\x06\xf7^\x0f\xf6ұO\xb4SY)\x8b\x12\x94\xac\xf7!\x00\xde\"X\xd5 찮\x8b\x10 rر=\xa8\xf5\x91}\x92\x88H5\x19hf\xdc\xc9 1\xe2p\xfa\xd2L\xa3\xa6\xd4\x1ew_|\x14\xf5\xa8\xdb\xfbl\x11\xc8#\x91\xf0\xe9\xc2g \xd1O\xbd.@\xe2\xa1]\xa1\x91\xe8Ѓ\xc1Ui\t\x87\x12\xb5\xb3s\xb5E\xb3\x15\xb8\x9b\xef\x94y\x10rS\x902\x16A\xeav\xee\xcbH\xf3\xaf\xfc\x9fK\x0f\xee\xeb?\x9f{zO\xe4\xf9 \xa0\xdd\xed\xfc\x12\x04Rt\xffx\xdfu\x14\x87e\f8\xc74\xe9\xce\xef*QV)\xd7\xebYۆ\xf1`\x8e\x99\xdc?\xd3\xdd!\x9c[C\x1c\xed\x8bX\x03-\x98\xe4\xf4\xbf\x15\xd6Q\xff%\xc0\xb6Ⳍˇ۷\xcfy\xa3Zq\x89%9\x92Ä\xf6\xa98pU4L\x17a6s\xaa\x11\xe5h6\xc5\U00037704\xb4\x16h΄\x7f\xef\a\x93S\x80\x9a\xc9\x06\xba9O\x8a?\x1d\xdbd\x02\xbe~y\xf8TXx\x12\xaf\xf3\xaap\xcf6\x16\x98A`\xd00M\x1a\xf1\x80\xfb\"D\x1c\x9a\t\n\x17(\"\xe8\n\x83\xc0\xb4\xaeɧ\x87(\"C1ƿ\x11\x1ef\xfd\xf9\x8e\x01\x92\x15e\xaaJ-\xd19!\x9f\x11\x9c\x0f#F~_\xa0\xba\x9a]\xa9\xe4Zlb\xb5s\x8a\x94l뚭j\\\x803\xed\xb1\x9c\xeb$\x90\xf74\xe5\xf4\xf9?\xf4\xa6&\r?S`̟jPv\x9c\x1e\x06e\xdbLY)\xe0Ai\xc12\xfd\x06\xad\x9b\xdc^\x1a\xb8\xbe~\xca\x1d\vJyI\xca\x1d\xd2\xe0\\V\x1a\x15=\x06\xf0)3u\xea\x90\xe5e\x85\xfe\x04\xdb@\xd9=\xa5#C\xbe\x8b|\xb9d4\xa7W]N]Z\xf1Q\xcf\xd0\f\x8e\x06\xc3\xf9\x1eUC\xf2\x05\xed'T\x91\xc2\xebU\xc448G\x97\u07b4(쾴\x8eD\x89\x9dvȻB\xff%\x12\x7f=&\xe2k\xbf\x86\xc7K!\x1a\xecR\xff\xa1\xad\v\xc9\xdd\nA\x1b\xd4,[\x15\x02_\xb9\xb7\xbe\x84\xf9\xb5\rĄ\x85\xd6\"\xf7\x15\xb4\xc9\xde\x13\n\xe9E\x893\x87\x05\xad\xbf\xcc^\xe4\vS\xe11\xad\xffRrQ\x95jJf\n!K\xa8\xf9'\x9c\xf4\x8a\x97C\xec@\xae\xc3+PC\xee\xb3PJ\x92\xd7L\xd4\xc8!=\x11?\x91\xca\n\xd7\x14\xe2\x04\x1b\x97\xea8\x91\xbd\xe3\xf9\xdfiIf@\x98\x06<_R\x98\rZ\xcb6\xe7lޏaV(o\xc5%\xc0V\xaauy%\xff\xda\xc6{\xfa\xb4\x12[\xb6r44\x11\xccU\xc9\"\xacۺ\xf6k\xfa\xc6\xf5\xf0\xf9\x80\xe7j\x85\xf9\xb0\xf8D}\xed\x14\x83\x15\xb3砺\xa399\xa3\xd5y\x84\x93V\vNx\xbfw\xb8\xcb\xf4&c\x90\x19\xba\x8b\x16&34\xf9\x0e\xa0?\x18\n\xc89\xe4\xd2X\x96f\xf7ʞ\x19\xfb\xde_\xbd'\x81\x1d\xf9\xbbĶt\x05\xe8J\xd5ɜ\xf8\xd7q\xd96+4$\t\xff\xfe>r\xd2L\xf2\xbe\xd8r\x99\xfaa}Ҡ@)V\x9bb\xdd\xdc\xdfo\xa7\x80\v\xabk\xb6\xef\xce\xe2\xf3#\xba\xcc\xf9G\x84ÍJfE\xe3\xb1x\xeft\x19\xb8\xfbV!\x9f\xfc\xe5>8\x18\xb6\xe9\xa7\x03\xa3\xf1\xee\x1b\x84/\xb3Éx\xd5J\xa6m\xa5\xdc\xed\xdb3\xaa\xb1\xec&\xa6\xfbxȽ\xbc\xf5\xf5\xefSqRT\x85\f\xab\a\xeb\xf6$c1\xfct\xe5\x12-^\x0e(\x9cq\x8e\xf1K\x9a\x9c\vZ\x92\x15 \x03\xe4_?oƟ9\xbc\xe8>\x9d`.V\x91ˊ\xc9M\xb6\x96\xa5\xa4\x0f\xb6\x95\x99>E\xc3Yo7<\xd0\x1f\xe9\xe8\xb2\xea4\xe9\xf4\x9c\xf3\x1e\xed\xf8\xf0\xd7\xefiWݛ\xf8\x02~\xfd\xed\xea\xff\x01\x00\x00\xff\xff\xd9H\xdbA\x14'\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4:Ks\x1b7\xd2w\xfd\x8a.吤\xca$\xe3|ߦ\xb6x\xb3\xe5͖v\x13\xafʔ}I\xe5\xd0\x1c49\x88f\x00,\x80\x11\xcd\xcd\xe6\xbfo5\x80\xe1\xbc@R\xa2\x93\x18\x17\x89x4\xfa\xfd\xc2\xccf\xb3+4\xf2\x03Y'\xb5Z\x02\x1aI\x1f=)\xfe\xe5\xe6\x0f\x7fus\xa9\x17\x8f/\xaf\x1e\xa4\x12K\xb8i\x9c\xd7\xf5;r\xba\xb1\x05\xbd\xa1\x8dT\xd2K\xad\xaej\xf2(\xd0\xe3\xf2\n\x00\x95\xd2\x1ey\xda\xf1O\x80B+ouU\x91\x9dmI\xcd\x1f\x9a5\xad\x1bY\t\xb2\x01x{\xf5\xe37\xf3\x97\xdf\xcd\xffr\x05\xa0\xb0\xa6%\x18-\x1eu\xd5Դ\xc6\xe2\xa11n\xfeH\x15Y=\x97\xfa\xca\x19*\x18\xf6\xd6\xea\xc6,\xa1[\x88gӽ\x11\xe7;->\x040\xaf\x03\x98\xb0RI\xe7\xff\x99[\xfdA:\x1fv\x98\xaa\xb1XM\x91\b\x8bN\xaamS\xa1\x9d,_\x01\xb8B\x1bZ\xc2[F\xc3`A\xe2\n \x91\x18К\x01\n\x11\x98\x86՝\x95ʓ\xbda\b-\xb3f \xc8\x15V\x1a\x1f\x982\xc2\x0f\x9cG\xdf8pMQ\x02:xK\xbbŭ\xba\xb3zk\xc9E\xe4\x00~qZݡ/\x970\x8f\xdb\xe7\xa6DGi52w\x15\x16Ҕ\xdf3\xca\xce[\xa9\xb69$\xeeeM \x1a\x1b\x84\xca\xd4\x17\x04\xbe\x94n\x82\xdd\x0e\x1dch} ;\x8fKXg\x88\xcecm\xc6H\xf5\x8eF\xac\x04z\xca\xe1t\xa3kS\x91'\x01뽧\x96\x92\x8d\xb65\xfa%H\xe5\xbf\xfb\xff\xe3\xecH\xfc\x9a\x87\xa3o\xb4\x1a\xf2\xe65\xcfBo:b²ڒ\xcd2H{\xac>\x05\x11\xcf\x00^\xf7\xceGL\"\xdc\xfe\xfcYTnUa\xa9&u\x19B\xb2;=Ŧ\x0f\xba\xbfj\xac\xd4V\xfa\xfd\x12^~\xf3T4\xd9>@o\xc0\x97\x04IyV^[\xdc\x12\xfc\xa0\x8b\xa8h\xbb\x92lR\xb4u\xd2\xfeR7\x95\x80u+\x18\x00\xe7\xb5\xcd*\x9b\xa1b\x1eO%\xb8-ؑ\xc6\r\xef\xfc#\f\xa2\xb0\x84Y\x83h\x9d\xe6<\xec\x90Z\xe5\xad\xe2Ֆ\x9ed\x11}\x96*-\xe8\xc0?\x9a\xa0%\x1d\x18\xab\vr\ue1212\x8c\x01\"o\xbb\x89\xb3\f*)\xeci\xf1iL\xa5Q\x90\x05\xaf\xa1D%*b2\x10\xbcE\xe56IE\xa6\x02l\x8f\xdd\xef\xcd\x10\x95\xf7i\xe1\x18:q\xd7\xe3\xcb讋\x92j\\\xa6\xbdڐzuw\xfb\xe1\xffV\x83iVcm\xc8zن\x8f8z\xc1\xb17\vCr\xff;\x1b\xac\x01\xf0\x05\xf1\x14\b\x8e\x92\xe4\x02\x1bR \x91p\x8a\xec\x91\x0e,\x19K\x8eM+h\x94\xde\x00*\xd0\xeb_\xa8\xf0\xf3\x11\xe8\x15Y\x06\xd3\xdaB\xa1\xd5#Y\x0f\x96\n\xbdU\xf2?\a؎y͗V\xe8\xc9\xf9`\x8cVa\x05\x8fX5\xf4\x02P\x89\x11\xe4\x1a\xf7`\x89\xef\x84F\xf5\xe0\x85\x03n\x8cǏ\xda\x12H\xb5\xd1K(\xbd7n\xb9Xl\xa5oS\x86B\xd7u\xa3\xa4\xdf/B\xf4\x97\xeb\xc6k\xeb\x16\x82\x1e\xa9Z8\xb9\x9d\xa1-J\xe9\xa9\xf0\x8d\xa5\x05\x1a9\v\x84\xa8\x906\xcck\xf1\x85MI\x86\x1b\\;\x11t\x1c!\xd2?C<\x1c\xfb\xd9\b0\x81\x8a$vR\xe0)fݻ\xbf\xad\xee\xa1\xc5$J*\n\xa5\xdb:\xe1K+\x1f\xe6\xa6T\x1b\xd6y>\xb7\xb1\xba\x0e0I\t\xa3\xa5\xf2\xe1GQIR\x1e\\\xb3\xae\xa5g5\xf8wCγ\xe8\xc6`oBZ\x05k\xb6%\xf6\x00b\xbc\xe1V\xc1\r\xd6Tݠ\xa3?YV,\x157c!\x89wg\xf9\xc3c#\xa9\x12!s8\x7fwVsy\xdcn\"\x12!\"x\r\bFRA\x83h\fR9O(\xd2$;AKi\xedE\xf4\xf4G\x91\xe4\xd1Em\x96\t G\x1e)\xe0\x1f\xab\x7f\xbd]\xfc]G:\x00\vN\xcdB\xad\x17\xf2\xed\x17\x87zO\x90\x93\x96\x04Wo4\xafQ\xc9\r9?O\xd0Ⱥ\x9f\xbe\xfd9\xcf?\x80\xef\xb5\x05\xfa\x88\\5\xbd\x00\x19y~\bf\xad\xdaH\x17\t?@\x84\x9d\xf4e@\xd4h\x91\b\xdc\x05\x12<>\xb0%G\x12\x1a\x82J>d\xec'\x8e\xeb\x90\xcduh\xfe\xca\xd6\xf3\xdb5|\x15\x9d\xd75\xff\xbc\x8eh\x1cҖ\xbe\x81u\xe8D+\xb3r\xbb\xa5.\xef\x9f(\v\x87Y\x0eP_\x83\xb6L\xab\xd2=\x10\x010\xcb)\xc6\a\x12\x13\xf4~\xfa\xf6\xe7k\xf8jȃ#WI%\xe8#|\xcb\xde'\xf0\xc6h\xf1\xf5\x1c\xee\x83\x1e\xec\x95Ǐ|SQjG\n\xb4\xaa\xf61\x01~$p\xba&\xd8QU\xcdb\x82(`\x87{Л#\xf7\xb4\"b\xd5D0h\xfd\xc9$1\xf1\xe1\xb4\xd1L\xb3\xa6v<\xcd^B\x16\xf5$\xeb\xfdl\x19\xc8\x139\x11ʅO\xe0D\xbf\xf4\xba\x80\x13\x0f͚\xac\"O\x81\x19B\x17\x8e\xf9P\x90\xf1n\xa1\x1f\xc9>J\xda-v\xda>H\xb5\x9d\xb12\u03a2\xd4\xdd\"t\xbb\x16_\x84?\x97\x12\x1e\xdaT\x9fJ}\x00\xf2\xf9X\xc0\xb7\xbb\xc5%\x1ch\xb3\xfb\xa7Ǯ\xa3|X\xa5\x84s\f\x93m~Wʢlk\xbd\x9e\xb7\xadQDw\x8cj\xff\x99l\x87\xf9\xdcX\xc6h?K\xad\xda\x19*\xc1\xff;\xe9<\xcf_\xc2\xd8F~\x92sy\x7f\xfb\xe6sZT#/\xf1$Gj\x988>\xce:\xacf5\x9aY܍^ײ\x18\xed\xe6\x1c\xfeV\xb0\x906\x92\xec\x99\xf4\xef\xdd`s\x9b\xa0f\xaa\x81Þg\xe5\x9f\x1e\xb7\x99\x84\xaf\xdf\xc5>\x95\x16\x9e\xe4\xd7yU\xb8ǭ\x03\xb4\x04\b5\x1aֈ\a\xda\xcfb\xc6aPr\xba\xc0\x19\xc1\xa11\bhL\xc51=f\x11\x19\x88)\xffM\xecA\x17\xe8;Ɛ\xac(ۮԊ\xbc\x97\xea32\xe7\xfd\b\x91ߗQ\x87\x9e]\xa1\xd5FnS\xb7s\xca)\xd5T\x15\xae+Z\x82\xb7ͱ\x9a\xeb$#\xefy\xcbi\xfa\xdf\xf7\xb6\xb6\x1a~\xa6\xc1\x98\xa7j\xd0v\x9c\x12C\xaa\xa9\xa7\xa8\xcc\xe0A\x1b\x89\x99yK\xceO\xac\x97\x17\xae\xaf\x9fccQ)/)\xb9c\x19\x9c\xabJ\x93\xa2\xa7\x04\xbe\xadL\xbd\ueabc\xacП\xe1\x1b\xb8\xba\xe7rd\x88\xf7,\xdf.\x19\xed\xe9u\x97\xdb)\xa3\xc5hf\xe8\x06G\x8b\x91\xbe'\xf5\x90BC\xfb\x19]\xa4\xf8Ȗx\x1a\x83\xa3o\x9f\xde8\xed\xbe\xb4\x8fą\x9d\xf1$\x0e\x8d\xfeK$\xfej\f$\xf4~\xadHF!k:\x94\xfeC_\x17\x8b\xbb5\x81\xb1d0\xdb\x15\x82йw\xa1\x85\xf9\xa5\x8b\xc0\xa4\x83Ƒ\b\x1d\xb4\xc9\xdd\x13\b\xed;\x93@O3>\x7f\x99\xbf\xc87\xa6\xe2\x9b_\xff\xa5\xe4\xa2.\xd5\x14̔\x85\xd8r-<ᴏ\x8d9\x8eu\xe0\x0e\xfc\x8a\xd0H\x84*\x94\x8b\xe4\rʊ\x04\xb4/\xd9τ\xb2\xa6\r\xa78\xd1ǵ}\x9c\x84\xde\xf1\xfa\xef\xb4$3L\x98&<\x7f\xa40\xc7O\x8dg$y;\xda\x0e\xa5\xae\x92\xbcTS\xafɲa\x86\aOP\xb4㺿(Qm\xb3N\xae}\xb0#\xa8\xd0yXw\x1f\x06\xe4\x88\uffd8\x8e)\xeb\xbfpv\xa3&\xe7p{Ν\xff\x18w\xc5\xce]:\x02\xb8֍\xcf\xdb\xef\x97.\xb9\xa0\xe7u\x0f\xb3M\xb1\xa1\xf7C_\xb6\xcen\xd3TU8ӏ\x1b\xdd\a\x1c\x01\xab5\xe53\xfe\x13\xad\xc3S\b\x96\xe8α\xea\x8e\xf7\xe4\xfc\xf1!؝t\xc8p\"\xb0\xbf\xa5]f\xb6\xf5s\x99\xa5\xbb\xe4<3K\x93/1\xfa\x8b\xb17\x9e\xe3\\\xbb\x96\x85y\xf8\xce!\xb3\xf6}\xf0*\xcfbv\xc2\xef\x12\xb7y\xe8\xadw\x96\x17>[\x98\xd8\xdf0\xff@%\xfab\xcb5!\xba\xf3\xad\x06EH\xa9\x91\x96\x9e\x04\x82\xeb\xf2\x1a\x84t\xa6\xc2\xfd\x81\x96P\xfa\xb1\xa9\xe6\xdfG:\x8bj=\xa6\xa1c\xa9\xec\xe9\x0e\xf7\xe1k\x91|]{\xda_\xc0\x19\x9f\x11\xd6\xf5qg\xf8{\xdcp\"\x15w\n\x8d+\xb5\xbf}sF5V\x87\x8d\xad=vee\b,\xe1\xe9-mJ\xaa\x90A\xb5\xf3n\xcfr\x16Ï\x87.\xd1\xe2\xd5\x00\u0099\xb8\x9f\xbee\xcaE\xd7\x15{\x01v@\xe1a\xf7f\xfc\x05NjC\x90A\x9f\x1a\xe41\x1e\xe5\xba\nZ\x85:B\xdb\xe9+;\x9c\r\xe4C\x82\xfe\xcc\x18\x9eU\xa7\xc9d\xc0\\\xf4`\xa77\xcd\xfeL\xb3><\xf7/\xe1\xd7߮\xfe\x17\x00\x00\xff\xfff=C\x19\x96(\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4Z͒\x1b\xb7\x11\xbe\xefSt\xad\x0f\xb6\xab4d\xa4$\xae\x14o\xd2*Nmbo\xb6DI\x17\x97\x0f\xe0\xa09\x03s\x06\x80\x01\f\xb9\xb4\xe3wO5\x80\x19\xce\x0fH.\xa9\x925\x17i\xf1\xd3\xf8\xf0u\xa3\xbb\xd1`\x96e7L\x8b\x8fh\xacPr\x01L\v|r(\xe9/;\xdb\xfc\xc3΄\x9ao_\xdel\x84\xe4\v\xb8k\xacS\xf5;\xb4\xaa19\xbeŵ\x90\xc2\t%ojt\x8c3\xc7\x167\x00LJ\xe5\x185[\xfa\x13 W\xd2\x19UUh\xb2\x02\xe5lӬpՈ\x8a\xa3\xf1\xc2ۥ\xb7\x7f\x99\xbd\xfcn\xf6\xf7\x1b\x00\xc9j\\\x80V|\xab\xaa\xa6F\x83\xd6)\x83v\xb6\xc5\n\x8d\x9a\tuc5\xe6$\xbc0\xaa\xd1\v8t\x84\xc9q\xe1\x00\xfaQ\xf1\x8f^λ \xc7wUº\xff$\xbb\x7f\x10\xd6\xf9!\xbaj\f\xab\x128|\xaf\x15\xb2h*f\xa6\xfd7\x006W\x1a\x17\xf0@P4ˑ\xdf\x00\xc4}zh\x190\xce=s\xacz4B:4w$\xa2e,\x03\x8e67B;\xcf\xcc\x18\"X\xc7\\c\xc16y\t\xcc\xc2\x03\xee\xe6\xf7\xf2Ѩ\u00a0\r\xf0\x00~\xb1J>2W.`\x16\x86\xcft\xc9,\xc6\xde@\xf1\xd2w\xc4&\xb7'\xcc\xd6\x19!\x8b\x14\x8a\xf7\xa2F\xe0\x8d\xf1\xaa\xa5\xfd\xe7\b\xae\x14v\no\xc7,A4\xceo<\r\xc6\xf7\x93H\xebX\xadǨzS\x03,\xce\x1c\xa6@ݩZW\xe8\x90\xc3j\xef\xb0\xdd\xcaZ\x99\x9a\xb9\x05\b\xe9\xbe\xfb\xdbq>\"a3?\xf5\xad\x92Cr\xdeP+\xf4\x9a\x03\x12\xd2V\x81&ɐr\xac\xfa\x14 \x8e\x04\xbc\xe9\xcd\x0fH\x82\xdc~\xfbY(dz\xa0\xd6\xe0J\x847,\xdf4\x1a\x96N\x19V \xfc\xa0\xf2\xa0\xc2]\x89\x06\xfd\x88U\x18A'\x18\x04\xe9N\x99\xa4\xea4\xe6\xb306\nke\x8d\xf47\\\xe8\xb3\xd8Wn\x90%\xed\xabuE3?B(\x996\xb2\xd7\x05>\xcb\xc0\xfaDJű\xc7\xda\x04\x97\xb0\xa0\x8d\xca\xd1\xda\x13\x86OB\x06H\x1e\x0e\rg)*яi\x015\xbaR\x8c\xa3\x01\xa7\xa0d\x92W\x18t\xe8\f\x93v\x1d-c\xaa\xc2v\xda\xfb\xbd\x1eB\xf9\xd0\xca\xeb\xf5L0\x85\xa1ۗ\xc1\r\xe6%\xd6l\x11\xc7*\x8d\xf2\xf5\xe3\xfdǿ.\a\xcd@\xb4h4N\xb4\x9e9|\xbd\xc0\xd3k\x85\xe1\x9e\xff\x97\r\xfa\x00h\x810\v8E \xb4\x9e\x8b\xe8_\x91GL\x81#a\xc1\xa06hQ\x86\x98D\xcdL\x82Z\xfd\x82\xb9\x9b\x8dD/ѐ\x18\xb0\xa5j*N\x81k\x8bƁ\xc1\\\x15R\xfc\xd6ɶD8-Z1\x87\xd6\xf9\x83h$\xab`˪\x06_\x00\x93|$\xb9f{0HkB#{\xf2\xfc\x04;\xc6\xf1\xa3\xb7&\xb9V\v(\x9d\xd3v1\x9f\x17µ\xe18Wu\xddH\xe1\xf6s\x1fYŪq\xca\xd89\xc7-Vs+\x8a\x8c\x99\xbc\x14\x0es\xd7\x18\x9c3-2\xbf\x11\xe9C\xf2\xac\xe6_\x99\x18\xc0\xed`ى\xa2\xc3\xe7\x83\xe8\x05ꡨJ'\x81EQa\x8b\a-P\x13Q\xf7\xee\x9f\xcb\xf7\xd0\"\t\x9a\nJ9\f\x9d\xf0\xd2\xea\x87\xd8\x14rM\x86O\xf3\xd6F\xd5^&J\xae\x95\x90\xce\xff\x91W\x02\xa5\x03۬j\xe1\xc8\f~m\xd0:R\xddX\xec\x9dOY`E\a\x8a\xfc\x00\x1f\x0f\xb8\x97p\xc7j\xac\xee\x98\xc5?YW\xa4\x15\x9b\x91\x12\x9e\xa5\xad~\"6\x1e\x1c\xe8\xedu\xb4Y\xd4\x11Վ\xfd\xdbRcN\x9a%ri\xaaX\x8b\x18I\xd6\xca\x00\x9b\x8c\x1f2\x95v\x01\xf4%#\xcax\xd09\xb3\xa3\xefMJP\x8bX\xf6\x1cy\x8cw6\x06\xaaj\x18\xa8\xfa\xdf$F\x1a\xd4\xca\n\xa7\xcc\xfe\x10)\xc7&qT;\xf4\xe5L\xe6X]\xb3\xbd;?\x13\x84\xe4\xc4;v&M\xce(H\xf5@\x95,\x14\x1d\xb2\x89:\xe0\xde\xd18\xb2s\x8b.\xbdYy4\xb2\t\t\x87\x1c\x13\xfa\xb9\xe4x\xdb+\xa5*dc6\xb5\xe2g6\xfd\xa8\xa2\xe30\xb8F\x83>\xfe\a7\xab\x95wƎ\tٺ\x8f\x90r\x83S\x89}\xac\xc8\xdd\x1cS\xcdq;\x84\x13!)\t\xf8\xf5\xe3}\x1bvZˊ\xd0'\x91\xa5\xcfO\xd2,\xe8[\v\xac\xb8\x0f\xd4\xe7\xd7NZ\b}\xf7\xeb\x00\xc2\xfb^\xa7\x80\x81\x16\x98\xe3 \ue050\xd6!㱑܍\xc1\xd8\xf7\"\xf8ԣ \xe9;\xc4GR\t0\xf2\xf1\x82ÿ\x97\xff}\x98\xffK\x85}\x00\xcb)\x13\xf2w\x15\xacQ\xba\x17\xdd}\x85\xa3\x15\x069\xdd>pV3)\xd6h\xdd,JCc\x7fz\xf5s\x9a?\x80\xef\x95\x01|b\x94\xf4\xbf\x00\x118\xef\xc2Fk5\u0086\x8dw\x12a'\\\xe9\x81j\xc5\xe3\x06w~\v\x8em\xe8Ą-4\b\x95\xd8`\x9a}\x80[\x9f<\x1d`\xfeN.\xe5\x8f[\xf8&8\x89[\xfa\xf36\xc0\xe8\x12\x84\xbe\xd79\xc0q%s\xe0\x8c(\n<$\xda\x13c\xa1\x80F\xa1\xe0[P\x86\xf6*UO\x84\x17Lz\n\x8e\x18\xf9\x04\xdeO\xaf~\xbe\x85o\x86\x1c\x1cYJH\x8eO\xf0\x8aθ\xe7F+\xfe\xed\f\xde{;\xd8KǞh\xa5\xbcT\x16%(Y\xedC\xbe\xb9E\xb0\xaaF\xd8aUe!\x15\xe3\xb0c{P\xeb#\xeb\xb4*\"\xd3d\xa0\x99q'ӱ\xc8\xc3\xe9C3\xcdO\xda\xefy\xe7\xc5\xe7+\xcf:\xbd_,\xd6?\x93\t\x9f\x98\x7f\x02\x13\xfd\xab\xce\x15Ll\x9a\x15\x1a\x89\x0e=\x19\\\xe5\x96x\xc8Q;;W[4[\x81\xbb\xf9N\x99\x8d\x90EFƘ\x05\xad۹/\xd9̿\xf2\xff\\\xbbq_g\xf9\xd4\xdd{!_\x8e\x02Z\xddίa\xa0ͣ\x9f\x1f\xbb\x8e\U000b0319\xddX&\x9d\xf9])\xf2\xb2\xbdU\xf5\xbcm\xcdxp\xc7L\xee\xbf\xd0\xd9!\x9e\x1bC\x88\xf6Y,8fLr\xfa\xbf\x15\xd6Q\xfb5\xc46ⓜˇ\xfb\xb7_\xf2D5\xe2\x1aOr\xe4\xb6\x10\xbe\xa7\xec\x80*\xab\x99\xce\xc2h\xe6T-\xf2\xd1hʕ\xef9)i-М\xc9\xfe\xde\r\x06\xb7Y{\"\xeb\xee\xc6\\\x94v[ɴ-\x95\xbb\x7f{\x06Dz\x1b\xd8b8\xe80&\x9d\xad,:\x12's\xcdg\xe0Y\x8a\xdf\x12n+\x89\x88\x86\xb6\x98*U\x88\x9cU`}\x9b\x8c\xc5\xca\b\xb3\x95=\x05\x94\xaaG\x8e\xe1\xf6\xab\x8a=\xbc\xde\x17<\x1c\xf7\xb4C\xc8\xc3\xd1-jeD!$\xab\x0e\x1e\xdb_\x1d%\xab\x99\xff+a\xab5\xd3Z\xc8\xe2\"n\xdb\xfa\xd6\x12\x9d\x13\xb2H$\xfa\xfd\xf2\xfb\xa9\xeb\xc0\xc9sr\xde\x05|\x18\x01\x01f\x10\x18\xed\x89T\xb5\xc1}\x16\xb2N\xcd\x04\xa5\x8c\x94\x15\xc6\xd4z\x85\xc0\xb4\xae(\xaf\v\x99d\xca7\xb5պ\\ɵ(b\xe5tʔl\xaa\x8a\xad*\\\x803ͱK[\xf2\xb8\xf7\v\x85g4\xfe\xa17\xb4U\xf7\x99RezW\x83\x02\xe6t3(\x9bz\n%\x83\x8d҂%\xda\xe9pN\x1c\x13u\xdc\xde^bR\xe1\xe4\x9f\xe1 ܙS\x05\x87\xe88\xe25$^\xb1\x83\xfbHG\xf3K\x1d\x8a\xc1_\x1b\xbaS\r\x11f\xe9\xda\xcah\x8cV\xfcfLZ\xdf\x17\x8f:\x0f\x9et\xdc1<\xf4\xa3\xde@\xc1\xb3\xcaR\xbeP~Ia*<\x87E\xdeC\x1a\xe0\xdaG2\xba`\\]\x9a\xa2;\xacvȻ7\x84k\xea6\xaf\xc7B|A\xd9\xf0xHD\x8d]\x91#ډ9\x94]B\x88\xd1\x065KZ\x04\xf8G\x01\xeb\v\xa3_\xdb MXh,r\xef['\x8b\x1f\x8d\t\x9c9\xcch\xfeu\x0e$]\xec\n\xcfs\xfdW\x98\xab*_S1S\x0eYG\x9b\x7f\x1fj\x1f\x06S\x94\x1d\xe4u\x84\x05q\xc8\xfd\x95\x1b\x94\x845\x13\x15r\xe8\x1e\x9f/f>\x01z\x9a\x8c}N\xf2k\xb4\x96\x15\xe7\x9c֏aT\xa8\xbc\xc5)\xc0V\xaaqG\xac\xf2k\x1b\x8f\xd6E1Y*~\x0eɃ\xe2\x1e\x86<\xfe\xe46E\x93PK\xff\x19\xee\"\x8c\xbe\xa8y\xaeHIcR\xae\xa6\x83|\xda\xd7\xc0\x89\x18\xf6\x80\xbbDk{\x82\x13]\x8f\xd1-$\xba&\xbf\a\xe8w\x86Jr*\xa7i\xfb\x922\xbb\xc7\xf6D\xdf\xf7\xfe\xb8\\\xc4v\xc4w\x8dC\xe8\xeaХ\xaaZ\x1f\xe0\x1f\xc9eS\xafА*V\xa9\x8c\x18\x98\xe4}ͥ\x8a\t\x9d\x846\f\aQ\xb1\x1e\x16\v\xe8\xfe\x94;\x05\\X]\xb1}\xb7\x19\x7f\x83\xa3#\x9d~N8\x9c\xab\xd6WQ\xe49\x92\xb7\x9d\xaeTw?ZH\xdfOOg\xfap&\xdb\xf7\xfdݏ\x11>\xcf\n'\xf2\xce\xe1\x8fC\xae1\x90\xe5@¹`\x11\x7f\xacr\xb9\x8f\x1f.\xf3g\xba\xf7${\x93F\x8f\x9c\xf7d\xc7'\xaf~K\xb3\xeaރ\x17\xf0\xfb\x1f7\xff\x0f\x00\x00\xff\xff;\xa8N\xc3\x13&\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xdc=[s\xdb8w\xef\xf9\x15\x98\xf4a\xdb\x19\xcbi\xa6\x97\xe9\xf8\xcd\xf5:\x8d\xfb}\xebx\xec4\xfb\f\x91G\">\x83\x00\x17\x00\xa5h\xdb\xfe\xf7\x0e\x0e.$%\x90\x84d˛-^2\xa6\x80\x03\xe0\xdc\xcf\xc1\x01\xb2X,\xdeц}\x03\xa5\x99\x14W\x846\f\xbe\x1b\x10\xf6/}\xf9\xfco\xfa\x92\xc9\x0f\x9b\x8f\uf799(\xaf\xc8M\xab\x8d\xac\x1fA\xcbV\x15\xf03\xac\x98`\x86I\xf1\xae\x06CKj\xe8\xd5;B\xa8\x10\xd2P\xfbY\xdb?\t)\xa40Jr\x0ej\xb1\x06q\xf9\xdc.a\xd92^\x82B\xe0a\xea\xcd?^~\xfc\xd7\xcb\x7fyG\x88\xa05\\\x11\x05\xdaH\x05\xfar\x03\x1c\x94\xbcd\xf2\x9dn\xa0\xb00\xd7J\xb6\xcd\x15\xe9~pc\xfc|n\xad\x8fn8~\xe1L\x9b\xbf\xf4\xbf\xfe\x95i\x83\xbf4\xbcU\x94w\x93\xe1G\xcdĺ\xe5T\xc5\xcf\xef\bхl\xe0\x8a\xdc\xdbi\x1aZ@\xf9\x8e\x10\xbft\x9cv\xe1W\xbd\xf9\xe8@\x14\x15\xd4ԭ\x87\x10ـ\xb8~\xb8\xfb\xf6OO\x83τ\x94\xa0\v\xc5\x1a\x83\b\xf8\x9fE\xfcN\xc2B\tӄ\x92o\xb8Q\xbb\x1aD<1\x155DA\xa3@\x830\x9a\x98\n\bm\x1a\xce\n\xc4;\x91\xab\x1e\xa40J\x93\x95\x92u\amI\x8b\xe7\xb6!F\x12J\fUk0\xe4/\xed\x12\x94\x00\x03\x9a\x14\xbc\xd5\x06\xd4e\x04\xd4(ـ2,`ٵ\x1e\xef\xf4\xbeNm\xcc6\x8b\v7\x8a\x94\x96\x89\xc0m\xc1\xe3\x13J\x8f>\"W\xc4TLw[\r\xdb#T\x10\xb9\xfc\x1b\x14\xe6r\x0f\xf4\x13(\v\x86\xe8J\xb6\xbc\xb4\xbc\xb7\x01e\x91Uȵ`\xbfG\xd8\xdan\xdcNʩ\x01m\b\x13\x06\x94\xa0\x9cl(o\xe1\x82PQ\xeeA\xae\xe9\x8e(\xb0s\x92V\xf4\xe0\xe1\x00\xbd\xbf\x8e_\x90xb%\xafHeL\xa3\xaf>|X3\x13$\xaa\x90u\xdd\nfv\x1fP8ز5R\xe9\x0f%l\x80\x7f\xd0l\xbd\xa0\xaa\xa8\x98\x81´\n>І-p#\x02\xa5\xea\xb2.\xff.\x12u0\xad\xd9Y\x1e\xd5F1\xb1\xee\xfd\x80\x02q\x04y\xac\xa88\xc6s\xa0\xdc\x16;*\xd8O\x16u\x8f\xb7O_\xfbLɴ'J\x8f7\xc7\xe8c\xb1\xc9\xc4\n\x94\x1b\x87\xacia\x82(\x1bɄ\xc1?\n\xce@\x18\xa2\xdbe͌e\x83\xdfZЖ\xdf\xe5>\xd8\x1b\xd4:d\t\xa4mJj\xa0\xdc\xefp'\xc8\r\xad\x81\xdfP\roL+K\x15\xbd\xb0DȢV_\x97\xeewv\xe8\xed\xfd\x104\xe2\bi\xbd\x16yj\xa0\x18H\x9a\x1d\xc6VA]\xac\xa4\x1a(\x19;d\x88\xa3\xb4\xf0\xdb洈U\x8b\xfb\xbf\xccq\x99m\xff\x1eG[~\xb3+k\x05\xfb\xad\x05T\xa6N\xfc\xe1P_\xa9\x9ej\x1f6\xcbF\xfb\xd4\x1dE\xb4m\xf0\xbd\xe0m\te\xd4\xeb\a\x1b\xcc\xd9\xc6\xed\x01\x144z\x94\t+D\xd6\xfaؽ\x88\xeeWT\xe0T\x01\x11\xd2$\xe01\xe1\xe0\x11&\x10\x03I\x9a`G\x03ubœ[&D\xb4\x9c\xd3%\x87+bT{\x88F7\x96*Ew#\xd8\n\x1e\xc0\x8b\x90\x15\x81xU\xc3Y\x81$\x8f\n\x05\xf1\xf5\xe7E\x15\xd3VQ\x86]>HΊ\xdd\f\xben\x93\x83\x82\xb4z\xd9\xf5;$K\xa8\xe8\x86I\x95\x12\x03\xa9\xb0kϞwjZZ-\xe9\x81\xec۸\xcc\r'\x91UI\xf9<\xc7\x10\x9fm\x9f\xce:\x90\x02\x1dʸ\x15Omo\xbb\x97@\xe0;\x14\xadI,\x93\x90\xb2E\xd3$\x15i\xa46\xe3t\x1fW]\xa4\xef\x1c\xa5~\x9c`\x9a\x83\x9d%Y\xdd5\xaf\x84\x03Q-\x0e\x06\nY\n\xb0ۨ-Q\xbb\xbeJ\xb6\xae\xef(RȒj(\x89\x14\xa33#\xbb\xb4\x1c\xb4\x9f\xabD\xce\xe8\xf4\xd0E\xb7\x7f\xf4x\b\xa7K\xe0D\x03\x87\xc2Hu\x88\xcc\x1c\x94\xba\x96\xa3XGP\x99ЦC\t\xe860\x01\x92XN\xdfV\xac\xa8\x9c\x87a\xd9\x13\xe1\x90R\x82\xb6\xda\x04]\xe6\xdd\xd8&\xc9\x1c\xf9\xfd$Sڣk3b\xb5\x0f/\xa5Q\xba\x96\xa1\x86\xbb\x96Dm\xa7{\x0ft\x8b\xffn\xe4\xe4\xb6\xff\x7f\"6\x18\x93\x13\x98vB\xfe\t\xba\x9f\xd9<=ʷ\x18ၾ$w+\x02ucv\x17\x84\x99\xf0uN\x12(\xe7\xbd9\xfeĴ9\x9e\xe93I\x93#\x13g\"L\x9c\xe2OH\x174\x19O\xdebd\xd3\xe4\xaf\xfdQ\x17\x84\xad\"\xd2\xcb\v\xb2b܀\xda\xc3\xfeI\xaa>P\xe65\x90\x91c\xf5\b\xe6\tLQ\xdd~\xb7.\x8e\xee\x92`\x99x\xd9\x1f\xec|\xe3\x10A\f\xcd\xf3\f\\\x82\xf12SPc\x1cN\xbe\"6\xbb/\xe8T_\xdf\xff|\x18+\xef\xb7\f\xce;\xd8Ȍйv\xbd\xb7\xa3\xfe\xfa|T\x10~A\x1f(\x06U.\xe7rA(y\x86\x9ds]\xa8 \x96>4tΘ^\x01&\x7f\x90Ϟa\x87`\xd2ٜÖ\xcb\r\xae=C\xc2\xf5O\xb5\x01\x0e\xed\x9a|X\xec\xf0d? \"0\x86\xcfe\x03\u05fc($r'閩KB\v\xb8?a\x9bY\xacҟ\xa3\x9f\xfaD\x0e\xf8I;ZZ\x89\xa9\x98\xcfij@\x99\xc9%\xa8k\xdf(ge\x9c\xc8\xc9ȝ\xb8 \xf7\xd2\xd8\x7f0@\xd3\xc8(?K\xd0\xf7\xd2\xe0\x97\xb3`\xd4-\xfc\x9c\xf8t3\xa0\xa0\t\xa7\xe5-\xc2\xfa9?g\xd3,\xb7E\xdc3M\ue10dW\x1cJ2\xa7\xc2\xf4\xae\x9b\xceMT\xb7\x1a\xd3uB\x8a\x05\xda\xcc\xe4L\x1e\xdfR\r\xd0\xfd\xe2I\xfd\x84_\xad\xb1p\xbf\xb8$3\xa7\x05\x94!\xb2\xc4\xec'5\xb0fE\xe6|5\xa85\x90ƪ\xf0<\x8e\xc8T\xac~7DZO\x9e\xf5\xee\xb7\xef\x8b\xe7\x98/XX\x93\xb3\xf0\x10\x8c\xac3p\xe0uw9\xbf\x9f\x85\x95ٌ^\x81\x13f\xbb\x8e$Gǻ\xe6 \xe5\x05\xe8@+\x8e.\xce,uiY\xe2\x11\x1a\xe5\x0fGX\x94#x\xe1X\xd5\xd0[\xbb3\xc15m\xacZ\xf8okiQ\x9a\xfe\x974\x94)}I\xae\xf1\xa4\x8c\xc3\xe07\x9f\x87\xeb\x81ɘ\xb2\xb1SY\xfe\xd9Pnm\xbfU\xe0\x82\x00w\x9e\x80\\\x1d\xf8E\x17d[I\xed\xcc\xf6\x8a\x01\xc7\xf3\x8a\xf7ϰ{\x7fa\xa7\x9f\x9d\xb2\xafd\xde߉\xf7·8P\x18\xd1ᐂ\xef\xc8{\xfc\xed\xfdK\\\xa9LN\xcd\xec6`њ6y\x1c*\x92\xc9\xfa\xae\r8\xa6\x9f\x9b\xef\x92\xf2\xdeɞ\xdam\x16\x8b6R\x9b\xcf\xe9\xbc\xe1\xc8z\x1e\u0088\xa1g\x9cȱ\xcdF\f>\x8f\x16\xf5\xbdu\"W\x06\x94\xcf%:\x1b\x10\xe2\x8f\x17Ff\xa9S\x99\xfebc2\x90\xc6\xfc\xaeE\xf0\f7\xb9\x83\x9b\x9c%\x1e\xe3\xb0Z\xbc\x1c\xe9\xed\xdf~\xef\xe53\xad\xe4ڿ\xfb\x1bym\x87\xba\x90uM\xf7O5\xb3\x96z\xe3F\x06\x9e\xf6\x80\x1c\xf5պEyε\xc8\x1d\x0f\xe1\xf9喙\x8a\tB\x83\xda\x00\xe5\x19\x8a\x92F\xa6rةVQM\x96\x00\"\xa6\xe8\x7f\x04W\xa2f\xe2\x0e' \x1f\xcf\xe0zDt\x9d\xd3ٽ\x894\x89\x94\x8f\x1f\x9c\xc9jdI\xb6\x15(\x180\xc6a\xde\x1d=U!M/eq\x84C\xda\xc8\xf2'MVLi\xd3_\x82&\xadΥ\xf5\x91\xe4\xb3\xeb\xfe\xcaj\x90\xad9'\x82o\xbbi\x06g\xcd5\xfd\xce\xea\xb6&\xb4\x96\xad3\xe6\x86\xd5\xf1TףwK\x99\x89\xc7V\x98\xbf1Ғ\xa0\xe1`\x80,a\x95>\xefM\xb5B\n\xcdJP\xa1J\xc1\x91\x8dI+\x98+\xcax\x9b:%J\xb5c#`q\xab\xd4I\x01\xf0\x177\xb2\x97w\xac\xe4v\x88\xa0̽\xe3A\x1a\x10\xb6\"\xcc\x10\x10\x85\xc58(\xa7\x92q\n\x8f\fD\r\xcb\xd5sy\n\xdc6\x10m\x9d\x87\x80\x05\n$\x13\x93)\xb7~\xf7O\x94\xf1s\x90\xcdr\xde'\xa9\x1e\x81\x96\xa7\xe4h~\xed\r' t\xab\xf0\xf0\xdf\xe9\x8e-\xe3yk\xb6\x94#\x9c\xb6\xa2\xa8\x00\x95\x90\x18\xea\x06\a\x9e\tm\x80\xe6\xf2\x82\xf5\x8aZ!\x98X\xe7\xd1.;\x11\xda5\x87\ua954\x1c\xe8\xf8)d\xd7,\xae\xdf@\x13\xfd\xdaM\xf3BM\xd4\x11\xc1\x1d\x9b#\x1d\xb2)j\x95\x16\xa1\xc6@\xdd8\x91\x93D\xb5\xa2o]Π\x88\x8e\t\xc3\xfd*^3\xbef\x82e\xd0v@\xd7;\xc1L\xdfy\xb4 \xce\xea<\xda\t\xa2;pJ\x86\xedn\x00\xc0\nh\x88Cp\xed\x91k\x8ep$\x97@hYB\xe9r\x97\xd6\x15\xf1a\x89+|\x1b)nH\xee\xeexO0\x8b\xb2\xa1\r\x82N\xccê\r,Z\xf1,\xe4V,0\x18\xd7G\xeb\x90\x13\xb3T/\x9dޜ\xac\x8c\xe6\xf5K\xbe\x9a\x9e\xd3BC~\xcd\xe7\xa9\xe0?\x9dA\xcbd\xf3\xcdQ\t\x8f).\x98\xd3k\xae\x00{\xe4\xc7\xd9UL\xcd?1\xd8\x1fJ߸b\xe9\x17\x95\xc5ݥA\xf5\x9c\xc2m\x05\xa6\x02\x15J\xb3\x17X\x92^N\x9e\x90v\xc1K\xac\x93\xb3L\x15\\dW\xfe\xb9W9\x87\xd1M\xcb\xf9\x85\xe5m\xda\xf2d8l$\x8a\xd8!geՏ\xa5=\x86\x9c\xea\x8bl<\xf6+-\x86\xf5\x85\xb1\n\"\x14\x18\xca0\xb3\xa7qj\xbfXX\xda;\xdf\x1f\x96S`\xfe/,\xff\x0f/=̨\x94\xc8Gcn\x95fDb\x02V\x82\xc1zh\xec\xea+|?_\xe8\xfbc\xe1\xd4@\xfd\xa5\xf1\x123\xea\xc2f\xa05\x01g\xaf\xde\x04\xadA\xab\x9d+\x10\xed\x80\xcf\x19\xda\xf1ׅ\xbb\x05\x11\xc0\xa4\xf8\xf5k\x05A|}\xf5>\xd3\xe4\x9fI%\xdbDU\xdf\x04\xcaf\xaa;\xe67<(\xf4\xf0\a\n`\xe8\xe6\xe3\xe5\xf0\x17#}\xd9\af\xd1\x12\x800(\xea2\xb3L\x94l\xc3ʖ\xf2 \xb5\xdd\x1d\x02\xc7@\x1d\x9f%\xa0IE\x04\xe3\x8e\x01\xc3\xf8\x01Ñ/\x8d;\x969Z\xc5M\xfb\xa2y\xd5!'ׄ\fk>F\xac\xe1\xb1\xc7\x17\xafR\x05\xfb\x87\xd4z\x1c_\xe1\x91\x13I\xccTs\x9cPÑY,\xf6\xe2\xf3\x96\x9c*\x8dcb\xee\xb3Ud\xbc~\x1dF\x16~\xe6k.\x8e\xc1\xce\xd9\xeb+ް\xaa\xe2mj)2+(^\xaf\x142/\xfa<\xa9\x14`>`\x19\xaf\x82\x98\xad}xQ@sҖfk\x1a\x8e\xa9d\x98\xa5N\x9e\x98\xbdY\xad\u009bU(\xbcm]\xc2$\x17M\xfexL\xe5A\x8c\x93~\xa1M\xc3\xc4\xfa\x90)rYg\x92m\xe6Y\xe6~o!\x03\x9e\xe9\x873]t8\x12\xfa\xba\xeb҉H2\xa4-\x990\xf2\x92\\\x8b\x9d\x87\x9b\x80\xd3\v\x1f\x854\a\x17\xd9첶\x8c\xf3\xfem-\x04;\r\xcaߙԴv\xab\x1a\xf3\xf6\x93t\x95j\xe0\x94\x9f\x148~ك\xd1ώ\xbe\xa5\xe7_\xb7ܰ\x86\x83\xf5\xe86\xacL\xde!3\x15\xec\"\x92\xff&\xf1\x86\xd4r\x87\x90\xbe]\xf4\x9eQ\xec\x9eq\x926\xbf\xc9\x13\xb6\x97Q\xcc~\\\x11{\x06\xcdrE\xf1\r\x8b\xd5߰H\xfd\xad\x8b\xd3g8k\xe6\xe7\xe3\x8a\xd0O>\x81\tG\xfd\xf7\xb2\x84\a\xa9\xcc\\p\xf2\xb0\xdf?q\x92\xda\v\xd8$/\x89\b]\x13\xbb\xc4\x10Ç\x17\xa7m*}\xe8\x19\xdc\xe9_di\xd76w\xc6\xf2\xb8\xd7\xfd\xe0\xae\xf2\n\x14\b\xf7\xcc\xc7\x7f>}\xb9\x8f\xf0S>\xaf\xf7\x8c\xf7\x9e\x97p\x1eL\xe9\x91\xe3\x8f\xe6|1\x93\xc3\x16\xfa\x00\xaf|.B\x1b\xf6\x1f\xf8\xaa\xdb\v\xd2A\xd7\x0fw\b#\xf8i\xf8L\\\xac\xa2\x88'\x96K\xb0\x16+\xa2jT,\xeeV\x03\x88Ê\xdf\xfe3JP\xba'\xb3\x82\xc5d\xa1\xc6\xcb\n\xdeÝ[\xc7\xd8,\x9f\xac\xd3(vD:\x8e\xac\x98*\x17\rUf\x87l\xa3/\x06k\bff*\x9d3\xaaX\x0f\x9f\x01K\xa27\xbc\xfe\x85g\x91\xbbfxڻ\x8f\xbbS\xd61~\xffd\xf6\xe6\xc9+\xaec\xdcb/\x10S\x89\xcf\xc9\x02\x93WK\x93yM\xf4\xf0\xed\xa4\xb4\xcbc\x1c=\xad\xe7l\x14\x1dRM\t0v<\xaa:-h\xa3\xabēK/\xd3u\xf8\x1a\x99\xa1\xa6}\xc9&\x1d\x80\xc1>YQ\xf5\xb4\xd5\x16\x82>\v\xdbFi\xc5a)\xddnm\xb3\xab{a\xfc\xa2\x97)x\x9b#\xe1\xcc\xe7\\N~\xc8šgD\xfd`\xf6˪\xb6CL\x9dp\x18<\xeb\xdae\x14\x19O;\xb1\x99π\xe4\x19\x8c\x13\x9e\xfe@|\xe5\xe2\x8a$_\x04\xc9|\xf5\xe3\x0fE\xf4\x84V\xd3E\x05e\xcb\xe1\xd47\xff\x9ez\xe3\xe7_\xfd\v\xb3e\xbc\xfbg\x91\xdd3\xd0\xd6g\x1e\xbe/\xe8)\xe1!\xf7)9\xe6\xf0ap\xe0\x9e\x17+\xdcK\x94E\x01Z\xafZ\x1e\xaa\x94\n\x05\xd4@\x19\xba3\x1dW|T\x9dM\xdbpIKP7R\xacX\xe2\x84d\x80\xd6\xff\x1at\xde\xe3\xd9\x02?\xb6\xaa{\xdaq\xf2Y\xbc\x17i\xae\x86*\xca9\xf0O\x8c\x83\xfeYn\x85]W\x86@>\xa4\xc6\xf5\xeee\x15\xad\xb2f}GD[/\xad\x93\vƌ\a\x8b+\xa9\xa6+\xa4\x1dޙ0\xb0\x86T|\xbdU\xcc\xc0SC\x95\x06\\Q\xc6\x0e~\xdd\x1b\xe2\xa2\xcf\x15\xa7kW\nW\xb2\x82\x1a\x88\x06\x18g\x18[>\x8e\xd7\b\x8b\xef\xb02I\x8e$\xbd\xb2\x85z\xecJƨX\x8f=/\x9a0\xd5\xc9\aF\x9dE.hc\xf0\x02\f\xd2\x11\x89h<\f|\xb4w\xef\x8d\xd1\x01\xd8qN\xf3e̾`N\x1bZ'\xa2\x84y\xbdss\b\x06\x9f\x05Ve\xaf\xee\xae\xff\xc0b,\xb0#[\xaac1u\xd2\xf7\xee`;0\xe8\xaa[\xd0P\x12\u0600 V\x14)\xe3PNq\xeaWL$\xab\r\xa8\x9ft\x84\x83\x95\x80\x96ş\fU&.\xfdЏYIUSsEJj`aG\x9f溥\x9fIU\xea\xc4\xe3@\xbc\xd9\xe6ţ\b\xd7n\xac\xf5s\xf7\xd1jК\xaeC\x10\xba\x05\x05d\r\xc2\xe2=\xe6\x16\x93\x1eS\xb8\xd2\xe7\x8dE,-\xb5(\xa4\x85i\xa9\x9f\xc0\xb9p\xf1\xf44\xbcO\x8cQ\xeczTE\xa7U\x85\xbf<\xf8\bT\xef?w}\x80\x8bO\xfd\xbe>I\xecv\xec\xceF\xa8+\xf0\xc4\a\x8f\r\x8b\x91uJ\xa6\x8dę\x8f2'\x95\x94\xcfYn\xf6\xe7رK'1\xe1X\t\xafL.ekz~\x8eGxb\x99\xf8\xfc\xe7+\xdb\x17\x84y\xed.P\x8d\xe5V\xf3<\xbd\xcf\x03H1\xbc\x95\x86\xf2`d,_\xc6\x0e\xd5\xc4\x03\x02O\xe1\xf1d\xcew\x17\xfb\x90\xf7^e\xef`W\xddS\x9e^\x13t\xd7\xc7\xc7Ҫ>\xeb\x97\x04\x12_\x01\xed|\x92\xb17\x17\xe7\xec\x1fB\xfd\x84\x8b\xca\xc0\xf1\xe7\xae\xf7\x18\x1e\xdd2\x9d\xc3\f\"\x1di\x12\f>L\x15%ㄥOx\xa9ME\xf5\x9c{\xfa`\xfbD\xb7\xa3g\xae\xa2\x13\xfa8\"\x95\xe9{\xae\vr\x0f\xdb\xc4W\x87,<\xfdB\xa9Jt\xb9\x13\x0fJ\xae\x15\xe8C\xa6[\xe0}F&֟\xa4z\xe0횉/\xe3\x95\xdfS\x9d\x1f\xa82\xcc2\xad[Ob\xecM\xb0q\x89\xdf\xe6G\x8f\xff\xc0\x04\xe5\xec\xf7\x94.\xef\xff87Ä\xbek<\xf2N\xb1P\x01\xf1s\n\xd0k\xe8\x9ft\xcf\xfc\x84y/ɽL\x8a\xb1? fC\xa0L\x93%h\xb3\x80\xd5J*\xe3\xf2\xf7\x8b\x05a\xab\xe0 Y\r\x81q\xa2{͞\xb0T\xe2=\x1e\xbd\x05\x87e\xe5S\x89\n\xad\x0e\x86\x9c5ݹ\x8c$-\n\x1b\x13\xc0\amh*6y\x91\x9e\xc6P\xd5\xcbJ\x8e\n\xb9\xeb\xf7\x8f9\xbe\xa8>\x10\x9cC\x1d^gw\x06\x9d\x8f\x9di\r^\xcb \xdab\xef\x14eB\x9c\x1a\xbb\x1b\x0f\xbb\xf3L\xcd\xd7\beL=\xfa\xfd\r\x1e\xe2\xf6\a\xac\xbe\x93%[QQ\xb1\x1e\xbd\xd0V)ٮ\xab\xc0\x9bc\x0e\x11)[\x8c\x9c\x1bT\x05:\xfc\xc7!\xa6U\xa2wh\xe7k,ƴt\\\uee0f\xf2\x02E\xad\xba\x8b-\x9d\xaa\x9a\xb0\xf9\xd9Y\xc2\x11\x88\xb3\xb6?\x01\x91\xea\x9d(&\xaf\xe0\xf8@\x9bM\xdc՝\xc2P\x12\tQ\x1b\xbf\x1a\x12\"\xc41$\xf4}\x89.\xe2\xf9a02棜\x88\x8ei'\x06\xb78\rj~\xd3}'h\xe8\xee\x1c\x87\x0e=\b\xfeNJ\xbb\r \x1c\x13\xf9\xe2\xdc\xe9\xb8\xf7ǍX7\xd1ۺ=9v\xfd\xb6\ac\xef\n\xa4\x8db\xbbiB\xbc\xf9\xf7l\x95\x92\x17\xf7\xbf3-9\xfc\xc3\xc1\xafo|\x95qK\x95`b}\x12F~\xf5c\x13\xf1\xbc\a{Έ>\xac\xfc\xd5b\xfa\xa4Y:\xf8\x88\f^\xf6\xf0\xecg\xf2_\xfe/\x00\x00\xff\xffP\a\xb5\x16Cm\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec=]s\x1c)\x92\xef\xfa\x15\x84\xeea?B\xdd^\xc7}ą\xde|\xb2gO\xb1\x1e[ai\xf4\xbctU\xb6\x9aQ\x15\xd4\x00\xd5r\xdf\xde\xfe\xf7\x8dL\xa0\xbe\xba\xe8\xa2Z-ygǼت\x86$\xc9L\xf2\x03\x12X,\x16g\xbc\x12\xf7\xa0\x8dP\xf2\x92\xf1J\xc0W\v\x12\xff2\xcb\xc7\xff6K\xa1\xdelߞ=\n\x99_\xb2\xab\xdaXU~\x01\xa3j\x9d\xc1{X\v)\xacP\xf2\xac\x04\xcbsn\xf9\xe5\x19c\\Je9~6\xf8'c\x99\x92V\xab\xa2\x00\xbdx\x00\xb9|\xacW\xb0\xaaE\x91\x83&\xe0\xa1\xebퟖo\xffk\xf9\x9fg\x8cI^\xc2%3\xd9\x06\xf2\xba\x00\xb3\xdcB\x01Z-\x85:3\x15d\b\xf4A\xab\xba\xbad\xed\x0f\xae\x91\xef\xd0!{\xeb\xdbӧB\x18\xfb\x97\xde\xe7\x8f\xc2X\xfa\xa9*j͋N\x7f\xf4\xd5\b\xf9P\x17\\\xb7\xdf\xcf\x183\x99\xaa\xe0\x92}®*\x9eA~Ƙǟ\xba^0\x9e\xe7D\x11^\xdch!-\xe8+U\xd4e\xa0Ă\xe5`2-*K#\xbe\xb5\xdcֆ\xa95\xb3\x1b\xe8\xf6\x83\xe5g\xa3\xe4\r\xb7\x9bK\xb64ToYm\xb8\t\xbf:\x129\x00\xfe\x93\xdd!n\xc6j!\x1f\xc6z{Ǯ\xb4\x92\f\xbeV\x1a\f\xa2\xccrb\xa0|`O\x1b\x90\xcc*\xa6kI\xa8\xfc\x0f\xcf\x1e\xebj\x04\x91\n\xb2\xe5\x00O\x8fI\xff\xe3\x14.w\x1b`\x057\x96YQ\x02\xe3\xbeC\xf6\xc4\r\xe1\xb0V\x9aٍ0\xd34A =l\x1d:\x1f\x87\x9f\x1dB9\xb7\xe0\xd1\xe9\x80\n»\xcc4\x90\xdcމ\x12\x8c\xe5e\x1f\xe6\xbb\aH\x00F$\xaaxmH8\xda\xd67\xddO\x0e\xc0J\xa9\x02\xb8\x80vX4\xb6\nu%\xa0\x80\xe6\f\xddN\x8d\x16FH\xb6\xae\xd1#]2\xd4\x12Q\x19\x11\xd2X\xe0\x11a>\x01\xef\xe0kV\xd49\xe4WEm,\xe8\xdbLU\x90\x87E\xa6Q͜\xca\xc3\x0f\a!\xfb\xf8\xa5\x10\x19 \x1f2WiA\x8b<1\xd1nC\x99]\x05n\xcd\tY\xed\x87\xd0\xc6(\x93\xbaŀņ\xe7\x7f<\xbf \t\xe8\xf7\xde\xef\xc70\xae\xa1!\xd3,\xddL\x16\x7f\xbc\x85\xb0PF\xa8;\xa9\xa3f\xf0\x9dk\xcdw\a\xb8\xde,\xa6\xbd\x00\xdfc\xb0\a\x9c\x97\xa1\xda7\xe2\xfd\xb0\xff\xdf\"\xf7O\xcboC\x8b\xce\\H\xe4s!\x8c\xed\xb1ٸU,$\xebX\b\xe9\t$\x1dLT\x93S\\\xfd'!\xe6I\xe7Nl\xb24\xb2\xe9'\xc0\xbf\x14%7J=\xa6P\xef\x7f\xb1^\xbb\x84\xc52\xda\x18a+\xd8\xf0\xadP\xda\f\x97I\xe1+d\xb5\x8dj\x16nY.\xd6k\xd0\b\x8b\x96\xf9\x9b]\x81C\xc4:\x1c\xbe\xb0\x8eʊV\x18\x8c\xabe:\xb2\x94\xa8\x11\x1b\n\x05\xa8Q\xa8\xce\xc1\xc1Ђ\x1c\x88\\lE^\xf3\x82|\t.37>\xde\xe0\x17\xd3j\x13\x02\xb1\x87\x7fT\xaa]q\x0eM\x18$2\xb1\xb7\xea\xa5$\xa0\x8f_bl\xb4_5N\x89\xb0\x94p\xb0od\xa6\xae\v0\xbe\xbb\x9c\xdc\xe4V']\xb4\xccrk\f\x05_A\xc1\f\x14\x90Y\xa5\xe3\x14J\x91\x03WR\x95n\x84\xb8#Z\xb6\x1fm\xb5\x83\x99\x00\xcb(\xc4݈l\xe3\xdcW\x144\x82\xc5r\x05\x86VExU\x15\x11\xd3ՖI\xe1\xf0\x9dM鍶$h\x90!ܘ.iK\xa2~n\xcb(\xd9۹٧\xfa\xf8:\xff(\xbe\xbf%\xa2\a\xabs\xa4\xb0Oh\x12F\xfb\x05\xc9\xf3!Jz\xa4\xb8\x00\xb3\xec\xac\xce\t\x1b\xbe\xa60\xb4\xe7?\xeem\xa5\xec\x11\xe5\xd7Ż\xe3&\xcc\f\xd6MΩ\x97e\\\xd3Ϳ\b\xdf\xc8d\xddz\x8b5\x8bg\x1f\xbb-/hW\xc03$\xbf`kQX \xa7j\nQ6\x83s\xa7$P\xaa\x05f\xb4Il\xb3͇f\xef(\xa1ŀVC\x00\xceA\x0fQ\x0e\xf1 \x01$k\\\v\xda4\x15\x1aJڌ\xa5H\xb2\xfb\x85\\\xc1w\x9f\xde\xc7c\xcfnI\x94ԽA%LZW\xde\r\x1c\xa3.\xae>T\t\xbf\x90\xbf\xd6\x04\x82n\x13\xfe\x82q\xf6\b;\xe7bqɐo)\x8b\xff|\xf8*\fv,s\xf6^\x81\xf9\xa4,}yQ*\xbbA\xbc\x06\x8d]O4A\xa5\xb3$H\xc4n\U00088ce5(\xa8\r?\x84a\xd7\x12C2G\xa2\x19\xddQ\xae\x90\xeb\xd2uVֆ\xb6Z\xa5\x92\v\xb7,6֛\xe7\x81\xd2=\x16\x9c\xa4c\xdf\xe9\x1d\x1a#\xf7\x8b\xcbZ*x\x06yآ\xa3t\x1an\xe1Ad3\xfa,A?\x00\xab\xd0,\xa4K\xcb\fE\xedG6_\xbc\xd2=\x87n\xf9\xbax\xacW\xa0%X0\v4k\v\x0fŪ2\x91.\xde&\x8c䜌\x95\x05\xce\xf5ĚAZ\x92\xaaG2r\x0eWO%\xd63\xc9D^\x04\xb9]IR\xd0Ml\x9dg\xbdf\xca\xcd1*\xa63\x16\xe7\x02\x94\x9c\xb6\xd6\xfe\x86\x96\x9ef\xe3\xdfYŅ6K\xf6\x8e2{\v\xe8\xfd\xe6\x17&;`\x12\xbb\xadh\x95\xfd\x97Zly\x81\xfe\a\x1a\bɠpވZ\xef\xf9j\x17\xeci\xa3\x8cs\x1b\x9aM\xbb\xf3Gع\x1d\xe5\xa4n\xbb\n\xeb\xfcZ\x9e;_fO\xf14\x8e\x8f\x92Ŏ\x9d\xd3o\xe7\xcfu\xeffH\xf4\x8c\xaa=Q.y\x95.ɔ7;'\xd0\xc0`=8DظI \xc5\x00a\x8a\x02ɢ\\)\x13I\x16\x89\xa0\x95 \xe87\xcaX\xb7\x0e\xd9\xf3\xf7G\x17*UX\x9cd|mA3c\x95\x0e)\x99\xa8\xf8S\x96\xe2\xbb\xe5n\x03\x06\xfc>\x94_\xf4t\x801\x8a=ou\x83\xb3*\xe7n/\x8c:\xe2\x19yOԶ\xd2*\x03\x13͋hK\xa2m\xeaQp\x9f\x0eͺ.w\xd1\xdf:Ik\xa7,J\x872ϑG\xd2\x1d\x11\x19}\xf8\xdaY\xa2F\xed\x82\x7f\xa7H\xeb182:\xafQ\x96|\x98\x0e\x9c\x8c\xee\x95k\x1d\xe6\x98\a\xe6\xc2-\xfdP\x93Ι\xe3u4\xa2\xfc\xcf\xe6ڔB^SG\xec\xed\v\xbaC^\x8b\xc7ң\xc6\xca\xf1N\xfaU\xe8\xac\xe5^\xf3\xc1\xe7\xd4)\xda\xf8\xd1\xd0c\xee\xfe\x9e\by\xd7R\xd9\xce2\xceL'\xbaR\xf9\xef\f[\vml\x17\rs \xb1j\x14\xd4\x11\xa1\xa7\xfc\xa0\xf5ё\xe7g\u05fa\xb3\xa0\xb8QO>qzN\xbc\x1dH\xba\xe1[\xf0\x99\xab 3UKZ\nC=\x80\xdd̀\xe8X\xe3\xac@\xa2\xbd\xeb4\x96u\x99N\x90\x05I\x92\x90\x93\xebf\xdd&?p\x91\xb6nŎc\xab=\x94\xc39V\x8e\x9fG!\xc1\xb3\x9bN_\U000af8acK\xc6K\xe4!\xb9\x1d\xa2\x84&\xa3ޱ\xbbI\xfb\xc4\x16d\xb4\xac\xc2YV\x15`\xc1\xa7m\xce\xc0#S҈\x1c\x1a\xd3\xefE@I\xc6ٚ\x8b\xa2\xd63\xb4\xeal\x92\xcf\r¼69}d\x95\x8eȂH\x94\xb8\xce>\xc3\v\x9e\xd6\xf8\x95\x9e\xe7Ǧ8\x8c\x1a\xe6\xfb\x8b\x95\x16\xca\x1d\x068\xbd\xcb\xe8ӎ\xb9\xdc}\xf7\x19\xbf\xfb\x8c\xdf}\xc69\x1d}\xf7\x19'\xcaw\x9f\xf1\xbb\xcfx\xb8|\xf7\x19S\xcaw\x9fq&\"\xdf\xcagL\xc1pAk\x9c\a*$a\x95\x98\n1\x85\xf6D_>\xe9ǟ\xd58I.\xf3\xf58ȑC<\x91\xe3\x171\xaf\xa35^Mr3\xce\xc00w\xdc)\xca\x04\x87\xf9\x04\xa7g\x02\x02\xa7?=s}\x10\xf2\tO\xcf\xf8!\xa4E\x18G\x9d\x9d\tD\x9a\x7fz\xe2\xc2'\x11\x95\xc0\xc3V\x8aK\xff\x88\x8d1&I\tx|\xe3\xe4\xf7\xbd\x8c\xc9\x17\x90\xa5W9\x913K\x9eFY\x7f\xfe\xc7\xf3_\a\x8bN˔(\x1b\xf6i\xeb\xd4xL?b,\xdfM\x8d\xecg\xa9\xfez\xa6\xc2Ie?\xf5DMC\xe4\b\xbc\xbeX\x0f\xa8\xfck\xd27\x16\xcaϕ\xb7\x96'8a\x7f=\x02/\xe9\x8c=7;\x99m\xb4\x92\xaa6~M\ba\xbd\xcbܽ\x03\x01dL\xd8G5\xc8\x7f\xb0\x8d\xaa#\xa76&H\x9b\x90E\x9bF\x90^R\xadO\x8c\x00˷o\x97\xfd_\xac\xf2)\xb6\xecI\xd8M\x04\x18\xddG\xc1\xf3\x1c\xe3\x82\u0381\x1e\xaf\a\xc2UIC\xa1\x8c\x00S\x9aIQ8\x89\r\x10z\xf2\xca>Wnu\xf0h\xbfiz\r+=\x11wn\xfam\x93-9\xed\xbe?#\xe9\xf6\xa4G\xa3\xbeYZ\xedqɴ\xa9+\x94\t\x89\xb3\xe9\xe9\xb2)lu%=I69BNM\x88\x9d\xbb\x02\xf1\xa2ɯ/\x93\xf2\x9aL\xb3\xb4\xf4ֹ\x14{\x95T\xd6WN`}\xbd\xb4\xd5\x19ɪ\xa7?\xf5\x92\xbe\x96~tveڲ\xcc\xe1\x84Ӥ4Ӥ\xa5\x9b\x94\x01\x1f5Ԥ\xf4ѹI\xa3I\x9cL\x9f\xae\xaf\x9a\x16\xfa\xaaɠ\xaf\x9f\x02:)m\x93\x15\xe6&y\x8e_r\x18ʴ\x03P|\v\xe1|.\x99\x94\xee\xb9\xe6ϊ;?\x0f`\xa1\xb0\x047\xf5\x15〲.\xac\xa8\x8a\xf6>\xb6X\xc0\xb9\x81]sY\xd1ϊ\x8e\xc8\xfb\x9b\xba>\x7fi$~9\x88j\xb8aOP\x14\x8c\xc7\xe6\xe6\x1e\x152w\x0fh\xa6\x16\x80\xb6\x11g\xb9\xbf\x8c\xc9_\x1ez\xe1\xa6\v\xdd\x06@\x16\xb6\x8c-\xf5qy\xf8\xa6\xaf\x83\x06,U\x8f\xedy\xe6.ޠo\xbfԠw\x8c\xee\x1dk|\xb3\xf6P\xa9\x9f\xe8\x06\x03Ӡ~\xbc:<\xb4g\xb2\x17\xe0\xb4ꁽ\x93\xce#\x18\xe2DmP\xef\xb4\x01\x1d*U\x8cӢ\xfdD@H\xd5@\x884Mq\xfe眲|\x89\xf0\xee\x14\x01^\x92\a4\xcf{\xfd\x86\xa7'\x8f=5\x99\x9e\x8c\x92tJ\xf2%½9\x01\xdf,\x7f5\xfd\x14\xe4\xfc\x8d\xe7\x17>\xf5\xf8R\xa7\x1dgP/\xf5t\xe3|ڽ\xd2i\xc6W?\xc5\xf8\x9a\xa7\x17g\x9dZLNϚ\x95q0'\xb5\xea\x19\xc7\xed\xd2r\t\xa6O!&\x9e>L\xcc4H\x1b\xfc\x91\xc3N<]8\xffTa\"\x7f\xe7L\xe9W>=\xf8ʧ\x06\xbf\xc5i\xc1\x04\tL\xa82\xffT\u0cf7\xa4\x94\xceAOn\xfb͑\xdaIyM\x8d\xe5\xfa\x88\r\xf6\xb5\xc2m\xb2X\xab\x17\x03\x90Y\xf2\x17\xf9ӣ\r\x87\xb6\xc1Q2;\x1eQo_\xb2u\xd7\xfa\x0e\xb1\x7f\xcd\xc1m]\x1a\xa88\x1a\x00\n\xdc(5+\xea*|\xe0\xd9f\xd0Æ\x1b\xb6V\xba䖝7\x9b\xc5o\\\a\xf8\xf7\xf9\x92\xb1\x1fT\x93\xabӽ/͈\xb2*v\x18\x89\xb1\xf3n\x83\xe7IIT:C\xcf7\xaa\x10Y\xc4\xe7\x1c\xbdW\xcf5ػl\x88n\xfe\xcb:\xd9\"\xb1\xc0\a\x9b\x8bp\xebb\xffJfw\x9f\xfb\x91k%\xbc\x12\x7f\xa6'\x95N\xb0\xea\xf6\xee\xe6\x9a`\x051\xa2\xb7\x9a\x9a\x04ņ\xe5+@\x97\xa1\x1d\xfb!}r\xbd\xeeA\xed\xe7\bw\x1f\xab\x80ܽL\x12\xdc\x16\xaf\x9a3\x85Z\xeb\xe6\xda\xe1r\xa8'\x94/.wL\xf9\xa7'\x84\xce\x17\x15\xd7v璉.zx\x04\xbb>\xb5jv\xd0Z\xed\xbf\xbc\xd2-=\xb2\x87GWh'{W\xf5\x93\a\x86\xf4|\x0eN\x87OUO\x9e\xa7~\x01\x9c\x0e\xbbP\v\xa2b\xe4\xa7h\x06\xe4\xc9W,\x8d\xbf\xa1\xffG\xb5\x85\xf7ѕ\xcb\xfe\xeb+\x83&#\xa9\x89\x01*]2\x1f\xa1`\x9b\x8fHw|?O\xed\xc5s\r\x03*\xfe\x8e\xf0\xe7,N\xde\xf6A\x8d?HB7\xa8\x87Nc^\x15=\xf5\xb4c7\xf7\x14\xb76\xaa\xd4O}\x1f\xb7\x86\xe5ɐ`\x10\x81%\xe4\xc17ZNEF\xab4\x7f\x80\x8fʽ\xad\x93\"&\xfd\x16\xbd\x97\x97\xbc\xe7\x16\xf2\xb5\xfd$\x8c)z?\xb6!\xc0\xf6|\xc6\xdeE\xff\x88\xed\x91O\x19X[\xba\x91ғ&\xef\xfd\xeb$\xa8\x8f\r \v\x02\x05\x1c\xb4\x15\xfew\xa3\x9e\xe8\x02\xfc\xf8\x1asx@\xa4\xf3\x86\x19\xd0A\x11J\xe1=j\x98uU(\x9e\x83\xbe\xa2GT\x12F\xfcS\xaf\xc1\xc0\x1d\xe8?\xc5\xe2\xedfd<\xa1\xe7\x17̒A\x8f\xae(\xa0\xf8A\x14`\x1c≦\xe1f\xbfec)\xear\xe5<\xd55\xfe\xd8tr\xc02\xbb\xa1\xd2\x06C\x05\x1a\xfdD\xb7\x15Q\x9b \xf9\x87\x89\xc1\x1a>\ni\xe1\x01\xc6c\xe8\t\x9b\xe0\xdeh \a (0\x8a\xf8\xfe\x12[y\xec\x11\xe4>\xdez \x03\xcdbdL\x8e\x95w\xabn\xee\xaf\f\xabeN\x1b\x00\xf7\x7f\xbe=J~\xb7\xbd\xf7e\x82NHQ\xef\xf7\xe3-;!BG;\x91O\x1fW\xe21X\xdc\x18\x95\t\x8a*\x9e\x84\xf5\xd79\xbe\xdc\x1d\xe2\x87\x02\xc4\x03\xd2Q\x1b\xf8\xfc$A\x7f\t\x16\xc8\\\xcbػ-\xd3\xda\xef\xa7=h\xd1\xf7Z\xac¾G`\f\x000\x15\xf6\xb9\x8c{\t(l\xaf\t\xd3H\x1c\xc4>\x01\xdcyG\xc8ik\x85\xb4\xe3\x9c!n\x9bVt\xd8tDCN\x8b\xed\xfd\x00\xc6 \x93\x9d\x1e}j\xaa\xb8Ӧ\x86\xfd^\x8cy\xa3\xb4c\x96\xe1@\xff\xb0\xf7kT\x83\x1f\xd4\xde1\xcd=\xaaF\xf6>\xd2CxyGr\xbc\x97\xde\xfdR\xaf\xda\a\x15\xd8\xdf\xfe~\xf6\x8f\x00\x00\x00\xff\xff)\x00\x87w>{\x00\x00"), diff --git a/config/crd/v2alpha1/bases/velero.io_datauploads.yaml b/config/crd/v2alpha1/bases/velero.io_datauploads.yaml index be2bb0861..c4c25cce6 100644 --- a/config/crd/v2alpha1/bases/velero.io_datauploads.yaml +++ b/config/crd/v2alpha1/bases/velero.io_datauploads.yaml @@ -33,6 +33,12 @@ spec: jsonPath: .status.progress.totalBytes name: Total Bytes type: integer + - description: Incremental bytes + format: int64 + jsonPath: .status.incrementalBytes + name: Incremental Bytes + priority: 10 + type: integer - description: Name of the Backup Storage Location where this backup should be stored jsonPath: .spec.backupStorageLocation @@ -173,6 +179,11 @@ spec: as a result of the DataUpload. nullable: true type: object + incrementalBytes: + description: IncrementalBytes holds the number of bytes new or changed + since the last backup + format: int64 + type: integer message: description: Message is a message about the DataUpload's status. type: string diff --git a/config/crd/v2alpha1/crds/crds.go b/config/crd/v2alpha1/crds/crds.go index 006c49754..53e1958e8 100644 --- a/config/crd/v2alpha1/crds/crds.go +++ b/config/crd/v2alpha1/crds/crds.go @@ -30,7 +30,7 @@ import ( var rawCRDs = [][]byte{ []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcYK\x93\xe3\xb8\r\xbe\xf7\xaf@M\x0es\x19\xbb3yl\xa5|\x9bq'U]\xd9\xe9q\xad;}\xa7$X\xe6\x0eE2|\xd8\xebM\xf2\xdfS %\x99\x92\xe8\xe7>|3\t\x82\x1f\x01\x10\xf8@\xcdf\xb3\a\xa6\xf9\x1b\x1a˕\\\x00\xd3\x1c\x7fr(韝\x7f\xfb\x9b\x9ds\xf5\xb8\xfb\xf8\xf0\x8d\xcbj\x01Ko\x9dj~@\xab\xbc)\xf1\t7\\rǕ|hб\x8a9\xb6x\x00`R*\xc7h\xd8\xd2_\x80RIg\x94\x10hf5\xca\xf97_`Ṩ\xd0\x04\xe5\xddֻ?\xce?~7\xff\xeb\x03\x80d\r.\x80\xf4Uj/\x85b\x95\x9d\xefP\xa0Qs\xae\x1e\xacƒ\x14\xd7Fy\xbd\x80\xe3D\\\xd8n\x1a\x01?1ǞZ\x1daXp\xeb\xfe9\x99\xfa\x9e[\x17\xa6\xb5\xf0\x86\x89\xd1\xdea\xc6rY{\xc1\xccp\xee\x01\xc0\x96J\xe3\x02^hk\xcdJ\xa4\xb1\xf6L\x01\xca\fXU\x05+1\xb12\\:4K%|\xd3Yg\x06\x15\xda\xd2p\xed\x82\x15RX`\x1dsނ\xf5\xe5\x16\x98\x85\x17\xdc?>˕Q\xb5A\x1ba\x01\xfch\x95\\1\xb7]\xc0<\x8a\xcf\xf5\x96Ylg\xa3)\xd7a\xa2\x1dr\a\xc2k\x9d\xe1\xb2\xce!x\xe5\rB\xe5Mp!\x9d\xbbDp[n\x87\xd0\xf6\xcc\x12<\xe3\xb0:\t$̓:\xebX\xa3Lj\x92\xa5\x11R\xc5\x1c\xe6\x00-U\xa3\x05:\xac\xa088쎱Q\xa6an\x01\\\xba\xef\xfer\xda\x16\xad\xb1\xe6a铒C\xc3|\xa6QH\x86#\x12\xf2R\x8d&k\x1d\xe5\x98\xf8%@\x1c)\xf8\x9c\xac\x8fH\xa2\xdet\xfc\"\x14\n9P\x1bp[\x84Ϭ\xfc\xe65\xac\x9d2\xacF\xf8^\x95\xd1}\xfb-\x1a\f\x12E\x94\xa0\xe8\x05N\xbeS&\xeb:\x8d\xe5<ʶ\xca:]#\xff\r7\xfa\xd5c\xab4Ȳ\xb1ե\x9ay\x90\xe0J\xe6\x03\xecS\x8dW\x05WjD\xa9*L,6\xc0\xc4-h\xa3J\xb4\xf6L\xc0\x93\x82\x01\x8a\x97\xe3\xc0\xc44Qb\xf7'&\xf4\x96}\x8cI\xa6\xdcb\xc3\x16\xed\n\xa5Q~Z=\xbf\xfdy=\x18\x863\t\x83\x95\xceR\xa6 \xf8\xda(\xa7J%\xa0@\xb7G\x94\xd1\xf5\x8dڡ\xa1\x9a\x8d\x93\x06C\xf4\x10@\x93z\x1fhO\x8d\xc6\xf1.\v\xb7\xba\x8f\x05&\x19\x1d\x9d㿳\xc1\x1c\x00\x1d=\xae\x82\x8a*\r\xc6c\xb5\xb9\x15\xab\xd6Z\xd1y܂AmТ\x8c\xb5\x87\x86\x99\x04U\xfc\x88\xa5\x9b\x8fT\xafѐ\x1a\xb0[\xe5EE\x87ݡq`\xb0T\xb5\xe4?\xf7\xba-8\x156\x15̡u\xe12\x1a\xc9\x04\xec\x98\xf0\xf8\x81\x8c6\xd2ܰ\x03\x18\xa4=\xc1\xcbD_X`\xc78\xbe\x90\x15\xb9ܨ\x05l\x9d\xd3v\xf1\xf8Xsו\xddR5\x8d\x97\xdc\x1d\x1e\x837x\xe1\x9d2\xf6\xb1\xc2\x1d\x8aG\xcb\xeb\x193\xe5\x96;,\x9d7\xf8\xc84\x9f\x85\x83\xc8Pz\xe7M\xf5\a\xd3\x16j;\xd8v\x12\x88\xf1\x17\n\xe6\r\xee\xa1*J\xb7\x82\xb5\xaa\xe2\x11\x8f^\xa0!2\xdd\x0f\x7f_\xbfB\x87$z*:\xe5(:\xb1K\xe7\x1f\xb2&\x97\x1b4q\xddƨ&\xe8DYiť\v\x7fJ\xc1Q:\xb0\xbeh\xb8\xa30\xf8\xb7G\xeb\xc8uc\xb5\xcb@M\xa0@\xf0\x9a\xf2A5\x16x\x96\xb0d\r\x8a%\xb3\xf8;\xfb\x8a\xbcbg䄫\xbc\x95\x12\xae\xb1p4o2\xd11\xa6\x13\xaeM3\xc8ZcI^%\xc3\xd22\xbe\xe1m%\xa14\xc0\x06\xb2C\v\xe5\xaf>\xfd\xb2\xd5d,t)\xdc\xe8\xf79\xa7\xa8C+\x93D\xde\xd6:\xdb\x16)1,R\xe9oR\x1f\rje\xb9S\xe6p\xac\x92\xe3P8\xe9\x15\xfa\x95L\x96(\xee9\xde2\xac\x04.+\xb29\xf6\xa1LI(j\r@\x95\xac\x15]\xae\x81+\xe0ّ\fŶE\x97?\xa8\xccV5.\xe1\xc8)!\xe5\x8e\xe3\xe3\x16J\tdc+R\x14~\xa1\xb2\xb0Tr\xc3\xeb\xe9\xc1S\xfa{*D.\xd84\x13\xb0ɖt\n\x8aNB2\v\x15jօ.\xa5\xf6\r\xaf\xbd9\xe5\xff\rGQM\xf2\xcfɛ\xd4\x1d8\xecr\x8f\x8f{\xe8\xdd\xedj\xabZRz\x9d\n\x19\xca\x06\xbe\x9b\x84\xe6\x14$\xc0\xf3&\xd1\xc8-\xbc{\a\xca\xc0\xbb\xd8\x13\xbd\xfb\x10W{.܌\x0f\xea\xff\x9e\v\xd1\xedrSt\x13\xc3\xf9\xba\xbep\xf2\x97 Dx\xbe\xaeo\xe5VS4(}3\xddp\x06\xcc;\x95\x19\x16\\\xfa\x9f2\xe3{.+\xb5\xb7\xb7\x1c\xb6\xe77D1\x95w\xf78\xfc\xebH\xc7\xc8\xef\x8e\bq\xf0\xb5S\xb0g<\xe1\x18\xfd\xee\xf6CFo\x81\x1b*H\x06\x9d7\x92\xd2\x01\x1aC\x19\xda\x06\x95\xcaO8\xcfٓZɴ\xdd*\xf7\xfct\xe1\x8c\xeb^\xb0˻\xcfO\x9d\x8b\xdfB\xd4\xf5ɷ\x95\x84\x8c\x97\b~\xc7\"\xabP\xd6\xefB\xbb\xe6?\xe3\x95xI\xb4C,T\xcdK&\xc0\x861\xd96\x81\xed!:\xddS@\xb9>o\f7\xed\xd6\x12\xbc\x81\xfb\xf4/\x04\xf7\x84\xd1z\xa8\xa2;\x8a2\xbc\xe6\x14,\xb2\x9f9ޱ\x9d\x12\xbe\t\xa2\xe4\x12\xac\xc0\xeb\x13\xb6\x06*\x1fD\xb6\n\x84\x8ao6h\x88Q\x05\xba\x157^\xbd-\xdf\xdbd\x13\xbeI\xffP\xa5j\x98\xd6XQoG\xc1\xd8\xfa\xf6&\xaf:fjto\x01\xf4\x05\x13\xbd&\xa2\x9d)\x88\x9a\x91\x83Z\xee\x1f.W\x10\x83\xd5\xdb2\xc3\xd4\xe9\xb7z\x9b\"<\xcdc\xa0m\xdaN8q\x82r\xe2\xad\x16O\xaf#\xab\xe2l\x19\x04л+v^\xbd\xe5XQo\x0ep[\xe6H\xa2m\xb2\xa18duBw\xa5[wއ\xb7\xbc\n\xf0\xf2,\xe2\xe5\x18\xf2\t\xbc\xc5\xe1\x17C&\xd2\xc5\rV\xb9\x92s\xdas3л\xec`y=\xb5\xc8\xef<\xcb\xf3\xe7\x91̸T\x8d\xa6\x8f\xf9}<1\xcc+\xa3\xd9\xf4J^\xd5h\x84g\x90k[\x8d\xf8\xb8ٺ\xbd\xf4&$\x9d\xf6ɓ\xba\xf7\xbb\x9a\rV\x96\xa8\x1dV\x9f\x0f\xc4B\xae *\x04@\x9e\x7f\x04\xfa\x97>\xd2\x14\xd4\xec֎\xa0\x83\xd4?T\xddS\x00>\x8d\x95\x84\xd7\nS%4b\n7R\xc9Ӡ\x01^\xa9\xe4\x85n\xfb}d\x0e\xb4,\xf0\x11bԓMO\x16Ej\xa7g\xb4~\"!\xbd\x10\xac\x10\xb8\x00g\xfc\xa9\xd6\"\xdfI\xc5w\xdf\xf4\x89﮶j\xaafj;\xd6?j\x85\xc7\xc7\xee\xc59g\xb2\xa3\xbe\xde`Q\x1dV\x80;\x94@\xcd2\xe3\x02\xabNg\xa6\xbf\xb8d\xf9\f\xe8)u\xfd-\x8dߠ\xb5\xac\xbet\x81\xbeD\xa9\xf8\x0e\xd4.\x01V\x10\xcf\x1d\xb3\xfc\xf7\xb6\xbd\xdb7\xf7\x1b\xbf\xce%\xbe\xb2\xdb8\x83%\xf4\xc6\x17\xc0\xacH&\x97\xd3zh\xa7\x93\x1a\x9civ^p\x9f\x19\xed\xeegfj\xd5^\xfa\xcc\xd4\xe4\x13R:\x19\x1f!r\x85\xb1\x9b\xcb\xea\xec\xbf\xd1d\xe6\xfe\x11.\xc3M\x96n\xf1\xdds\xdd\xfb\xa7\x8c\xad\x12\xdd\r\x0f\xdfV\xa4o\n4\xe4\x86\"G\xf8\xc3\vx\xe2\xb5\x1c\xf9\xeb5\xf4\xbdKP5\x87\xd7-Q\x93\xf8\xfe\xd2us\x15\xb7Z\xb0C\x7f\x98\x94\xa1f\x94\x1fo\xcd\xe4y\xfdV\x92\xda\x7f\xeb\xca3\xaf\xf3\x8d\f\\hf\xc2|\xff\r\xeb\xb7\xd9\xe1\xcc\xeb\xcb\xf0\x9b\xe2]\xad\xd4@åR\xd0~\xe3\xbc=\x83\x0f\xb7\xf9=\x93w\xd6z\x93\xc1\x80\xbcJt\xb7\xaf\xa5\xe9\x88/\xfaO\b\v\xf8\xcf\xff\x1e\xfe\x1f\x00\x00\xff\xff73Hq. \x00\x00"), - []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcZIs\xe3\xb8\x15\xbe\xfbW\xbc\xea\x1c\xe6b\xc9\xe9,S)\xdd\xdarR\xe5ʴ\xdb\xd5r|\x87\xc8'\x11c\x10`\xb0H\xe3,\xff}\xea\x01\x04\x05\x92\x90(i\xa6\x9b\x87\xae\x16\x96\x87\xb7\xe1{\v<\x9b\xcdnX\xc3_Q\x1b\xae\xe4\x02X\xc3\xf1\x17\x8b\x92~\x99\xf9\xdb\xdf̜\xab\xbb\xddǛ7.\xcb\x05,\x9d\xb1\xaa\xfe\x8aF9]\xe0\x03n\xb8\xe4\x96+yS\xa3e%\xb3lq\x03\xc0\xa4T\x96Ѱ\xa1\x9f\x00\x85\x92V+!P϶(\xe7on\x8dk\xc7E\x89\xda\x13\x8fG\xef\xfe8\xff\xf8\xe3\xfc\xaf7\x00\x92ո\x00\xa2\xe7\x1a\xa1Xi\xe6;\x14\xa8՜\xab\x1b\xd3`Ad\xb7Z\xb9f\x01\x87\x89\xb0\xad=2\xb0\xfb\xc0,\xfb\x97\xa7\xe0\a\x057\xf6\x9f\x83\x89\x9f\xb8\xb1~\xb2\x11N3\xd1;Տ\x1b.\xb7N0\x9d\xce\xdc\x00\x98B5\xb8\x80':\xb2a\x05\xd2X+\x89ga\x06\xac,\xbdn\x98x\xd6\\Z\xd4K%\\\x1du2\x83\x12M\xa1yc\xbd\xec\a\x86\xc0Xf\x9d\x01\xe3\x8a\n\x98\x81'\xdc\xdf=\xcag\xad\xb6\x1aM`\t\xe0g\xa3\xe43\xb3\xd5\x02\xe6a\xf9\xbc\xa9\x98\xc1v6\xa8o\xe5'\xda!\xfbN\xdc\x1a\xab\xb9\xdc\xe6\xce\x7f\xe15B\xe9\xb47\x1b\xc9\\ ؊\x9b\x94\xb1=3Ĝ\xb6X\x1ee\xc3\xcf\x131cY\xdd\f\xf9I\xb6\x06\x86Jf1\xc7\xceRՍ@\x8b%\xac\xdf-F!6J\xd7\xcc.\x80K\xfb\xe3_\x8ek\xa2U\xd5\xdco}P\xb2\xaf\x96{\x1a\x85d8pB\x16ڢ\xce\xeaFY&~\v#\x96\b\xdc'\xfb\x03'\x81n:>\xc9\n\xb9\x1b\xa8\r\xd8\n\xe1\x9e\x15o\xae\x81\x95U\x9am\x11~RE0\u07beB\xdd\x1ao\x1d\x96\x98J9Q\xc2:J\f`\xac\xd2Y+6X\xccî\x96n$;0e\xff\xcc\xdf\xd9\xc9\n\x8d,\xebd\x11e\xe6~\x05W2\xefi\x9f\xb6x\x96\x97\xa5ڔ\xaa\xc4Nu\x98r\xc4\r4Z\x15h\xcc\t\xbf\xa7\xed=\x1e\x9e\x0e\x03#\xb5\x84\x15\xbb?1\xd1T\xecc@\x99\xa2\u009a-\xda\x1d\xaaA\xf9\xe9\xf9\xf1\xf5ϫ\xde0\x1c\xc5\fVXC`A\xac7ZYU(\x01k\xb4{D\xe9q\vj\xb5CM \xb7\xe5\xd2\x00\x93eG\x13\xd2\x05\a\xa8&'\xf7\xf4h6L\xb6\xee\xa4\x1aԩف\x8elP[\x1e\xd17|IXIF\aB\xfco֛\x03 \xb9\xc3.()\xbe`\x90\xaa\xc5V,[U\x05\xbbq\x03\x1a\x1b\x8d\x06e\x8884\xcc$\xa8\xf5\xcfX\xd8\xf9\x80\xf4\n5\x91\x89\xf7\xa1Pr\x87ڂ\xc6Bm%\xffOGۀU\xfeP\xc1,\x1a\xeb/\xa4\x96L\xc0\x8e\t\x87\xb7\x03\xed\xd1W\xb3w\xd0Hg\x82\x93\t=\xbf\xc1\f\xf9\xf8\xac4\x02\x97\x1b\xb5\x80\xca\xda\xc6,\xee\xee\xb6\xdc\xc6`[\xa8\xbav\x92\xdb\xf7;o\f\xbevVisW\xe2\x0eŝ\xe1\xdb\x19\xd3E\xc5-\x16\xd6i\xbcc\r\x9fyA\xa4\x0f\xb8\xf3\xba\xfc\x83nó\xe9\x1d;\xf2\xc2\xf0\xf9@y\x81y(~ҕ`-\xa9 \xe2\xc1\n4D\xaa\xfb\xfa\xf7\xd5\vDN\x82\xa5\x82Q\x0eKGz\x89\xf6!mr\xb9A\x1d\xf6m\xb4\xaa=M\x94e\xa3\xb8\xb4\xfeG!8J\vƭkn\xc9\r\xfe\xed\xd0X2ݐ\xec\xd2'$\xb0Fp\rAA9\\\xf0(a\xc9j\x14Kf\xf0;ۊ\xacbfd\x84\xb3\xac\x95\xa6Y\xc3\xc5A\xbd\xc9D̔\x8e\x98\xf6\x00\x1f\xab\x06\v\xb2)\xa9\x956\xf1\roc\ta\x00KV\xf6\xb5\x93\xbf\xf6\xf4eC\xc8pє\xab\xd1w\x9f#\x14y\x95\t~\xc7P\xd7F&яL\xe9w\x00\xf9v\x8f\xc6F\x19n\x95~'\xc2!4\x0e\xdd\xe0\xa8E\xe8+\x98,P\\#\xde\xd2\xef\x04.K\xd28vnL\x00\x14\xa8zF\x95\xdc*\xbaX\x89!\xe0\xd1\xd2\n\xf2j\x836/\xa6̄2.\xe1\x90MB\x9a5\x0eE]+%\x90\r5X\x18\xbe\x92\xac1\x95\xb2\x13\x02?n \xae|yo\x90\x0e_\xae\x1eo\xe9\x9f8N\x1e\xb4\xe3e\v\xf1t\xcb(\xafʛ\xad\xb5\xf3r\xf5\b\xa6\xdd>6\x92tB\xb0\xb5\xc0\x05X\xedƂ\x1dwXϽ\xe6;Թ\x99\xe1\xcd\xf1\v\xa3\x17\x86m\xe0\x8c\xcfV\xfd\xd0+e\xfa\x18\xa5\\*iQ\xe6ltҫ苒.\x053Y\x9e\a\x9c\xad\xd2\xf5\xb9k\x12\tB\xe1W؊\xe5\xf9\x82\x10t\xbd\x1c\x87M\xbc\xcb\xcd`\xcfmu\x95D႞-P\xb2<+O{߃8jsB\x98\xe7ץ\x97wJ2\n7\xd7H\xb6\xeb\x19\xfd\f\xd9\xfa^\x92\x93n\xc0\xe51\xe1\x14\xa1\x00\x81\x19\x96\xe0\x9a\xcby'\xd0\xe1\x1a\xcb1ϳ\x9e\xbd2\xd3}\xa1\x8f \xc9(2A\x9bt~\xa6\xb4r\xa9\xe4\x86o\xc7g\xa7\xf5\xf3\xa9k{R\xb4Q\xc4K\x8e$\x8dS\x80#Nf>Ý\xc5\xe8G\xb9\xe1\x86o\x9d>\x86F\x1b\x8e\xa2\x1c%0\x93\x004\xa1\x0f\xcf\xc45q\xa4\x93,\xc6\xef\x16R\x93\xcc>xI\x8aR!\xfc\x8de\x00\x82\xee\x03En\xe0\xc3\aP\x1a>\x84^ˇ۰\xdbqag\xbcW^\xec\xb9\x10\xf1\x94\x8b\"hWRPA\xa7\xdcTh\xc9\xea\xe0ˀ\xc6@\x15\x96\x8aO/\xbeU\xb0g\x89ȼ\xd2|\xcbIᲛ9$c-ֵ]\v\x8fd\x1e\x8a\xb3\xfe١\xa5!\xb4<\x90\xa3\xeb\x1c\x0e'\xb4g\xb2\xf4\xf9B7_\xb6W/sq'\x15\xf2\xfc\xba\x9c\xb2Wwp\x06\xcaix_\xf1\xa2ꛎ\x8fA\x15\xc0\xb27\xf4\xb9\xf7\x05l\xe61|\x96\xcf\xc4\ak\x86\xb7o0\x9d\xba\xecp\xaao\xe8\xec\xec\xf3\xeb\xf2\xacj\xc57RΫWB\x87\xb4\xd5r\xe1\xb4\xf6\x95`\x18U\x9b\xab*\x16V\x14\xd8X,\xefߟT9\xe5\xf4\x9fz\x8b\x89\x11yN+)cj\xdf\\\u0086]ZrDv\xbb\x06\xd85\xd7\xf4Ӑ\x88o\x85\xe82\x01\xccq\x01\x11\xc0\xe68\xd3\x00/\xe4ྔ\xff!`$m\xf3\xc8K\xd7st\xe8\x88B\xec\xaeR\xad>\xa3\xfd\xd7E\xd9|\xa9\x16\x1a\xcbi\xeb\xf0\xaa\xbamLf\xac;\x16\vL\xdfӌ\x1d\xed\x9c\xc6\x0e\xe4:}\x05jX\x02\xeeP\x02\x95\xe2\x8c\v\x8aݞd\x06\xc0NSi\x83Xx\xbe\x88=\x9a\xd8\xcf\xcb6˦-\x99Q\xc2\x18;\xa51\xbb\x14\xf2+\x1a'2I\xc37L!Ñ\xa1[`\xb2)\xe4\xe9r\x96\x19`\xa0\x03\x91\x167\x8e\x81\xd6\xd9J\xca\xe6\x955\x1aöS\x88\xf69\xac\n\x9d\xbdv\v\xb05\xa5Q}\xd6~0-\xd0^\x04Wr\x1aS/B\xd2^S\xfebN\xbe\xac\xce\xe0\xe5ˊ\x0e\xf9\xb2\xfa\xad\xbc\xa0tu\xae\xb0bΪ̰\xe0\xd2\xfd\x92\x19\xdfsY\xaa\xfd\xf8~\x9d\x10\xb5a\xb6\x9a\x10\xf4\x99\xd9*\xc6э\x13\xc2\xef\x19\xe5\x97mj\xb6F\x02\x8e\xdf+\xcd\xf4\xad\xa7)\xf6hM.\xce\xe39w\xe6\x98\xe6\x9fp\x9f\x19\x8dq)3\xf5\xdc\x06\xbb\xcc\xd4\xe8e6\x9d\fݽ\x1c\xa6Ĺ,\xcd\xee\xf133\xf7\x0f\x1f\x05.\xd2s\xcb\xdf5a\xae\xeb\x13VJ\xc4\xc8\xe6\x1f-\xa5\xabר\xc9\b\xfeYtЯ\xa0\xbc;\xb1X\x86p\xb2\xbfK\xf6=\xa59\xbcT\xdc\xc4\xcef,\xd7Jn\x1a\xc1\xde;Y\xa6\xb0\xb5í\xe1\x8b\xd5\xd8IN\xb7\x04\xbb'\xe4|;'\xf7\x0e\xdc\xff\xc6/\xba\x83\xf9\xeei\xf8ۜp\"0\xc4\xeb\xfd\xf8pf\x1d\xfa\xf8\x10\xaf\"/QZ*\xad\x0f\xaf\x84\x87\x8a\xc6w\x9ds\xba\x1cv\xdb/+\xc2z\x7fXpUQڣ0\x91\xae\xb5\x7f\xe7\x90K\x8aV\x04\x06\x04A\xfe]j9|\x89\xbe\xed\x1e\xb6\x99m\x1fNJ\x8a\xc9-\xe6*=%)\a\xf09\xc4\xe5\xf9W_\xa0\xef\x99ze\xbdj4\xe89/\x13\xdam/1\x1dq\xeb\xee\xb5r\x01\xff\xfd\xffͯ\x01\x00\x00\xff\xff\xee\xe6t\xbc\x8f$\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcZIs\xe3\xb8\x15\xbe\xfbW\xbc\xea\x1c\xe6Ғ\xa7\xb3L\xa5tk\xcbI\x95*3nW\xcb\xf1\x1d\"\x9fD\x8cA\x80\xc1\"\x8d\xb3\xfc\xf7\xd4\x03\b\n$!Q\xd2\xf4\f\x0f]-,\x0fo\xc3\xf7\x16x6\x9bݱ\x86\xbf\xa26\\\xc9\x05\xb0\x86\xe3/\x16%\xfd2\U000f7fda9W\xf7\xfbOwo\\\x96\vX:cU\xfd\x15\x8dr\xba\xc0G\xdcr\xc9-W\xf2\xaeF\xcbJf\xd9\xe2\x0e\x80I\xa9,\xa3aC?\x01\n%\xadVB\xa0\x9e\xedP\xce\xdf\xdc\x067\x8e\x8b\x12\xb5'\x1e\x8f\xde\x7f?\xff\xf4\xc3\xfc/w\x00\x92ո\x00\xa2\xe7\x1a\xa1Xi\xe6{\x14\xa8՜\xab;\xd3`AdwZ\xb9f\x01lj\xb0\xad=2\xb0\xfb\xc8,\xfb\xa7\xa7\xe0\a\x057\xf6\x1f\x83\x89\x1f\xb9\xb1~\xb2\x11N3\xd1;Տ\x1b.wN0\x9d\xce\xdc\x01\x98B5\xb8\x80':\xb2a\x05\xd2X+\x89ga\x06\xac,\xbdn\x98x\xd6\\Z\xd4K%\\\x1du2\x83\x12M\xa1yc\xbd\xecG\x86\xc0Xf\x9d\x01\xe3\x8a\n\x98\x81'<ܯ\xe4\xb3V;\x8d&\xb0\x04\xf0\xb3Q\xf2\x99\xd9j\x01\xf3\xb0|\xdeT\xcc`;\x1bԷ\xf6\x13\xed\x90}'n\x8d\xd5\\\xeer\xe7\xbf\xf0\x1a\xa1tڛ\x8dd.\x10l\xc5M\xca\u0601\x19bN[,O\xb2\xe1牘\xb1\xacn\x86\xfc$[\x03C%\xb3\x98cg\xa9\xeaF\xa0\xc5\x126\xef\x16\xa3\x10[\xa5kf\x17\xc0\xa5\xfd\xe1ϧ5Ѫj\xee\xb7>*\xd9W\xcb\x03\x8dB2\x1c8!\v\xedPgu\xa3,\x13\xbf\x86\x11K\x04\x1e\x92\xfd\x81\x93@7\x1d\x9fde%\v\x8d5\xca\xdb\x18\xe2\xc7\xddcnR\xd2\xe9l\xa3\xb9\xd2ܾ/\xe0\xd3\xf7\x97\xb2I\xb7\x02\xd4\x16l\x85\xf0\xc0\x8a7\xd7\xc0\xda*\xcdv\b?\xaa\"\xf8ءB\xdd\xfa\xd8&,1\x95r\xa2\x84M4\f\x80\xb1Jg\x9d\xad\xc1b\x1ev\xb5t#ف\xc7\xf5\xcf\xfc\xc6w\xa1\xd0Ȳw!\x82\xe1ܯ\xe0J\xe6/\xc4\xe7\x1d^t\x19RmJUb\xa7:L9\xe2\x06\x1a\xad\n4\xe6\xcc\xf5\xa4\xed=\x1e\x9e\x8e\x03#\xb5\x84\x15\xfb?2\xd1T\xecS\x00â\u009a-\xda\x1d\xaaA\xf9\xf9y\xf5\xfa\xa7uo\x18NB\x1b+\xac!L#\xd6\x1b\xad\xac*\x94\x80\r\xda\x03\xa2\xf4\xf0\n\xb5ڣ&,\xdeqi\x80ɲ\xa3\t\xe9\x82cD!\xd7\xf7\xf4h6L\xb6\xee\xa4\x1aԩ\xd9ɕi\xcc\xf2\x18$\u0097D\xbfdt \xc4\x7fg\xbd9\x00\x92;삒\xc2 \x06\xa9\xda\x10\x80e\xab\xaa`7n@c\xa3\xd1\xd0\xf5\xf2^\xa5\xb6\xc0$\xa8\xcd\xcfX\xd8\xf9\x80\xf4\x1a5\x91\x89\xf7\xa1Pr\x8fڂ\xc6B\xed$\xffwGۀU\xfeP\xc1,\x1a\xeb/\xa4\x96L\xc0\x9e\t\x87\x1f\aڣ\xaff\uf811\xce\x04'\x13z~\x83\x19\xf2\xf1\x93\xd2\b\\n\xd5\x02*k\x1b\xb3\xb8\xbf\xdfq\x1bs\x82Bյ\x93ܾ\xdf{c\xf0\x8d\xb3J\x9b\xfb\x12\xf7(\xee\r\xdf͘.*n\xb1\xb0N\xe3=k\xf8\xcc\v\"}^0\xaf\xcb?\xe86\x8b0\xbdcG^\x18>\x1fϯ0\x0f\x85y\xba\x12\xac%\x15D\xa4M.\xb7\xa8þ\xadV\xb5\xa7\x89\xb2l\x14\x97\xd6\xff(\x04Gi\xc1\xb8M\xcd-\xb9\xc1\xbf\x1c\x1aK\xa6\x1b\x92]\xfa\xbc\t6\b\xae!((\x87\vV\x12\x96\xacF\xb1d\x06\x7fg[\x91Ǔ\x8cp\x91\xb5\xd2lp\xb88\xa87\x99\x88\t\xdd\t\xd3\x1e\xe1c\xdd`A6%\xb5\xd2&\xbe\xe5m,!\f`\xc9ʾv\xf2מ\xbel\b\x19.\x9ar5\xfa\x1er\x84\"\xaf2\xc1\xef\x18\xea\xda\xc8$\xfa\x91)\xfd\x8e \xdf\xee\xd1\xd8(í\xd2\xefD8\x84ơ\x1b\x9c\xb4\b}\x05\x93\x05\x8a[\xc4[\xfa\x9d\xc0eI\x1a\xc7\u038d\t\x80\x02UϨ\x92;E\x17+1\x04\xac,\xad \xaf6h\xf3b\xcaL(\xe3\x12\x8eI/\xa4\xc9\xedPԍR\x02\xd9P\x83\x85\xe1k\xc9\x1aS);!\xf0j\vq\xe5\xcb{\x83t\xf8r\xbd\xfaH\xff\xc4q\xf2\xa0=/[\x88\xa7[F\xd9V\xdel\xad\x9d\x97\xeb\x15\x98v\xfb\xd8H\xd2\t\xc16\x02\x17`\xb5\x1b\vv\xdaa=\xf7\x9a\xefQ\xe7f\x867\xc7/\x8c^\x18\xb6\x813>\xa9\xf6C\xafT\x90`\x94r\xa9\xa4E\x99\xb3\xd1Y\xaf\xa2/J\xba\x14\xccdy\x1ep\xb6N\xd7\xe7\xaeI$\b\x85_a+\x96\xe7\vB\xd0\xf5r\x1c7\xf1.7\x83\x03\xb7\xd5M\x12\x85\vz\xb1@\xc9\xf2\xac<\xed}\x0f\xe2\xa8\xed\x19a\x9e_\x97^\xde)\xc9(\xdc\xdc\"پg\xf4\vd\xeb{IN\xba\x01\x97\xa7\x84S\x84\x02\x04fX\x82k\xae\xe7\x9d@\x87k,\xc7<\xcfz\xf6\xcaL\xf7\x85>\x81$\xa3\xc8\x04m\xd2\xf9\x13\xa5\x95K%\xb7|7>;-\xf3\xcf]۳\xa2\x8d\"^r$i\x9c\x02\x1cq2\xf3\x19\xee,F?\xca\r\xb7|\xe7\xf4)4\xdar\x14\xe5(\x81\x99\x04\xa0\t}x&n\x89#\x9dd1~\xb7\x90\x9ad\xf6\xc1KR\x94\n\xe1o,\x03\x10t\x1f)r\x03\x1f>\x80\xd2\xf0!\xb4\x84>|\f\xbb\x1d\x17v\xc6{\xe5Ł\v\x11O\xb9*\x82v%\x05\x15t\xcaM\x85\x96\xac\x0e\xbe\fh\fTa\xa9\xf8\xf4\xe2[\x05\aƓ\xb4\xbe;\xdd|\xcc\xd0\xdd\xe0\x96r@\x8d\xd6iIQ\x18\xb5\xa6\xb4\xc8x\x92\xcae\xc2\xd0\x19IM\x12\x12'\xa4\x1cFO/\x05\xfd\x7f\x88\xe5)\x00d\x04\xc8\xd9\xf8\x1c\x87>e\xef\xfao\xb7\x98b\xdd'\x11\x99W\x9a\xef8)\\v3\xc7d\xacź\xb6k\xe1\x91\xccCq\xd6?;\xb44\x84\x96Grt\x9d\xc3\xe1\x84\xf6L\x96>_\xe8\xe6\xcb\xf6\xeae.\xee\xa4B\x9e_\x97S\xf6\xea\x0e\xce@9\r\x1f*^T}\xd3\xf11\xa8\x02X\xf6\x86>\xf7\xbe\x82\xcd<\x86\xcf\xf2\x99\xf8`\xcd\xf0\xf6\r\xa6S\x97\x1dN\xf5\r\x9d\x9d}~]^T\xad\xf8F\xcae\xf5Jh\xe4\xb6Z.\x9c־\x12\f\xa3j{S\xc5\u008a\x02\x1b\x8b\xe5\xc3\xfb\x93*\xa7\x9c\xfeso11\"/i%eL\xed\x9bKذkK\x8e\xc8n\xd7\x00\xbb\xe5\x9a~\x1e\x12\xf1\xad\x10]&\x809. \x02\u061cf\x1a\xe0\x85\x1cܗ\xf2\xdf\x05\x8c\xa4m\x1ey\xe9z\x8e\x0e\x1dQ\x88=W\xaa\xd5g\xb4\xff\xb6(\x9b/\xd5B\xff;m\x1d\xdeT\xb7\x8dɌu\xc7b\x81\xe9{\x9a\xb1\xf1\x9e\xd3ؑ\\\xa7\xaf@\rK\xc0=J\xa0R\x9cqA\xb1ۓ\xcc\x00\xd8y*m\x10\v\xaf,\xb1G\x13\xfby\xd9fٴ%3J\x18\xa3\xd9oi\xcc.\x85\xfc\x8aƉL\xd2\xf0\x1b\xa6\x90\xe1\xc8\xd0-0\xd9\x14\xf2|9\xcb\f0ЁH\x8b\x1b\xa7@\xebb%e\xf3\xca\xe1\xdb\xc4T\xd5>X\x0e\x95\x12\xadSKWoP\x13\xb7\xfe\x85\x04$\x1e(-,*&w\xd9\xc4#v\xf8\x11\x043\xb6u\xb7\x93\x1e\x92>\xb1\f%K\x9fD\x8e_\x8dư\xdd\x14X\xff\x14V\x85\xa6e\xbb\x05؆2ľֿ3m\f\xb9\n\x89\xe5t\xb8\xb8*H\xf4\xde\x1b\xae\xe6\xe4\xcb\xfa\x02^\xbe\xac\xe9\x90/\xeb_\xcb\vJW\xe7jF\xe6\xac\xca\f\v.\xdd/\x99\xf1\x03\x97\xa5:\x8c\xa1㌨\r\xb3Մ\xa0\xcf\xccV1E\xd8:!\xfc\x9eQ\xea\xdcf\x9d\x1b$L\xfcV\x19\xb4\xef\xaaM\xb1Gkr)\f^\x02\a\xa74\xff\x84\x87\xcch\f\xb9\x99\xa9\xe76\x8eg\xa6Fo\xe3\xe9dh\\\xe6\xe02\xceeiv\xcfϙ\xb9\xbf\xfb\x00w\x95\x9e[\xfen\x89\xe0]\v\xf4\x88o\xfe5y\x84r\xfdV\f\x95\x14\x89\xc52\x84\x93\xfd]\x1d\xe3)\xcd\xe1\xa5\xe2&6mc%Zr\xd3\b\xf6\xde\xc92\x156:\xdc\x1a>ƍ\x9d\xe4|\xb7\xb3{\xc4\xcfw\xaaΣ2L \xb3\x9fW\xa7Cη8\xe1L̋\xd7{\xf5xa\x89\xbdz\x8cW\x91\x97(-\xdf\xf2\xe4\x01\xf4X\xac\xf9\x86zN\x97Ç\x84\xeb\xea\xcbޟv\xdcTo\xf7(Ld\xa2\xed_\x9a\xe4\xf2\xbd5\x81\x01A\x90\x7fr[\x0e\x1f\xd9?v\x11\x9d\xd9\xf6\xdd/\x04\xff\\\x11\xab$\xa57>=\xba>\xb5\xec\v\xf4{f\x95Y\xaf\x1a\rz\xce˄v\xdb&MGܦ{\x88]\xc0\x7f\xfew\xf7\xff\x00\x00\x00\xff\xff\x12=\xc7\xe9\x11&\x00\x00"), } var CRDs = crds() diff --git a/internal/volume/volumes_information.go b/internal/volume/volumes_information.go index d02dac269..463b81f46 100644 --- a/internal/volume/volumes_information.go +++ b/internal/volume/volumes_information.go @@ -170,6 +170,9 @@ type SnapshotDataMovementInfo struct { // Moved snapshot data size. Size int64 `json:"size"` + // Moved snapshot incremental size. + IncrementalSize int64 `json:"incrementalSize,omitempty"` + // The DataUpload's Status.Phase value Phase velerov2alpha1.DataUploadPhase } @@ -217,6 +220,9 @@ type PodVolumeInfo struct { // The snapshot corresponding volume size. Size int64 `json:"size,omitempty"` + // The incremental snapshot size. + IncrementalSize int64 `json:"incrementalSize,omitempty"` + // The type of the uploader that uploads the data. The valid values are `kopia` and `restic`. UploaderType string `json:"uploaderType"` @@ -240,14 +246,15 @@ type PodVolumeInfo struct { func newPodVolumeInfoFromPVB(pvb *velerov1api.PodVolumeBackup) *PodVolumeInfo { return &PodVolumeInfo{ - SnapshotHandle: pvb.Status.SnapshotID, - Size: pvb.Status.Progress.TotalBytes, - UploaderType: pvb.Spec.UploaderType, - VolumeName: pvb.Spec.Volume, - PodName: pvb.Spec.Pod.Name, - PodNamespace: pvb.Spec.Pod.Namespace, - NodeName: pvb.Spec.Node, - Phase: pvb.Status.Phase, + SnapshotHandle: pvb.Status.SnapshotID, + Size: pvb.Status.Progress.TotalBytes, + IncrementalSize: pvb.Status.IncrementalBytes, + UploaderType: pvb.Spec.UploaderType, + VolumeName: pvb.Spec.Volume, + PodName: pvb.Spec.Pod.Name, + PodNamespace: pvb.Spec.Pod.Namespace, + NodeName: pvb.Spec.Node, + Phase: pvb.Status.Phase, } } diff --git a/pkg/apis/velero/v1/pod_volume_backup_types.go b/pkg/apis/velero/v1/pod_volume_backup_types.go index 546616c5a..b246906fb 100644 --- a/pkg/apis/velero/v1/pod_volume_backup_types.go +++ b/pkg/apis/velero/v1/pod_volume_backup_types.go @@ -118,6 +118,10 @@ type PodVolumeBackupStatus struct { // +optional Progress shared.DataMoveOperationProgress `json:"progress,omitempty"` + // IncrementalBytes holds the number of bytes new or changed since the last backup + // +optional + IncrementalBytes int64 `json:"incrementalBytes,omitempty"` + // AcceptedTimestamp records the time the pod volume backup is to be prepared. // The server's time is used for AcceptedTimestamp // +optional @@ -134,6 +138,7 @@ type PodVolumeBackupStatus struct { // +kubebuilder:printcolumn:name="Started",type="date",JSONPath=".status.startTimestamp",description="Time duration since this PodVolumeBackup was started" // +kubebuilder:printcolumn:name="Bytes Done",type="integer",format="int64",JSONPath=".status.progress.bytesDone",description="Completed bytes" // +kubebuilder:printcolumn:name="Total Bytes",type="integer",format="int64",JSONPath=".status.progress.totalBytes",description="Total bytes" +// +kubebuilder:printcolumn:name="Incremental Bytes",type="integer",format="int64",JSONPath=".status.incrementalBytes",description="Incremental bytes",priority=10 // +kubebuilder:printcolumn:name="Storage Location",type="string",JSONPath=".spec.backupStorageLocation",description="Name of the Backup Storage Location where this backup should be stored" // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since this PodVolumeBackup was created" // +kubebuilder:printcolumn:name="Node",type="string",JSONPath=".status.node",description="Name of the node where the PodVolumeBackup is processed" diff --git a/pkg/apis/velero/v2alpha1/data_upload_types.go b/pkg/apis/velero/v2alpha1/data_upload_types.go index d4c5a28da..751da4555 100644 --- a/pkg/apis/velero/v2alpha1/data_upload_types.go +++ b/pkg/apis/velero/v2alpha1/data_upload_types.go @@ -155,6 +155,10 @@ type DataUploadStatus struct { // +optional Progress shared.DataMoveOperationProgress `json:"progress,omitempty"` + // IncrementalBytes holds the number of bytes new or changed since the last backup + // +optional + IncrementalBytes int64 `json:"incrementalBytes,omitempty"` + // Node is name of the node where the DataUpload is processed. // +optional Node string `json:"node,omitempty"` @@ -185,6 +189,7 @@ type DataUploadStatus struct { // +kubebuilder:printcolumn:name="Started",type="date",JSONPath=".status.startTimestamp",description="Time duration since this DataUpload was started" // +kubebuilder:printcolumn:name="Bytes Done",type="integer",format="int64",JSONPath=".status.progress.bytesDone",description="Completed bytes" // +kubebuilder:printcolumn:name="Total Bytes",type="integer",format="int64",JSONPath=".status.progress.totalBytes",description="Total bytes" +// +kubebuilder:printcolumn:name="Incremental Bytes",type="integer",format="int64",JSONPath=".status.incrementalBytes",description="Incremental bytes",priority=10 // +kubebuilder:printcolumn:name="Storage Location",type="string",JSONPath=".spec.backupStorageLocation",description="Name of the Backup Storage Location where this backup should be stored" // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since this DataUpload was created" // +kubebuilder:printcolumn:name="Node",type="string",JSONPath=".status.node",description="Name of the node where the DataUpload is processed" diff --git a/pkg/backup/backup.go b/pkg/backup/backup.go index 824c44875..528ca0d84 100644 --- a/pkg/backup/backup.go +++ b/pkg/backup/backup.go @@ -1198,6 +1198,7 @@ func updateVolumeInfos( volumeInfos[index].SnapshotDataMovementInfo.SnapshotHandle = dataUpload.Status.SnapshotID volumeInfos[index].SnapshotDataMovementInfo.RetainedSnapshot = dataUpload.Spec.CSISnapshot.VolumeSnapshot volumeInfos[index].SnapshotDataMovementInfo.Size = dataUpload.Status.Progress.TotalBytes + volumeInfos[index].SnapshotDataMovementInfo.IncrementalSize = dataUpload.Status.IncrementalBytes volumeInfos[index].SnapshotDataMovementInfo.Phase = dataUpload.Status.Phase if dataUpload.Status.Phase == velerov2alpha1.DataUploadPhaseCompleted { diff --git a/pkg/backup/backup_test.go b/pkg/backup/backup_test.go index eb6c2d9d4..6918c99f5 100644 --- a/pkg/backup/backup_test.go +++ b/pkg/backup/backup_test.go @@ -5578,6 +5578,7 @@ func TestUpdateVolumeInfos(t *testing.T) { CSISnapshot(&velerov2alpha1.CSISnapshotSpec{VolumeSnapshot: "vs-1"}). SnapshotID("snapshot-id"). Progress(shared.DataMoveOperationProgress{TotalBytes: 1000}). + IncrementalBytes(500). Phase(velerov2alpha1.DataUploadPhaseFailed). SourceNamespace("ns-1"). SourcePVC("pvc-1"). @@ -5603,6 +5604,7 @@ func TestUpdateVolumeInfos(t *testing.T) { RetainedSnapshot: "vs-1", SnapshotHandle: "snapshot-id", Size: 1000, + IncrementalSize: 500, Phase: velerov2alpha1.DataUploadPhaseFailed, }, }, @@ -5616,6 +5618,7 @@ func TestUpdateVolumeInfos(t *testing.T) { CSISnapshot(&velerov2alpha1.CSISnapshotSpec{VolumeSnapshot: "vs-1"}). SnapshotID("snapshot-id"). Progress(shared.DataMoveOperationProgress{TotalBytes: 1000}). + IncrementalBytes(500). Phase(velerov2alpha1.DataUploadPhaseCompleted). SourceNamespace("ns-1"). SourcePVC("pvc-1"). @@ -5641,6 +5644,7 @@ func TestUpdateVolumeInfos(t *testing.T) { RetainedSnapshot: "vs-1", SnapshotHandle: "snapshot-id", Size: 1000, + IncrementalSize: 500, Phase: velerov2alpha1.DataUploadPhaseCompleted, }, }, @@ -5655,6 +5659,7 @@ func TestUpdateVolumeInfos(t *testing.T) { CSISnapshot(&velerov2alpha1.CSISnapshotSpec{VolumeSnapshot: "vs-1"}). SnapshotID("snapshot-id"). Progress(shared.DataMoveOperationProgress{TotalBytes: 1000}). + IncrementalBytes(500). Phase(velerov2alpha1.DataUploadPhaseCompleted). SourceNamespace("ns-1"). SourcePVC("pvc-1"). diff --git a/pkg/builder/data_upload_builder.go b/pkg/builder/data_upload_builder.go index f6bfba68e..c8fa34956 100644 --- a/pkg/builder/data_upload_builder.go +++ b/pkg/builder/data_upload_builder.go @@ -145,6 +145,12 @@ func (d *DataUploadBuilder) Progress(progress shared.DataMoveOperationProgress) return d } +// IncrementalBytes sets the DataUpload's IncrementalBytes. +func (d *DataUploadBuilder) IncrementalBytes(incrementalBytes int64) *DataUploadBuilder { + d.object.Status.IncrementalBytes = incrementalBytes + return d +} + // Node sets the DataUpload's Node. func (d *DataUploadBuilder) Node(node string) *DataUploadBuilder { d.object.Status.Node = node diff --git a/pkg/cmd/util/output/backup_describer.go b/pkg/cmd/util/output/backup_describer.go index 3b6c5ae19..8777c52f5 100644 --- a/pkg/cmd/util/output/backup_describer.go +++ b/pkg/cmd/util/output/backup_describer.go @@ -713,6 +713,9 @@ func describeDataMovement(d *Describer, details bool, info *volume.BackupVolumeI d.Printf("\t\t\t\tData Mover: %s\n", dataMover) d.Printf("\t\t\t\tUploader Type: %s\n", info.SnapshotDataMovementInfo.UploaderType) d.Printf("\t\t\t\tMoved data Size (bytes): %d\n", info.SnapshotDataMovementInfo.Size) + if info.SnapshotDataMovementInfo.IncrementalSize > 0 { + d.Printf("\t\t\t\tIncremental data Size (bytes): %d\n", info.SnapshotDataMovementInfo.IncrementalSize) + } d.Printf("\t\t\t\tResult: %s\n", info.Result) } else { d.Printf("\t\t\tData Movement: %s\n", "included, specify --details for more information") @@ -835,7 +838,7 @@ func describePodVolumeBackups(d *Describer, details bool, podVolumeBackups []vel backupsByPod := new(volumesByPod) for _, backup := range backupsByPhase[phase] { - backupsByPod.Add(backup.Spec.Pod.Namespace, backup.Spec.Pod.Name, backup.Spec.Volume, phase, backup.Status.Progress) + backupsByPod.Add(backup.Spec.Pod.Namespace, backup.Spec.Pod.Name, backup.Spec.Volume, phase, backup.Status.Progress, backup.Status.IncrementalBytes) } d.Printf("\t\t%s:\n", phase) @@ -885,7 +888,8 @@ type volumesByPod struct { // Add adds a pod volume with the specified pod namespace, name // and volume to the appropriate group. -func (v *volumesByPod) Add(namespace, name, volume, phase string, progress veleroapishared.DataMoveOperationProgress) { +// Used for both backup and restore +func (v *volumesByPod) Add(namespace, name, volume, phase string, progress veleroapishared.DataMoveOperationProgress, incrementalBytes int64) { if v.volumesByPodMap == nil { v.volumesByPodMap = make(map[string]*podVolumeGroup) } @@ -895,6 +899,12 @@ func (v *volumesByPod) Add(namespace, name, volume, phase string, progress veler // append backup progress percentage if backup is in progress if phase == "In Progress" && progress.TotalBytes != 0 { volume = fmt.Sprintf("%s (%.2f%%)", volume, float64(progress.BytesDone)/float64(progress.TotalBytes)*100) + } else if phase == string(velerov1api.PodVolumeBackupPhaseCompleted) && incrementalBytes > 0 { + volume = fmt.Sprintf("%s (size: %v, incremental size: %v)", volume, progress.TotalBytes, incrementalBytes) + } else if (phase == string(velerov1api.PodVolumeBackupPhaseCompleted) || + phase == string(velerov1api.PodVolumeRestorePhaseCompleted)) && + progress.TotalBytes > 0 { + volume = fmt.Sprintf("%s (size: %v)", volume, progress.TotalBytes) } if group, ok := v.volumesByPodMap[key]; !ok { diff --git a/pkg/cmd/util/output/backup_describer_test.go b/pkg/cmd/util/output/backup_describer_test.go index 96e25466f..0de03bdaa 100644 --- a/pkg/cmd/util/output/backup_describer_test.go +++ b/pkg/cmd/util/output/backup_describer_test.go @@ -597,11 +597,12 @@ func TestCSISnapshots(t *testing.T) { Result: volume.VolumeResultFailed, SnapshotDataMoved: true, SnapshotDataMovementInfo: &volume.SnapshotDataMovementInfo{ - UploaderType: "fake-uploader", - SnapshotHandle: "fake-repo-id-5", - OperationID: "fake-operation-5", - Size: 100, - Phase: velerov2alpha1.DataUploadPhaseFailed, + UploaderType: "fake-uploader", + SnapshotHandle: "fake-repo-id-5", + OperationID: "fake-operation-5", + Size: 100, + IncrementalSize: 50, + Phase: velerov2alpha1.DataUploadPhaseFailed, }, }, }, @@ -613,6 +614,7 @@ func TestCSISnapshots(t *testing.T) { Data Mover: velero Uploader Type: fake-uploader Moved data Size (bytes): 100 + Incremental data Size (bytes): 50 Result: failed `, }, diff --git a/pkg/cmd/util/output/backup_structured_describer.go b/pkg/cmd/util/output/backup_structured_describer.go index ad8d8381d..904afa34e 100644 --- a/pkg/cmd/util/output/backup_structured_describer.go +++ b/pkg/cmd/util/output/backup_structured_describer.go @@ -464,6 +464,10 @@ func describeDataMovementInSF(details bool, info *volume.BackupVolumeInfo, snaps dataMovement["uploaderType"] = info.SnapshotDataMovementInfo.UploaderType dataMovement["result"] = string(info.Result) + if info.SnapshotDataMovementInfo.Size > 0 || info.SnapshotDataMovementInfo.IncrementalSize > 0 { + dataMovement["size"] = info.SnapshotDataMovementInfo.Size + dataMovement["incrementalSize"] = info.SnapshotDataMovementInfo.IncrementalSize + } snapshotDetail["dataMovement"] = dataMovement } else { @@ -534,7 +538,7 @@ func describePodVolumeBackupsInSF(backups []velerov1api.PodVolumeBackup, details // group the backups in the current phase by pod (i.e. "ns/name") backupsByPod := new(volumesByPod) for _, backup := range backupsByPhase[phase] { - backupsByPod.Add(backup.Spec.Pod.Namespace, backup.Spec.Pod.Name, backup.Spec.Volume, phase, backup.Status.Progress) + backupsByPod.Add(backup.Spec.Pod.Namespace, backup.Spec.Pod.Name, backup.Spec.Volume, phase, backup.Status.Progress, backup.Status.IncrementalBytes) } backupsByPods := make([]map[string]string, 0) diff --git a/pkg/cmd/util/output/restore_describer.go b/pkg/cmd/util/output/restore_describer.go index 4bd3bff1f..a89943e74 100644 --- a/pkg/cmd/util/output/restore_describer.go +++ b/pkg/cmd/util/output/restore_describer.go @@ -408,7 +408,7 @@ func describePodVolumeRestores(d *Describer, restores []velerov1api.PodVolumeRes restoresByPod := new(volumesByPod) for _, restore := range restoresByPhase[phase] { - restoresByPod.Add(restore.Spec.Pod.Namespace, restore.Spec.Pod.Name, restore.Spec.Volume, phase, restore.Status.Progress) + restoresByPod.Add(restore.Spec.Pod.Namespace, restore.Spec.Pod.Name, restore.Spec.Volume, phase, restore.Status.Progress, 0) } d.Printf("\t%s:\n", phase) diff --git a/pkg/controller/data_upload_controller.go b/pkg/controller/data_upload_controller.go index 46704e5b1..e2f8787ed 100644 --- a/pkg/controller/data_upload_controller.go +++ b/pkg/controller/data_upload_controller.go @@ -493,6 +493,7 @@ func (r *DataUploadReconciler) OnDataUploadCompleted(ctx context.Context, namesp du.Status.Path = result.Backup.Source.ByPath du.Status.Phase = velerov2alpha1api.DataUploadPhaseCompleted du.Status.SnapshotID = result.Backup.SnapshotID + du.Status.IncrementalBytes = result.Backup.IncrementalBytes du.Status.CompletionTimestamp = &metav1.Time{Time: r.Clock.Now()} if result.Backup.EmptySnapshot { du.Status.Message = "volume was empty so no data was upload" diff --git a/pkg/controller/pod_volume_backup_controller.go b/pkg/controller/pod_volume_backup_controller.go index 625ec8337..aceaab780 100644 --- a/pkg/controller/pod_volume_backup_controller.go +++ b/pkg/controller/pod_volume_backup_controller.go @@ -526,6 +526,7 @@ func (r *PodVolumeBackupReconciler) OnDataPathCompleted(ctx context.Context, nam pvb.Status.Phase = velerov1api.PodVolumeBackupPhaseCompleted pvb.Status.SnapshotID = result.Backup.SnapshotID pvb.Status.CompletionTimestamp = &completionTime + pvb.Status.IncrementalBytes = result.Backup.IncrementalBytes if result.Backup.EmptySnapshot { pvb.Status.Message = "volume was empty so no snapshot was taken" } diff --git a/pkg/datamover/backup_micro_service_test.go b/pkg/datamover/backup_micro_service_test.go index c5e0e273a..160fcaac7 100644 --- a/pkg/datamover/backup_micro_service_test.go +++ b/pkg/datamover/backup_micro_service_test.go @@ -156,7 +156,7 @@ func TestOnDataUploadCompleted(t *testing.T) { { name: "marshal fail", marshalErr: errors.New("fake-marshal-error"), - expectedErr: "Failed to marshal backup result { false { } 0}: fake-marshal-error", + expectedErr: "Failed to marshal backup result { false { } 0 0}: fake-marshal-error", }, { name: "succeed", diff --git a/pkg/datapath/file_system.go b/pkg/datapath/file_system.go index 1ddf4b346..e1fa0ea5f 100644 --- a/pkg/datapath/file_system.go +++ b/pkg/datapath/file_system.go @@ -182,7 +182,7 @@ func (fs *fileSystemBR) StartBackup(source AccessPoint, uploaderConfig map[strin fs.wgDataPath.Done() }() - snapshotID, emptySnapshot, totalBytes, err := fs.uploaderProv.RunBackup(fs.ctx, source.ByPath, backupParam.RealSource, backupParam.Tags, backupParam.ForceFull, + snapshotID, emptySnapshot, totalBytes, incrementalBytes, err := fs.uploaderProv.RunBackup(fs.ctx, source.ByPath, backupParam.RealSource, backupParam.Tags, backupParam.ForceFull, backupParam.ParentSnapshot, source.VolMode, uploaderConfig, fs) if err == provider.ErrorCanceled { @@ -194,7 +194,7 @@ func (fs *fileSystemBR) StartBackup(source AccessPoint, uploaderConfig map[strin } fs.callbacks.OnFailed(context.Background(), fs.namespace, fs.jobName, dataPathErr) } else { - fs.callbacks.OnCompleted(context.Background(), fs.namespace, fs.jobName, Result{Backup: BackupResult{snapshotID, emptySnapshot, source, totalBytes}}) + fs.callbacks.OnCompleted(context.Background(), fs.namespace, fs.jobName, Result{Backup: BackupResult{snapshotID, emptySnapshot, source, totalBytes, incrementalBytes}}) } }() diff --git a/pkg/datapath/file_system_test.go b/pkg/datapath/file_system_test.go index 4e196595e..e3573e053 100644 --- a/pkg/datapath/file_system_test.go +++ b/pkg/datapath/file_system_test.go @@ -96,7 +96,7 @@ func TestAsyncBackup(t *testing.T) { t.Run(test.name, func(t *testing.T) { fs := newFileSystemBR("job-1", "test", nil, "velero", Callbacks{}, velerotest.NewLogger()).(*fileSystemBR) mockProvider := providerMock.NewProvider(t) - mockProvider.On("RunBackup", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(test.result.Backup.SnapshotID, test.result.Backup.EmptySnapshot, test.result.Backup.TotalBytes, test.err) + mockProvider.On("RunBackup", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(test.result.Backup.SnapshotID, test.result.Backup.EmptySnapshot, test.result.Backup.TotalBytes, test.result.Backup.IncrementalBytes, test.err) mockProvider.On("Close", mock.Anything).Return(nil) fs.uploaderProv = mockProvider fs.initialized = true diff --git a/pkg/datapath/types.go b/pkg/datapath/types.go index 52b9bddd6..a9c2331a6 100644 --- a/pkg/datapath/types.go +++ b/pkg/datapath/types.go @@ -30,10 +30,11 @@ type Result struct { // BackupResult represents the result of a backup type BackupResult struct { - SnapshotID string `json:"snapshotID"` - EmptySnapshot bool `json:"emptySnapshot"` - Source AccessPoint `json:"source,omitempty"` - TotalBytes int64 `json:"totalBytes,omitempty"` + SnapshotID string `json:"snapshotID"` + EmptySnapshot bool `json:"emptySnapshot"` + Source AccessPoint `json:"source,omitempty"` + TotalBytes int64 `json:"totalBytes,omitempty"` + IncrementalBytes int64 `json:"incrementalBytes,omitempty"` } // RestoreResult represents the result of a restore diff --git a/pkg/podvolume/backup_micro_service_test.go b/pkg/podvolume/backup_micro_service_test.go index ed6785b57..eb10b622a 100644 --- a/pkg/podvolume/backup_micro_service_test.go +++ b/pkg/podvolume/backup_micro_service_test.go @@ -155,7 +155,7 @@ func TestOnDataPathCompleted(t *testing.T) { { name: "marshal fail", marshalErr: errors.New("fake-marshal-error"), - expectedErr: "Failed to marshal backup result { false { } 0}: fake-marshal-error", + expectedErr: "Failed to marshal backup result { false { } 0 0}: fake-marshal-error", }, { name: "succeed", diff --git a/pkg/uploader/kopia/progress.go b/pkg/uploader/kopia/progress.go index b4e9ce1f2..5071398d0 100644 --- a/pkg/uploader/kopia/progress.go +++ b/pkg/uploader/kopia/progress.go @@ -177,3 +177,7 @@ func (p *Progress) EstimationParameters() upload.EstimationParameters { func (p *Progress) Enabled() bool { return true } + +func (p *Progress) GetIncrementalSize() int64 { + return p.estimatedTotalBytes - p.cachedBytes +} diff --git a/pkg/uploader/provider/kopia.go b/pkg/uploader/provider/kopia.go index b09b8a571..5bdc67562 100644 --- a/pkg/uploader/provider/kopia.go +++ b/pkg/uploader/provider/kopia.go @@ -120,13 +120,13 @@ func (kp *kopiaProvider) RunBackup( parentSnapshot string, volMode uploader.PersistentVolumeMode, uploaderCfg map[string]string, - updater uploader.ProgressUpdater) (string, bool, int64, error) { + updater uploader.ProgressUpdater) (string, bool, int64, int64, error) { if updater == nil { - return "", false, 0, errors.New("Need to initial backup progress updater first") + return "", false, 0, 0, errors.New("Need to initial backup progress updater first") } if path == "" { - return "", false, 0, errors.New("path is empty") + return "", false, 0, 0, errors.New("path is empty") } log := kp.log.WithFields(logrus.Fields{ @@ -136,7 +136,8 @@ func (kp *kopiaProvider) RunBackup( }) repoWriter := kopia.NewShimRepo(kp.bkRepo) kpUploader := upload.NewUploader(repoWriter) - kpUploader.Progress = kopia.NewProgress(updater, backupProgressCheckInterval, log) + progress := kopia.NewProgress(updater, backupProgressCheckInterval, log) + kpUploader.Progress = progress kpUploader.FailFast = true quit := make(chan struct{}) log.Info("Starting backup") @@ -175,9 +176,9 @@ func (kp *kopiaProvider) RunBackup( if kpUploader.IsCanceled() { log.Warn("Kopia backup is canceled") - return snapshotID, false, 0, ErrorCanceled + return snapshotID, false, 0, 0, ErrorCanceled } - return snapshotID, false, 0, errors.Wrapf(err, "Failed to run kopia backup") + return snapshotID, false, 0, 0, errors.Wrapf(err, "Failed to run kopia backup") } // which ensure that the statistic data of TotalBytes equal to BytesDone when finished @@ -189,7 +190,7 @@ func (kp *kopiaProvider) RunBackup( ) log.Debugf("Kopia backup finished, snapshot ID %s, backup size %d", snapshotInfo.ID, snapshotInfo.Size) - return snapshotInfo.ID, false, snapshotInfo.Size, nil + return snapshotInfo.ID, false, snapshotInfo.Size, progress.GetIncrementalSize(), nil } func (kp *kopiaProvider) GetPassword(param any) (string, error) { diff --git a/pkg/uploader/provider/kopia_test.go b/pkg/uploader/provider/kopia_test.go index 6231d5d62..861ce1997 100644 --- a/pkg/uploader/provider/kopia_test.go +++ b/pkg/uploader/provider/kopia_test.go @@ -106,7 +106,7 @@ func TestRunBackup(t *testing.T) { tc.volMode = uploader.PersistentVolumeFilesystem } BackupFunc = tc.hookBackupFunc - _, _, _, err := kp.RunBackup(t.Context(), "var", "", nil, false, "", tc.volMode, map[string]string{}, &updater) + _, _, _, _, err := kp.RunBackup(t.Context(), "var", "", nil, false, "", tc.volMode, map[string]string{}, &updater) if tc.notError { assert.NoError(t, err) } else { diff --git a/pkg/uploader/provider/mocks/Provider.go b/pkg/uploader/provider/mocks/Provider.go index f09472d56..d4c3e83c3 100644 --- a/pkg/uploader/provider/mocks/Provider.go +++ b/pkg/uploader/provider/mocks/Provider.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.53.5. DO NOT EDIT. package mocks @@ -34,7 +34,7 @@ func (_m *Provider) Close(ctx context.Context) error { } // RunBackup provides a mock function with given fields: ctx, path, realSource, tags, forceFull, parentSnapshot, volMode, uploaderCfg, updater -func (_m *Provider) RunBackup(ctx context.Context, path string, realSource string, tags map[string]string, forceFull bool, parentSnapshot string, volMode uploader.PersistentVolumeMode, uploaderCfg map[string]string, updater uploader.ProgressUpdater) (string, bool, int64, error) { +func (_m *Provider) RunBackup(ctx context.Context, path string, realSource string, tags map[string]string, forceFull bool, parentSnapshot string, volMode uploader.PersistentVolumeMode, uploaderCfg map[string]string, updater uploader.ProgressUpdater) (string, bool, int64, int64, error) { ret := _m.Called(ctx, path, realSource, tags, forceFull, parentSnapshot, volMode, uploaderCfg, updater) if len(ret) == 0 { @@ -44,8 +44,9 @@ func (_m *Provider) RunBackup(ctx context.Context, path string, realSource strin var r0 string var r1 bool var r2 int64 - var r3 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, map[string]string, bool, string, uploader.PersistentVolumeMode, map[string]string, uploader.ProgressUpdater) (string, bool, int64, error)); ok { + var r3 int64 + var r4 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, map[string]string, bool, string, uploader.PersistentVolumeMode, map[string]string, uploader.ProgressUpdater) (string, bool, int64, int64, error)); ok { return rf(ctx, path, realSource, tags, forceFull, parentSnapshot, volMode, uploaderCfg, updater) } if rf, ok := ret.Get(0).(func(context.Context, string, string, map[string]string, bool, string, uploader.PersistentVolumeMode, map[string]string, uploader.ProgressUpdater) string); ok { @@ -66,13 +67,19 @@ func (_m *Provider) RunBackup(ctx context.Context, path string, realSource strin r2 = ret.Get(2).(int64) } - if rf, ok := ret.Get(3).(func(context.Context, string, string, map[string]string, bool, string, uploader.PersistentVolumeMode, map[string]string, uploader.ProgressUpdater) error); ok { + if rf, ok := ret.Get(3).(func(context.Context, string, string, map[string]string, bool, string, uploader.PersistentVolumeMode, map[string]string, uploader.ProgressUpdater) int64); ok { r3 = rf(ctx, path, realSource, tags, forceFull, parentSnapshot, volMode, uploaderCfg, updater) } else { - r3 = ret.Error(3) + r3 = ret.Get(3).(int64) } - return r0, r1, r2, r3 + if rf, ok := ret.Get(4).(func(context.Context, string, string, map[string]string, bool, string, uploader.PersistentVolumeMode, map[string]string, uploader.ProgressUpdater) error); ok { + r4 = rf(ctx, path, realSource, tags, forceFull, parentSnapshot, volMode, uploaderCfg, updater) + } else { + r4 = ret.Error(4) + } + + return r0, r1, r2, r3, r4 } // RunRestore provides a mock function with given fields: ctx, snapshotID, volumePath, volMode, uploaderConfig, updater diff --git a/pkg/uploader/provider/provider.go b/pkg/uploader/provider/provider.go index 0d77dffad..fe1dd3091 100644 --- a/pkg/uploader/provider/provider.go +++ b/pkg/uploader/provider/provider.go @@ -50,7 +50,7 @@ type Provider interface { parentSnapshot string, volMode uploader.PersistentVolumeMode, uploaderCfg map[string]string, - updater uploader.ProgressUpdater) (string, bool, int64, error) + updater uploader.ProgressUpdater) (string, bool, int64, int64, error) // RunRestore which will do restore for one specific volume with given snapshot id and return error // updater is used for updating backup progress which implement by third-party RunRestore( diff --git a/pkg/uploader/provider/restic.go b/pkg/uploader/provider/restic.go index 4eb755759..5b8f51fbc 100644 --- a/pkg/uploader/provider/restic.go +++ b/pkg/uploader/provider/restic.go @@ -124,21 +124,21 @@ func (rp *resticProvider) RunBackup( parentSnapshot string, volMode uploader.PersistentVolumeMode, uploaderCfg map[string]string, - updater uploader.ProgressUpdater) (string, bool, int64, error) { + updater uploader.ProgressUpdater) (string, bool, int64, int64, error) { if updater == nil { - return "", false, 0, errors.New("Need to initial backup progress updater first") + return "", false, 0, 0, errors.New("Need to initial backup progress updater first") } if path == "" { - return "", false, 0, errors.New("path is empty") + return "", false, 0, 0, errors.New("path is empty") } if realSource != "" { - return "", false, 0, errors.New("real source is not empty, this is not supported by restic uploader") + return "", false, 0, 0, errors.New("real source is not empty, this is not supported by restic uploader") } if volMode == uploader.PersistentVolumeBlock { - return "", false, 0, errors.New("unable to support block mode") + return "", false, 0, 0, errors.New("unable to support block mode") } log := rp.log.WithFields(logrus.Fields{ @@ -149,7 +149,7 @@ func (rp *resticProvider) RunBackup( if len(uploaderCfg) > 0 { parallelFilesUpload, err := uploaderutil.GetParallelFilesUpload(uploaderCfg) if err != nil { - return "", false, 0, errors.Wrap(err, "failed to get uploader config") + return "", false, 0, 0, errors.Wrap(err, "failed to get uploader config") } if parallelFilesUpload > 0 { log.Warnf("ParallelFilesUpload is set to %d, but restic does not support parallel file uploads. Ignoring.", parallelFilesUpload) @@ -171,9 +171,9 @@ func (rp *resticProvider) RunBackup( if err != nil { if strings.Contains(stderrBuf, "snapshot is empty") { log.Debugf("Restic backup got empty dir with %s path", path) - return "", true, 0, nil + return "", true, 0, 0, nil } - return "", false, 0, errors.WithStack(fmt.Errorf("error running restic backup command %s with error: %v stderr: %v", backupCmd.String(), err, stderrBuf)) + return "", false, 0, 0, errors.WithStack(fmt.Errorf("error running restic backup command %s with error: %v stderr: %v", backupCmd.String(), err, stderrBuf)) } // GetSnapshotID snapshotIDCmd := resticGetSnapshotFunc(rp.repoIdentifier, rp.credentialsFile, tags) @@ -184,10 +184,10 @@ func (rp *resticProvider) RunBackup( } snapshotID, err := resticGetSnapshotIDFunc(snapshotIDCmd) if err != nil { - return "", false, 0, errors.WithStack(fmt.Errorf("error getting snapshot id with error: %v", err)) + return "", false, 0, 0, errors.WithStack(fmt.Errorf("error getting snapshot id with error: %v", err)) } log.Infof("Run command=%s, stdout=%s, stderr=%s", backupCmd.String(), summary, stderrBuf) - return snapshotID, false, 0, nil + return snapshotID, false, 0, 0, nil } // RunRestore runs a `restore` command and monitors the volume size to diff --git a/pkg/uploader/provider/restic_test.go b/pkg/uploader/provider/restic_test.go index 3f450f554..24eb11e04 100644 --- a/pkg/uploader/provider/restic_test.go +++ b/pkg/uploader/provider/restic_test.go @@ -149,9 +149,9 @@ func TestResticRunBackup(t *testing.T) { } if !tc.nilUpdater { updater := FakeBackupProgressUpdater{PodVolumeBackup: &velerov1api.PodVolumeBackup{}, Log: tc.rp.log, Ctx: t.Context(), Cli: fake.NewClientBuilder().WithScheme(util.VeleroScheme).Build()} - _, _, _, err = tc.rp.RunBackup(t.Context(), "var", "", map[string]string{}, false, parentSnapshot, tc.volMode, map[string]string{}, &updater) + _, _, _, _, err = tc.rp.RunBackup(t.Context(), "var", "", map[string]string{}, false, parentSnapshot, tc.volMode, map[string]string{}, &updater) } else { - _, _, _, err = tc.rp.RunBackup(t.Context(), "var", "", map[string]string{}, false, parentSnapshot, tc.volMode, map[string]string{}, nil) + _, _, _, _, err = tc.rp.RunBackup(t.Context(), "var", "", map[string]string{}, false, parentSnapshot, tc.volMode, map[string]string{}, nil) } tc.rp.log.Infof("test name %v error %v", tc.name, err) diff --git a/site/content/docs/main/csi-snapshot-data-movement.md b/site/content/docs/main/csi-snapshot-data-movement.md index 930fc1be5..3e96dcd6a 100644 --- a/site/content/docs/main/csi-snapshot-data-movement.md +++ b/site/content/docs/main/csi-snapshot-data-movement.md @@ -116,12 +116,17 @@ velero backup create NAME --snapshot-move-data --data-mover DATA-MOVER-NAME OPTI When the backup starts, you will see the `VolumeSnapshot` and `VolumeSnapshotContent` objects created, but after the backup finishes, the objects will disappear. After snapshots are created, you will see one or more `DataUpload` CRs created. You may also see some intermediate objects (i.e., pods, PVCs, PVs) created in Velero namespace or the cluster scope, they are to help data movers to move data. And they will be removed after the backup completes. -The phase of a `DataUpload` CR changes several times during the backup process and finally goes to one of the terminal status, `Completed`, `Failed` or `Cancelled`. You can see the phase changes as well as the data upload progress by watching the `DataUpload` CRs: +The phase of a `DataUpload` CR changes several times during the backup process and finally goes to one of the terminal status, `Completed`, `Failed` or `Cancelled`. You can see the phase changes as well as the data upload progress by watching the `DataUpload` CRs. While the `DataUpload` is being processed, progress is shown with `BYTES DONE` representing the amount of volume data that has been processed so far and `TOTAL BYTES` representing the estimated total volume data. Upon completion, these two numbers will be the same. In addition, once the `DataUpload` is done, `INCREMENTAL BYTES` will be filled in with the amount of data which is new or changed since the last backup of this volume. Note that the actual uploaded content may be smaller than `INCREMENTAL BYTES` due to kopia deduplication, compression, etc. ```bash kubectl -n velero get datauploads -l velero.io/backup-name=YOUR_BACKUP_NAME -w ``` +By default, `INCREMENTAL BYTES` is not displayed in the `kubectl get` output. To see this extended field, the `-o wide` arg is needed: +```bash +kubectl -n velero get datauploads -o wide -l velero.io/backup-name=YOUR_BACKUP_NAME -w +``` + When the backup completes, you can view information about the backups: ```bash From c2840f1c747af5a53e95f048b46ba386dfe00e92 Mon Sep 17 00:00:00 2001 From: Shubham Pampattiwar Date: Mon, 27 Oct 2025 12:44:31 -0700 Subject: [PATCH 075/104] Fix tests: populate createdName for all created resources Update test expectations to include createdName field for resources with action 'created'. Also ensure namespaces track their created names when created via EnsureNamespaceExistsAndIsReady. Signed-off-by: Shubham Pampattiwar --- pkg/restore/restore.go | 4 ++-- pkg/restore/restore_test.go | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/restore/restore.go b/pkg/restore/restore.go index 52c947835..c6ad23dd3 100644 --- a/pkg/restore/restore.go +++ b/pkg/restore/restore.go @@ -741,7 +741,7 @@ func (ctx *restoreContext) processSelectedResource( namespace: ns.Namespace, name: ns.Name, } - ctx.restoredItems[itemKey] = restoredItemStatus{action: ItemRestoreResultCreated, itemExists: true} + ctx.restoredItems[itemKey] = restoredItemStatus{action: ItemRestoreResultCreated, itemExists: true, createdName: ns.Name} } // Keep track of namespaces that we know exist so we don't @@ -1142,7 +1142,7 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso namespace: nsToEnsure.Namespace, name: nsToEnsure.Name, } - ctx.restoredItems[itemKey] = restoredItemStatus{action: ItemRestoreResultCreated, itemExists: true} + ctx.restoredItems[itemKey] = restoredItemStatus{action: ItemRestoreResultCreated, itemExists: true, createdName: nsToEnsure.Name} } } else { if boolptr.IsSetToFalse(ctx.restore.Spec.IncludeClusterResources) { diff --git a/pkg/restore/restore_test.go b/pkg/restore/restore_test.go index 54523731f..95b283cbe 100644 --- a/pkg/restore/restore_test.go +++ b/pkg/restore/restore_test.go @@ -1091,8 +1091,8 @@ func TestRestoreItems(t *testing.T) { ), }, expectedRestoreItems: map[itemKey]restoredItemStatus{ - {resource: "v1/Namespace", namespace: "", name: "ns-1"}: {action: "created", itemExists: true}, - {resource: "v1/Pod", namespace: "ns-1", name: "pod-1"}: {action: "created", itemExists: true}, + {resource: "v1/Namespace", namespace: "", name: "ns-1"}: {action: "created", itemExists: true, createdName: "ns-1"}, + {resource: "v1/Pod", namespace: "ns-1", name: "pod-1"}: {action: "created", itemExists: true, createdName: "pod-1"}, }, }, { @@ -1201,7 +1201,7 @@ func TestRestoreItems(t *testing.T) { test.ServiceAccounts(builder.ForServiceAccount("ns-1", "sa-1").Result()), }, expectedRestoreItems: map[itemKey]restoredItemStatus{ - {resource: "v1/Namespace", namespace: "", name: "ns-1"}: {action: "created", itemExists: true}, + {resource: "v1/Namespace", namespace: "", name: "ns-1"}: {action: "created", itemExists: true, createdName: "ns-1"}, {resource: "v1/ServiceAccount", namespace: "ns-1", name: "sa-1"}: {action: "skipped", itemExists: true}, }, }, @@ -1220,7 +1220,7 @@ func TestRestoreItems(t *testing.T) { test.Secrets(builder.ForSecret("ns-1", "sa-1").ObjectMeta(builder.WithLabels("velero.io/backup-name", "backup-1", "velero.io/restore-name", "restore-1")).Data(map[string][]byte{"key-1": []byte("value-1")}).Result()), }, expectedRestoreItems: map[itemKey]restoredItemStatus{ - {resource: "v1/Namespace", namespace: "", name: "ns-1"}: {action: "created", itemExists: true}, + {resource: "v1/Namespace", namespace: "", name: "ns-1"}: {action: "created", itemExists: true, createdName: "ns-1"}, {resource: "v1/Secret", namespace: "ns-1", name: "sa-1"}: {action: "updated", itemExists: true}, }, }, @@ -1239,7 +1239,7 @@ func TestRestoreItems(t *testing.T) { test.Secrets(builder.ForSecret("ns-1", "sa-1").ObjectMeta(builder.WithLabels("velero.io/backup-name", "backup-1", "velero.io/restore-name", "restore-1")).Data(map[string][]byte{"key-1": []byte("value-1")}).Result()), }, expectedRestoreItems: map[itemKey]restoredItemStatus{ - {resource: "v1/Namespace", namespace: "", name: "ns-1"}: {action: "created", itemExists: true}, + {resource: "v1/Namespace", namespace: "", name: "ns-1"}: {action: "created", itemExists: true, createdName: "ns-1"}, {resource: "v1/Secret", namespace: "ns-1", name: "sa-1"}: {action: "updated", itemExists: true}, }, }, From 5e9605131bebc7ff5bcbff42ba43a6b2537b07d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 20:02:29 +0000 Subject: [PATCH 076/104] Bump actions/upload-artifact from 4 to 5 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/e2e-test-kind.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2e-test-kind.yaml b/.github/workflows/e2e-test-kind.yaml index 47979a27c..0f5972f57 100644 --- a/.github/workflows/e2e-test-kind.yaml +++ b/.github/workflows/e2e-test-kind.yaml @@ -185,7 +185,7 @@ jobs: timeout-minutes: 30 - name: Upload debug bundle if: ${{ failure() }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: DebugBundle path: /home/runner/work/velero/velero/test/e2e/debug-bundle* From b1e5e4408fcbe55f4a0454edec6cdf3eace6eea6 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Fri, 24 Oct 2025 17:28:17 +0800 Subject: [PATCH 077/104] exposer supports cache volume Signed-off-by: Lyndon-Li --- changelogs/unreleased/9362-Lyndon-Li | 1 + pkg/exposer/cache_volume_test.go | 80 ++++++++++++ pkg/exposer/generic_restore.go | 17 +-- pkg/exposer/generic_restore_test.go | 168 +++++++++++++++++++++++++- pkg/exposer/pod_volume.go | 17 +-- pkg/exposer/pod_volume_test.go | 174 ++++++++++++++++++++++++++- 6 files changed, 430 insertions(+), 27 deletions(-) create mode 100644 changelogs/unreleased/9362-Lyndon-Li create mode 100644 pkg/exposer/cache_volume_test.go diff --git a/changelogs/unreleased/9362-Lyndon-Li b/changelogs/unreleased/9362-Lyndon-Li new file mode 100644 index 000000000..791b3836d --- /dev/null +++ b/changelogs/unreleased/9362-Lyndon-Li @@ -0,0 +1 @@ +Support cache volume for generic restore exposer and pod volume exposer \ No newline at end of file diff --git a/pkg/exposer/cache_volume_test.go b/pkg/exposer/cache_volume_test.go new file mode 100644 index 000000000..03e3a797c --- /dev/null +++ b/pkg/exposer/cache_volume_test.go @@ -0,0 +1,80 @@ +/* +Copyright 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 exposer + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestGetCacheVolumeSize(t *testing.T) { + tests := []struct { + name string + dataSize int64 + info *CacheConfigs + expected int64 + }{ + { + name: "nil info", + dataSize: 1024, + expected: 0, + }, + { + name: "0 data size", + info: &CacheConfigs{Limit: 1 << 30, ResidentThreshold: 5120}, + expected: 2 << 30, + }, + { + name: "0 threshold", + dataSize: 2048, + info: &CacheConfigs{Limit: 1 << 30}, + expected: 2 << 30, + }, + { + name: "data size is smaller", + dataSize: 2048, + info: &CacheConfigs{Limit: 1 << 30, ResidentThreshold: 5120}, + expected: 0, + }, + { + name: "data size is lager", + dataSize: 2048, + info: &CacheConfigs{Limit: 1 << 30, ResidentThreshold: 1024}, + expected: 2 << 30, + }, + { + name: "limit smaller than 1G", + dataSize: 2048, + info: &CacheConfigs{Limit: 5120, ResidentThreshold: 1024}, + expected: 1 << 30, + }, + { + name: "larger than 1G after inflate", + dataSize: 2048, + info: &CacheConfigs{Limit: (1 << 30) - 1024, ResidentThreshold: 1024}, + expected: 2 << 30, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + size := getCacheVolumeSize(test.dataSize, test.info) + require.Equal(t, test.expected, size) + }) + } +} diff --git a/pkg/exposer/generic_restore.go b/pkg/exposer/generic_restore.go index a2d4ab020..c10370072 100644 --- a/pkg/exposer/generic_restore.go +++ b/pkg/exposer/generic_restore.go @@ -316,19 +316,12 @@ func (e *genericRestoreExposer) DiagnoseExpose(ctx context.Context, ownerObject diag += fmt.Sprintf("error getting restore pvc %s, err: %v\n", restorePVCName, err) } - var cachePVC *corev1api.PersistentVolumeClaim - if pod.Spec.Volumes != nil { - for _, v := range pod.Spec.Volumes { - if v.Name == cacheVolumeName { - cachePVC, err = e.kubeClient.CoreV1().PersistentVolumeClaims(ownerObject.Namespace).Get(ctx, getCachePVCName(ownerObject), metav1.GetOptions{}) - if err != nil { - cachePVC = nil - diag += fmt.Sprintf("error getting cache pvc %s, err: %v\n", getCachePVCName(ownerObject), err) - } - - break - } + cachePVC, err := e.kubeClient.CoreV1().PersistentVolumeClaims(ownerObject.Namespace).Get(ctx, getCachePVCName(ownerObject), metav1.GetOptions{}) + if err != nil { + cachePVC = nil + if !apierrors.IsNotFound(err) { + diag += fmt.Sprintf("error getting cache pvc %s, err: %v\n", getCachePVCName(ownerObject), err) } } diff --git a/pkg/exposer/generic_restore_test.go b/pkg/exposer/generic_restore_test.go index 271e4e7d6..9f32ce1d1 100644 --- a/pkg/exposer/generic_restore_test.go +++ b/pkg/exposer/generic_restore_test.go @@ -26,6 +26,7 @@ import ( appsv1api "k8s.io/api/apps/v1" corev1api "k8s.io/api/core/v1" storagev1api "k8s.io/api/storage/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes/fake" @@ -105,6 +106,10 @@ func TestRestoreExpose(t *testing.T) { targetPVCName string targetNamespace string kubeReactors []reactor + cacheVolume *CacheConfigs + expectBackupPod bool + expectBackupPVC bool + expectCachePVC bool err string }{ { @@ -167,6 +172,70 @@ func TestRestoreExpose(t *testing.T) { }, err: "error to create restore pvc: fake-create-error", }, + { + name: "succeed", + targetPVCName: "fake-target-pvc", + targetNamespace: "fake-ns", + ownerRestore: restore, + kubeClientObj: []runtime.Object{ + targetPVCObj, + daemonSet, + storageClass, + }, + expectBackupPod: true, + expectBackupPVC: true, + }, + { + name: "succeed, cache config, no cache volume", + targetPVCName: "fake-target-pvc", + targetNamespace: "fake-ns", + ownerRestore: restore, + kubeClientObj: []runtime.Object{ + targetPVCObj, + daemonSet, + storageClass, + }, + cacheVolume: &CacheConfigs{}, + expectBackupPod: true, + expectBackupPVC: true, + }, + { + name: "create cache volume fail", + targetPVCName: "fake-target-pvc", + targetNamespace: "fake-ns", + ownerRestore: restore, + kubeClientObj: []runtime.Object{ + targetPVCObj, + daemonSet, + storageClass, + }, + cacheVolume: &CacheConfigs{Limit: 1024}, + kubeReactors: []reactor{ + { + verb: "create", + resource: "persistentvolumeclaims", + reactorFunc: func(action clientTesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, errors.New("fake-create-error") + }, + }, + }, + err: "error to create cache pvc: fake-create-error", + }, + { + name: "succeed with cache volume", + targetPVCName: "fake-target-pvc", + targetNamespace: "fake-ns", + ownerRestore: restore, + kubeClientObj: []runtime.Object{ + targetPVCObj, + daemonSet, + storageClass, + }, + cacheVolume: &CacheConfigs{Limit: 1024}, + expectBackupPod: true, + expectBackupPVC: true, + expectCachePVC: true, + }, } for _, test := range tests { @@ -203,9 +272,36 @@ func TestRestoreExpose(t *testing.T) { Resources: corev1api.ResourceRequirements{}, ExposeTimeout: time.Millisecond, LoadAffinity: nil, + CacheVolume: test.cacheVolume, }, ) - require.EqualError(t, err, test.err) + + if test.err != "" { + require.EqualError(t, err, test.err) + } else { + require.NoError(t, err) + } + + _, err = exposer.kubeClient.CoreV1().Pods(ownerObject.Namespace).Get(t.Context(), ownerObject.Name, metav1.GetOptions{}) + if test.expectBackupPod { + require.NoError(t, err) + } else { + require.True(t, apierrors.IsNotFound(err)) + } + + _, err = exposer.kubeClient.CoreV1().PersistentVolumeClaims(ownerObject.Namespace).Get(t.Context(), ownerObject.Name, metav1.GetOptions{}) + if test.expectBackupPVC { + require.NoError(t, err) + } else { + require.True(t, apierrors.IsNotFound(err)) + } + + _, err = exposer.kubeClient.CoreV1().PersistentVolumeClaims(ownerObject.Namespace).Get(t.Context(), getCachePVCName(ownerObject), metav1.GetOptions{}) + if test.expectCachePVC { + require.NoError(t, err) + } else { + require.True(t, apierrors.IsNotFound(err)) + } }) } } @@ -651,6 +747,38 @@ func Test_ReastoreDiagnoseExpose(t *testing.T) { }, } + cachePVCWithVolumeName := corev1api.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: velerov1.DefaultNamespace, + Name: "fake-restore-cache", + UID: "fake-cache-pvc-uid", + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: restore.APIVersion, + Kind: restore.Kind, + Name: restore.Name, + UID: restore.UID, + }, + }, + }, + Spec: corev1api.PersistentVolumeClaimSpec{ + VolumeName: "fake-pv-cache", + }, + Status: corev1api.PersistentVolumeClaimStatus{ + Phase: corev1api.ClaimPending, + }, + } + + cachePV := corev1api.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: "fake-pv-cache", + }, + Status: corev1api.PersistentVolumeStatus{ + Phase: corev1api.VolumePending, + Message: "fake-pv-message", + }, + } + nodeAgentPod := corev1api.Pod{ ObjectMeta: metav1.ObjectMeta{ Namespace: velerov1.DefaultNamespace, @@ -762,6 +890,44 @@ Pod velero/fake-restore, phase Pending, node name fake-node Pod condition Initialized, status True, reason , message fake-pod-message PVC velero/fake-restore, phase Pending, binding to fake-pv PV fake-pv, phase Pending, reason , message fake-pv-message +end diagnose restore exposer`, + }, + { + name: "cache pvc with volume name, no pv", + ownerRestore: restore, + kubeClientObj: []runtime.Object{ + &restorePodWithNodeName, + &restorePVCWithVolumeName, + &cachePVCWithVolumeName, + &nodeAgentPod, + }, + expected: `begin diagnose restore exposer +Pod velero/fake-restore, phase Pending, node name fake-node +Pod condition Initialized, status True, reason , message fake-pod-message +PVC velero/fake-restore, phase Pending, binding to fake-pv +error getting restore pv fake-pv, err: persistentvolumes "fake-pv" not found +PVC velero/fake-restore-cache, phase Pending, binding to fake-pv-cache +error getting cache pv fake-pv-cache, err: persistentvolumes "fake-pv-cache" not found +end diagnose restore exposer`, + }, + { + name: "cache pvc with volume name, pv exists", + ownerRestore: restore, + kubeClientObj: []runtime.Object{ + &restorePodWithNodeName, + &restorePVCWithVolumeName, + &cachePVCWithVolumeName, + &restorePV, + &cachePV, + &nodeAgentPod, + }, + expected: `begin diagnose restore exposer +Pod velero/fake-restore, phase Pending, node name fake-node +Pod condition Initialized, status True, reason , message fake-pod-message +PVC velero/fake-restore, phase Pending, binding to fake-pv +PV fake-pv, phase Pending, reason , message fake-pv-message +PVC velero/fake-restore-cache, phase Pending, binding to fake-pv-cache +PV fake-pv-cache, phase Pending, reason , message fake-pv-message end diagnose restore exposer`, }, { diff --git a/pkg/exposer/pod_volume.go b/pkg/exposer/pod_volume.go index 1702fb0f5..1f18056d0 100644 --- a/pkg/exposer/pod_volume.go +++ b/pkg/exposer/pod_volume.go @@ -279,19 +279,12 @@ func (e *podVolumeExposer) DiagnoseExpose(ctx context.Context, ownerObject corev diag += fmt.Sprintf("error getting hosting pod %s, err: %v\n", hostingPodName, err) } - var cachePVC *corev1api.PersistentVolumeClaim - if pod.Spec.Volumes != nil { - for _, v := range pod.Spec.Volumes { - if v.Name == cacheVolumeName { - cachePVC, err = e.kubeClient.CoreV1().PersistentVolumeClaims(ownerObject.Namespace).Get(ctx, getCachePVCName(ownerObject), metav1.GetOptions{}) - if err != nil { - cachePVC = nil - diag += fmt.Sprintf("error getting cache pvc %s, err: %v\n", getCachePVCName(ownerObject), err) - } - - break - } + cachePVC, err := e.kubeClient.CoreV1().PersistentVolumeClaims(ownerObject.Namespace).Get(ctx, getCachePVCName(ownerObject), metav1.GetOptions{}) + if err != nil { + cachePVC = nil + if !apierrors.IsNotFound(err) { + diag += fmt.Sprintf("error getting cache pvc %s, err: %v\n", getCachePVCName(ownerObject), err) } } diff --git a/pkg/exposer/pod_volume_test.go b/pkg/exposer/pod_volume_test.go index f48e9376b..ebf76efe9 100644 --- a/pkg/exposer/pod_volume_test.go +++ b/pkg/exposer/pod_volume_test.go @@ -11,10 +11,12 @@ import ( "github.com/stretchr/testify/require" appsv1api "k8s.io/api/apps/v1" corev1api "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/fake" + clientTesting "k8s.io/client-go/testing" clientFake "sigs.k8s.io/controller-runtime/pkg/client/fake" velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" @@ -72,6 +74,9 @@ func TestPodVolumeExpose(t *testing.T) { exposeParam PodVolumeExposeParam funcGetPodVolumeHostPath func(context.Context, *corev1api.Pod, string, kubernetes.Interface, filesystem.Interface, logrus.FieldLogger) (datapath.AccessPoint, error) funcExtractPodVolumeHostPath func(context.Context, string, kubernetes.Interface, string, string) (string, error) + kubeReactors []reactor + expectBackupPod bool + expectCachePVC bool err string }{ { @@ -189,6 +194,7 @@ func TestPodVolumeExpose(t *testing.T) { funcExtractPodVolumeHostPath: func(context.Context, string, kubernetes.Interface, string, string) (string, error) { return "/var/lib/kubelet/pods/pod-id-xxx/volumes/kubernetes.io~csi/pvc-id-xxx/mount", nil }, + expectBackupPod: true, }, { name: "succeed with privileged pod", @@ -212,6 +218,89 @@ func TestPodVolumeExpose(t *testing.T) { funcExtractPodVolumeHostPath: func(context.Context, string, kubernetes.Interface, string, string) (string, error) { return "/var/lib/kubelet/pods/pod-id-xxx/volumes/kubernetes.io~csi/pvc-id-xxx/mount", nil }, + expectBackupPod: true, + }, + { + name: "succeed, cache config, no cache volume", + ownerBackup: backup, + exposeParam: PodVolumeExposeParam{ + ClientNamespace: "fake-ns", + ClientPodName: "fake-client-pod", + ClientPodVolume: "fake-client-volume", + CacheVolume: &CacheConfigs{}, + }, + kubeClientObj: []runtime.Object{ + podWithNode, + node, + daemonSet, + }, + funcGetPodVolumeHostPath: func(context.Context, *corev1api.Pod, string, kubernetes.Interface, filesystem.Interface, logrus.FieldLogger) (datapath.AccessPoint, error) { + return datapath.AccessPoint{ + ByPath: "/host_pods/pod-id-xxx/volumes/kubernetes.io~csi/pvc-id-xxx/mount", + }, nil + }, + funcExtractPodVolumeHostPath: func(context.Context, string, kubernetes.Interface, string, string) (string, error) { + return "/var/lib/kubelet/pods/pod-id-xxx/volumes/kubernetes.io~csi/pvc-id-xxx/mount", nil + }, + expectBackupPod: true, + }, + { + name: "create cache volume fail", + ownerBackup: backup, + exposeParam: PodVolumeExposeParam{ + ClientNamespace: "fake-ns", + ClientPodName: "fake-client-pod", + ClientPodVolume: "fake-client-volume", + CacheVolume: &CacheConfigs{Limit: 1024}, + }, + kubeClientObj: []runtime.Object{ + podWithNode, + node, + daemonSet, + }, + funcGetPodVolumeHostPath: func(context.Context, *corev1api.Pod, string, kubernetes.Interface, filesystem.Interface, logrus.FieldLogger) (datapath.AccessPoint, error) { + return datapath.AccessPoint{ + ByPath: "/host_pods/pod-id-xxx/volumes/kubernetes.io~csi/pvc-id-xxx/mount", + }, nil + }, + funcExtractPodVolumeHostPath: func(context.Context, string, kubernetes.Interface, string, string) (string, error) { + return "/var/lib/kubelet/pods/pod-id-xxx/volumes/kubernetes.io~csi/pvc-id-xxx/mount", nil + }, + kubeReactors: []reactor{ + { + verb: "create", + resource: "persistentvolumeclaims", + reactorFunc: func(action clientTesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, errors.New("fake-create-error") + }, + }, + }, + err: "error to create cache pvc: fake-create-error", + }, + { + name: "succeed with cache volume", + ownerBackup: backup, + exposeParam: PodVolumeExposeParam{ + ClientNamespace: "fake-ns", + ClientPodName: "fake-client-pod", + ClientPodVolume: "fake-client-volume", + CacheVolume: &CacheConfigs{Limit: 1024}, + }, + kubeClientObj: []runtime.Object{ + podWithNode, + node, + daemonSet, + }, + funcGetPodVolumeHostPath: func(context.Context, *corev1api.Pod, string, kubernetes.Interface, filesystem.Interface, logrus.FieldLogger) (datapath.AccessPoint, error) { + return datapath.AccessPoint{ + ByPath: "/host_pods/pod-id-xxx/volumes/kubernetes.io~csi/pvc-id-xxx/mount", + }, nil + }, + funcExtractPodVolumeHostPath: func(context.Context, string, kubernetes.Interface, string, string) (string, error) { + return "/var/lib/kubelet/pods/pod-id-xxx/volumes/kubernetes.io~csi/pvc-id-xxx/mount", nil + }, + expectBackupPod: true, + expectCachePVC: true, }, } @@ -219,6 +308,10 @@ func TestPodVolumeExpose(t *testing.T) { t.Run(test.name, func(t *testing.T) { fakeKubeClient := fake.NewSimpleClientset(test.kubeClientObj...) + for _, reactor := range test.kubeReactors { + fakeKubeClient.Fake.PrependReactor(reactor.verb, reactor.resource, reactor.reactorFunc) + } + exposer := podVolumeExposer{ kubeClient: fakeKubeClient, log: velerotest.NewLogger(), @@ -248,9 +341,23 @@ func TestPodVolumeExpose(t *testing.T) { require.NoError(t, err) _, err = exposer.kubeClient.CoreV1().Pods(ownerObject.Namespace).Get(t.Context(), ownerObject.Name, metav1.GetOptions{}) - assert.NoError(t, err) + require.NoError(t, err) } else { - assert.EqualError(t, err, test.err) + require.EqualError(t, err, test.err) + } + + _, err = exposer.kubeClient.CoreV1().Pods(ownerObject.Namespace).Get(t.Context(), ownerObject.Name, metav1.GetOptions{}) + if test.expectBackupPod { + require.NoError(t, err) + } else { + require.True(t, apierrors.IsNotFound(err)) + } + + _, err = exposer.kubeClient.CoreV1().PersistentVolumeClaims(ownerObject.Namespace).Get(t.Context(), getCachePVCName(ownerObject), metav1.GetOptions{}) + if test.expectCachePVC { + require.NoError(t, err) + } else { + require.True(t, apierrors.IsNotFound(err)) } }) } @@ -517,6 +624,38 @@ func TestPodVolumeDiagnoseExpose(t *testing.T) { }, } + cachePVCWithVolumeName := corev1api.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: velerov1.DefaultNamespace, + Name: "fake-backup-cache", + UID: "fake-cache-pvc-uid", + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: backup.APIVersion, + Kind: backup.Kind, + Name: backup.Name, + UID: backup.UID, + }, + }, + }, + Spec: corev1api.PersistentVolumeClaimSpec{ + VolumeName: "fake-pv-cache", + }, + Status: corev1api.PersistentVolumeClaimStatus{ + Phase: corev1api.ClaimPending, + }, + } + + cachePV := corev1api.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: "fake-pv-cache", + }, + Status: corev1api.PersistentVolumeStatus{ + Phase: corev1api.VolumePending, + Message: "fake-pv-message", + }, + } + nodeAgentPod := corev1api.Pod{ ObjectMeta: metav1.ObjectMeta{ Namespace: velerov1.DefaultNamespace, @@ -589,6 +728,37 @@ end diagnose pod volume exposer`, expected: `begin diagnose pod volume exposer Pod velero/fake-backup, phase Pending, node name fake-node Pod condition Initialized, status True, reason , message fake-pod-message +end diagnose pod volume exposer`, + }, + { + name: "cache pvc with volume name, no pv", + ownerBackup: backup, + kubeClientObj: []runtime.Object{ + &backupPodWithNodeName, + &cachePVCWithVolumeName, + &nodeAgentPod, + }, + expected: `begin diagnose pod volume exposer +Pod velero/fake-backup, phase Pending, node name fake-node +Pod condition Initialized, status True, reason , message fake-pod-message +PVC velero/fake-backup-cache, phase Pending, binding to fake-pv-cache +error getting cache pv fake-pv-cache, err: persistentvolumes "fake-pv-cache" not found +end diagnose pod volume exposer`, + }, + { + name: "cache pvc with volume name, pv exists", + ownerBackup: backup, + kubeClientObj: []runtime.Object{ + &backupPodWithNodeName, + &cachePVCWithVolumeName, + &cachePV, + &nodeAgentPod, + }, + expected: `begin diagnose pod volume exposer +Pod velero/fake-backup, phase Pending, node name fake-node +Pod condition Initialized, status True, reason , message fake-pod-message +PVC velero/fake-backup-cache, phase Pending, binding to fake-pv-cache +PV fake-pv-cache, phase Pending, reason , message fake-pv-message end diagnose pod volume exposer`, }, { From 31a7236c7dda9ada8143149bfb0d76c92a422764 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Wed, 29 Oct 2025 14:17:54 +0800 Subject: [PATCH 078/104] issue 9365: prevent multiple update of PVR Signed-off-by: Lyndon-Li --- changelogs/unreleased/9375-Lyndon-Li | 1 + pkg/podvolume/restorer.go | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/9375-Lyndon-Li diff --git a/changelogs/unreleased/9375-Lyndon-Li b/changelogs/unreleased/9375-Lyndon-Li new file mode 100644 index 000000000..b60f84894 --- /dev/null +++ b/changelogs/unreleased/9375-Lyndon-Li @@ -0,0 +1 @@ +Fix issue #9365, prevent fake completion notification due to multiple update of single PVR \ No newline at end of file diff --git a/pkg/podvolume/restorer.go b/pkg/podvolume/restorer.go index 1b15f9d53..47219ae99 100644 --- a/pkg/podvolume/restorer.go +++ b/pkg/podvolume/restorer.go @@ -92,12 +92,18 @@ func newRestorer( _, _ = pvrInformer.AddEventHandler( cache.ResourceEventHandlerFuncs{ - UpdateFunc: func(_, obj any) { - pvr := obj.(*velerov1api.PodVolumeRestore) + UpdateFunc: func(oldObj, newObj any) { + pvr := newObj.(*velerov1api.PodVolumeRestore) + pvrOld := oldObj.(*velerov1api.PodVolumeRestore) + if pvr.GetLabels()[velerov1api.RestoreUIDLabel] != string(restore.UID) { return } + if pvr.Status.Phase == pvrOld.Status.Phase { + return + } + if pvr.Status.Phase == velerov1api.PodVolumeRestorePhaseCompleted || pvr.Status.Phase == velerov1api.PodVolumeRestorePhaseFailed || pvr.Status.Phase == velerov1api.PodVolumeRestorePhaseCanceled { r.resultsLock.Lock() defer r.resultsLock.Unlock() From 7178946debdb0b488005a049d3349e0c0759be26 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Tue, 28 Oct 2025 15:34:13 +0800 Subject: [PATCH 079/104] cache volume configuration Signed-off-by: Lyndon-Li --- changelogs/unreleased/9370-Lyndon-Li | 1 + pkg/builder/storage_class_builder.go | 7 ++ pkg/cmd/cli/nodeagent/server.go | 55 ++++++++++- pkg/cmd/cli/nodeagent/server_test.go | 140 ++++++++++++++++++++++++--- pkg/install/daemonset.go | 4 + pkg/install/daemonset_test.go | 4 + pkg/install/resources.go | 4 + pkg/types/node_agent.go | 11 +++ 8 files changed, 211 insertions(+), 15 deletions(-) create mode 100644 changelogs/unreleased/9370-Lyndon-Li diff --git a/changelogs/unreleased/9370-Lyndon-Li b/changelogs/unreleased/9370-Lyndon-Li new file mode 100644 index 000000000..43025c589 --- /dev/null +++ b/changelogs/unreleased/9370-Lyndon-Li @@ -0,0 +1 @@ +Add cache volume configuration \ No newline at end of file diff --git a/pkg/builder/storage_class_builder.go b/pkg/builder/storage_class_builder.go index 9e83ee957..b865dcfea 100644 --- a/pkg/builder/storage_class_builder.go +++ b/pkg/builder/storage_class_builder.go @@ -17,6 +17,7 @@ limitations under the License. package builder import ( + corev1api "k8s.io/api/core/v1" storagev1api "k8s.io/api/storage/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -87,3 +88,9 @@ func (b *StorageClassBuilder) Provisioner(provisioner string) *StorageClassBuild b.object.Provisioner = provisioner return b } + +// ReclaimPolicy sets StorageClass's reclaimPolicy. +func (b *StorageClassBuilder) ReclaimPolicy(policy corev1api.PersistentVolumeReclaimPolicy) *StorageClassBuilder { + b.object.ReclaimPolicy = &policy + return b +} diff --git a/pkg/cmd/cli/nodeagent/server.go b/pkg/cmd/cli/nodeagent/server.go index d3563c0f5..dbd471eb8 100644 --- a/pkg/cmd/cli/nodeagent/server.go +++ b/pkg/cmd/cli/nodeagent/server.go @@ -84,6 +84,7 @@ type nodeAgentServerConfig struct { resourceTimeout time.Duration dataMoverPrepareTimeout time.Duration nodeAgentConfig string + backupRepoConfig string } func NewServerCommand(f client.Factory) *cobra.Command { @@ -121,6 +122,7 @@ func NewServerCommand(f client.Factory) *cobra.Command { command.Flags().DurationVar(&config.dataMoverPrepareTimeout, "data-mover-prepare-timeout", config.dataMoverPrepareTimeout, "How long to wait for preparing a DataUpload/DataDownload. Default is 30 minutes.") command.Flags().StringVar(&config.metricsAddress, "metrics-address", config.metricsAddress, "The address to expose prometheus metrics") command.Flags().StringVar(&config.nodeAgentConfig, "node-agent-configmap", config.nodeAgentConfig, "The name of ConfigMap containing node-agent configurations.") + command.Flags().StringVar(&config.backupRepoConfig, "backup-repository-configmap", config.backupRepoConfig, "The name of ConfigMap containing backup repository configurations.") return command } @@ -140,6 +142,7 @@ type nodeAgentServer struct { csiSnapshotClient *snapshotv1client.Clientset dataPathMgr *datapath.Manager dataPathConfigs *velerotypes.NodeAgentConfigs + backupRepoConfigs map[string]string vgdpCounter *exposer.VgdpCounter } @@ -254,6 +257,11 @@ func newNodeAgentServer(logger logrus.FieldLogger, factory client.Factory, confi if err := s.getDataPathConfigs(); err != nil { return nil, err } + + if err := s.getBackupRepoConfigs(); err != nil { + return nil, err + } + s.dataPathMgr = datapath.NewManager(s.getDataPathConcurrentNum(defaultDataPathConcurrentNum)) return s, nil @@ -329,6 +337,14 @@ func (s *nodeAgentServer) run() { } } + if s.dataPathConfigs != nil && s.dataPathConfigs.CachePVCConfig != nil { + if err := s.validateCachePVCConfig(*s.dataPathConfigs.CachePVCConfig); err != nil { + s.logger.WithError(err).Warnf("Ignore cache config %v", s.dataPathConfigs.CachePVCConfig) + } else { + s.logger.Infof("Using cache volume configs %v", s.dataPathConfigs.CachePVCConfig) + } + } + pvbReconciler := controller.NewPodVolumeBackupReconciler(s.mgr.GetClient(), s.mgr, s.kubeClient, s.dataPathMgr, s.vgdpCounter, s.nodeName, s.config.dataMoverPrepareTimeout, s.config.resourceTimeout, podResources, s.metrics, s.logger, dataMovePriorityClass, privilegedFsBackup) if err := pvbReconciler.SetupWithManager(s.mgr); err != nil { s.logger.Fatal(err, "unable to create controller", "controller", constant.ControllerPodVolumeBackup) @@ -557,14 +573,32 @@ func (s *nodeAgentServer) getDataPathConfigs() error { configs, err := getConfigsFunc(s.ctx, s.namespace, s.kubeClient, s.config.nodeAgentConfig) if err != nil { - s.logger.WithError(err).Errorf("Failed to get node agent configs from configMap %s, ignore it", s.config.nodeAgentConfig) - return err + return errors.Wrapf(err, "error getting node agent configs from configMap %s", s.config.nodeAgentConfig) } s.dataPathConfigs = configs return nil } +func (s *nodeAgentServer) getBackupRepoConfigs() error { + if s.config.backupRepoConfig == "" { + s.logger.Info("No backup repo configMap is specified") + return nil + } + + cm, err := s.kubeClient.CoreV1().ConfigMaps(s.namespace).Get(s.ctx, s.config.backupRepoConfig, metav1.GetOptions{}) + if err != nil { + return errors.Wrapf(err, "error getting backup repo configs from configMap %s", s.config.backupRepoConfig) + } + + if cm.Data == nil { + return errors.Errorf("no data is in the backup repo configMap %s", s.config.backupRepoConfig) + } + + s.backupRepoConfigs = cm.Data + return nil +} + func (s *nodeAgentServer) getDataPathConcurrentNum(defaultNum int) int { configs := s.dataPathConfigs @@ -620,3 +654,20 @@ func (s *nodeAgentServer) getDataPathConcurrentNum(defaultNum int) int { return concurrentNum } + +func (s *nodeAgentServer) validateCachePVCConfig(config velerotypes.CachePVC) error { + if config.StorageClass == "" { + return errors.New("storage class is absent") + } + + sc, err := s.kubeClient.StorageV1().StorageClasses().Get(s.ctx, config.StorageClass, metav1.GetOptions{}) + if err != nil { + return errors.Wrapf(err, "error getting storage class %s", config.StorageClass) + } + + if sc.ReclaimPolicy != nil && *sc.ReclaimPolicy != corev1api.PersistentVolumeReclaimDelete { + return errors.Errorf("unexpected storage class reclaim policy %v", *sc.ReclaimPolicy) + } + + return nil +} diff --git a/pkg/cmd/cli/nodeagent/server_test.go b/pkg/cmd/cli/nodeagent/server_test.go index cb1750e6b..152016ab6 100644 --- a/pkg/cmd/cli/nodeagent/server_test.go +++ b/pkg/cmd/cli/nodeagent/server_test.go @@ -24,6 +24,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" corev1api "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -34,6 +35,8 @@ import ( "github.com/vmware-tanzu/velero/pkg/nodeagent" testutil "github.com/vmware-tanzu/velero/pkg/test" velerotypes "github.com/vmware-tanzu/velero/pkg/types" + + velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" ) func Test_validatePodVolumesHostPath(t *testing.T) { @@ -142,11 +145,10 @@ func Test_getDataPathConfigs(t *testing.T) { getFunc func(context.Context, string, kubernetes.Interface, string) (*velerotypes.NodeAgentConfigs, error) configMapName string expectConfigs *velerotypes.NodeAgentConfigs - expectLog string + expectedErr string }{ { - name: "no config specified", - expectLog: "No node-agent configMap is specified", + name: "no config specified", }, { name: "failed to get configs", @@ -154,7 +156,7 @@ func Test_getDataPathConfigs(t *testing.T) { getFunc: func(context.Context, string, kubernetes.Interface, string) (*velerotypes.NodeAgentConfigs, error) { return nil, errors.New("fake-get-error") }, - expectLog: "Failed to get node agent configs from configMap node-agent-config, ignore it", + expectedErr: "error getting node agent configs from configMap node-agent-config: fake-get-error", }, { name: "configs cm not found", @@ -162,7 +164,7 @@ func Test_getDataPathConfigs(t *testing.T) { getFunc: func(context.Context, string, kubernetes.Interface, string) (*velerotypes.NodeAgentConfigs, error) { return nil, errors.New("fake-not-found-error") }, - expectLog: "Failed to get node agent configs from configMap node-agent-config, ignore it", + expectedErr: "error getting node agent configs from configMap node-agent-config: fake-not-found-error", }, { @@ -177,23 +179,21 @@ func Test_getDataPathConfigs(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - logBuffer := "" - s := &nodeAgentServer{ config: nodeAgentServerConfig{ nodeAgentConfig: test.configMapName, }, - logger: testutil.NewSingleLogger(&logBuffer), + logger: testutil.NewLogger(), } getConfigsFunc = test.getFunc - s.getDataPathConfigs() - assert.Equal(t, test.expectConfigs, s.dataPathConfigs) - if test.expectLog == "" { - assert.Empty(t, logBuffer) + err := s.getDataPathConfigs() + if test.expectedErr == "" { + require.NoError(t, err) + assert.Equal(t, test.expectConfigs, s.dataPathConfigs) } else { - assert.Contains(t, logBuffer, test.expectLog) + require.EqualError(t, err, test.expectedErr) } }) } @@ -416,3 +416,117 @@ func Test_getDataPathConcurrentNum(t *testing.T) { }) } } + +func TestGetBackupRepoConfigs(t *testing.T) { + cmNoData := builder.ForConfigMap(velerov1api.DefaultNamespace, "backup-repo-config").Result() + cmWithData := builder.ForConfigMap(velerov1api.DefaultNamespace, "backup-repo-config").Data("cacheLimit", "100").Result() + + tests := []struct { + name string + configMapName string + kubeClientObj []runtime.Object + expectConfigs map[string]string + expectedErr string + }{ + { + name: "no config specified", + }, + { + name: "failed to get configs", + configMapName: "backup-repo-config", + expectedErr: "error getting backup repo configs from configMap backup-repo-config: configmaps \"backup-repo-config\" not found", + }, + { + name: "configs data not found", + kubeClientObj: []runtime.Object{cmNoData}, + configMapName: "backup-repo-config", + expectedErr: "no data is in the backup repo configMap backup-repo-config", + }, + { + name: "succeed", + configMapName: "backup-repo-config", + kubeClientObj: []runtime.Object{cmWithData}, + expectConfigs: map[string]string{"cacheLimit": "100"}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + fakeKubeClient := fake.NewSimpleClientset(test.kubeClientObj...) + + s := &nodeAgentServer{ + namespace: velerov1api.DefaultNamespace, + kubeClient: fakeKubeClient, + config: nodeAgentServerConfig{ + backupRepoConfig: test.configMapName, + }, + logger: testutil.NewLogger(), + } + + err := s.getBackupRepoConfigs() + if test.expectedErr == "" { + require.NoError(t, err) + require.Equal(t, test.expectConfigs, s.backupRepoConfigs) + } else { + require.EqualError(t, err, test.expectedErr) + } + }) + } +} + +func TestValidateCachePVCConfig(t *testing.T) { + scWithRetainPolicy := builder.ForStorageClass("fake-storage-class").ReclaimPolicy(corev1api.PersistentVolumeReclaimRetain).Result() + scWithDeletePolicy := builder.ForStorageClass("fake-storage-class").ReclaimPolicy(corev1api.PersistentVolumeReclaimDelete).Result() + scWithNoPolicy := builder.ForStorageClass("fake-storage-class").Result() + + tests := []struct { + name string + config velerotypes.CachePVC + kubeClientObj []runtime.Object + expectedErr string + }{ + { + name: "no storage class", + expectedErr: "storage class is absent", + }, + { + name: "failed to get storage class", + config: velerotypes.CachePVC{StorageClass: "fake-storage-class"}, + expectedErr: "error getting storage class fake-storage-class: storageclasses.storage.k8s.io \"fake-storage-class\" not found", + }, + { + name: "storage class reclaim policy is not expected", + config: velerotypes.CachePVC{StorageClass: "fake-storage-class"}, + kubeClientObj: []runtime.Object{scWithRetainPolicy}, + expectedErr: "unexpected storage class reclaim policy Retain", + }, + { + name: "storage class reclaim policy is delete", + config: velerotypes.CachePVC{StorageClass: "fake-storage-class"}, + kubeClientObj: []runtime.Object{scWithDeletePolicy}, + }, + { + name: "storage class with no reclaim policy", + config: velerotypes.CachePVC{StorageClass: "fake-storage-class"}, + kubeClientObj: []runtime.Object{scWithNoPolicy}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + fakeKubeClient := fake.NewSimpleClientset(test.kubeClientObj...) + + s := &nodeAgentServer{ + kubeClient: fakeKubeClient, + } + + err := s.validateCachePVCConfig(test.config) + + if test.expectedErr == "" { + require.NoError(t, err) + } else { + require.EqualError(t, err, test.expectedErr) + } + }) + } +} diff --git a/pkg/install/daemonset.go b/pkg/install/daemonset.go index 98f30cc69..ee63f3736 100644 --- a/pkg/install/daemonset.go +++ b/pkg/install/daemonset.go @@ -57,6 +57,10 @@ func DaemonSet(namespace string, opts ...podTemplateOption) *appsv1api.DaemonSet daemonSetArgs = append(daemonSetArgs, fmt.Sprintf("--node-agent-configmap=%s", c.nodeAgentConfigMap)) } + if len(c.backupRepoConfigMap) > 0 { + daemonSetArgs = append(daemonSetArgs, fmt.Sprintf("--backup-repository-configmap=%s", c.backupRepoConfigMap)) + } + userID := int64(0) mountPropagationMode := corev1api.MountPropagationHostToContainer diff --git a/pkg/install/daemonset_test.go b/pkg/install/daemonset_test.go index 77a1ebae8..139d3dcd0 100644 --- a/pkg/install/daemonset_test.go +++ b/pkg/install/daemonset_test.go @@ -60,6 +60,10 @@ func TestDaemonSet(t *testing.T) { assert.Len(t, ds.Spec.Template.Spec.Containers[0].Args, 3) assert.Equal(t, "--node-agent-configmap=node-agent-config-map", ds.Spec.Template.Spec.Containers[0].Args[2]) + ds = DaemonSet("velero", WithBackupRepoConfigMap("backup-repo-config-map")) + assert.Len(t, ds.Spec.Template.Spec.Containers[0].Args, 3) + assert.Equal(t, "--backup-repository-configmap=backup-repo-config-map", ds.Spec.Template.Spec.Containers[0].Args[2]) + ds = DaemonSet("velero", WithServiceAccountName("test-sa")) assert.Equal(t, "test-sa", ds.Spec.Template.Spec.ServiceAccountName) diff --git a/pkg/install/resources.go b/pkg/install/resources.go index 344fc599f..1d0ffa568 100644 --- a/pkg/install/resources.go +++ b/pkg/install/resources.go @@ -426,6 +426,10 @@ func AllResources(o *VeleroOptions) *unstructured.UnstructuredList { dsOpts = append(dsOpts, WithNodeAgentConfigMap(o.NodeAgentConfigMap)) } + if len(o.BackupRepoConfigMap) > 0 { + dsOpts = append(dsOpts, WithBackupRepoConfigMap(o.BackupRepoConfigMap)) + } + if len(o.KubeletRootDir) > 0 { dsOpts = append(dsOpts, WithKubeletRootDir(o.KubeletRootDir)) } diff --git a/pkg/types/node_agent.go b/pkg/types/node_agent.go index b335df275..121079dda 100644 --- a/pkg/types/node_agent.go +++ b/pkg/types/node_agent.go @@ -66,6 +66,14 @@ type RestorePVC struct { IgnoreDelayBinding bool `json:"ignoreDelayBinding,omitempty"` } +type CachePVC struct { + // StorageClass specifies the storage class for cache PVC + StorageClass string + + // ResidentThreshold specifies the minimum size of the backup data to create cache PVC + ResidentThreshold int64 +} + type NodeAgentConfigs struct { // LoadConcurrency is the config for data path load concurrency per node. LoadConcurrency *LoadConcurrency `json:"loadConcurrency,omitempty"` @@ -87,4 +95,7 @@ type NodeAgentConfigs struct { // PrivilegedFsBackup determines whether to create fs-backup pods as privileged pods PrivilegedFsBackup bool `json:"privilegedFsBackup,omitempty"` + + // CachePVCConfig is the config for cachePVC + CachePVCConfig *CachePVC `json:"cachePVC,omitempty"` } From 9556a39a89105b4a32771ba03684b4279445987e Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Mon, 3 Nov 2025 15:09:37 +0800 Subject: [PATCH 080/104] repo provider interface refactor for repo static configuration Signed-off-by: Lyndon-Li --- changelogs/unreleased/9379-Lyndon-Li | 1 + pkg/repository/manager/manager.go | 68 +++++++++++++++++++- pkg/repository/manager/manager_test.go | 17 +++++ pkg/repository/mocks/ConfigManager.go | 84 +++++++++++++++++++++++++ pkg/repository/mocks/Manager.go | 42 ++++++++++--- pkg/repository/provider/provider.go | 14 ++++- pkg/repository/provider/restic.go | 6 +- pkg/repository/provider/unified_repo.go | 35 +++++++++-- 8 files changed, 249 insertions(+), 18 deletions(-) create mode 100644 changelogs/unreleased/9379-Lyndon-Li create mode 100644 pkg/repository/mocks/ConfigManager.go diff --git a/changelogs/unreleased/9379-Lyndon-Li b/changelogs/unreleased/9379-Lyndon-Li new file mode 100644 index 000000000..481bf8bdd --- /dev/null +++ b/changelogs/unreleased/9379-Lyndon-Li @@ -0,0 +1 @@ +Refactor repo provider interface for static configuration \ No newline at end of file diff --git a/pkg/repository/manager/manager.go b/pkg/repository/manager/manager.go index 7027c9650..ebbf2e8e2 100644 --- a/pkg/repository/manager/manager.go +++ b/pkg/repository/manager/manager.go @@ -60,7 +60,19 @@ type Manager interface { BatchForget(context.Context, *velerov1api.BackupRepository, []string) []error // DefaultMaintenanceFrequency returns the default maintenance frequency from the specific repo - DefaultMaintenanceFrequency(repo *velerov1api.BackupRepository) (time.Duration, error) + DefaultMaintenanceFrequency(*velerov1api.BackupRepository) (time.Duration, error) + + // ClientSideCacheLimit returns the max cache size required on client side + ClientSideCacheLimit(*velerov1api.BackupRepository) (int64, error) +} + +// ConfigProvider defines the methods to get configurations of a backup repository +type ConfigManager interface { + // DefaultMaintenanceFrequency returns the default maintenance frequency from the specific repo + DefaultMaintenanceFrequency(string) (time.Duration, error) + + // ClientSideCacheLimit returns the max cache size required on client side + ClientSideCacheLimit(string, map[string]string) (int64, error) } type manager struct { @@ -74,6 +86,11 @@ type manager struct { log logrus.FieldLogger } +type configManager struct { + providers map[string]provider.ConfigProvider + log logrus.FieldLogger +} + // NewManager create a new repository manager. func NewManager( namespace string, @@ -101,6 +118,20 @@ func NewManager( return mgr } +// NewConfigManager create a new repository config manager. +func NewConfigManager( + log logrus.FieldLogger, +) ConfigManager { + mgr := &configManager{ + providers: map[string]provider.ConfigProvider{}, + log: log, + } + + mgr.providers[velerov1api.BackupRepositoryTypeKopia] = provider.NewUnifiedRepoConfigProvider(velerov1api.BackupRepositoryTypeKopia, mgr.log) + + return mgr +} + func (m *manager) InitRepo(repo *velerov1api.BackupRepository) error { m.repoLocker.LockExclusive(repo.Name) defer m.repoLocker.UnlockExclusive(repo.Name) @@ -227,12 +258,16 @@ func (m *manager) DefaultMaintenanceFrequency(repo *velerov1api.BackupRepository return 0, errors.WithStack(err) } - param, err := m.assembleRepoParam(repo) + return prd.DefaultMaintenanceFrequency(), nil +} + +func (m *manager) ClientSideCacheLimit(repo *velerov1api.BackupRepository) (int64, error) { + prd, err := m.getRepositoryProvider(repo) if err != nil { return 0, errors.WithStack(err) } - return prd.DefaultMaintenanceFrequency(context.Background(), param), nil + return prd.ClientSideCacheLimit(repo.Spec.RepositoryConfig), nil } func (m *manager) getRepositoryProvider(repo *velerov1api.BackupRepository) (provider.Provider, error) { @@ -256,3 +291,30 @@ func (m *manager) assembleRepoParam(repo *velerov1api.BackupRepository) (provide BackupRepo: repo, }, nil } + +func (cm *configManager) DefaultMaintenanceFrequency(repoType string) (time.Duration, error) { + prd, err := cm.getRepositoryProvider(repoType) + if err != nil { + return 0, errors.WithStack(err) + } + + return prd.DefaultMaintenanceFrequency(), nil +} + +func (cm *configManager) ClientSideCacheLimit(repoType string, repoOption map[string]string) (int64, error) { + prd, err := cm.getRepositoryProvider(repoType) + if err != nil { + return 0, errors.WithStack(err) + } + + return prd.ClientSideCacheLimit(repoOption), nil +} + +func (cm *configManager) getRepositoryProvider(repoType string) (provider.ConfigProvider, error) { + switch repoType { + case velerov1api.BackupRepositoryTypeKopia: + return cm.providers[velerov1api.BackupRepositoryTypeKopia], nil + default: + return nil, fmt.Errorf("failed to get provider for repository %s", repoType) + } +} diff --git a/pkg/repository/manager/manager_test.go b/pkg/repository/manager/manager_test.go index d743e267a..ea38c7448 100644 --- a/pkg/repository/manager/manager_test.go +++ b/pkg/repository/manager/manager_test.go @@ -47,3 +47,20 @@ func TestGetRepositoryProvider(t *testing.T) { _, err = mgr.getRepositoryProvider(repo) require.Error(t, err) } + +func TestGetRepositoryConfigProvider(t *testing.T) { + mgr := NewConfigManager(nil).(*configManager) + + // empty repository type + _, err := mgr.getRepositoryProvider("") + require.Error(t, err) + + // valid repository type + provider, err := mgr.getRepositoryProvider(velerov1.BackupRepositoryTypeKopia) + require.NoError(t, err) + assert.NotNil(t, provider) + + // invalid repository type + _, err = mgr.getRepositoryProvider(velerov1.BackupRepositoryTypeRestic) + require.Error(t, err) +} diff --git a/pkg/repository/mocks/ConfigManager.go b/pkg/repository/mocks/ConfigManager.go new file mode 100644 index 000000000..590f49c33 --- /dev/null +++ b/pkg/repository/mocks/ConfigManager.go @@ -0,0 +1,84 @@ +// Code generated by mockery v2.53.2. DO NOT EDIT. + +package mocks + +import ( + mock "github.com/stretchr/testify/mock" + + time "time" +) + +// ConfigManager is an autogenerated mock type for the ConfigManager type +type ConfigManager struct { + mock.Mock +} + +// ClientSideCacheLimit provides a mock function with given fields: repoType, repoOption +func (_m *ConfigManager) ClientSideCacheLimit(repoType string, repoOption map[string]string) (int64, error) { + ret := _m.Called(repoType, repoOption) + + if len(ret) == 0 { + panic("no return value specified for ClientSideCacheLimit") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(string, map[string]string) (int64, error)); ok { + return rf(repoType, repoOption) + } + if rf, ok := ret.Get(0).(func(string, map[string]string) int64); ok { + r0 = rf(repoType, repoOption) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(string, map[string]string) error); ok { + r1 = rf(repoType, repoOption) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// DefaultMaintenanceFrequency provides a mock function with given fields: repoType +func (_m *ConfigManager) DefaultMaintenanceFrequency(repoType string) (time.Duration, error) { + ret := _m.Called(repoType) + + if len(ret) == 0 { + panic("no return value specified for DefaultMaintenanceFrequency") + } + + var r0 time.Duration + var r1 error + if rf, ok := ret.Get(0).(func(string) (time.Duration, error)); ok { + return rf(repoType) + } + if rf, ok := ret.Get(0).(func(string) time.Duration); ok { + r0 = rf(repoType) + } else { + r0 = ret.Get(0).(time.Duration) + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(repoType) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewConfigManager creates a new instance of ConfigManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewConfigManager(t interface { + mock.TestingT + Cleanup(func()) +}) *ConfigManager { + mock := &ConfigManager{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/repository/mocks/Manager.go b/pkg/repository/mocks/Manager.go index 226411775..954967adc 100644 --- a/pkg/repository/mocks/Manager.go +++ b/pkg/repository/mocks/Manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.53.2. DO NOT EDIT. package mocks @@ -37,6 +37,34 @@ func (_m *Manager) BatchForget(_a0 context.Context, _a1 *v1.BackupRepository, _a return r0 } +// ClientSideCacheLimit provides a mock function with given fields: _a0 +func (_m *Manager) ClientSideCacheLimit(_a0 *v1.BackupRepository) (int64, error) { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for ClientSideCacheLimit") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(*v1.BackupRepository) (int64, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(*v1.BackupRepository) int64); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(*v1.BackupRepository) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // ConnectToRepo provides a mock function with given fields: repo func (_m *Manager) ConnectToRepo(repo *v1.BackupRepository) error { ret := _m.Called(repo) @@ -55,9 +83,9 @@ func (_m *Manager) ConnectToRepo(repo *v1.BackupRepository) error { return r0 } -// DefaultMaintenanceFrequency provides a mock function with given fields: repo -func (_m *Manager) DefaultMaintenanceFrequency(repo *v1.BackupRepository) (time.Duration, error) { - ret := _m.Called(repo) +// DefaultMaintenanceFrequency provides a mock function with given fields: _a0 +func (_m *Manager) DefaultMaintenanceFrequency(_a0 *v1.BackupRepository) (time.Duration, error) { + ret := _m.Called(_a0) if len(ret) == 0 { panic("no return value specified for DefaultMaintenanceFrequency") @@ -66,16 +94,16 @@ func (_m *Manager) DefaultMaintenanceFrequency(repo *v1.BackupRepository) (time. var r0 time.Duration var r1 error if rf, ok := ret.Get(0).(func(*v1.BackupRepository) (time.Duration, error)); ok { - return rf(repo) + return rf(_a0) } if rf, ok := ret.Get(0).(func(*v1.BackupRepository) time.Duration); ok { - r0 = rf(repo) + r0 = rf(_a0) } else { r0 = ret.Get(0).(time.Duration) } if rf, ok := ret.Get(1).(func(*v1.BackupRepository) error); ok { - r1 = rf(repo) + r1 = rf(_a0) } else { r1 = ret.Error(1) } diff --git a/pkg/repository/provider/provider.go b/pkg/repository/provider/provider.go index 822e69aba..7681d830b 100644 --- a/pkg/repository/provider/provider.go +++ b/pkg/repository/provider/provider.go @@ -32,6 +32,8 @@ type RepoParam struct { // Provider defines the methods to manipulate a backup repository type Provider interface { + ConfigProvider + // InitRepo is to initialize a repository from a new storage place InitRepo(ctx context.Context, param RepoParam) error @@ -60,7 +62,13 @@ type Provider interface { // BatchForget is to delete a list of snapshots from the repository BatchForget(ctx context.Context, snapshotIDs []string, param RepoParam) []error - - // DefaultMaintenanceFrequency returns the default frequency to run maintenance - DefaultMaintenanceFrequency(ctx context.Context, param RepoParam) time.Duration +} + +// ConfigProvider defines the methods to get configurations of a backup repository +type ConfigProvider interface { + // DefaultMaintenanceFrequency returns the default frequency to run maintenance + DefaultMaintenanceFrequency() time.Duration + + // ClientSideCacheLimit returns the max cache size required on client side + ClientSideCacheLimit(repoOption map[string]string) int64 } diff --git a/pkg/repository/provider/restic.go b/pkg/repository/provider/restic.go index 3ca5988cb..ad4e0a257 100644 --- a/pkg/repository/provider/restic.go +++ b/pkg/repository/provider/restic.go @@ -90,6 +90,10 @@ func (r *resticRepositoryProvider) BatchForget(ctx context.Context, snapshotIDs return errs } -func (r *resticRepositoryProvider) DefaultMaintenanceFrequency(ctx context.Context, param RepoParam) time.Duration { +func (r *resticRepositoryProvider) DefaultMaintenanceFrequency() time.Duration { return r.svc.DefaultMaintenanceFrequency() } + +func (r *resticRepositoryProvider) ClientSideCacheLimit(repoOption map[string]string) int64 { + return 0 +} diff --git a/pkg/repository/provider/unified_repo.go b/pkg/repository/provider/unified_repo.go index c13665d2d..be3dfc089 100644 --- a/pkg/repository/provider/unified_repo.go +++ b/pkg/repository/provider/unified_repo.go @@ -46,6 +46,12 @@ type unifiedRepoProvider struct { log logrus.FieldLogger } +type unifiedRepoConfigProvider struct { + repoService udmrepo.BackupRepoService + repoBackend string + log logrus.FieldLogger +} + // this func is assigned to a package-level variable so it can be // replaced when unit-testing var getS3Credentials = repoconfig.GetS3Credentials @@ -86,9 +92,18 @@ func NewUnifiedRepoProvider( return &repo } -func GetUnifiedRepoClientSideCacheLimit(repoOption map[string]string, repoBackend string, log logrus.FieldLogger) int64 { - repoService := createRepoService(repoBackend, log) - return repoService.ClientSideCacheLimit(repoOption) +func NewUnifiedRepoConfigProvider( + repoBackend string, + log logrus.FieldLogger, +) ConfigProvider { + repo := unifiedRepoConfigProvider{ + repoBackend: repoBackend, + log: log, + } + + repo.repoService = createRepoService(repoBackend, log) + + return &repo } func (urp *unifiedRepoProvider) InitRepo(ctx context.Context, param RepoParam) error { @@ -375,10 +390,14 @@ func (urp *unifiedRepoProvider) BatchForget(ctx context.Context, snapshotIDs []s return errs } -func (urp *unifiedRepoProvider) DefaultMaintenanceFrequency(ctx context.Context, param RepoParam) time.Duration { +func (urp *unifiedRepoProvider) DefaultMaintenanceFrequency() time.Duration { return urp.repoService.DefaultMaintenanceFrequency() } +func (urp *unifiedRepoProvider) ClientSideCacheLimit(repoOption map[string]string) int64 { + return urp.repoService.ClientSideCacheLimit(repoOption) +} + func (urp *unifiedRepoProvider) GetPassword(param any) (string, error) { _, ok := param.(RepoParam) if !ok { @@ -429,6 +448,14 @@ func (urp *unifiedRepoProvider) GetStoreOptions(param any) (map[string]string, e return storeOptions, nil } +func (urcp *unifiedRepoConfigProvider) DefaultMaintenanceFrequency() time.Duration { + return urcp.repoService.DefaultMaintenanceFrequency() +} + +func (urcp *unifiedRepoConfigProvider) ClientSideCacheLimit(repoOption map[string]string) int64 { + return urcp.repoService.ClientSideCacheLimit(repoOption) +} + func getRepoPassword(secretStore credentials.SecretStore) (string, error) { if secretStore == nil { return "", errors.New("invalid credentials interface") From 597cee545add922bc932f8b10d42ee986a897a12 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Mon, 3 Nov 2025 15:09:37 +0800 Subject: [PATCH 081/104] repo provider interface refactor for repo static configuration Signed-off-by: Lyndon-Li --- changelogs/unreleased/9379-Lyndon-Li | 1 + pkg/repository/manager/manager.go | 68 +++++++++++++++++++- pkg/repository/manager/manager_test.go | 17 +++++ pkg/repository/mocks/ConfigManager.go | 84 +++++++++++++++++++++++++ pkg/repository/mocks/Manager.go | 42 ++++++++++--- pkg/repository/provider/provider.go | 14 ++++- pkg/repository/provider/restic.go | 6 +- pkg/repository/provider/unified_repo.go | 35 +++++++++-- 8 files changed, 249 insertions(+), 18 deletions(-) create mode 100644 changelogs/unreleased/9379-Lyndon-Li create mode 100644 pkg/repository/mocks/ConfigManager.go diff --git a/changelogs/unreleased/9379-Lyndon-Li b/changelogs/unreleased/9379-Lyndon-Li new file mode 100644 index 000000000..481bf8bdd --- /dev/null +++ b/changelogs/unreleased/9379-Lyndon-Li @@ -0,0 +1 @@ +Refactor repo provider interface for static configuration \ No newline at end of file diff --git a/pkg/repository/manager/manager.go b/pkg/repository/manager/manager.go index 7027c9650..ebbf2e8e2 100644 --- a/pkg/repository/manager/manager.go +++ b/pkg/repository/manager/manager.go @@ -60,7 +60,19 @@ type Manager interface { BatchForget(context.Context, *velerov1api.BackupRepository, []string) []error // DefaultMaintenanceFrequency returns the default maintenance frequency from the specific repo - DefaultMaintenanceFrequency(repo *velerov1api.BackupRepository) (time.Duration, error) + DefaultMaintenanceFrequency(*velerov1api.BackupRepository) (time.Duration, error) + + // ClientSideCacheLimit returns the max cache size required on client side + ClientSideCacheLimit(*velerov1api.BackupRepository) (int64, error) +} + +// ConfigProvider defines the methods to get configurations of a backup repository +type ConfigManager interface { + // DefaultMaintenanceFrequency returns the default maintenance frequency from the specific repo + DefaultMaintenanceFrequency(string) (time.Duration, error) + + // ClientSideCacheLimit returns the max cache size required on client side + ClientSideCacheLimit(string, map[string]string) (int64, error) } type manager struct { @@ -74,6 +86,11 @@ type manager struct { log logrus.FieldLogger } +type configManager struct { + providers map[string]provider.ConfigProvider + log logrus.FieldLogger +} + // NewManager create a new repository manager. func NewManager( namespace string, @@ -101,6 +118,20 @@ func NewManager( return mgr } +// NewConfigManager create a new repository config manager. +func NewConfigManager( + log logrus.FieldLogger, +) ConfigManager { + mgr := &configManager{ + providers: map[string]provider.ConfigProvider{}, + log: log, + } + + mgr.providers[velerov1api.BackupRepositoryTypeKopia] = provider.NewUnifiedRepoConfigProvider(velerov1api.BackupRepositoryTypeKopia, mgr.log) + + return mgr +} + func (m *manager) InitRepo(repo *velerov1api.BackupRepository) error { m.repoLocker.LockExclusive(repo.Name) defer m.repoLocker.UnlockExclusive(repo.Name) @@ -227,12 +258,16 @@ func (m *manager) DefaultMaintenanceFrequency(repo *velerov1api.BackupRepository return 0, errors.WithStack(err) } - param, err := m.assembleRepoParam(repo) + return prd.DefaultMaintenanceFrequency(), nil +} + +func (m *manager) ClientSideCacheLimit(repo *velerov1api.BackupRepository) (int64, error) { + prd, err := m.getRepositoryProvider(repo) if err != nil { return 0, errors.WithStack(err) } - return prd.DefaultMaintenanceFrequency(context.Background(), param), nil + return prd.ClientSideCacheLimit(repo.Spec.RepositoryConfig), nil } func (m *manager) getRepositoryProvider(repo *velerov1api.BackupRepository) (provider.Provider, error) { @@ -256,3 +291,30 @@ func (m *manager) assembleRepoParam(repo *velerov1api.BackupRepository) (provide BackupRepo: repo, }, nil } + +func (cm *configManager) DefaultMaintenanceFrequency(repoType string) (time.Duration, error) { + prd, err := cm.getRepositoryProvider(repoType) + if err != nil { + return 0, errors.WithStack(err) + } + + return prd.DefaultMaintenanceFrequency(), nil +} + +func (cm *configManager) ClientSideCacheLimit(repoType string, repoOption map[string]string) (int64, error) { + prd, err := cm.getRepositoryProvider(repoType) + if err != nil { + return 0, errors.WithStack(err) + } + + return prd.ClientSideCacheLimit(repoOption), nil +} + +func (cm *configManager) getRepositoryProvider(repoType string) (provider.ConfigProvider, error) { + switch repoType { + case velerov1api.BackupRepositoryTypeKopia: + return cm.providers[velerov1api.BackupRepositoryTypeKopia], nil + default: + return nil, fmt.Errorf("failed to get provider for repository %s", repoType) + } +} diff --git a/pkg/repository/manager/manager_test.go b/pkg/repository/manager/manager_test.go index d743e267a..ea38c7448 100644 --- a/pkg/repository/manager/manager_test.go +++ b/pkg/repository/manager/manager_test.go @@ -47,3 +47,20 @@ func TestGetRepositoryProvider(t *testing.T) { _, err = mgr.getRepositoryProvider(repo) require.Error(t, err) } + +func TestGetRepositoryConfigProvider(t *testing.T) { + mgr := NewConfigManager(nil).(*configManager) + + // empty repository type + _, err := mgr.getRepositoryProvider("") + require.Error(t, err) + + // valid repository type + provider, err := mgr.getRepositoryProvider(velerov1.BackupRepositoryTypeKopia) + require.NoError(t, err) + assert.NotNil(t, provider) + + // invalid repository type + _, err = mgr.getRepositoryProvider(velerov1.BackupRepositoryTypeRestic) + require.Error(t, err) +} diff --git a/pkg/repository/mocks/ConfigManager.go b/pkg/repository/mocks/ConfigManager.go new file mode 100644 index 000000000..590f49c33 --- /dev/null +++ b/pkg/repository/mocks/ConfigManager.go @@ -0,0 +1,84 @@ +// Code generated by mockery v2.53.2. DO NOT EDIT. + +package mocks + +import ( + mock "github.com/stretchr/testify/mock" + + time "time" +) + +// ConfigManager is an autogenerated mock type for the ConfigManager type +type ConfigManager struct { + mock.Mock +} + +// ClientSideCacheLimit provides a mock function with given fields: repoType, repoOption +func (_m *ConfigManager) ClientSideCacheLimit(repoType string, repoOption map[string]string) (int64, error) { + ret := _m.Called(repoType, repoOption) + + if len(ret) == 0 { + panic("no return value specified for ClientSideCacheLimit") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(string, map[string]string) (int64, error)); ok { + return rf(repoType, repoOption) + } + if rf, ok := ret.Get(0).(func(string, map[string]string) int64); ok { + r0 = rf(repoType, repoOption) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(string, map[string]string) error); ok { + r1 = rf(repoType, repoOption) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// DefaultMaintenanceFrequency provides a mock function with given fields: repoType +func (_m *ConfigManager) DefaultMaintenanceFrequency(repoType string) (time.Duration, error) { + ret := _m.Called(repoType) + + if len(ret) == 0 { + panic("no return value specified for DefaultMaintenanceFrequency") + } + + var r0 time.Duration + var r1 error + if rf, ok := ret.Get(0).(func(string) (time.Duration, error)); ok { + return rf(repoType) + } + if rf, ok := ret.Get(0).(func(string) time.Duration); ok { + r0 = rf(repoType) + } else { + r0 = ret.Get(0).(time.Duration) + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(repoType) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewConfigManager creates a new instance of ConfigManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewConfigManager(t interface { + mock.TestingT + Cleanup(func()) +}) *ConfigManager { + mock := &ConfigManager{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/repository/mocks/Manager.go b/pkg/repository/mocks/Manager.go index 226411775..954967adc 100644 --- a/pkg/repository/mocks/Manager.go +++ b/pkg/repository/mocks/Manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.53.2. DO NOT EDIT. package mocks @@ -37,6 +37,34 @@ func (_m *Manager) BatchForget(_a0 context.Context, _a1 *v1.BackupRepository, _a return r0 } +// ClientSideCacheLimit provides a mock function with given fields: _a0 +func (_m *Manager) ClientSideCacheLimit(_a0 *v1.BackupRepository) (int64, error) { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for ClientSideCacheLimit") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(*v1.BackupRepository) (int64, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(*v1.BackupRepository) int64); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(*v1.BackupRepository) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // ConnectToRepo provides a mock function with given fields: repo func (_m *Manager) ConnectToRepo(repo *v1.BackupRepository) error { ret := _m.Called(repo) @@ -55,9 +83,9 @@ func (_m *Manager) ConnectToRepo(repo *v1.BackupRepository) error { return r0 } -// DefaultMaintenanceFrequency provides a mock function with given fields: repo -func (_m *Manager) DefaultMaintenanceFrequency(repo *v1.BackupRepository) (time.Duration, error) { - ret := _m.Called(repo) +// DefaultMaintenanceFrequency provides a mock function with given fields: _a0 +func (_m *Manager) DefaultMaintenanceFrequency(_a0 *v1.BackupRepository) (time.Duration, error) { + ret := _m.Called(_a0) if len(ret) == 0 { panic("no return value specified for DefaultMaintenanceFrequency") @@ -66,16 +94,16 @@ func (_m *Manager) DefaultMaintenanceFrequency(repo *v1.BackupRepository) (time. var r0 time.Duration var r1 error if rf, ok := ret.Get(0).(func(*v1.BackupRepository) (time.Duration, error)); ok { - return rf(repo) + return rf(_a0) } if rf, ok := ret.Get(0).(func(*v1.BackupRepository) time.Duration); ok { - r0 = rf(repo) + r0 = rf(_a0) } else { r0 = ret.Get(0).(time.Duration) } if rf, ok := ret.Get(1).(func(*v1.BackupRepository) error); ok { - r1 = rf(repo) + r1 = rf(_a0) } else { r1 = ret.Error(1) } diff --git a/pkg/repository/provider/provider.go b/pkg/repository/provider/provider.go index 822e69aba..7681d830b 100644 --- a/pkg/repository/provider/provider.go +++ b/pkg/repository/provider/provider.go @@ -32,6 +32,8 @@ type RepoParam struct { // Provider defines the methods to manipulate a backup repository type Provider interface { + ConfigProvider + // InitRepo is to initialize a repository from a new storage place InitRepo(ctx context.Context, param RepoParam) error @@ -60,7 +62,13 @@ type Provider interface { // BatchForget is to delete a list of snapshots from the repository BatchForget(ctx context.Context, snapshotIDs []string, param RepoParam) []error - - // DefaultMaintenanceFrequency returns the default frequency to run maintenance - DefaultMaintenanceFrequency(ctx context.Context, param RepoParam) time.Duration +} + +// ConfigProvider defines the methods to get configurations of a backup repository +type ConfigProvider interface { + // DefaultMaintenanceFrequency returns the default frequency to run maintenance + DefaultMaintenanceFrequency() time.Duration + + // ClientSideCacheLimit returns the max cache size required on client side + ClientSideCacheLimit(repoOption map[string]string) int64 } diff --git a/pkg/repository/provider/restic.go b/pkg/repository/provider/restic.go index 3ca5988cb..ad4e0a257 100644 --- a/pkg/repository/provider/restic.go +++ b/pkg/repository/provider/restic.go @@ -90,6 +90,10 @@ func (r *resticRepositoryProvider) BatchForget(ctx context.Context, snapshotIDs return errs } -func (r *resticRepositoryProvider) DefaultMaintenanceFrequency(ctx context.Context, param RepoParam) time.Duration { +func (r *resticRepositoryProvider) DefaultMaintenanceFrequency() time.Duration { return r.svc.DefaultMaintenanceFrequency() } + +func (r *resticRepositoryProvider) ClientSideCacheLimit(repoOption map[string]string) int64 { + return 0 +} diff --git a/pkg/repository/provider/unified_repo.go b/pkg/repository/provider/unified_repo.go index c13665d2d..be3dfc089 100644 --- a/pkg/repository/provider/unified_repo.go +++ b/pkg/repository/provider/unified_repo.go @@ -46,6 +46,12 @@ type unifiedRepoProvider struct { log logrus.FieldLogger } +type unifiedRepoConfigProvider struct { + repoService udmrepo.BackupRepoService + repoBackend string + log logrus.FieldLogger +} + // this func is assigned to a package-level variable so it can be // replaced when unit-testing var getS3Credentials = repoconfig.GetS3Credentials @@ -86,9 +92,18 @@ func NewUnifiedRepoProvider( return &repo } -func GetUnifiedRepoClientSideCacheLimit(repoOption map[string]string, repoBackend string, log logrus.FieldLogger) int64 { - repoService := createRepoService(repoBackend, log) - return repoService.ClientSideCacheLimit(repoOption) +func NewUnifiedRepoConfigProvider( + repoBackend string, + log logrus.FieldLogger, +) ConfigProvider { + repo := unifiedRepoConfigProvider{ + repoBackend: repoBackend, + log: log, + } + + repo.repoService = createRepoService(repoBackend, log) + + return &repo } func (urp *unifiedRepoProvider) InitRepo(ctx context.Context, param RepoParam) error { @@ -375,10 +390,14 @@ func (urp *unifiedRepoProvider) BatchForget(ctx context.Context, snapshotIDs []s return errs } -func (urp *unifiedRepoProvider) DefaultMaintenanceFrequency(ctx context.Context, param RepoParam) time.Duration { +func (urp *unifiedRepoProvider) DefaultMaintenanceFrequency() time.Duration { return urp.repoService.DefaultMaintenanceFrequency() } +func (urp *unifiedRepoProvider) ClientSideCacheLimit(repoOption map[string]string) int64 { + return urp.repoService.ClientSideCacheLimit(repoOption) +} + func (urp *unifiedRepoProvider) GetPassword(param any) (string, error) { _, ok := param.(RepoParam) if !ok { @@ -429,6 +448,14 @@ func (urp *unifiedRepoProvider) GetStoreOptions(param any) (map[string]string, e return storeOptions, nil } +func (urcp *unifiedRepoConfigProvider) DefaultMaintenanceFrequency() time.Duration { + return urcp.repoService.DefaultMaintenanceFrequency() +} + +func (urcp *unifiedRepoConfigProvider) ClientSideCacheLimit(repoOption map[string]string) int64 { + return urcp.repoService.ClientSideCacheLimit(repoOption) +} + func getRepoPassword(secretStore credentials.SecretStore) (string, error) { if secretStore == nil { return "", errors.New("invalid credentials interface") From 7dbe2b43585123fa3f25eb88024e4ebc0c93c7c3 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Tue, 4 Nov 2025 16:59:52 +0800 Subject: [PATCH 082/104] cache volume for data download Signed-off-by: Lyndon-Li --- pkg/cmd/cli/nodeagent/server.go | 12 +++++++++ pkg/controller/data_download_controller.go | 25 +++++++++++++++++++ .../data_download_controller_test.go | 2 +- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/pkg/cmd/cli/nodeagent/server.go b/pkg/cmd/cli/nodeagent/server.go index dbd471eb8..6bcebbcfb 100644 --- a/pkg/cmd/cli/nodeagent/server.go +++ b/pkg/cmd/cli/nodeagent/server.go @@ -60,6 +60,7 @@ import ( "github.com/vmware-tanzu/velero/pkg/exposer" "github.com/vmware-tanzu/velero/pkg/metrics" "github.com/vmware-tanzu/velero/pkg/nodeagent" + repository "github.com/vmware-tanzu/velero/pkg/repository/manager" velerotypes "github.com/vmware-tanzu/velero/pkg/types" "github.com/vmware-tanzu/velero/pkg/util/filesystem" "github.com/vmware-tanzu/velero/pkg/util/kube" @@ -144,6 +145,7 @@ type nodeAgentServer struct { dataPathConfigs *velerotypes.NodeAgentConfigs backupRepoConfigs map[string]string vgdpCounter *exposer.VgdpCounter + repoConfigMgr repository.ConfigManager } func newNodeAgentServer(logger logrus.FieldLogger, factory client.Factory, config nodeAgentServerConfig) (*nodeAgentServer, error) { @@ -237,6 +239,7 @@ func newNodeAgentServer(logger logrus.FieldLogger, factory client.Factory, confi namespace: factory.Namespace(), nodeName: nodeName, metricsAddress: config.metricsAddress, + repoConfigMgr: repository.NewConfigManager(logger), } // the cache isn't initialized yet when "validatePodVolumesHostPath" is called, the client returned by the manager cannot @@ -386,6 +389,12 @@ func (s *nodeAgentServer) run() { s.logger.Infof("Using customized restorePVC config %v", restorePVCConfig) } + var cachePVCConfig *velerotypes.CachePVC + if s.dataPathConfigs != nil && s.dataPathConfigs.CachePVCConfig != nil { + cachePVCConfig = s.dataPathConfigs.CachePVCConfig + s.logger.Infof("Using customized cachePVC config %v", cachePVCConfig) + } + dataDownloadReconciler := controller.NewDataDownloadReconciler( s.mgr.GetClient(), s.mgr, @@ -394,12 +403,15 @@ func (s *nodeAgentServer) run() { s.vgdpCounter, loadAffinity, restorePVCConfig, + s.backupRepoConfigs, + cachePVCConfig, podResources, s.nodeName, s.config.dataMoverPrepareTimeout, s.logger, s.metrics, dataMovePriorityClass, + s.repoConfigMgr, ) if err := dataDownloadReconciler.SetupWithManager(s.mgr); err != nil { diff --git a/pkg/controller/data_download_controller.go b/pkg/controller/data_download_controller.go index 23328d387..b3f2044d9 100644 --- a/pkg/controller/data_download_controller.go +++ b/pkg/controller/data_download_controller.go @@ -49,6 +49,7 @@ import ( "github.com/vmware-tanzu/velero/pkg/exposer" "github.com/vmware-tanzu/velero/pkg/metrics" "github.com/vmware-tanzu/velero/pkg/nodeagent" + repository "github.com/vmware-tanzu/velero/pkg/repository/manager" velerotypes "github.com/vmware-tanzu/velero/pkg/types" "github.com/vmware-tanzu/velero/pkg/uploader" "github.com/vmware-tanzu/velero/pkg/util" @@ -68,11 +69,14 @@ type DataDownloadReconciler struct { vgdpCounter *exposer.VgdpCounter loadAffinity []*kube.LoadAffinity restorePVCConfig velerotypes.RestorePVC + backupRepoConfigs map[string]string + cacheVolumeConfigs *velerotypes.CachePVC podResources corev1api.ResourceRequirements preparingTimeout time.Duration metrics *metrics.ServerMetrics cancelledDataDownload map[string]time.Time dataMovePriorityClass string + repoConfigMgr repository.ConfigManager } func NewDataDownloadReconciler( @@ -83,12 +87,15 @@ func NewDataDownloadReconciler( counter *exposer.VgdpCounter, loadAffinity []*kube.LoadAffinity, restorePVCConfig velerotypes.RestorePVC, + backupRepoConfigs map[string]string, + cacheVolumeConfigs *velerotypes.CachePVC, podResources corev1api.ResourceRequirements, nodeName string, preparingTimeout time.Duration, logger logrus.FieldLogger, metrics *metrics.ServerMetrics, dataMovePriorityClass string, + repoConfigMgr repository.ConfigManager, ) *DataDownloadReconciler { return &DataDownloadReconciler{ client: client, @@ -99,6 +106,8 @@ func NewDataDownloadReconciler( nodeName: nodeName, restoreExposer: exposer.NewGenericRestoreExposer(kubeClient, logger), restorePVCConfig: restorePVCConfig, + backupRepoConfigs: backupRepoConfigs, + cacheVolumeConfigs: cacheVolumeConfigs, dataPathMgr: dataPathMgr, vgdpCounter: counter, loadAffinity: loadAffinity, @@ -107,6 +116,7 @@ func NewDataDownloadReconciler( metrics: metrics, cancelledDataDownload: make(map[string]time.Time), dataMovePriorityClass: dataMovePriorityClass, + repoConfigMgr: repoConfigMgr, } } @@ -882,6 +892,19 @@ func (r *DataDownloadReconciler) setupExposeParam(dd *velerov2alpha1api.DataDown } } + var cacheVolume *exposer.CacheConfigs + if r.cacheVolumeConfigs != nil { + if limit, err := r.repoConfigMgr.ClientSideCacheLimit(velerov1api.BackupRepositoryTypeKopia, r.backupRepoConfigs); err != nil { + log.WithError(err).Warnf("Failed to get client side cache limit for repo type %s from configs %v", velerov1api.BackupRepositoryTypeKopia, r.backupRepoConfigs) + } else { + cacheVolume = &exposer.CacheConfigs{ + Limit: limit, + StorageClass: r.cacheVolumeConfigs.StorageClass, + ResidentThreshold: r.cacheVolumeConfigs.ResidentThreshold, + } + } + } + return exposer.GenericRestoreExposeParam{ TargetPVCName: dd.Spec.TargetVolume.PVC, TargetNamespace: dd.Spec.TargetVolume.Namespace, @@ -895,6 +918,8 @@ func (r *DataDownloadReconciler) setupExposeParam(dd *velerov2alpha1api.DataDown RestorePVCConfig: r.restorePVCConfig, LoadAffinity: r.loadAffinity, PriorityClassName: r.dataMovePriorityClass, + RestoreSize: dd.Spec.SnapshotSize, + CacheVolume: cacheVolume, }, nil } diff --git a/pkg/controller/data_download_controller_test.go b/pkg/controller/data_download_controller_test.go index d260056e6..3b5f1002a 100644 --- a/pkg/controller/data_download_controller_test.go +++ b/pkg/controller/data_download_controller_test.go @@ -129,7 +129,7 @@ func initDataDownloadReconcilerWithError(t *testing.T, objects []any, needError dataPathMgr := datapath.NewManager(1) - return NewDataDownloadReconciler(&fakeClient, nil, fakeKubeClient, dataPathMgr, nil, nil, velerotypes.RestorePVC{}, corev1api.ResourceRequirements{}, "test-node", time.Minute*5, velerotest.NewLogger(), metrics.NewServerMetrics(), ""), nil + return NewDataDownloadReconciler(&fakeClient, nil, fakeKubeClient, dataPathMgr, nil, nil, velerotypes.RestorePVC{}, nil, nil, corev1api.ResourceRequirements{}, "test-node", time.Minute*5, velerotest.NewLogger(), metrics.NewServerMetrics(), "", nil), nil } func TestDataDownloadReconcile(t *testing.T) { From bd7d28f004c77d2b9dfa89a8f1c68740e5cac25f Mon Sep 17 00:00:00 2001 From: Scott Seago Date: Tue, 4 Nov 2025 16:53:30 -0500 Subject: [PATCH 083/104] don't copy securitycontext from first container if configmap found Signed-off-by: Scott Seago --- changelogs/unreleased/9389-sseago | 1 + pkg/restore/actions/pod_volume_restore_action.go | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/9389-sseago diff --git a/changelogs/unreleased/9389-sseago b/changelogs/unreleased/9389-sseago new file mode 100644 index 000000000..f054c96e3 --- /dev/null +++ b/changelogs/unreleased/9389-sseago @@ -0,0 +1 @@ +don't copy securitycontext from first container if configmap found diff --git a/pkg/restore/actions/pod_volume_restore_action.go b/pkg/restore/actions/pod_volume_restore_action.go index 9f3ee6a41..eb7cb8f6d 100644 --- a/pkg/restore/actions/pod_volume_restore_action.go +++ b/pkg/restore/actions/pod_volume_restore_action.go @@ -185,8 +185,8 @@ func (a *PodVolumeRestoreAction) Execute(input *velero.RestoreItemActionExecuteI securityContextSet = true } } - // if first container in pod has a SecurityContext set, then copy this security context - if len(pod.Spec.Containers) != 0 && pod.Spec.Containers[0].SecurityContext != nil { + // if securityContext configmap is unavailable but first container in pod has a SecurityContext set, then copy this security context + if !securityContextSet && len(pod.Spec.Containers) != 0 && pod.Spec.Containers[0].SecurityContext != nil { securityContext = *pod.Spec.Containers[0].SecurityContext.DeepCopy() securityContextSet = true } From 6e54879f4d717fd195d430f9c98b6c24deca0544 Mon Sep 17 00:00:00 2001 From: Tiger Kaovilai Date: Wed, 5 Nov 2025 14:22:49 -0500 Subject: [PATCH 084/104] update debug bundle artifact name to include Kubernetes version and job index Signed-off-by: Tiger Kaovilai --- .github/workflows/e2e-test-kind.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2e-test-kind.yaml b/.github/workflows/e2e-test-kind.yaml index 0f5972f57..db774e409 100644 --- a/.github/workflows/e2e-test-kind.yaml +++ b/.github/workflows/e2e-test-kind.yaml @@ -187,5 +187,5 @@ jobs: if: ${{ failure() }} uses: actions/upload-artifact@v5 with: - name: DebugBundle + name: DebugBundle-k8s-${{ matrix.k8s }}-job-${{ strategy.job-index }} path: /home/runner/work/velero/velero/test/e2e/debug-bundle* From 21b998e2c5b79f995eefa9e6c61472fa68c4ec46 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Thu, 6 Nov 2025 15:15:33 +0800 Subject: [PATCH 085/104] cache volume for data download Signed-off-by: Lyndon-Li --- changelogs/unreleased/9391-Lyndon-Li | 1 + pkg/cmd/cli/nodeagent/server.go | 16 ++++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) create mode 100644 changelogs/unreleased/9391-Lyndon-Li diff --git a/changelogs/unreleased/9391-Lyndon-Li b/changelogs/unreleased/9391-Lyndon-Li new file mode 100644 index 000000000..a5176d5ef --- /dev/null +++ b/changelogs/unreleased/9391-Lyndon-Li @@ -0,0 +1 @@ +Cache volume support for DataDownload \ No newline at end of file diff --git a/pkg/cmd/cli/nodeagent/server.go b/pkg/cmd/cli/nodeagent/server.go index 6bcebbcfb..f155ae01e 100644 --- a/pkg/cmd/cli/nodeagent/server.go +++ b/pkg/cmd/cli/nodeagent/server.go @@ -348,6 +348,16 @@ func (s *nodeAgentServer) run() { } } + var cachePVCConfig *velerotypes.CachePVC + if s.dataPathConfigs != nil && s.dataPathConfigs.CachePVCConfig != nil { + cachePVCConfig = s.dataPathConfigs.CachePVCConfig + s.logger.Infof("Using customized cachePVC config %v", cachePVCConfig) + } + + if s.backupRepoConfigs != nil { + s.logger.Infof("Using backup repo config %v", s.backupRepoConfigs) + } + pvbReconciler := controller.NewPodVolumeBackupReconciler(s.mgr.GetClient(), s.mgr, s.kubeClient, s.dataPathMgr, s.vgdpCounter, s.nodeName, s.config.dataMoverPrepareTimeout, s.config.resourceTimeout, podResources, s.metrics, s.logger, dataMovePriorityClass, privilegedFsBackup) if err := pvbReconciler.SetupWithManager(s.mgr); err != nil { s.logger.Fatal(err, "unable to create controller", "controller", constant.ControllerPodVolumeBackup) @@ -389,12 +399,6 @@ func (s *nodeAgentServer) run() { s.logger.Infof("Using customized restorePVC config %v", restorePVCConfig) } - var cachePVCConfig *velerotypes.CachePVC - if s.dataPathConfigs != nil && s.dataPathConfigs.CachePVCConfig != nil { - cachePVCConfig = s.dataPathConfigs.CachePVCConfig - s.logger.Infof("Using customized cachePVC config %v", cachePVCConfig) - } - dataDownloadReconciler := controller.NewDataDownloadReconciler( s.mgr.GetClient(), s.mgr, From 82367e7ff644706a7012eb2dcad3b1247afe4aff Mon Sep 17 00:00:00 2001 From: Xun Jiang/Bruce Jiang <59276555+blackpiglet@users.noreply.github.com> Date: Wed, 12 Nov 2025 01:56:27 +0800 Subject: [PATCH 086/104] Fix the Job build error when BackupReposiotry name longer than 63. (#9350) * Fix the Job build error when BackupReposiotry name longer than 63. Fix the Job build error. Consider the name length limitation change in job list code. Use hash to replace the GetValidName function. Signed-off-by: Xun Jiang * Use ref_name to replace ref. Signed-off-by: Xun Jiang --------- Signed-off-by: Xun Jiang --- .github/workflows/push.yml | 2 +- changelogs/unreleased/9350-blackpiglet | 1 + .../backup_repository_controller.go | 2 +- pkg/label/label.go | 12 ++ pkg/label/label_test.go | 26 +++ pkg/repository/maintenance/maintenance.go | 36 +++- .../maintenance/maintenance_test.go | 159 +++++++++++++----- 7 files changed, 182 insertions(+), 56 deletions(-) create mode 100644 changelogs/unreleased/9350-blackpiglet diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index a9f19b09f..c82689cc6 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -12,7 +12,7 @@ jobs: get-go-version: uses: ./.github/workflows/get-go-version.yaml with: - ref: ${{ github.ref }} + ref: ${{ github.ref_name }} build: name: Build diff --git a/changelogs/unreleased/9350-blackpiglet b/changelogs/unreleased/9350-blackpiglet new file mode 100644 index 000000000..eb3e5fde7 --- /dev/null +++ b/changelogs/unreleased/9350-blackpiglet @@ -0,0 +1 @@ +Fix the Job build error when BackupReposiotry name longer than 63. diff --git a/pkg/controller/backup_repository_controller.go b/pkg/controller/backup_repository_controller.go index 0356a1f9a..d2d32d745 100644 --- a/pkg/controller/backup_repository_controller.go +++ b/pkg/controller/backup_repository_controller.go @@ -275,7 +275,7 @@ func (r *BackupRepoReconciler) Reconcile(ctx context.Context, req ctrl.Request) log.WithError(err).Warn("Failed to get keepLatestMaintenanceJobs from ConfigMap, using CLI parameter value") } - if err := maintenance.DeleteOldJobs(r.Client, req.Name, keepJobs, log); err != nil { + if err := maintenance.DeleteOldJobs(r.Client, *backupRepo, keepJobs, log); err != nil { log.WithError(err).Warn("Failed to delete old maintenance jobs") } } diff --git a/pkg/label/label.go b/pkg/label/label.go index 98d232f24..bfd28b836 100644 --- a/pkg/label/label.go +++ b/pkg/label/label.go @@ -18,6 +18,7 @@ package label import ( "crypto/sha256" + "crypto/sha3" "encoding/hex" "fmt" @@ -49,6 +50,17 @@ func GetValidName(label string) string { return label[:charsFromLabel] + strSha[:6] } +// ReturnNameOrHash returns the original name if it is within the DNS1035LabelMaxLength limit, +// otherwise it returns the sha3 Sum224 hash(length is 56) of the name. +func ReturnNameOrHash(name string) string { + if len(name) <= validation.DNS1035LabelMaxLength { + return name + } + + hash := sha3.Sum224([]byte(name)) + return hex.EncodeToString(hash[:]) +} + // NewSelectorForBackup returns a Selector based on the backup name. // This is useful for interacting with Listers that need a Selector. func NewSelectorForBackup(name string) labels.Selector { diff --git a/pkg/label/label_test.go b/pkg/label/label_test.go index 8c4f456dc..cec24da09 100644 --- a/pkg/label/label_test.go +++ b/pkg/label/label_test.go @@ -48,6 +48,32 @@ func TestGetValidLabelName(t *testing.T) { } } +func TestReturnNameOrHash(t *testing.T) { + tests := []struct { + name string + label string + expectedLabel string + }{ + { + name: "valid label name should not be modified", + label: "short label value", + expectedLabel: "short label value", + }, + { + name: "label with more than 63 characters should be modified", + label: "this_is_a_very_long_label_value_that_will_be_rejected_by_Kubernetes", + expectedLabel: "1a7399f2d00e268fc12daf431d6667319d1461e2609981070bb7e85c", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + labelVal := ReturnNameOrHash(test.label) + assert.Equal(t, test.expectedLabel, labelVal) + }) + } +} + func TestNewSelectorForBackup(t *testing.T) { selector := NewSelectorForBackup("my-backup") assert.Equal(t, "velero.io/backup-name=my-backup", selector.String()) diff --git a/pkg/repository/maintenance/maintenance.go b/pkg/repository/maintenance/maintenance.go index e43918d4d..f8e287640 100644 --- a/pkg/repository/maintenance/maintenance.go +++ b/pkg/repository/maintenance/maintenance.go @@ -32,11 +32,13 @@ import ( corev1api "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" "sigs.k8s.io/controller-runtime/pkg/client" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + velerolabel "github.com/vmware-tanzu/velero/pkg/label" velerotypes "github.com/vmware-tanzu/velero/pkg/types" "github.com/vmware-tanzu/velero/pkg/util" "github.com/vmware-tanzu/velero/pkg/util/kube" @@ -68,11 +70,22 @@ func GenerateJobName(repo string) string { } // DeleteOldJobs deletes old maintenance jobs and keeps the latest N jobs -func DeleteOldJobs(cli client.Client, repo string, keep int, logger logrus.FieldLogger) error { +func DeleteOldJobs(cli client.Client, repo velerov1api.BackupRepository, keep int, logger logrus.FieldLogger) error { logger.Infof("Start to delete old maintenance jobs. %d jobs will be kept.", keep) // Get the maintenance job list by label jobList := &batchv1api.JobList{} - err := cli.List(context.TODO(), jobList, client.MatchingLabels(map[string]string{RepositoryNameLabel: repo})) + err := cli.List( + context.TODO(), + jobList, + &client.ListOptions{ + Namespace: repo.Namespace, + LabelSelector: labels.SelectorFromSet( + map[string]string{ + RepositoryNameLabel: velerolabel.ReturnNameOrHash(repo.Name), + }, + ), + }, + ) if err != nil { return err } @@ -339,10 +352,17 @@ func WaitJobComplete(cli client.Client, ctx context.Context, jobName, ns string, // and then return the maintenance jobs' status in the range of limit func WaitAllJobsComplete(ctx context.Context, cli client.Client, repo *velerov1api.BackupRepository, limit int, log logrus.FieldLogger) ([]velerov1api.BackupRepositoryMaintenanceStatus, error) { jobList := &batchv1api.JobList{} - err := cli.List(context.TODO(), jobList, &client.ListOptions{ - Namespace: repo.Namespace, - }, - client.MatchingLabels(map[string]string{RepositoryNameLabel: repo.Name}), + err := cli.List( + context.TODO(), + jobList, + &client.ListOptions{ + Namespace: repo.Namespace, + LabelSelector: labels.SelectorFromSet( + map[string]string{ + RepositoryNameLabel: velerolabel.ReturnNameOrHash(repo.Name), + }, + ), + }, ) if err != nil { @@ -558,7 +578,7 @@ func buildJob( } podLabels := map[string]string{ - RepositoryNameLabel: repo.Name, + RepositoryNameLabel: velerolabel.ReturnNameOrHash(repo.Name), } for _, k := range util.ThirdPartyLabels { @@ -588,7 +608,7 @@ func buildJob( Name: GenerateJobName(repo.Name), Namespace: repo.Namespace, Labels: map[string]string{ - RepositoryNameLabel: repo.Name, + RepositoryNameLabel: velerolabel.ReturnNameOrHash(repo.Name), }, }, Spec: batchv1api.JobSpec{ diff --git a/pkg/repository/maintenance/maintenance_test.go b/pkg/repository/maintenance/maintenance_test.go index 93d8f9b2f..e32cb457f 100644 --- a/pkg/repository/maintenance/maintenance_test.go +++ b/pkg/repository/maintenance/maintenance_test.go @@ -40,6 +40,7 @@ import ( velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" "github.com/vmware-tanzu/velero/pkg/builder" + velerolabel "github.com/vmware-tanzu/velero/pkg/label" "github.com/vmware-tanzu/velero/pkg/repository/provider" velerotest "github.com/vmware-tanzu/velero/pkg/test" velerotypes "github.com/vmware-tanzu/velero/pkg/types" @@ -48,7 +49,7 @@ import ( "github.com/vmware-tanzu/velero/pkg/util/logging" ) -func TestGenerateJobName1(t *testing.T) { +func TestGenerateJobName(t *testing.T) { testCases := []struct { repo string expectedStart string @@ -82,59 +83,62 @@ func TestGenerateJobName1(t *testing.T) { } func TestDeleteOldJobs(t *testing.T) { // Set up test repo and keep value - repo := "test-repo" - keep := 2 - - // Create some maintenance jobs for testing - var objs []client.Object - // Create a newer job - newerJob := &batchv1api.Job{ + repo := &velerov1api.BackupRepository{ ObjectMeta: metav1.ObjectMeta{ - Name: "job1", - Namespace: "default", - Labels: map[string]string{RepositoryNameLabel: repo}, + Name: "label with more than 63 characters should be modified", + Namespace: velerov1api.DefaultNamespace, + }, + } + keep := 1 + + jobArray := []client.Object{ + &batchv1api.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "job-0", + Namespace: velerov1api.DefaultNamespace, + Labels: map[string]string{RepositoryNameLabel: velerolabel.ReturnNameOrHash(repo.Name)}, + }, + Spec: batchv1api.JobSpec{}, + }, + &batchv1api.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "job-1", + Namespace: velerov1api.DefaultNamespace, + Labels: map[string]string{RepositoryNameLabel: velerolabel.ReturnNameOrHash(repo.Name)}, + }, + Spec: batchv1api.JobSpec{}, + }, + } + + newJob := &batchv1api.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "job-new", + Namespace: velerov1api.DefaultNamespace, + Labels: map[string]string{RepositoryNameLabel: velerolabel.ReturnNameOrHash(repo.Name)}, }, Spec: batchv1api.JobSpec{}, } - objs = append(objs, newerJob) - // Create older jobs - for i := 2; i <= 3; i++ { - olderJob := &batchv1api.Job{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("job%d", i), - Namespace: "default", - Labels: map[string]string{RepositoryNameLabel: repo}, - CreationTimestamp: metav1.Time{ - Time: metav1.Now().Add(time.Duration(-24*i) * time.Hour), - }, - }, - Spec: batchv1api.JobSpec{}, - } - objs = append(objs, olderJob) - } - // Create a fake Kubernetes client + + // Create a fake Kubernetes client with 2 jobs. scheme := runtime.NewScheme() _ = batchv1api.AddToScheme(scheme) - cli := fake.NewClientBuilder().WithScheme(scheme).WithObjects(objs...).Build() + cli := fake.NewClientBuilder().WithScheme(scheme).WithObjects(jobArray...).Build() + + // Create a new job + require.NoError(t, cli.Create(t.Context(), newJob)) // Call the function - err := DeleteOldJobs(cli, repo, keep, velerotest.NewLogger()) - require.NoError(t, err) + require.NoError(t, DeleteOldJobs(cli, *repo, keep, velerotest.NewLogger())) // Get the remaining jobs jobList := &batchv1api.JobList{} - err = cli.List(t.Context(), jobList, client.MatchingLabels(map[string]string{RepositoryNameLabel: repo})) - require.NoError(t, err) + require.NoError(t, cli.List(t.Context(), jobList, client.MatchingLabels(map[string]string{RepositoryNameLabel: repo.Name}))) // We expect the number of jobs to be equal to 'keep' assert.Len(t, jobList.Items, keep) - // We expect that the oldest jobs were deleted - // Job3 should not be present in the remaining list - assert.NotContains(t, jobList.Items, objs[2]) - - // Job2 should also not be present in the remaining list - assert.NotContains(t, jobList.Items, objs[1]) + // Only the new created job should be left. + assert.Equal(t, jobList.Items[0].Name, newJob.Name) } func TestWaitForJobComplete(t *testing.T) { @@ -571,7 +575,7 @@ func TestWaitAllJobsComplete(t *testing.T) { repo := &velerov1api.BackupRepository{ ObjectMeta: metav1.ObjectMeta{ Namespace: veleroNamespace, - Name: "fake-repo", + Name: "label with more than 63 characters should be modified", }, Spec: velerov1api.BackupRepositorySpec{ BackupStorageLocation: "default", @@ -595,7 +599,7 @@ func TestWaitAllJobsComplete(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "job1", Namespace: veleroNamespace, - Labels: map[string]string{RepositoryNameLabel: "fake-repo"}, + Labels: map[string]string{RepositoryNameLabel: velerolabel.ReturnNameOrHash(repo.Name)}, CreationTimestamp: metav1.Time{Time: now}, }, } @@ -604,7 +608,7 @@ func TestWaitAllJobsComplete(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "job1", Namespace: veleroNamespace, - Labels: map[string]string{RepositoryNameLabel: "fake-repo"}, + Labels: map[string]string{RepositoryNameLabel: velerolabel.ReturnNameOrHash(repo.Name)}, CreationTimestamp: metav1.Time{Time: now}, }, Status: batchv1api.JobStatus{ @@ -624,7 +628,7 @@ func TestWaitAllJobsComplete(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "job2", Namespace: veleroNamespace, - Labels: map[string]string{RepositoryNameLabel: "fake-repo"}, + Labels: map[string]string{RepositoryNameLabel: velerolabel.ReturnNameOrHash(repo.Name)}, CreationTimestamp: metav1.Time{Time: now.Add(time.Hour)}, }, Status: batchv1api.JobStatus{ @@ -645,7 +649,7 @@ func TestWaitAllJobsComplete(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "job3", Namespace: veleroNamespace, - Labels: map[string]string{RepositoryNameLabel: "fake-repo"}, + Labels: map[string]string{RepositoryNameLabel: velerolabel.ReturnNameOrHash(repo.Name)}, CreationTimestamp: metav1.Time{Time: now.Add(time.Hour * 2)}, }, Status: batchv1api.JobStatus{ @@ -665,7 +669,7 @@ func TestWaitAllJobsComplete(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "job4", Namespace: veleroNamespace, - Labels: map[string]string{RepositoryNameLabel: "fake-repo"}, + Labels: map[string]string{RepositoryNameLabel: velerolabel.ReturnNameOrHash(repo.Name)}, CreationTimestamp: metav1.Time{Time: now.Add(time.Hour * 3)}, }, Status: batchv1api.JobStatus{ @@ -698,7 +702,7 @@ func TestWaitAllJobsComplete(t *testing.T) { { name: "list job error", runtimeScheme: schemeFail, - expectedError: "error listing maintenance job for repo fake-repo: no kind is registered for the type v1.JobList in scheme", + expectedError: "error listing maintenance job for repo label with more than 63 characters should be modified: no kind is registered for the type v1.JobList in scheme", }, { name: "job not exist", @@ -943,6 +947,7 @@ func TestBuildJob(t *testing.T) { expectedSecurityContext *corev1api.SecurityContext expectedPodSecurityContext *corev1api.PodSecurityContext expectedImagePullSecrets []corev1api.LocalObjectReference + backupRepository *velerov1api.BackupRepository }{ { name: "Valid maintenance job without third party labels", @@ -1060,6 +1065,64 @@ func TestBuildJob(t *testing.T) { expectedJobName: "", expectedError: true, }, + { + name: "Valid maintenance job with third party labels and BackupRepository name longer than 63", + m: &velerotypes.JobConfigs{ + PodResources: &kube.PodResources{ + CPURequest: "100m", + MemoryRequest: "128Mi", + CPULimit: "200m", + MemoryLimit: "256Mi", + }, + }, + deploy: deploy2, + logLevel: logrus.InfoLevel, + logFormat: logging.NewFormatFlag(), + expectedError: false, + expectedEnv: []corev1api.EnvVar{ + { + Name: "test-name", + Value: "test-value", + }, + }, + expectedEnvFrom: []corev1api.EnvFromSource{ + { + ConfigMapRef: &corev1api.ConfigMapEnvSource{ + LocalObjectReference: corev1api.LocalObjectReference{ + Name: "test-configmap", + }, + }, + }, + { + SecretRef: &corev1api.SecretEnvSource{ + LocalObjectReference: corev1api.LocalObjectReference{ + Name: "test-secret", + }, + }, + }, + }, + expectedPodLabel: map[string]string{ + RepositoryNameLabel: velerolabel.ReturnNameOrHash("label with more than 63 characters should be modified"), + "azure.workload.identity/use": "fake-label-value", + }, + expectedSecurityContext: nil, + expectedPodSecurityContext: nil, + expectedImagePullSecrets: []corev1api.LocalObjectReference{ + { + Name: "imagePullSecret1", + }, + }, + backupRepository: &velerov1api.BackupRepository{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "velero", + Name: "label with more than 63 characters should be modified", + }, + Spec: velerov1api.BackupRepositorySpec{ + VolumeNamespace: "test-123", + RepositoryType: "kopia", + }, + }, + }, } param := provider.RepoParam{ @@ -1083,6 +1146,10 @@ func TestBuildJob(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + if tc.backupRepository != nil { + param.BackupRepo = tc.backupRepository + } + // Create a fake clientset with resources objs := []runtime.Object{param.BackupLocation, param.BackupRepo} From f947092f1a213ddb82f80522c6980e70140b168b Mon Sep 17 00:00:00 2001 From: lyndon-li <98304688+Lyndon-Li@users.noreply.github.com> Date: Wed, 12 Nov 2025 02:02:56 +0800 Subject: [PATCH 087/104] cache volume for PVR (#9397) Signed-off-by: Lyndon-Li --- changelogs/unreleased/9397-Lyndon-Li | 1 + pkg/cmd/cli/nodeagent/server.go | 2 +- .../pod_volume_restore_controller.go | 28 +++++++++++++++++-- .../pod_volume_restore_controller_test.go | 2 +- 4 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 changelogs/unreleased/9397-Lyndon-Li diff --git a/changelogs/unreleased/9397-Lyndon-Li b/changelogs/unreleased/9397-Lyndon-Li new file mode 100644 index 000000000..b5291f6c8 --- /dev/null +++ b/changelogs/unreleased/9397-Lyndon-Li @@ -0,0 +1 @@ +Cache volume for PVR \ No newline at end of file diff --git a/pkg/cmd/cli/nodeagent/server.go b/pkg/cmd/cli/nodeagent/server.go index f155ae01e..779088784 100644 --- a/pkg/cmd/cli/nodeagent/server.go +++ b/pkg/cmd/cli/nodeagent/server.go @@ -363,7 +363,7 @@ func (s *nodeAgentServer) run() { s.logger.Fatal(err, "unable to create controller", "controller", constant.ControllerPodVolumeBackup) } - pvrReconciler := controller.NewPodVolumeRestoreReconciler(s.mgr.GetClient(), s.mgr, s.kubeClient, s.dataPathMgr, s.vgdpCounter, s.nodeName, s.config.dataMoverPrepareTimeout, s.config.resourceTimeout, podResources, s.logger, dataMovePriorityClass, privilegedFsBackup) + pvrReconciler := controller.NewPodVolumeRestoreReconciler(s.mgr.GetClient(), s.mgr, s.kubeClient, s.dataPathMgr, s.vgdpCounter, s.nodeName, s.config.dataMoverPrepareTimeout, s.config.resourceTimeout, s.backupRepoConfigs, cachePVCConfig, podResources, s.logger, dataMovePriorityClass, privilegedFsBackup, s.repoConfigMgr) if err := pvrReconciler.SetupWithManager(s.mgr); err != nil { s.logger.WithError(err).Fatal("Unable to create the pod volume restore controller") } diff --git a/pkg/controller/pod_volume_restore_controller.go b/pkg/controller/pod_volume_restore_controller.go index 0ed06b980..87b2353f5 100644 --- a/pkg/controller/pod_volume_restore_controller.go +++ b/pkg/controller/pod_volume_restore_controller.go @@ -48,15 +48,18 @@ import ( "github.com/vmware-tanzu/velero/pkg/datapath" "github.com/vmware-tanzu/velero/pkg/exposer" "github.com/vmware-tanzu/velero/pkg/nodeagent" + repository "github.com/vmware-tanzu/velero/pkg/repository/manager" "github.com/vmware-tanzu/velero/pkg/restorehelper" + velerotypes "github.com/vmware-tanzu/velero/pkg/types" "github.com/vmware-tanzu/velero/pkg/uploader" "github.com/vmware-tanzu/velero/pkg/util" "github.com/vmware-tanzu/velero/pkg/util/kube" ) func NewPodVolumeRestoreReconciler(client client.Client, mgr manager.Manager, kubeClient kubernetes.Interface, dataPathMgr *datapath.Manager, - counter *exposer.VgdpCounter, nodeName string, preparingTimeout time.Duration, resourceTimeout time.Duration, podResources corev1api.ResourceRequirements, - logger logrus.FieldLogger, dataMovePriorityClass string, privileged bool) *PodVolumeRestoreReconciler { + counter *exposer.VgdpCounter, nodeName string, preparingTimeout time.Duration, resourceTimeout time.Duration, backupRepoConfigs map[string]string, + cacheVolumeConfigs *velerotypes.CachePVC, podResources corev1api.ResourceRequirements, logger logrus.FieldLogger, dataMovePriorityClass string, + privileged bool, repoConfigMgr repository.ConfigManager) *PodVolumeRestoreReconciler { return &PodVolumeRestoreReconciler{ client: client, mgr: mgr, @@ -65,6 +68,8 @@ func NewPodVolumeRestoreReconciler(client client.Client, mgr manager.Manager, ku nodeName: nodeName, clock: &clocks.RealClock{}, podResources: podResources, + backupRepoConfigs: backupRepoConfigs, + cacheVolumeConfigs: cacheVolumeConfigs, dataPathMgr: dataPathMgr, vgdpCounter: counter, preparingTimeout: preparingTimeout, @@ -73,6 +78,7 @@ func NewPodVolumeRestoreReconciler(client client.Client, mgr manager.Manager, ku cancelledPVR: make(map[string]time.Time), dataMovePriorityClass: dataMovePriorityClass, privileged: privileged, + repoConfigMgr: repoConfigMgr, } } @@ -84,6 +90,8 @@ type PodVolumeRestoreReconciler struct { nodeName string clock clocks.WithTickerAndDelayedExecution podResources corev1api.ResourceRequirements + backupRepoConfigs map[string]string + cacheVolumeConfigs *velerotypes.CachePVC exposer exposer.PodVolumeExposer dataPathMgr *datapath.Manager vgdpCounter *exposer.VgdpCounter @@ -92,6 +100,7 @@ type PodVolumeRestoreReconciler struct { cancelledPVR map[string]time.Time dataMovePriorityClass string privileged bool + repoConfigMgr repository.ConfigManager } // +kubebuilder:rbac:groups=velero.io,resources=podvolumerestores,verbs=get;list;watch;create;update;patch;delete @@ -886,6 +895,19 @@ func (r *PodVolumeRestoreReconciler) setupExposeParam(pvr *velerov1api.PodVolume } } + var cacheVolume *exposer.CacheConfigs + if r.cacheVolumeConfigs != nil { + if limit, err := r.repoConfigMgr.ClientSideCacheLimit(velerov1api.BackupRepositoryTypeKopia, r.backupRepoConfigs); err != nil { + log.WithError(err).Warnf("Failed to get client side cache limit for repo type %s from configs %v", velerov1api.BackupRepositoryTypeKopia, r.backupRepoConfigs) + } else { + cacheVolume = &exposer.CacheConfigs{ + Limit: limit, + StorageClass: r.cacheVolumeConfigs.StorageClass, + ResidentThreshold: r.cacheVolumeConfigs.ResidentThreshold, + } + } + } + return exposer.PodVolumeExposeParam{ Type: exposer.PodVolumeExposeTypeRestore, ClientNamespace: pvr.Spec.Pod.Namespace, @@ -896,6 +918,8 @@ func (r *PodVolumeRestoreReconciler) setupExposeParam(pvr *velerov1api.PodVolume HostingPodTolerations: hostingPodTolerations, OperationTimeout: r.resourceTimeout, Resources: r.podResources, + RestoreSize: pvr.Spec.SnapshotSize, + CacheVolume: cacheVolume, // Priority class name for the data mover pod, retrieved from node-agent-configmap PriorityClassName: r.dataMovePriorityClass, Privileged: r.privileged, diff --git a/pkg/controller/pod_volume_restore_controller_test.go b/pkg/controller/pod_volume_restore_controller_test.go index e993815b5..be09f9c62 100644 --- a/pkg/controller/pod_volume_restore_controller_test.go +++ b/pkg/controller/pod_volume_restore_controller_test.go @@ -617,7 +617,7 @@ func initPodVolumeRestoreReconcilerWithError(objects []runtime.Object, cliObj [] dataPathMgr := datapath.NewManager(1) - return NewPodVolumeRestoreReconciler(fakeClient, nil, fakeKubeClient, dataPathMgr, nil, "test-node", time.Minute*5, time.Minute, corev1api.ResourceRequirements{}, velerotest.NewLogger(), "", false), nil + return NewPodVolumeRestoreReconciler(fakeClient, nil, fakeKubeClient, dataPathMgr, nil, "test-node", time.Minute*5, time.Minute, nil, nil, corev1api.ResourceRequirements{}, velerotest.NewLogger(), "", false, nil), nil } func TestPodVolumeRestoreReconcile(t *testing.T) { From b9cf90f11cabe852fa8dfed788dc0f3d81632b2f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 13:03:40 -0500 Subject: [PATCH 088/104] Bump golangci/golangci-lint-action from 8 to 9 (#9404) Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 8 to 9. - [Release notes](https://github.com/golangci/golangci-lint-action/releases) - [Commits](https://github.com/golangci/golangci-lint-action/compare/v8...v9) --- updated-dependencies: - dependency-name: golangci/golangci-lint-action dependency-version: '9' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pr-linter-check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-linter-check.yml b/.github/workflows/pr-linter-check.yml index 81a2bdd64..6ff4a0367 100644 --- a/.github/workflows/pr-linter-check.yml +++ b/.github/workflows/pr-linter-check.yml @@ -26,7 +26,7 @@ jobs: go-version: ${{ needs.get-go-version.outputs.version }} - name: Linter check - uses: golangci/golangci-lint-action@v8 + uses: golangci/golangci-lint-action@v9 with: version: v2.1.1 args: --verbose From ad11b38468fcf980e7ace2eb86dfb446b215db09 Mon Sep 17 00:00:00 2001 From: Xun Jiang/Bruce Jiang <59276555+blackpiglet@users.noreply.github.com> Date: Wed, 12 Nov 2025 02:04:47 +0800 Subject: [PATCH 089/104] Remove PVC node selection E2E test case. (#9405) According to #7904, remove the corresponding E2E case. Signed-off-by: Xun Jiang --- test/e2e/basic/pvc-selected-node-changing.go | 174 ------------------- test/e2e/e2e_suite_test.go | 6 - 2 files changed, 180 deletions(-) delete mode 100644 test/e2e/basic/pvc-selected-node-changing.go diff --git a/test/e2e/basic/pvc-selected-node-changing.go b/test/e2e/basic/pvc-selected-node-changing.go deleted file mode 100644 index fc2b64a38..000000000 --- a/test/e2e/basic/pvc-selected-node-changing.go +++ /dev/null @@ -1,174 +0,0 @@ -package basic - -import ( - "context" - "fmt" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" - . "github.com/vmware-tanzu/velero/test" - . "github.com/vmware-tanzu/velero/test/e2e/test" - "github.com/vmware-tanzu/velero/test/util/common" - . "github.com/vmware-tanzu/velero/test/util/k8s" - . "github.com/vmware-tanzu/velero/test/util/velero" -) - -type PVCSelectedNodeChanging struct { - TestCase - labels map[string]string - data map[string]string - configmaptName string - namespace string - oldNodeName string - newNodeName string - volume string - podName string - mappedNS string - pvcName string - ann string -} - -var PVCSelectedNodeChangingTest func() = TestFunc(&PVCSelectedNodeChanging{}) - -func (p *PVCSelectedNodeChanging) Init() error { - p.TestCase.Init() - p.CaseBaseName = "psnc-" + p.UUIDgen - p.namespace = p.CaseBaseName - p.mappedNS = p.namespace + "-mapped" - p.TestMsg = &TestMSG{ - Desc: "Changing PVC node selector", - FailedMSG: "Failed to changing PVC node selector", - Text: "Change node selectors of persistent volume claims during restores", - } - p.BackupName = "backup-" + p.CaseBaseName - p.RestoreName = "restore-" + p.CaseBaseName - p.labels = map[string]string{"velero.io/plugin-config": "", - "velero.io/change-pvc-node-selector": "RestoreItemAction"} - p.configmaptName = "change-pvc-node-selector-config" - p.volume = "volume-1" - p.podName = "pod-1" - p.pvcName = "pvc-1" - p.ann = "volume.kubernetes.io/selected-node" - p.BackupArgs = []string{ - "create", "--namespace", p.VeleroCfg.VeleroNamespace, "backup", p.BackupName, - "--include-namespaces", p.namespace, - "--snapshot-volumes=false", "--wait", - } - p.RestoreArgs = []string{ - "create", "--namespace", p.VeleroCfg.VeleroNamespace, "restore", p.RestoreName, - "--from-backup", p.BackupName, "--namespace-mappings", fmt.Sprintf("%s:%s", p.namespace, p.mappedNS), "--wait", - } - return nil -} - -func (p *PVCSelectedNodeChanging) CreateResources() error { - By(fmt.Sprintf("Create namespace %s", p.namespace), func() { - labels := make(map[string]string) - if p.VeleroCfg.WorkerOS == common.WorkerOSWindows { - labels = map[string]string{ - "pod-security.kubernetes.io/enforce": "privileged", - "pod-security.kubernetes.io/enforce-version": "latest", - } - } - Expect(CreateNamespaceWithLabel(p.Ctx, p.Client, p.namespace, labels)).To(Succeed(), - fmt.Sprintf("Failed to create namespace %s", p.namespace)) - }) - - By(fmt.Sprintf("Create pod %s in namespace %s", p.podName, p.namespace), func() { - nodeNameList, err := GetWorkerNodes(p.Ctx, p.VeleroCfg.WorkerOS) - Expect(err).To(Succeed()) - for _, nodeName := range nodeNameList { - p.oldNodeName = nodeName - fmt.Printf("Create PVC on node %s\n", p.oldNodeName) - pvcAnn := map[string]string{p.ann: nodeName} - _, err := CreatePod( - p.Client, - p.namespace, - p.podName, - StorageClassName, - p.pvcName, - []string{p.volume}, - pvcAnn, - nil, - p.VeleroCfg.ImageRegistryProxy, - p.VeleroCfg.WorkerOS, - ) - Expect(err).To(Succeed()) - err = WaitForPods(p.Ctx, p.Client, p.namespace, []string{p.podName}) - Expect(err).To(Succeed()) - break - } - }) - - By("Prepare ConfigMap data", func() { - nodeNameList, err := GetWorkerNodes(p.Ctx, p.VeleroCfg.WorkerOS) - Expect(err).To(Succeed()) - // Expect Windows node or Linux node number are no less than 2. - Expect(len(nodeNameList)).To(BeNumerically(">=", 2)) - for _, nodeName := range nodeNameList { - if nodeName != p.oldNodeName { - p.newNodeName = nodeName - break - } - } - p.data = map[string]string{p.oldNodeName: p.newNodeName} - }) - - By(fmt.Sprintf("Create ConfigMap %s in namespace %s", p.configmaptName, p.VeleroCfg.VeleroNamespace), func() { - cm, err := CreateConfigMap(p.Client.ClientGo, p.VeleroCfg.VeleroNamespace, p.configmaptName, p.labels, p.data) - Expect(err).To(Succeed(), fmt.Sprintf("failed to create configmap in the namespace %q", p.VeleroCfg.VeleroNamespace)) - fmt.Printf("Configmap: %v", cm) - }) - return nil -} - -func (p *PVCSelectedNodeChanging) Destroy() error { - By(fmt.Sprintf("Start to destroy namespace %s......", p.CaseBaseName), func() { - Expect(CleanupNamespacesWithPoll(p.Ctx, p.Client, p.CaseBaseName)).To(Succeed(), - fmt.Sprintf("Failed to delete namespace %s", p.CaseBaseName)) - }) - return nil -} - -func (p *PVCSelectedNodeChanging) Restore() error { - By(fmt.Sprintf("Start to restore %s .....", p.RestoreName), func() { - Expect(VeleroRestoreExec(p.Ctx, p.VeleroCfg.VeleroCLI, - p.VeleroCfg.VeleroNamespace, p.RestoreName, - p.RestoreArgs, velerov1api.RestorePhaseCompleted)).To( - Succeed(), - func() string { - RunDebug(context.Background(), p.VeleroCfg.VeleroCLI, - p.VeleroCfg.VeleroNamespace, "", p.RestoreName) - return "Fail to restore workload" - }) - err := WaitForPods(p.Ctx, p.Client, p.mappedNS, []string{p.podName}) - Expect(err).To(Succeed()) - }) - return nil -} -func (p *PVCSelectedNodeChanging) Verify() error { - By(fmt.Sprintf("PVC selected node should be %s", p.newNodeName), func() { - pvcNameList, err := GetPvcByPVCName(p.Ctx, p.mappedNS, p.pvcName) - Expect(err).To(Succeed()) - Expect(pvcNameList).Should(HaveLen(1)) - pvc, err := GetPVC(p.Ctx, p.Client, p.mappedNS, pvcNameList[0]) - Expect(err).To(Succeed()) - Expect(pvc.Annotations[p.ann]).To(Equal(p.newNodeName)) - }) - return nil -} - -func (p *PVCSelectedNodeChanging) Clean() error { - if CurrentSpecReport().Failed() && p.VeleroCfg.FailFast { - fmt.Println("Test case failed and fail fast is enabled. Skip resource clean up.") - } else { - p.TestCase.Clean() - By(fmt.Sprintf("Clean namespace with prefix %s after test", p.mappedNS), func() { - CleanupNamespaces(p.Ctx, p.Client, p.mappedNS) - }) - } - - return nil -} diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go index 71d501e60..5e7be7adc 100644 --- a/test/e2e/e2e_suite_test.go +++ b/test/e2e/e2e_suite_test.go @@ -440,12 +440,6 @@ var _ = Describe( StorageClasssChangingTest, ) -var _ = Describe( - "Node selectors of persistent volume claims can be changed during restores", - Label("Basic", "SelectedNode", "SKIP_KIND"), - PVCSelectedNodeChangingTest, -) - var _ = Describe( "Backup/restore of 2500 namespaces", Label("Scale", "LongTime"), From 67cf896eaf5f216fae43fd1bd77856c9d04dfad7 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Mon, 10 Nov 2025 17:11:02 +0800 Subject: [PATCH 090/104] fix backup repo init error Signed-off-by: Lyndon-Li --- changelogs/unreleased/9407-Lyndon-Li | 1 + pkg/repository/provider/unified_repo.go | 6 +- .../udmrepo/kopialib/backend/backend.go | 3 + .../udmrepo/kopialib/backend/common.go | 7 + .../udmrepo/kopialib/backend/file_system.go | 8 + pkg/repository/udmrepo/kopialib/lib_repo.go | 103 +--- .../udmrepo/kopialib/lib_repo_test.go | 172 ------ pkg/repository/udmrepo/kopialib/repo_init.go | 283 +++++++++- .../udmrepo/kopialib/repo_init_test.go | 528 +++++++++++++++++- 9 files changed, 833 insertions(+), 278 deletions(-) create mode 100644 changelogs/unreleased/9407-Lyndon-Li diff --git a/changelogs/unreleased/9407-Lyndon-Li b/changelogs/unreleased/9407-Lyndon-Li new file mode 100644 index 000000000..ee6c403ef --- /dev/null +++ b/changelogs/unreleased/9407-Lyndon-Li @@ -0,0 +1 @@ +Fix issue #9400, connect repo first time after creation so that init params could be written \ No newline at end of file diff --git a/pkg/repository/provider/unified_repo.go b/pkg/repository/provider/unified_repo.go index be3dfc089..8171c6dbe 100644 --- a/pkg/repository/provider/unified_repo.go +++ b/pkg/repository/provider/unified_repo.go @@ -189,7 +189,7 @@ func (urp *unifiedRepoProvider) PrepareRepo(ctx context.Context, param RepoParam "repo UID": param.BackupRepo.UID, }) - log.Debug("Start to prepare repo") + log.Info("Start to prepare repo") repoOption, err := udmrepo.NewRepoOptions( udmrepo.WithPassword(urp, param), @@ -211,7 +211,7 @@ func (urp *unifiedRepoProvider) PrepareRepo(ctx context.Context, param RepoParam if created, err := urp.repoService.IsCreated(ctx, *repoOption); err != nil { return errors.Wrap(err, "error to check backup repo") } else if created { - log.Debug("Repo has already been initialized remotely") + log.Info("Repo has already been initialized") return nil } @@ -224,7 +224,7 @@ func (urp *unifiedRepoProvider) PrepareRepo(ctx context.Context, param RepoParam return errors.Wrap(err, "error to create backup repo") } - log.Debug("Prepare repo complete") + log.Info("Prepare repo complete") return nil } diff --git a/pkg/repository/udmrepo/kopialib/backend/backend.go b/pkg/repository/udmrepo/kopialib/backend/backend.go index c173eabc6..bf6726837 100644 --- a/pkg/repository/udmrepo/kopialib/backend/backend.go +++ b/pkg/repository/udmrepo/kopialib/backend/backend.go @@ -18,12 +18,15 @@ package backend import ( "context" + "errors" "github.com/sirupsen/logrus" "github.com/kopia/kopia/repo/blob" ) +var ErrStoreNotExist = errors.New("store does not exist") + // Store defines the methods for Kopia to establish a connection to // the backend storage type Store interface { diff --git a/pkg/repository/udmrepo/kopialib/backend/common.go b/pkg/repository/udmrepo/kopialib/backend/common.go index a54923003..7af061204 100644 --- a/pkg/repository/udmrepo/kopialib/backend/common.go +++ b/pkg/repository/udmrepo/kopialib/backend/common.go @@ -92,3 +92,10 @@ func SetupConnectOptions(ctx context.Context, repoOptions udmrepo.RepoOptions) r }, } } + +func RepoOwnerFromRepoOptions(repoOptions udmrepo.RepoOptions) string { + hostname := optionalHaveStringWithDefault(udmrepo.GenOptionOwnerDomain, repoOptions.GeneralOptions, udmrepo.GetRepoDomain()) + username := optionalHaveStringWithDefault(udmrepo.GenOptionOwnerName, repoOptions.GeneralOptions, udmrepo.GetRepoUser()) + + return username + "@" + hostname +} diff --git a/pkg/repository/udmrepo/kopialib/backend/file_system.go b/pkg/repository/udmrepo/kopialib/backend/file_system.go index 075099cf8..f0999e832 100644 --- a/pkg/repository/udmrepo/kopialib/backend/file_system.go +++ b/pkg/repository/udmrepo/kopialib/backend/file_system.go @@ -18,6 +18,7 @@ package backend import ( "context" + "os" "path/filepath" "github.com/sirupsen/logrus" @@ -62,6 +63,13 @@ func (c *FsBackend) Connect(ctx context.Context, isCreate bool, logger logrus.Fi if !filepath.IsAbs(c.options.Path) { return nil, errors.Errorf("filesystem repository path is not absolute, path: %s", c.options.Path) } + + if !isCreate { + if _, err := os.Stat(c.options.Path); err != nil { + return nil, ErrStoreNotExist + } + } + ctx = logging.WithLogger(ctx, logger) return filesystem.New(ctx, &c.options, isCreate) diff --git a/pkg/repository/udmrepo/kopialib/lib_repo.go b/pkg/repository/udmrepo/kopialib/lib_repo.go index 58c4a9ea9..23fe4e7e6 100644 --- a/pkg/repository/udmrepo/kopialib/lib_repo.go +++ b/pkg/repository/udmrepo/kopialib/lib_repo.go @@ -98,11 +98,26 @@ func NewKopiaRepoService(logger logrus.FieldLogger) udmrepo.BackupRepoService { func (ks *kopiaRepoService) Create(ctx context.Context, repoOption udmrepo.RepoOptions) error { repoCtx := kopia.SetupKopiaLog(ctx, ks.logger) - if err := CreateBackupRepo(repoCtx, repoOption, ks.logger); err != nil { - return err + status, err := GetRepositoryStatus(ctx, repoOption, ks.logger) + if err != nil { + return errors.Wrap(err, "error getting repo status") } - return writeInitParameters(repoCtx, repoOption, ks.logger) + if status != RepoStatusSystemNotCreated && status != RepoStatusNotInitialized { + return errors.Errorf("unexpected repo status %v", status) + } + + if status == RepoStatusSystemNotCreated { + if err := CreateBackupRepo(repoCtx, repoOption, ks.logger); err != nil { + return errors.Wrap(err, "error creating backup repo") + } + } + + if err := InitializeBackupRepo(ctx, repoOption, ks.logger); err != nil { + return errors.Wrap(err, "error initializing backup repo") + } + + return nil } func (ks *kopiaRepoService) Connect(ctx context.Context, repoOption udmrepo.RepoOptions) error { @@ -114,7 +129,17 @@ func (ks *kopiaRepoService) Connect(ctx context.Context, repoOption udmrepo.Repo func (ks *kopiaRepoService) IsCreated(ctx context.Context, repoOption udmrepo.RepoOptions) (bool, error) { repoCtx := kopia.SetupKopiaLog(ctx, ks.logger) - return IsBackupRepoCreated(repoCtx, repoOption, ks.logger) + status, err := GetRepositoryStatus(repoCtx, repoOption, ks.logger) + if err != nil { + return false, err + } + + if status != RepoStatusCreated { + ks.logger.Infof("Repo is not fully created, status %v", status) + return false, nil + } + + return true, nil } func (ks *kopiaRepoService) Open(ctx context.Context, repoOption udmrepo.RepoOptions) (udmrepo.BackupRepo, error) { @@ -612,73 +637,3 @@ func openKopiaRepo(ctx context.Context, configFile string, password string, _ *o return r, nil } - -func writeInitParameters(ctx context.Context, repoOption udmrepo.RepoOptions, logger logrus.FieldLogger) error { - r, err := openKopiaRepo(ctx, repoOption.ConfigFilePath, repoOption.RepoPassword, nil) - if err != nil { - return err - } - - defer func() { - c := r.Close(ctx) - if c != nil { - logger.WithError(c).Error("Failed to close repo") - } - }() - - err = repo.WriteSession(ctx, r, repo.WriteSessionOptions{ - Purpose: "set init parameters", - }, func(ctx context.Context, w repo.RepositoryWriter) error { - p := maintenance.DefaultParams() - - if overwriteFullMaintainInterval != time.Duration(0) { - logger.Infof("Full maintenance interval change from %v to %v", p.FullCycle.Interval, overwriteFullMaintainInterval) - p.FullCycle.Interval = overwriteFullMaintainInterval - } - - if overwriteQuickMaintainInterval != time.Duration(0) { - logger.Infof("Quick maintenance interval change from %v to %v", p.QuickCycle.Interval, overwriteQuickMaintainInterval) - p.QuickCycle.Interval = overwriteQuickMaintainInterval - } - // the repoOption.StorageOptions are set via - // udmrepo.WithStoreOptions -> udmrepo.GetStoreOptions (interface) - // -> pkg/repository/provider.GetStoreOptions(param interface{}) -> pkg/repository/provider.getStorageVariables(..., backupRepoConfig) - // where backupRepoConfig comes from param.(RepoParam).BackupRepo.Spec.RepositoryConfig map[string]string - // where RepositoryConfig comes from pkg/controller/getBackupRepositoryConfig(...) - // where it gets a configMap name from pkg/cmd/server/config/Config.BackupRepoConfig - // which gets set via velero server flag `backup-repository-configmap` "The name of ConfigMap containing backup repository configurations." - // and data stored as json under ConfigMap.Data[repoType] where repoType is BackupRepository.Spec.RepositoryType: either kopia or restic - // repoOption.StorageOptions[udmrepo.StoreOptionKeyFullMaintenanceInterval] would for example look like - // configMapName.data.kopia: {"fullMaintenanceInterval": "eagerGC"} - fullMaintIntervalOption := udmrepo.FullMaintenanceIntervalOptions(repoOption.StorageOptions[udmrepo.StoreOptionKeyFullMaintenanceInterval]) - priorMaintInterval := p.FullCycle.Interval - switch fullMaintIntervalOption { - case udmrepo.FastGC: - p.FullCycle.Interval = udmrepo.FastGCInterval - case udmrepo.EagerGC: - p.FullCycle.Interval = udmrepo.EagerGCInterval - case udmrepo.NormalGC: - p.FullCycle.Interval = udmrepo.NormalGCInterval - case "": // do nothing - default: - return errors.Errorf("invalid full maintenance interval option %s", fullMaintIntervalOption) - } - if priorMaintInterval != p.FullCycle.Interval { - logger.Infof("Full maintenance interval change from %v to %v", priorMaintInterval, p.FullCycle.Interval) - } - - p.Owner = r.ClientOptions().UsernameAtHost() - - if err := maintenance.SetParams(ctx, w, &p); err != nil { - return errors.Wrap(err, "error to set maintenance params") - } - - return nil - }) - - if err != nil { - return errors.Wrap(err, "error to init write repo parameters") - } - - return nil -} diff --git a/pkg/repository/udmrepo/kopialib/lib_repo_test.go b/pkg/repository/udmrepo/kopialib/lib_repo_test.go index a363ef807..18bc0601c 100644 --- a/pkg/repository/udmrepo/kopialib/lib_repo_test.go +++ b/pkg/repository/udmrepo/kopialib/lib_repo_test.go @@ -24,7 +24,6 @@ import ( "time" "github.com/kopia/kopia/repo" - "github.com/kopia/kopia/repo/maintenance" "github.com/kopia/kopia/repo/manifest" "github.com/kopia/kopia/repo/object" "github.com/pkg/errors" @@ -264,177 +263,6 @@ func TestMaintain(t *testing.T) { } } -func TestWriteInitParameters(t *testing.T) { - var directRpo *repomocks.DirectRepository - assertFullMaintIntervalEqual := func(expected, actual *maintenance.Params) bool { - return assert.Equal(t, expected.FullCycle.Interval, actual.FullCycle.Interval) - } - testCases := []struct { - name string - repoOptions udmrepo.RepoOptions - returnRepo *repomocks.DirectRepository - returnRepoWriter *repomocks.DirectRepositoryWriter - repoOpen func(context.Context, string, string, *repo.Options) (repo.Repository, error) - newRepoWriterError error - replaceManifestError error - // expected replacemanifest params to be received by maintenance.SetParams, and therefore writeInitParameters - expectedReplaceManifestsParams *maintenance.Params - // allows for asserting only certain fields are set as expected - assertReplaceManifestsParams func(*maintenance.Params, *maintenance.Params) bool - expectedErr string - }{ - { - name: "repo open fail, repo not exist", - repoOptions: udmrepo.RepoOptions{ - ConfigFilePath: "/tmp", - GeneralOptions: map[string]string{}, - }, - repoOpen: func(context.Context, string, string, *repo.Options) (repo.Repository, error) { - return nil, os.ErrNotExist - }, - expectedErr: "error to open repo, repo doesn't exist: file does not exist", - }, - { - name: "repo open fail, other error", - repoOptions: udmrepo.RepoOptions{ - ConfigFilePath: "/tmp", - GeneralOptions: map[string]string{}, - }, - repoOpen: func(context.Context, string, string, *repo.Options) (repo.Repository, error) { - return nil, errors.New("fake-repo-open-error") - }, - expectedErr: "error to open repo: fake-repo-open-error", - }, - { - name: "write session fail", - repoOptions: udmrepo.RepoOptions{ - ConfigFilePath: "/tmp", - GeneralOptions: map[string]string{}, - }, - repoOpen: func(context.Context, string, string, *repo.Options) (repo.Repository, error) { - return directRpo, nil - }, - returnRepo: new(repomocks.DirectRepository), - newRepoWriterError: errors.New("fake-new-writer-error"), - expectedErr: "error to init write repo parameters: unable to create writer: fake-new-writer-error", - }, - { - name: "set repo param fail", - repoOptions: udmrepo.RepoOptions{ - ConfigFilePath: "/tmp", - GeneralOptions: map[string]string{}, - }, - repoOpen: func(context.Context, string, string, *repo.Options) (repo.Repository, error) { - return directRpo, nil - }, - returnRepo: new(repomocks.DirectRepository), - returnRepoWriter: new(repomocks.DirectRepositoryWriter), - replaceManifestError: errors.New("fake-replace-manifest-error"), - expectedErr: "error to init write repo parameters: error to set maintenance params: put manifest: fake-replace-manifest-error", - }, - { - name: "repo with maintenance interval has expected params", - repoOptions: udmrepo.RepoOptions{ - ConfigFilePath: "/tmp", - StorageOptions: map[string]string{ - udmrepo.StoreOptionKeyFullMaintenanceInterval: string(udmrepo.FastGC), - }, - }, - repoOpen: func(context.Context, string, string, *repo.Options) (repo.Repository, error) { - return directRpo, nil - }, - returnRepo: new(repomocks.DirectRepository), - returnRepoWriter: new(repomocks.DirectRepositoryWriter), - expectedReplaceManifestsParams: &maintenance.Params{ - FullCycle: maintenance.CycleParams{ - Interval: udmrepo.FastGCInterval, - }, - }, - assertReplaceManifestsParams: assertFullMaintIntervalEqual, - }, - { - name: "repo with empty maintenance interval has expected params", - repoOptions: udmrepo.RepoOptions{ - ConfigFilePath: "/tmp", - StorageOptions: map[string]string{ - udmrepo.StoreOptionKeyFullMaintenanceInterval: string(""), - }, - }, - repoOpen: func(context.Context, string, string, *repo.Options) (repo.Repository, error) { - return directRpo, nil - }, - returnRepo: new(repomocks.DirectRepository), - returnRepoWriter: new(repomocks.DirectRepositoryWriter), - expectedReplaceManifestsParams: &maintenance.Params{ - FullCycle: maintenance.CycleParams{ - Interval: udmrepo.NormalGCInterval, - }, - }, - assertReplaceManifestsParams: assertFullMaintIntervalEqual, - }, - { - name: "repo with invalid maintenance interval has expected errors", - repoOptions: udmrepo.RepoOptions{ - ConfigFilePath: "/tmp", - StorageOptions: map[string]string{ - udmrepo.StoreOptionKeyFullMaintenanceInterval: string("foo"), - }, - }, - repoOpen: func(context.Context, string, string, *repo.Options) (repo.Repository, error) { - return directRpo, nil - }, - returnRepo: new(repomocks.DirectRepository), - returnRepoWriter: new(repomocks.DirectRepositoryWriter), - expectedErr: "error to init write repo parameters: invalid full maintenance interval option foo", - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - logger := velerotest.NewLogger() - ctx := t.Context() - - if tc.repoOpen != nil { - kopiaRepoOpen = tc.repoOpen - } - - if tc.returnRepo != nil { - directRpo = tc.returnRepo - } - - if tc.returnRepo != nil { - tc.returnRepo.On("NewWriter", mock.Anything, mock.Anything).Return(ctx, tc.returnRepoWriter, tc.newRepoWriterError) - tc.returnRepo.On("ClientOptions").Return(repo.ClientOptions{}) - tc.returnRepo.On("Close", mock.Anything).Return(nil) - } - - if tc.returnRepoWriter != nil { - tc.returnRepoWriter.On("Close", mock.Anything).Return(nil) - if tc.replaceManifestError != nil { - tc.returnRepoWriter.On("ReplaceManifests", mock.Anything, mock.Anything, mock.Anything).Return(manifest.ID(""), tc.replaceManifestError) - } - if tc.expectedReplaceManifestsParams != nil { - tc.returnRepoWriter.On("ReplaceManifests", mock.Anything, mock.AnythingOfType("map[string]string"), mock.AnythingOfType("*maintenance.Params")).Return(manifest.ID(""), nil) - tc.returnRepoWriter.On("Flush", mock.Anything).Return(nil) - } - } - - err := writeInitParameters(ctx, tc.repoOptions, logger) - - if tc.expectedErr == "" { - require.NoError(t, err) - } else { - require.EqualError(t, err, tc.expectedErr) - } - if tc.expectedReplaceManifestsParams != nil { - actualReplaceManifestsParams, converted := tc.returnRepoWriter.Calls[0].Arguments.Get(2).(*maintenance.Params) - assert.True(t, converted) - tc.assertReplaceManifestsParams(tc.expectedReplaceManifestsParams, actualReplaceManifestsParams) - } - }) - } -} - func TestShouldLog(t *testing.T) { testCases := []struct { name string diff --git a/pkg/repository/udmrepo/kopialib/repo_init.go b/pkg/repository/udmrepo/kopialib/repo_init.go index 872d2df5c..dc5c3b686 100644 --- a/pkg/repository/udmrepo/kopialib/repo_init.go +++ b/pkg/repository/udmrepo/kopialib/repo_init.go @@ -18,13 +18,18 @@ package kopialib import ( "context" + "encoding/json" + "io" + "slices" "strings" + "time" "github.com/sirupsen/logrus" "github.com/kopia/kopia/repo" "github.com/kopia/kopia/repo/blob" "github.com/kopia/kopia/repo/format" + "github.com/kopia/kopia/repo/maintenance" "github.com/pkg/errors" "github.com/vmware-tanzu/velero/pkg/repository/udmrepo" @@ -45,6 +50,22 @@ var backendStores = []kopiaBackendStore{ {udmrepo.StorageTypeS3, "an S3 bucket", &backend.S3Backend{}}, } +const udmRepoBlobID = "udmrepo.Repository" + +type udmRepoMetadata struct { + UniqueID []byte `json:"uniqueID"` +} + +type RepoStatus int + +const ( + RepoStatusUnknown = 0 + RepoStatusCorrupted = 1 + RepoStatusSystemNotCreated = 2 + RepoStatusNotInitialized = 3 + RepoStatusCreated = 4 +) + // CreateBackupRepo creates a Kopia repository and then connect to it. // The storage must be empty, otherwise, it will fail func CreateBackupRepo(ctx context.Context, repoOption udmrepo.RepoOptions, logger logrus.FieldLogger) error { @@ -73,14 +94,9 @@ func ConnectBackupRepo(ctx context.Context, repoOption udmrepo.RepoOptions, logg return errors.New("invalid config file path") } - backendStore, err := setupBackendStore(ctx, repoOption.StorageType, repoOption.StorageOptions, logger) + st, err := connectStore(ctx, repoOption, logger) if err != nil { - return errors.Wrap(err, "error to setup backend storage") - } - - st, err := backendStore.store.Connect(ctx, false, logger) - if err != nil { - return errors.Wrap(err, "error to connect to storage") + return err } err = connectWithStorage(ctx, st, repoOption) @@ -91,32 +107,119 @@ func ConnectBackupRepo(ctx context.Context, repoOption udmrepo.RepoOptions, logg return nil } -func IsBackupRepoCreated(ctx context.Context, repoOption udmrepo.RepoOptions, logger logrus.FieldLogger) (bool, error) { - backendStore, err := setupBackendStore(ctx, repoOption.StorageType, repoOption.StorageOptions, logger) - if err != nil { - return false, errors.Wrap(err, "error to setup backend storage") - } - - st, err := backendStore.store.Connect(ctx, false, logger) - if err != nil { - return false, errors.Wrap(err, "error to connect to storage") +func GetRepositoryStatus(ctx context.Context, repoOption udmrepo.RepoOptions, logger logrus.FieldLogger) (RepoStatus, error) { + st, err := connectStore(ctx, repoOption, logger) + if errors.Is(err, backend.ErrStoreNotExist) { + return RepoStatusSystemNotCreated, nil + } else if err != nil { + return RepoStatusUnknown, err } var formatBytes byteBuffer if err := st.GetBlob(ctx, format.KopiaRepositoryBlobID, 0, -1, &formatBytes); err != nil { if errors.Is(err, blob.ErrBlobNotFound) { - return false, nil + logger.Debug("Kopia repository blob is not found") + return RepoStatusSystemNotCreated, nil } - return false, errors.Wrap(err, "error to read format blob") + return RepoStatusUnknown, errors.Wrap(err, "error reading format blob") } - _, err = format.ParseKopiaRepositoryJSON(formatBytes.buffer) + repoFmt, err := format.ParseKopiaRepositoryJSON(formatBytes.buffer) if err != nil { - return false, err + return RepoStatusCorrupted, err } - return true, nil + var initInfoBytes byteBuffer + if err := st.GetBlob(ctx, udmRepoBlobID, 0, -1, &initInfoBytes); err != nil { + if errors.Is(err, blob.ErrBlobNotFound) { + logger.Debug("Udm repo metadata blob is not found") + return RepoStatusNotInitialized, nil + } + + return RepoStatusUnknown, errors.Wrap(err, "error reading udm repo blob") + } + + udmpRepo := &udmRepoMetadata{} + if err := json.Unmarshal(initInfoBytes.buffer, udmpRepo); err != nil { + return RepoStatusCorrupted, errors.Wrap(err, "invalid udm repo blob") + } + + if !slices.Equal(udmpRepo.UniqueID, repoFmt.UniqueID) { + return RepoStatusCorrupted, errors.Errorf("unique ID doesn't match: %v(%v)", udmpRepo.UniqueID, repoFmt.UniqueID) + } + + return RepoStatusCreated, nil +} + +func InitializeBackupRepo(ctx context.Context, repoOption udmrepo.RepoOptions, logger logrus.FieldLogger) error { + if repoOption.ConfigFilePath == "" { + return errors.New("invalid config file path") + } + + st, err := connectStore(ctx, repoOption, logger) + if err != nil { + return err + } + + err = connectWithStorage(ctx, st, repoOption) + if err != nil { + return errors.Wrap(err, "error connecting repo with storage") + } + + err = writeInitParameters(ctx, repoOption, logger) + if err != nil { + return errors.Wrap(err, "error writing init parameters") + } + + err = writeUdmRepoMetadata(ctx, st) + if err != nil { + return errors.Wrap(err, "error writing udm repo metadata") + } + + return nil +} + +func writeUdmRepoMetadata(ctx context.Context, st blob.Storage) error { + var formatBytes byteBuffer + if err := st.GetBlob(ctx, format.KopiaRepositoryBlobID, 0, -1, &formatBytes); err != nil { + return errors.Wrap(err, "error reading format blob") + } + + repoFmt, err := format.ParseKopiaRepositoryJSON(formatBytes.buffer) + if err != nil { + return err + } + + udmpRepo := &udmRepoMetadata{ + UniqueID: repoFmt.UniqueID, + } + + bytes, err := json.Marshal(udmpRepo) + if err != nil { + return errors.Wrap(err, "error marshaling udm repo metadata") + } + + err = st.PutBlob(ctx, udmRepoBlobID, &byteBuffer{bytes}, blob.PutOptions{}) + if err != nil { + return errors.Wrap(err, "error writing udm repo metadata") + } + + return nil +} + +func connectStore(ctx context.Context, repoOption udmrepo.RepoOptions, logger logrus.FieldLogger) (blob.Storage, error) { + backendStore, err := setupBackendStore(ctx, repoOption.StorageType, repoOption.StorageOptions, logger) + if err != nil { + return nil, errors.Wrap(err, "error to setup backend storage") + } + + st, err := backendStore.store.Connect(ctx, false, logger) + if err != nil { + return nil, errors.Wrap(err, "error to connect to storage") + } + + return st, nil } func findBackendStore(storage string) *kopiaBackendStore { @@ -185,11 +288,21 @@ type byteBuffer struct { buffer []byte } -func (b *byteBuffer) Write(p []byte) (n int, err error) { +type byteBufferReader struct { + buffer []byte + pos int +} + +func (b *byteBuffer) Write(p []byte) (int, error) { b.buffer = append(b.buffer, p...) return len(p), nil } +func (b *byteBuffer) WriteTo(w io.Writer) (int64, error) { + n, err := w.Write(b.buffer) + return int64(n), err +} + func (b *byteBuffer) Reset() { b.buffer = nil } @@ -197,3 +310,129 @@ func (b *byteBuffer) Reset() { func (b *byteBuffer) Length() int { return len(b.buffer) } + +func (b *byteBuffer) Reader() io.ReadSeekCloser { + return &byteBufferReader{buffer: b.buffer} +} + +func (b *byteBufferReader) Close() error { + return nil +} + +func (b *byteBufferReader) Read(out []byte) (int, error) { + if b.pos == len(b.buffer) { + return 0, io.EOF + } + + copied := copy(out, b.buffer[b.pos:]) + b.pos += copied + + return copied, nil +} + +func (b *byteBufferReader) Seek(offset int64, whence int) (int64, error) { + newOffset := b.pos + + switch whence { + case io.SeekStart: + newOffset = int(offset) + case io.SeekCurrent: + newOffset += int(offset) + case io.SeekEnd: + newOffset = len(b.buffer) + int(offset) + } + + if newOffset < 0 || newOffset > len(b.buffer) { + return -1, errors.New("invalid seek") + } + + b.pos = newOffset + + return int64(newOffset), nil +} + +var funcGetParam = maintenance.GetParams + +func writeInitParameters(ctx context.Context, repoOption udmrepo.RepoOptions, logger logrus.FieldLogger) error { + r, err := openKopiaRepo(ctx, repoOption.ConfigFilePath, repoOption.RepoPassword, nil) + if err != nil { + return err + } + + defer func() { + c := r.Close(ctx) + if c != nil { + logger.WithError(c).Error("Failed to close repo") + } + }() + + params, err := funcGetParam(ctx, r) + if err != nil { + return errors.Wrap(err, "error getting existing maintenance params") + } + + if params.Owner == backend.RepoOwnerFromRepoOptions(repoOption) { + logger.Warn("Init parameters already exists, skip") + return nil + } + + if params.Owner != "" { + logger.Warnf("Overwriting existing init params %v", params) + } + + err = repo.WriteSession(ctx, r, repo.WriteSessionOptions{ + Purpose: "set init parameters", + }, func(ctx context.Context, w repo.RepositoryWriter) error { + p := maintenance.DefaultParams() + + if overwriteFullMaintainInterval != time.Duration(0) { + logger.Infof("Full maintenance interval change from %v to %v", p.FullCycle.Interval, overwriteFullMaintainInterval) + p.FullCycle.Interval = overwriteFullMaintainInterval + } + + if overwriteQuickMaintainInterval != time.Duration(0) { + logger.Infof("Quick maintenance interval change from %v to %v", p.QuickCycle.Interval, overwriteQuickMaintainInterval) + p.QuickCycle.Interval = overwriteQuickMaintainInterval + } + // the repoOption.StorageOptions are set via + // udmrepo.WithStoreOptions -> udmrepo.GetStoreOptions (interface) + // -> pkg/repository/provider.GetStoreOptions(param interface{}) -> pkg/repository/provider.getStorageVariables(..., backupRepoConfig) + // where backupRepoConfig comes from param.(RepoParam).BackupRepo.Spec.RepositoryConfig map[string]string + // where RepositoryConfig comes from pkg/controller/getBackupRepositoryConfig(...) + // where it gets a configMap name from pkg/cmd/server/config/Config.BackupRepoConfig + // which gets set via velero server flag `backup-repository-configmap` "The name of ConfigMap containing backup repository configurations." + // and data stored as json under ConfigMap.Data[repoType] where repoType is BackupRepository.Spec.RepositoryType: either kopia or restic + // repoOption.StorageOptions[udmrepo.StoreOptionKeyFullMaintenanceInterval] would for example look like + // configMapName.data.kopia: {"fullMaintenanceInterval": "eagerGC"} + fullMaintIntervalOption := udmrepo.FullMaintenanceIntervalOptions(repoOption.StorageOptions[udmrepo.StoreOptionKeyFullMaintenanceInterval]) + priorMaintInterval := p.FullCycle.Interval + switch fullMaintIntervalOption { + case udmrepo.FastGC: + p.FullCycle.Interval = udmrepo.FastGCInterval + case udmrepo.EagerGC: + p.FullCycle.Interval = udmrepo.EagerGCInterval + case udmrepo.NormalGC: + p.FullCycle.Interval = udmrepo.NormalGCInterval + case "": // do nothing + default: + return errors.Errorf("invalid full maintenance interval option %s", fullMaintIntervalOption) + } + if priorMaintInterval != p.FullCycle.Interval { + logger.Infof("Full maintenance interval change from %v to %v", priorMaintInterval, p.FullCycle.Interval) + } + + p.Owner = r.ClientOptions().UsernameAtHost() + + if err := maintenance.SetParams(ctx, w, &p); err != nil { + return errors.Wrap(err, "error to set maintenance params") + } + + return nil + }) + + if err != nil { + return errors.Wrap(err, "error to init write repo parameters") + } + + return nil +} diff --git a/pkg/repository/udmrepo/kopialib/repo_init_test.go b/pkg/repository/udmrepo/kopialib/repo_init_test.go index d4333f634..c2feefc60 100644 --- a/pkg/repository/udmrepo/kopialib/repo_init_test.go +++ b/pkg/repository/udmrepo/kopialib/repo_init_test.go @@ -18,9 +18,14 @@ package kopialib import ( "context" + "io" + "os" "testing" + "github.com/kopia/kopia/repo" "github.com/kopia/kopia/repo/blob" + "github.com/kopia/kopia/repo/maintenance" + "github.com/kopia/kopia/repo/manifest" velerotest "github.com/vmware-tanzu/velero/pkg/test" @@ -29,6 +34,8 @@ import ( "github.com/stretchr/testify/require" "github.com/vmware-tanzu/velero/pkg/repository/udmrepo" + "github.com/vmware-tanzu/velero/pkg/repository/udmrepo/kopialib/backend" + repomocks "github.com/vmware-tanzu/velero/pkg/repository/udmrepo/kopialib/backend/mocks" storagemocks "github.com/vmware-tanzu/velero/pkg/repository/udmrepo/kopialib/backend/mocks" "github.com/pkg/errors" @@ -239,7 +246,7 @@ func TestConnectBackupRepo(t *testing.T) { } } -func TestIsBackupRepoCreated(t *testing.T) { +func TestGetRepositoryStatus(t *testing.T) { testCases := []struct { name string backendStore *storagemocks.Store @@ -248,7 +255,7 @@ func TestIsBackupRepoCreated(t *testing.T) { setupError error returnStore *storagemocks.Storage retFuncGetBlob func(context.Context, blob.ID, int64, int64, blob.OutputBuffer) error - expected bool + expected RepoStatus expectedErr string }{ { @@ -256,6 +263,7 @@ func TestIsBackupRepoCreated(t *testing.T) { repoOptions: udmrepo.RepoOptions{ ConfigFilePath: "fake-file", }, + expected: RepoStatusUnknown, expectedErr: "error to setup backend storage: error to find storage type", }, { @@ -266,6 +274,7 @@ func TestIsBackupRepoCreated(t *testing.T) { }, backendStore: new(storagemocks.Store), setupError: errors.New("fake-setup-error"), + expected: RepoStatusUnknown, expectedErr: "error to setup backend storage: error to setup storage: fake-setup-error", }, { @@ -276,10 +285,21 @@ func TestIsBackupRepoCreated(t *testing.T) { }, backendStore: new(storagemocks.Store), connectErr: errors.New("fake-connect-error"), + expected: RepoStatusUnknown, expectedErr: "error to connect to storage: fake-connect-error", }, { - name: "get blob error", + name: "storage not exist", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "fake-file", + StorageType: udmrepo.StorageTypeAzure, + }, + backendStore: new(storagemocks.Store), + connectErr: backend.ErrStoreNotExist, + expected: RepoStatusSystemNotCreated, + }, + { + name: "get repo blob error", repoOptions: udmrepo.RepoOptions{ ConfigFilePath: "fake-file", StorageType: udmrepo.StorageTypeAzure, @@ -289,10 +309,24 @@ func TestIsBackupRepoCreated(t *testing.T) { retFuncGetBlob: func(context.Context, blob.ID, int64, int64, blob.OutputBuffer) error { return errors.New("fake-get-blob-error") }, - expectedErr: "error to read format blob: fake-get-blob-error", + expected: RepoStatusUnknown, + expectedErr: "error reading format blob: fake-get-blob-error", }, { - name: "wrong format", + name: "no repo blob", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "fake-file", + StorageType: udmrepo.StorageTypeAzure, + }, + backendStore: new(storagemocks.Store), + returnStore: new(storagemocks.Storage), + retFuncGetBlob: func(context.Context, blob.ID, int64, int64, blob.OutputBuffer) error { + return blob.ErrBlobNotFound + }, + expected: RepoStatusSystemNotCreated, + }, + { + name: "wrong repo format", repoOptions: udmrepo.RepoOptions{ ConfigFilePath: "fake-file", StorageType: udmrepo.StorageTypeAzure, @@ -303,8 +337,105 @@ func TestIsBackupRepoCreated(t *testing.T) { output.Write([]byte("fake-buffer")) return nil }, + expected: RepoStatusCorrupted, expectedErr: "invalid format blob: invalid character 'k' in literal false (expecting 'l')", }, + { + name: "get udm repo blob error", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "fake-file", + StorageType: udmrepo.StorageTypeAzure, + }, + backendStore: new(storagemocks.Store), + returnStore: new(storagemocks.Storage), + retFuncGetBlob: func(ctx context.Context, blobID blob.ID, offset int64, length int64, output blob.OutputBuffer) error { + if blobID == udmRepoBlobID { + return errors.New("fake-get-blob-error") + } else { + output.Write([]byte(`{"tool":"","buildVersion":"","buildInfo":"","uniqueID":[],"keyAlgo":"","encryption":""}`)) + return nil + } + }, + expected: RepoStatusUnknown, + expectedErr: "error reading udm repo blob: fake-get-blob-error", + }, + { + name: "no udm repo blob", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "fake-file", + StorageType: udmrepo.StorageTypeAzure, + }, + backendStore: new(storagemocks.Store), + returnStore: new(storagemocks.Storage), + retFuncGetBlob: func(ctx context.Context, blobID blob.ID, offset int64, length int64, output blob.OutputBuffer) error { + if blobID == udmRepoBlobID { + return blob.ErrBlobNotFound + } else { + output.Write([]byte(`{"tool":"","buildVersion":"","buildInfo":"","uniqueID":[],"keyAlgo":"","encryption":""}`)) + return nil + } + }, + expected: RepoStatusNotInitialized, + }, + { + name: "wrong udm repo metadata", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "fake-file", + StorageType: udmrepo.StorageTypeAzure, + }, + backendStore: new(storagemocks.Store), + returnStore: new(storagemocks.Storage), + retFuncGetBlob: func(ctx context.Context, blobID blob.ID, offset int64, length int64, output blob.OutputBuffer) error { + if blobID == udmRepoBlobID { + output.Write([]byte("fake-buffer")) + } else { + output.Write([]byte(`{"tool":"","buildVersion":"","buildInfo":"","uniqueID":[],"keyAlgo":"","encryption":""}`)) + } + + return nil + }, + expected: RepoStatusCorrupted, + expectedErr: "invalid udm repo blob: invalid character 'k' in literal false (expecting 'l')", + }, + { + name: "wrong unique id", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "fake-file", + StorageType: udmrepo.StorageTypeAzure, + }, + backendStore: new(storagemocks.Store), + returnStore: new(storagemocks.Storage), + retFuncGetBlob: func(ctx context.Context, blobID blob.ID, offset int64, length int64, output blob.OutputBuffer) error { + if blobID == udmRepoBlobID { + output.Write([]byte(`{"uniqueID":[4,5,6]}`)) + } else { + output.Write([]byte(`{"tool":"","buildVersion":"","buildInfo":"","uniqueID":[1,2,3],"keyAlgo":"","encryption":""}`)) + } + + return nil + }, + expected: RepoStatusCorrupted, + expectedErr: "unique ID doesn't match: [4 5 6]([1 2 3])", + }, + { + name: "succeed", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "fake-file", + StorageType: udmrepo.StorageTypeAzure, + }, + backendStore: new(storagemocks.Store), + returnStore: new(storagemocks.Storage), + retFuncGetBlob: func(ctx context.Context, blobID blob.ID, offset int64, length int64, output blob.OutputBuffer) error { + if blobID == udmRepoBlobID { + output.Write([]byte(`{"uniqueID":[1,2,3]}`)) + } else { + output.Write([]byte(`{"tool":"","buildVersion":"","buildInfo":"","uniqueID":[1,2,3],"keyAlgo":"","encryption":""}`)) + } + + return nil + }, + expected: RepoStatusCreated, + }, } logger := velerotest.NewLogger() @@ -326,7 +457,7 @@ func TestIsBackupRepoCreated(t *testing.T) { tc.returnStore.On("GetBlob", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.retFuncGetBlob) } - created, err := IsBackupRepoCreated(t.Context(), tc.repoOptions, logger) + status, err := GetRepositoryStatus(t.Context(), tc.repoOptions, logger) if tc.expectedErr == "" { require.NoError(t, err) @@ -334,7 +465,390 @@ func TestIsBackupRepoCreated(t *testing.T) { require.EqualError(t, err, tc.expectedErr) } - assert.Equal(t, tc.expected, created) + assert.Equal(t, tc.expected, status) }) } } + +func TestWriteInitParameters(t *testing.T) { + var directRpo *repomocks.DirectRepository + assertFullMaintIntervalEqual := func(expected, actual *maintenance.Params) bool { + return assert.Equal(t, expected.FullCycle.Interval, actual.FullCycle.Interval) + } + testCases := []struct { + name string + repoOptions udmrepo.RepoOptions + returnRepo *repomocks.DirectRepository + returnRepoWriter *repomocks.DirectRepositoryWriter + repoOpen func(context.Context, string, string, *repo.Options) (repo.Repository, error) + newRepoWriterError error + replaceManifestError error + getParam func(context.Context, repo.Repository) (*maintenance.Params, error) + // expected replacemanifest params to be received by maintenance.SetParams, and therefore writeInitParameters + expectedReplaceManifestsParams *maintenance.Params + // allows for asserting only certain fields are set as expected + assertReplaceManifestsParams func(*maintenance.Params, *maintenance.Params) bool + expectedErr string + }{ + { + name: "repo open fail, repo not exist", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "/tmp", + GeneralOptions: map[string]string{}, + }, + repoOpen: func(context.Context, string, string, *repo.Options) (repo.Repository, error) { + return nil, os.ErrNotExist + }, + expectedErr: "error to open repo, repo doesn't exist: file does not exist", + }, + { + name: "repo open fail, other error", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "/tmp", + GeneralOptions: map[string]string{}, + }, + repoOpen: func(context.Context, string, string, *repo.Options) (repo.Repository, error) { + return nil, errors.New("fake-repo-open-error") + }, + expectedErr: "error to open repo: fake-repo-open-error", + }, + { + name: "get params error", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "/tmp", + GeneralOptions: map[string]string{}, + }, + repoOpen: func(context.Context, string, string, *repo.Options) (repo.Repository, error) { + return directRpo, nil + }, + getParam: func(context.Context, repo.Repository) (*maintenance.Params, error) { + return nil, errors.New("fake-get-param-error") + }, + returnRepo: new(repomocks.DirectRepository), + expectedErr: "error getting existing maintenance params: fake-get-param-error", + }, + { + name: "existing param with identical owner", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "/tmp", + GeneralOptions: map[string]string{}, + }, + repoOpen: func(context.Context, string, string, *repo.Options) (repo.Repository, error) { + return directRpo, nil + }, + getParam: func(context.Context, repo.Repository) (*maintenance.Params, error) { + return &maintenance.Params{ + Owner: "default@default", + }, nil + }, + }, + { + name: "existing param with different owner", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "/tmp", + GeneralOptions: map[string]string{}, + }, + repoOpen: func(context.Context, string, string, *repo.Options) (repo.Repository, error) { + return directRpo, nil + }, + getParam: func(context.Context, repo.Repository) (*maintenance.Params, error) { + return &maintenance.Params{ + Owner: "fake-owner", + }, nil + }, + returnRepo: new(repomocks.DirectRepository), + returnRepoWriter: new(repomocks.DirectRepositoryWriter), + expectedReplaceManifestsParams: &maintenance.Params{ + FullCycle: maintenance.CycleParams{ + Interval: udmrepo.NormalGCInterval, + }, + }, + assertReplaceManifestsParams: assertFullMaintIntervalEqual, + }, + { + name: "write session fail", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "/tmp", + GeneralOptions: map[string]string{}, + }, + repoOpen: func(context.Context, string, string, *repo.Options) (repo.Repository, error) { + return directRpo, nil + }, + returnRepo: new(repomocks.DirectRepository), + newRepoWriterError: errors.New("fake-new-writer-error"), + expectedErr: "error to init write repo parameters: unable to create writer: fake-new-writer-error", + }, + { + name: "set repo param fail", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "/tmp", + GeneralOptions: map[string]string{}, + }, + repoOpen: func(context.Context, string, string, *repo.Options) (repo.Repository, error) { + return directRpo, nil + }, + returnRepo: new(repomocks.DirectRepository), + returnRepoWriter: new(repomocks.DirectRepositoryWriter), + replaceManifestError: errors.New("fake-replace-manifest-error"), + expectedErr: "error to init write repo parameters: error to set maintenance params: put manifest: fake-replace-manifest-error", + }, + { + name: "repo with maintenance interval has expected params", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "/tmp", + StorageOptions: map[string]string{ + udmrepo.StoreOptionKeyFullMaintenanceInterval: string(udmrepo.FastGC), + }, + }, + repoOpen: func(context.Context, string, string, *repo.Options) (repo.Repository, error) { + return directRpo, nil + }, + returnRepo: new(repomocks.DirectRepository), + returnRepoWriter: new(repomocks.DirectRepositoryWriter), + expectedReplaceManifestsParams: &maintenance.Params{ + FullCycle: maintenance.CycleParams{ + Interval: udmrepo.FastGCInterval, + }, + }, + assertReplaceManifestsParams: assertFullMaintIntervalEqual, + }, + { + name: "repo with empty maintenance interval has expected params", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "/tmp", + StorageOptions: map[string]string{ + udmrepo.StoreOptionKeyFullMaintenanceInterval: string(""), + }, + }, + repoOpen: func(context.Context, string, string, *repo.Options) (repo.Repository, error) { + return directRpo, nil + }, + returnRepo: new(repomocks.DirectRepository), + returnRepoWriter: new(repomocks.DirectRepositoryWriter), + expectedReplaceManifestsParams: &maintenance.Params{ + FullCycle: maintenance.CycleParams{ + Interval: udmrepo.NormalGCInterval, + }, + }, + assertReplaceManifestsParams: assertFullMaintIntervalEqual, + }, + { + name: "repo with invalid maintenance interval has expected errors", + repoOptions: udmrepo.RepoOptions{ + ConfigFilePath: "/tmp", + StorageOptions: map[string]string{ + udmrepo.StoreOptionKeyFullMaintenanceInterval: string("foo"), + }, + }, + repoOpen: func(context.Context, string, string, *repo.Options) (repo.Repository, error) { + return directRpo, nil + }, + returnRepo: new(repomocks.DirectRepository), + returnRepoWriter: new(repomocks.DirectRepositoryWriter), + expectedErr: "error to init write repo parameters: invalid full maintenance interval option foo", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + logger := velerotest.NewLogger() + ctx := t.Context() + + if tc.repoOpen != nil { + kopiaRepoOpen = tc.repoOpen + } + + if tc.returnRepo != nil { + directRpo = tc.returnRepo + } + + if tc.returnRepo != nil { + tc.returnRepo.On("NewWriter", mock.Anything, mock.Anything).Return(ctx, tc.returnRepoWriter, tc.newRepoWriterError) + tc.returnRepo.On("ClientOptions").Return(repo.ClientOptions{}) + tc.returnRepo.On("Close", mock.Anything).Return(nil) + } + + if tc.returnRepoWriter != nil { + tc.returnRepoWriter.On("Close", mock.Anything).Return(nil) + if tc.replaceManifestError != nil { + tc.returnRepoWriter.On("ReplaceManifests", mock.Anything, mock.Anything, mock.Anything).Return(manifest.ID(""), tc.replaceManifestError) + } + if tc.expectedReplaceManifestsParams != nil { + tc.returnRepoWriter.On("ReplaceManifests", mock.Anything, mock.AnythingOfType("map[string]string"), mock.AnythingOfType("*maintenance.Params")).Return(manifest.ID(""), nil) + tc.returnRepoWriter.On("Flush", mock.Anything).Return(nil) + } + } + + if tc.getParam != nil { + funcGetParam = tc.getParam + } else { + funcGetParam = func(ctx context.Context, rep repo.Repository) (*maintenance.Params, error) { + return &maintenance.Params{}, nil + } + } + + err := writeInitParameters(ctx, tc.repoOptions, logger) + + if tc.expectedErr == "" { + require.NoError(t, err) + } else { + require.EqualError(t, err, tc.expectedErr) + } + if tc.expectedReplaceManifestsParams != nil { + actualReplaceManifestsParams, converted := tc.returnRepoWriter.Calls[0].Arguments.Get(2).(*maintenance.Params) + assert.True(t, converted) + tc.assertReplaceManifestsParams(tc.expectedReplaceManifestsParams, actualReplaceManifestsParams) + } + }) + } +} + +func TestWriteUdmRepoMetadata(t *testing.T) { + testCases := []struct { + name string + retFuncGetBlob func(context.Context, blob.ID, int64, int64, blob.OutputBuffer) error + retFuncPutBlob func(context.Context, blob.ID, blob.Bytes, blob.PutOptions) error + replaceMetadata *udmRepoMetadata + expectedErr string + }{ + { + name: "get repo blob error", + retFuncGetBlob: func(context.Context, blob.ID, int64, int64, blob.OutputBuffer) error { + return errors.New("fake-get-blob-error") + }, + expectedErr: "error reading format blob: fake-get-blob-error", + }, + { + name: "wrong repo format", + retFuncGetBlob: func(ctx context.Context, id blob.ID, offset int64, length int64, output blob.OutputBuffer) error { + output.Write([]byte("fake-buffer")) + return nil + }, + expectedErr: "invalid format blob: invalid character 'k' in literal false (expecting 'l')", + }, + { + name: "put udm repo metadata blob error", + retFuncGetBlob: func(ctx context.Context, blobID blob.ID, offset int64, length int64, output blob.OutputBuffer) error { + output.Write([]byte(`{"tool":"","buildVersion":"","buildInfo":"","uniqueID":[],"keyAlgo":"","encryption":""}`)) + return nil + }, + retFuncPutBlob: func(context.Context, blob.ID, blob.Bytes, blob.PutOptions) error { + return errors.New("fake-put-blob-error") + }, + expectedErr: "error writing udm repo metadata: fake-put-blob-error", + }, + { + name: "succeed", + retFuncGetBlob: func(ctx context.Context, blobID blob.ID, offset int64, length int64, output blob.OutputBuffer) error { + output.Write([]byte(`{"tool":"","buildVersion":"","buildInfo":"","uniqueID":[],"keyAlgo":"","encryption":""}`)) + return nil + }, + retFuncPutBlob: func(context.Context, blob.ID, blob.Bytes, blob.PutOptions) error { + return nil + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + storage := new(storagemocks.Storage) + if tc.retFuncGetBlob != nil { + storage.On("GetBlob", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.retFuncGetBlob) + } + + if tc.retFuncPutBlob != nil { + storage.On("PutBlob", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.retFuncPutBlob) + } + + err := writeUdmRepoMetadata(t.Context(), storage) + + if tc.expectedErr == "" { + require.NoError(t, err) + } else { + require.EqualError(t, err, tc.expectedErr) + } + }) + } +} + +type testRecv struct { + buffer []byte +} + +func (r *testRecv) Write(p []byte) (n int, err error) { + r.buffer = append(r.buffer, p...) + return len(p), nil +} + +func TestByteBuffer(t *testing.T) { + buffer := &byteBuffer{} + written, err := buffer.Write([]byte("12345")) + require.NoError(t, err) + require.Equal(t, 5, written) + + written, err = buffer.Write([]byte("67890")) + require.NoError(t, err) + require.Equal(t, 5, written) + require.Equal(t, 10, buffer.Length()) + + recv := &testRecv{} + copied, err := buffer.WriteTo(recv) + require.NoError(t, err) + require.Equal(t, int64(10), copied) + require.Equal(t, []byte("1234567890"), recv.buffer) + + buffer.Reset() + require.Zero(t, buffer.Length()) +} + +func TestByteBufferReader(t *testing.T) { + buffer := &byteBufferReader{buffer: []byte("123456789012345678901234567890")} + off, err := buffer.Seek(100, io.SeekStart) + require.Equal(t, int64(-1), off) + require.EqualError(t, err, "invalid seek") + require.Zero(t, buffer.pos) + + off, err = buffer.Seek(-100, io.SeekEnd) + require.Equal(t, int64(-1), off) + require.EqualError(t, err, "invalid seek") + require.Zero(t, buffer.pos) + + off, err = buffer.Seek(3, io.SeekCurrent) + require.Equal(t, int64(3), off) + require.NoError(t, err) + require.Equal(t, 3, buffer.pos) + + output := make([]byte, 6) + read, err := buffer.Read(output) + require.NoError(t, err) + require.Equal(t, 6, read) + require.Equal(t, 9, buffer.pos) + require.Equal(t, []byte("456789"), output) + + off, err = buffer.Seek(21, io.SeekStart) + require.Equal(t, int64(21), off) + require.NoError(t, err) + require.Equal(t, 21, buffer.pos) + + output = make([]byte, 6) + read, err = buffer.Read(output) + require.NoError(t, err) + require.Equal(t, 6, read) + require.Equal(t, 27, buffer.pos) + require.Equal(t, []byte("234567"), output) + + output = make([]byte, 6) + read, err = buffer.Read(output) + require.NoError(t, err) + require.Equal(t, 3, read) + require.Equal(t, 30, buffer.pos) + require.Equal(t, []byte{'8', '9', '0', 0, 0, 0}, output) + + output = make([]byte, 6) + read, err = buffer.Read(output) + require.Zero(t, read) + require.Equal(t, io.EOF, err) + + err = buffer.Close() + require.NoError(t, err) +} From 2579ef10938273cbf5707d9021e14ec80cdab1bf Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Tue, 18 Nov 2025 18:25:41 +0800 Subject: [PATCH 091/104] doc for cache volume Signed-off-by: Lyndon-Li --- changelogs/unreleased/9418-Lyndon-Li | 1 + .../docs/main/csi-snapshot-data-movement.md | 7 ++- .../docs/main/data-movement-cache-volume.md | 46 +++++++++++++++++++ site/content/docs/main/file-system-backup.md | 9 ++-- site/data/docs/main-toc.yml | 8 ++-- 5 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 changelogs/unreleased/9418-Lyndon-Li create mode 100644 site/content/docs/main/data-movement-cache-volume.md diff --git a/changelogs/unreleased/9418-Lyndon-Li b/changelogs/unreleased/9418-Lyndon-Li new file mode 100644 index 000000000..7fa2c380e --- /dev/null +++ b/changelogs/unreleased/9418-Lyndon-Li @@ -0,0 +1 @@ +Fix issue #9276, add doc for cache volume support \ No newline at end of file diff --git a/site/content/docs/main/csi-snapshot-data-movement.md b/site/content/docs/main/csi-snapshot-data-movement.md index 3e96dcd6a..a83cbac49 100644 --- a/site/content/docs/main/csi-snapshot-data-movement.md +++ b/site/content/docs/main/csi-snapshot-data-movement.md @@ -376,7 +376,10 @@ For Velero built-in data mover, Velero uses [BestEffort as the QoS][13] for data If you want to constraint the CPU/memory usage, you need to [Customize Data Mover Pod Resource Limits][11]. The CPU/memory consumption is always related to the scale of data to be backed up/restored, refer to [Performance Guidance][12] for more details, so it is highly recommended that you perform your own testing to find the best resource limits for your data. During the restore, the repository may also cache data/metadata so as to reduce the network footprint and speed up the restore. The repository uses its own policy to store and clean up the cache. -For Kopia repository, the cache is stored in the data mover pod's root file system. Velero allows you to configure a limit of the cache size so that the data mover pod won't be evicted due to running out of the ephemeral storage. For more details, check [Backup Repository Configuration][17]. +For Kopia repository, by default, the cache is stored in the data mover pod's root file system. If your root file system space is limited, the data mover pods may be evicted due to running out of the ephemeral storage, which causes the restore fails. To cope with this problem, Velero allows you: +- configure a limit of the cache size per backup repository, for more details, check [Backup Repository Configuration][17]. +- configure a dedicated volume for cache data, for more details, check [Data Movement Cache Volume][21]. + ### Node Selection @@ -416,4 +419,6 @@ Sometimes, `RestorePVC` needs to be configured to increase the performance of re [18]: https://github.com/vmware-tanzu/velero/pull/7576 [19]: data-movement-restore-pvc-configuration.md [20]: node-agent-prepare-queue-length.md +[21]: data-movement-cache-volume.md + diff --git a/site/content/docs/main/data-movement-cache-volume.md b/site/content/docs/main/data-movement-cache-volume.md new file mode 100644 index 000000000..c23f9efb1 --- /dev/null +++ b/site/content/docs/main/data-movement-cache-volume.md @@ -0,0 +1,46 @@ +--- +title: "Cache PVC Configuration for Data Movement Restore" +layout: docs +--- + +Velero data movement restore (i.e., for CSI snapshot data movement and fs-backup) may request the backup repository to cache data locally so as to reduce the data request from the remote backup storage. +The cache behavior is decided by the specific backup repository, and Velero allows you to configure a cache limit for the backup repositories who support it (i.e., kopia repository). For more details, see [Backup Repository Configuration][1]. +The size of cache may significantly impact on the performance. Specifically, if the cache size is too small, the restore throughput will be severely reduced and much more data would be downloaded from the backup storage. +By default, the cache data location is in the data mover pods' root disk. In some environments, the pods's root disk size is very limited, some a large cache size would cause the data mover pods evicted because of running out of ephemeral disk. + +To cope with the problems and guarantee the data mover pods always run with a fine tuned local cache, Velero supports dedicated cache PVCs for data movement restore, for CSI snapshot data movement and fs-backup. + +By default, Velero data mover pods run without cache PVCs. To enable cache PVC, you need to fill the cache PVC configurations in the node-agent configMap. + +A sample of cache PVC configuration as part of the ConfigMap would look like: +```json +{ + "cachePVC": { + "thresholdInGB": 1, + "storageClass": "sc-wffc" + } +} +``` + +To create the configMap, save something like the above sample to a file and then run below commands: +```shell +kubectl create cm node-agent-config -n velero --from-file= +``` + +A must-have field in the configuration is `storageClass` which tells Velero which storage class is used to provision the cache PVC. Velero relies on Kubernetes dynamic provision process to provision the PVC, static provision is not supported. + +The cache PVC behavior could be further fine tuned through `thresholdInGB`. Its value is compared to the size of the backup, if the size is smaller than this value, no cache PVC would be created when restoring from the backup. This ensures that cache PVCs are not created in vain when the backup size is too small and can be accommodated in the data mover pods' root disk. + +This configuration decides whether and how to provision cache PVCs, but it doesn't decide their size. Instead, the size is decided by the specific backup repository. Specifically, Velero asks a cache limit from the backup repository and uses this limit to calculate the cache PVC size. +The cache limit is decided by the backup repository itself, for Kopia repository, if `cacheLimitMB` is specified in the backup repository configuration, its value will be used; otherwise, a default limit (5 GB) is used. +Then Velero inflates the limit with 20% by considering the non-payload overheads and delay cache cleanup behavior varying on backup repositories. + +Take Kopia repository and the above cache PVC configuration for example: +- When `cacheLimitMB` is not available for the repository, a 6GB cache PVC is created for the backup that is larger than 1GB; otherwise, no cache volume is created +- When `cacheLimitMB` is specified as `10240` for the repository, a 12GB cache PVC is created for the backup that is larger than 1GB; otherwise, no cache volume is created + +To enable both the node-agent configMap and backup repository configMap, specify the flags in velero installation by CLI: +`velero install --node-agent-configmap= --backup-repository-configmap=` + + +[1]: backup-repository-configuration.md \ No newline at end of file diff --git a/site/content/docs/main/file-system-backup.md b/site/content/docs/main/file-system-backup.md index b4d904f1b..f74571b4c 100644 --- a/site/content/docs/main/file-system-backup.md +++ b/site/content/docs/main/file-system-backup.md @@ -693,7 +693,7 @@ spec: ## Priority Class Configuration -For Velero built-in data mover, data mover pods launched during file system backup will use the priority class name configured in the node-agent configmap. The node-agent daemonset itself gets its priority class from the `--node-agent-priority-class-name` flag during Velero installation. This can help ensure proper scheduling behavior in resource-constrained environments. For more details on configuring data mover pod resources, see [Data Movement Pod Resource Configuration][data-movement-config]. +For Velero built-in data mover, data mover pods launched during file system backup will use the priority class name configured in the node-agent configmap. The node-agent daemonset itself gets its priority class from the `--node-agent-priority-class-name` flag during Velero installation. This can help ensure proper scheduling behavior in resource-constrained environments. For more details on configuring data mover pod resources, see [Data Movement Pod Resource Configuration][21]. ## Resource Consumption @@ -712,7 +712,9 @@ totalPreservedMemory = (128M + 24M * numOfCPUCores) * numOfWorkerNodes However, whether and when this limit is reached is related to the data you are backing up/restoring. During the restore, the repository may also cache data/metadata so as to reduce the network footprint and speed up the restore. The repository uses its own policy to store and clean up the cache. -For Kopia repository, the cache is stored in the node-agent pod's root file system. Velero allows you to configure a limit of the cache size so that the node-agent pod won't be evicted due to running out of the ephemeral storage. For more details, check [Backup Repository Configuration][18]. +For Kopia repository, by default, the cache is stored in the data mover pod's root file system. If your root file system space is limited, the data mover pods may be evicted due to running out of the ephemeral storage, which causes the restore fails. To cope with this problem, Velero allows you: +- configure a limit of the cache size per backup repository, for more details, check [Backup Repository Configuration][18]. +- configure a dedicated volume for cache data, for more details, check [Data Movement Cache Volume][22]. ## Restic Deprecation @@ -766,4 +768,5 @@ Velero still effectively manage restic repository, though you cannot write any n [18]: backup-repository-configuration.md [19]: node-agent-concurrency.md [20]: node-agent-prepare-queue-length.md -[data-movement-config]: data-movement-pod-resource-configuration.md +[21]: data-movement-pod-resource-configuration.md +[22]: data-movement-cache-volume.md diff --git a/site/data/docs/main-toc.yml b/site/data/docs/main-toc.yml index 8b93bc400..a8ff1a739 100644 --- a/site/data/docs/main-toc.yml +++ b/site/data/docs/main-toc.yml @@ -44,9 +44,7 @@ toc: - page: Restore Resource Modifiers url: /restore-resource-modifiers - page: Run in any namespace - url: /namespace - - page: File system backup - url: /file-system-backup + url: /namespace - page: CSI Support url: /csi - page: Volume Group Snapshots @@ -67,6 +65,8 @@ toc: subfolderitems: - page: CSI Snapshot Data Mover url: /csi-snapshot-data-movement + - page: File system backup + url: /file-system-backup - page: Data Movement Backup PVC Configuration url: /data-movement-backup-pvc-configuration - page: Data Movement Restore PVC Configuration @@ -75,6 +75,8 @@ toc: url: /data-movement-pod-resource-configuration - page: Data Movement Node Selection Configuration url: /data-movement-node-selection + - page: Data Movement Cache PVC Configuration + url: /data-movement-cache-volume.md - page: Node-agent Concurrency url: /node-agent-concurrency - title: Plugins From dc3da29f3ee666162527f149fbcbe9dd6ba3fa61 Mon Sep 17 00:00:00 2001 From: Shubham Pampattiwar Date: Tue, 18 Nov 2025 15:40:30 -0800 Subject: [PATCH 092/104] Apply volume policies to VolumeGroupSnapshot PVC filtering VolumeGroupSnapshots were querying all PVCs with matching labels directly from the cluster without respecting volume policies. This caused errors when labeled PVCs included both CSI and non-CSI volumes, or volumes from different CSI drivers that were excluded by policies. This change filters PVCs by volume policy before VGS grouping, ensuring only PVCs that should be snapshotted are included in the group. A warning is logged when PVCs are excluded from VGS due to volume policy. Fixes #9344 Signed-off-by: Shubham Pampattiwar --- pkg/backup/actions/csi/pvc_action.go | 60 ++++- pkg/backup/actions/csi/pvc_action_test.go | 274 ++++++++++++++++++++++ 2 files changed, 332 insertions(+), 2 deletions(-) diff --git a/pkg/backup/actions/csi/pvc_action.go b/pkg/backup/actions/csi/pvc_action.go index c91d7a2b4..62c51accc 100644 --- a/pkg/backup/actions/csi/pvc_action.go +++ b/pkg/backup/actions/csi/pvc_action.go @@ -621,8 +621,30 @@ func (p *pvcBackupItemAction) getVolumeSnapshotReference( return nil, errors.Wrapf(err, "failed to list PVCs in VolumeGroupSnapshot group %q in namespace %q", group, pvc.Namespace) } + // Filter PVCs by volume policy + filteredPVCs, err := p.filterPVCsByVolumePolicy(groupedPVCs, backup) + if err != nil { + return nil, errors.Wrapf(err, "failed to filter PVCs by volume policy for VolumeGroupSnapshot group %q", group) + } + + // Warn if any PVCs were filtered out + if len(filteredPVCs) < len(groupedPVCs) { + for _, originalPVC := range groupedPVCs { + found := false + for _, filteredPVC := range filteredPVCs { + if originalPVC.Name == filteredPVC.Name { + found = true + break + } + } + if !found { + p.log.Warnf("PVC %s/%s has VolumeGroupSnapshot label %s=%s but is excluded by volume policy", originalPVC.Namespace, originalPVC.Name, vgsLabelKey, group) + } + } + } + // Determine the CSI driver for the grouped PVCs - driver, err := p.determineCSIDriver(groupedPVCs) + driver, err := p.determineCSIDriver(filteredPVCs) if err != nil { return nil, errors.Wrapf(err, "failed to determine CSI driver for PVCs in VolumeGroupSnapshot group %q", group) } @@ -643,7 +665,7 @@ func (p *pvcBackupItemAction) getVolumeSnapshotReference( } // Wait for all the VS objects associated with the VGS to have status and VGS Name (VS readiness is checked in legacy flow) and get the PVC-to-VS map - vsMap, err := p.waitForVGSAssociatedVS(ctx, groupedPVCs, newVGS, backup.Spec.CSISnapshotTimeout.Duration) + vsMap, err := p.waitForVGSAssociatedVS(ctx, filteredPVCs, newVGS, backup.Spec.CSISnapshotTimeout.Duration) if err != nil { return nil, errors.Wrapf(err, "timeout waiting for VolumeSnapshots to have status created via VolumeGroupSnapshot %s", newVGS.Name) } @@ -734,6 +756,40 @@ func (p *pvcBackupItemAction) listGroupedPVCs(ctx context.Context, namespace, la return pvcList.Items, nil } +func (p *pvcBackupItemAction) filterPVCsByVolumePolicy( + pvcs []corev1api.PersistentVolumeClaim, + backup *velerov1api.Backup, +) ([]corev1api.PersistentVolumeClaim, error) { + var filteredPVCs []corev1api.PersistentVolumeClaim + + for _, pvc := range pvcs { + // Convert PVC to unstructured for ShouldPerformSnapshotWithBackup + pvcMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&pvc) + if err != nil { + return nil, errors.Wrapf(err, "failed to convert PVC %s/%s to unstructured", pvc.Namespace, pvc.Name) + } + unstructuredPVC := &unstructured.Unstructured{Object: pvcMap} + + // Check if this PVC should be snapshotted according to volume policies + shouldSnapshot, err := volumehelper.ShouldPerformSnapshotWithBackup( + unstructuredPVC, + kuberesource.PersistentVolumeClaims, + *backup, + p.crClient, + p.log, + ) + if err != nil { + return nil, errors.Wrapf(err, "failed to check volume policy for PVC %s/%s", pvc.Namespace, pvc.Name) + } + + if shouldSnapshot { + filteredPVCs = append(filteredPVCs, pvc) + } + } + + return filteredPVCs, nil +} + func (p *pvcBackupItemAction) determineCSIDriver( pvcs []corev1api.PersistentVolumeClaim, ) (string, error) { diff --git a/pkg/backup/actions/csi/pvc_action_test.go b/pkg/backup/actions/csi/pvc_action_test.go index 795e3c038..8589a740e 100644 --- a/pkg/backup/actions/csi/pvc_action_test.go +++ b/pkg/backup/actions/csi/pvc_action_test.go @@ -586,6 +586,280 @@ func TestListGroupedPVCs(t *testing.T) { } } +func TestFilterPVCsByVolumePolicy(t *testing.T) { + tests := []struct { + name string + pvcs []corev1api.PersistentVolumeClaim + pvs []corev1api.PersistentVolume + volumePolicyStr string + expectCount int + expectError bool + }{ + { + name: "All PVCs should be included when no volume policy", + pvcs: []corev1api.PersistentVolumeClaim{ + { + ObjectMeta: metav1.ObjectMeta{Name: "pvc-1", Namespace: "ns-1"}, + Spec: corev1api.PersistentVolumeClaimSpec{ + VolumeName: "pv-1", + StorageClassName: pointer.String("sc-1"), + }, + Status: corev1api.PersistentVolumeClaimStatus{Phase: corev1api.ClaimBound}, + }, + { + ObjectMeta: metav1.ObjectMeta{Name: "pvc-2", Namespace: "ns-1"}, + Spec: corev1api.PersistentVolumeClaimSpec{ + VolumeName: "pv-2", + StorageClassName: pointer.String("sc-1"), + }, + Status: corev1api.PersistentVolumeClaimStatus{Phase: corev1api.ClaimBound}, + }, + }, + pvs: []corev1api.PersistentVolume{ + { + ObjectMeta: metav1.ObjectMeta{Name: "pv-1"}, + Spec: corev1api.PersistentVolumeSpec{ + PersistentVolumeSource: corev1api.PersistentVolumeSource{ + CSI: &corev1api.CSIPersistentVolumeSource{Driver: "csi-driver-1"}, + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{Name: "pv-2"}, + Spec: corev1api.PersistentVolumeSpec{ + PersistentVolumeSource: corev1api.PersistentVolumeSource{ + CSI: &corev1api.CSIPersistentVolumeSource{Driver: "csi-driver-1"}, + }, + }, + }, + }, + expectCount: 2, + }, + { + name: "Filter out NFS PVC by volume policy", + pvcs: []corev1api.PersistentVolumeClaim{ + { + ObjectMeta: metav1.ObjectMeta{Name: "pvc-csi", Namespace: "ns-1"}, + Spec: corev1api.PersistentVolumeClaimSpec{ + VolumeName: "pv-csi", + StorageClassName: pointer.String("sc-1"), + }, + Status: corev1api.PersistentVolumeClaimStatus{Phase: corev1api.ClaimBound}, + }, + { + ObjectMeta: metav1.ObjectMeta{Name: "pvc-nfs", Namespace: "ns-1"}, + Spec: corev1api.PersistentVolumeClaimSpec{ + VolumeName: "pv-nfs", + StorageClassName: pointer.String("sc-nfs"), + }, + Status: corev1api.PersistentVolumeClaimStatus{Phase: corev1api.ClaimBound}, + }, + }, + pvs: []corev1api.PersistentVolume{ + { + ObjectMeta: metav1.ObjectMeta{Name: "pv-csi"}, + Spec: corev1api.PersistentVolumeSpec{ + PersistentVolumeSource: corev1api.PersistentVolumeSource{ + CSI: &corev1api.CSIPersistentVolumeSource{Driver: "csi-driver"}, + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{Name: "pv-nfs"}, + Spec: corev1api.PersistentVolumeSpec{ + PersistentVolumeSource: corev1api.PersistentVolumeSource{ + NFS: &corev1api.NFSVolumeSource{ + Server: "nfs-server", + Path: "/export", + }, + }, + }, + }, + }, + volumePolicyStr: ` +version: v1 +volumePolicies: +- conditions: + nfs: {} + action: + type: skip +`, + expectCount: 1, + }, + { + name: "All PVCs filtered out by volume policy", + pvcs: []corev1api.PersistentVolumeClaim{ + { + ObjectMeta: metav1.ObjectMeta{Name: "pvc-nfs-1", Namespace: "ns-1"}, + Spec: corev1api.PersistentVolumeClaimSpec{ + VolumeName: "pv-nfs-1", + StorageClassName: pointer.String("sc-nfs"), + }, + Status: corev1api.PersistentVolumeClaimStatus{Phase: corev1api.ClaimBound}, + }, + { + ObjectMeta: metav1.ObjectMeta{Name: "pvc-nfs-2", Namespace: "ns-1"}, + Spec: corev1api.PersistentVolumeClaimSpec{ + VolumeName: "pv-nfs-2", + StorageClassName: pointer.String("sc-nfs"), + }, + Status: corev1api.PersistentVolumeClaimStatus{Phase: corev1api.ClaimBound}, + }, + }, + pvs: []corev1api.PersistentVolume{ + { + ObjectMeta: metav1.ObjectMeta{Name: "pv-nfs-1"}, + Spec: corev1api.PersistentVolumeSpec{ + PersistentVolumeSource: corev1api.PersistentVolumeSource{ + NFS: &corev1api.NFSVolumeSource{ + Server: "nfs-server", + Path: "/export/1", + }, + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{Name: "pv-nfs-2"}, + Spec: corev1api.PersistentVolumeSpec{ + PersistentVolumeSource: corev1api.PersistentVolumeSource{ + NFS: &corev1api.NFSVolumeSource{ + Server: "nfs-server", + Path: "/export/2", + }, + }, + }, + }, + }, + volumePolicyStr: ` +version: v1 +volumePolicies: +- conditions: + nfs: {} + action: + type: skip +`, + expectCount: 0, + }, + { + name: "Filter out non-CSI PVCs from mixed driver group", + pvcs: []corev1api.PersistentVolumeClaim{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-linstor", + Namespace: "ns-1", + Labels: map[string]string{"app.kubernetes.io/instance": "myapp"}, + }, + Spec: corev1api.PersistentVolumeClaimSpec{ + VolumeName: "pv-linstor", + StorageClassName: pointer.String("sc-linstor"), + }, + Status: corev1api.PersistentVolumeClaimStatus{Phase: corev1api.ClaimBound}, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-nfs", + Namespace: "ns-1", + Labels: map[string]string{"app.kubernetes.io/instance": "myapp"}, + }, + Spec: corev1api.PersistentVolumeClaimSpec{ + VolumeName: "pv-nfs", + StorageClassName: pointer.String("sc-nfs"), + }, + Status: corev1api.PersistentVolumeClaimStatus{Phase: corev1api.ClaimBound}, + }, + }, + pvs: []corev1api.PersistentVolume{ + { + ObjectMeta: metav1.ObjectMeta{Name: "pv-linstor"}, + Spec: corev1api.PersistentVolumeSpec{ + PersistentVolumeSource: corev1api.PersistentVolumeSource{ + CSI: &corev1api.CSIPersistentVolumeSource{Driver: "linstor.csi.linbit.com"}, + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{Name: "pv-nfs"}, + Spec: corev1api.PersistentVolumeSpec{ + PersistentVolumeSource: corev1api.PersistentVolumeSource{ + NFS: &corev1api.NFSVolumeSource{ + Server: "nfs-server", + Path: "/export", + }, + }, + }, + }, + }, + volumePolicyStr: ` +version: v1 +volumePolicies: +- conditions: + nfs: {} + action: + type: skip +`, + expectCount: 1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + objs := []runtime.Object{} + for i := range tt.pvs { + objs = append(objs, &tt.pvs[i]) + } + + client := velerotest.NewFakeControllerRuntimeClient(t, objs...) + + backup := &velerov1api.Backup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-backup", + Namespace: "velero", + }, + Spec: velerov1api.BackupSpec{}, + } + + // Add volume policy ConfigMap if specified + if tt.volumePolicyStr != "" { + cm := &corev1api.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "volume-policy", + Namespace: "velero", + }, + Data: map[string]string{ + "volume-policy": tt.volumePolicyStr, + }, + } + require.NoError(t, client.Create(context.Background(), cm)) + + backup.Spec.ResourcePolicy = &corev1api.TypedLocalObjectReference{ + Kind: "ConfigMap", + Name: "volume-policy", + } + } + + action := &pvcBackupItemAction{ + log: velerotest.NewLogger(), + crClient: client, + } + + result, err := action.filterPVCsByVolumePolicy(tt.pvcs, backup) + if tt.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Len(t, result, tt.expectCount) + + // For mixed driver scenarios, verify filtered result can determine single CSI driver + if tt.name == "Filter out non-CSI PVCs from mixed driver group" && len(result) > 0 { + driver, err := action.determineCSIDriver(result) + require.NoError(t, err, "After filtering, determineCSIDriver should not fail with multiple drivers error") + require.Equal(t, "linstor.csi.linbit.com", driver, "Should have the Linstor driver after filtering out NFS") + } + } + }) + } +} + func TestDetermineCSIDriver(t *testing.T) { tests := []struct { name string From c870eb16452ff78982bf7437236358cafc3d519c Mon Sep 17 00:00:00 2001 From: Shubham Pampattiwar Date: Tue, 18 Nov 2025 15:42:53 -0800 Subject: [PATCH 093/104] Add changelog entry for PR #9419 Signed-off-by: Shubham Pampattiwar --- changelogs/unreleased/9419-shubham-pampattiwar | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/unreleased/9419-shubham-pampattiwar diff --git a/changelogs/unreleased/9419-shubham-pampattiwar b/changelogs/unreleased/9419-shubham-pampattiwar new file mode 100644 index 000000000..9f21ac8ca --- /dev/null +++ b/changelogs/unreleased/9419-shubham-pampattiwar @@ -0,0 +1 @@ +Apply volume policies to VolumeGroupSnapshot PVC filtering From 324c2fb448a8bf8a8dd4a18a9847a637b0c65e45 Mon Sep 17 00:00:00 2001 From: Shubham Pampattiwar Date: Tue, 18 Nov 2025 15:46:30 -0800 Subject: [PATCH 094/104] Document volume policy interaction with VolumeGroupSnapshots Add documentation explaining how volume policies are applied before VGS grouping, including examples and troubleshooting guidance for the multiple CSI drivers scenario. Signed-off-by: Shubham Pampattiwar --- .../docs/main/volume-group-snapshots.md | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/site/content/docs/main/volume-group-snapshots.md b/site/content/docs/main/volume-group-snapshots.md index cb2e545d2..95cf33ff9 100644 --- a/site/content/docs/main/volume-group-snapshots.md +++ b/site/content/docs/main/volume-group-snapshots.md @@ -298,6 +298,96 @@ You can customize the label key that Velero uses to identify VGS groups. This is 3. **Default Value (Lowest Priority):** If you don't provide any custom configuration, Velero defaults to using `velero.io/volume-group`. +## Volume Policies and VolumeGroupSnapshots + +Volume policies control which volumes should be backed up and how (snapshot vs filesystem backup). When using VolumeGroupSnapshots, volume policies are applied **before** grouping PVCs. + +### How Volume Policies Affect VGS + +When Velero processes PVCs for a VolumeGroupSnapshot: + +1. **Label Matching:** All PVCs with the matching VGS label are identified +2. **Policy Filtering:** Volume policies are evaluated for each PVC +3. **Group Creation:** Only PVCs that should be snapshotted (not excluded by policy) are included in the VGS +4. **Warning Logging:** If any PVCs are excluded from the group by volume policy, a warning is logged + +This behavior ensures that volume policies take precedence over VGS labels. The VGS label indicates "group these volumes **if they're being backed up**", while the volume policy determines "which volumes to back up". + +### Example Scenario + +Consider an application with mixed storage types where some volumes should be excluded: + +```yaml +# Database PVC using CSI driver (should be backed up) +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: db-data + namespace: my-app + labels: + app.kubernetes.io/instance: myapp # VGS label +spec: + storageClassName: csi-storage + # ... + +--- +# Config PVC using NFS (should be excluded) +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: config-data + namespace: my-app + labels: + app.kubernetes.io/instance: myapp # Same VGS label +spec: + storageClassName: nfs-storage + # ... +``` + +**Volume Policy Configuration:** +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: velero-volume-policies + namespace: velero +data: + volume-policy: | + version: v1 + volumePolicies: + - conditions: + nfs: {} + action: + type: skip +``` + +**Backup Configuration:** +```yaml +apiVersion: velero.io/v1 +kind: Backup +metadata: + name: myapp-backup +spec: + includedNamespaces: + - my-app + volumeGroupSnapshotLabelKey: app.kubernetes.io/instance + resourcePolicy: + kind: ConfigMap + name: velero-volume-policies +``` + +**Result:** +- The NFS PVC (`config-data`) is filtered out by the volume policy +- Only the CSI PVC (`db-data`) is included in the VolumeGroupSnapshot +- A warning is logged: `PVC my-app/config-data has VolumeGroupSnapshot label app.kubernetes.io/instance=myapp but is excluded by volume policy` +- The backup succeeds with a single-volume VGS instead of failing with "multiple CSI drivers" error + +### Best Practices + +1. **Use Specific Labels:** When possible, use VGS labels that only target volumes you want to group, rather than relying on volume policies for filtering +2. **Monitor Warnings:** Review backup logs for volume policy exclusion warnings to ensure intended PVCs are being backed up +3. **Test Configurations:** Verify that your volume policy and VGS label combinations produce the expected grouping in a test environment + ## Troubleshooting ### Common Issues and Solutions @@ -334,6 +424,36 @@ kubectl logs -n kube-system -l app=ebs-csi-controller --tail=100 - Check VolumeGroupSnapshotClass configuration - Ensure storage backend supports group snapshots +#### Multiple CSI Drivers Error + +**Symptoms:** Backup fails with error about multiple CSI drivers found +``` +Error backing up item: failed to determine CSI driver for PVCs in VolumeGroupSnapshot group: +found multiple CSI drivers: linstor.csi.linbit.com and nfs.csi.k8s.io +``` + +**Cause:** PVCs with the same VGS label use different CSI drivers or include non-CSI volumes + +**Solutions:** +1. Use more specific labels that only match PVCs using the same CSI driver +2. Use volume policies to exclude PVCs that shouldn't be snapshotted: + ```yaml + apiVersion: v1 + kind: ConfigMap + metadata: + name: velero-volume-policies + namespace: velero + data: + volume-policy: | + version: v1 + volumePolicies: + - conditions: + nfs: {} + action: + type: skip + ``` +3. Check backup logs for volume policy warnings to verify filtering is working + #### VolumeGroupSnapshot Setup: Default VolumeSnapshotClass Required **Issue** From c565da2ea6d7ca14e76dc4c84965b726a01261e1 Mon Sep 17 00:00:00 2001 From: Shubham Pampattiwar Date: Tue, 18 Nov 2025 15:58:09 -0800 Subject: [PATCH 095/104] Fix linter error: use t.Context() instead of context.Background() Signed-off-by: Shubham Pampattiwar --- pkg/backup/actions/csi/pvc_action_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/backup/actions/csi/pvc_action_test.go b/pkg/backup/actions/csi/pvc_action_test.go index 8589a740e..6280b3ebd 100644 --- a/pkg/backup/actions/csi/pvc_action_test.go +++ b/pkg/backup/actions/csi/pvc_action_test.go @@ -829,7 +829,7 @@ volumePolicies: "volume-policy": tt.volumePolicyStr, }, } - require.NoError(t, client.Create(context.Background(), cm)) + require.NoError(t, client.Create(t.Context(), cm)) backup.Spec.ResourcePolicy = &corev1api.TypedLocalObjectReference{ Kind: "ConfigMap", From 39892abef232ef49a549f880b685282565cea18e Mon Sep 17 00:00:00 2001 From: lyndon-li <98304688+Lyndon-Li@users.noreply.github.com> Date: Wed, 19 Nov 2025 10:50:16 +0800 Subject: [PATCH 096/104] Update site/content/docs/main/data-movement-cache-volume.md Co-authored-by: Tiger Kaovilai Signed-off-by: lyndon-li <98304688+Lyndon-Li@users.noreply.github.com> --- site/content/docs/main/data-movement-cache-volume.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/docs/main/data-movement-cache-volume.md b/site/content/docs/main/data-movement-cache-volume.md index c23f9efb1..b86c10edc 100644 --- a/site/content/docs/main/data-movement-cache-volume.md +++ b/site/content/docs/main/data-movement-cache-volume.md @@ -6,7 +6,7 @@ layout: docs Velero data movement restore (i.e., for CSI snapshot data movement and fs-backup) may request the backup repository to cache data locally so as to reduce the data request from the remote backup storage. The cache behavior is decided by the specific backup repository, and Velero allows you to configure a cache limit for the backup repositories who support it (i.e., kopia repository). For more details, see [Backup Repository Configuration][1]. The size of cache may significantly impact on the performance. Specifically, if the cache size is too small, the restore throughput will be severely reduced and much more data would be downloaded from the backup storage. -By default, the cache data location is in the data mover pods' root disk. In some environments, the pods's root disk size is very limited, some a large cache size would cause the data mover pods evicted because of running out of ephemeral disk. +By default, the cache data location is in the data mover pods' root disk. In some environments, the pods' root disk size is very limited, so a large cache size would cause the data mover pods evicted because of running out of ephemeral disk. To cope with the problems and guarantee the data mover pods always run with a fine tuned local cache, Velero supports dedicated cache PVCs for data movement restore, for CSI snapshot data movement and fs-backup. From 9dc27555bc1d2027ee75ce17bfd87b40658815df Mon Sep 17 00:00:00 2001 From: lyndon-li <98304688+Lyndon-Li@users.noreply.github.com> Date: Wed, 19 Nov 2025 10:50:25 +0800 Subject: [PATCH 097/104] Update site/content/docs/main/data-movement-cache-volume.md Co-authored-by: Tiger Kaovilai Signed-off-by: lyndon-li <98304688+Lyndon-Li@users.noreply.github.com> --- site/content/docs/main/data-movement-cache-volume.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/docs/main/data-movement-cache-volume.md b/site/content/docs/main/data-movement-cache-volume.md index b86c10edc..95ba80c1b 100644 --- a/site/content/docs/main/data-movement-cache-volume.md +++ b/site/content/docs/main/data-movement-cache-volume.md @@ -33,7 +33,7 @@ The cache PVC behavior could be further fine tuned through `thresholdInGB`. Its This configuration decides whether and how to provision cache PVCs, but it doesn't decide their size. Instead, the size is decided by the specific backup repository. Specifically, Velero asks a cache limit from the backup repository and uses this limit to calculate the cache PVC size. The cache limit is decided by the backup repository itself, for Kopia repository, if `cacheLimitMB` is specified in the backup repository configuration, its value will be used; otherwise, a default limit (5 GB) is used. -Then Velero inflates the limit with 20% by considering the non-payload overheads and delay cache cleanup behavior varying on backup repositories. +Then Velero inflates the limit by 20% by considering the non-payload overheads and delay cache cleanup behavior varying on backup repositories. Take Kopia repository and the above cache PVC configuration for example: - When `cacheLimitMB` is not available for the repository, a 6GB cache PVC is created for the backup that is larger than 1GB; otherwise, no cache volume is created From a3169aeff3bec65d844f9000a3719d6c60cab9a9 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Wed, 19 Nov 2025 15:59:12 +0800 Subject: [PATCH 098/104] add doc for GOMAXPROCS behavior change Signed-off-by: Lyndon-Li --- changelogs/unreleased/9420-Lyndon-Li | 1 + .../docs/main/csi-snapshot-data-movement.md | 7 +++++++ site/content/docs/main/file-system-backup.md | 15 +++++---------- 3 files changed, 13 insertions(+), 10 deletions(-) create mode 100644 changelogs/unreleased/9420-Lyndon-Li diff --git a/changelogs/unreleased/9420-Lyndon-Li b/changelogs/unreleased/9420-Lyndon-Li new file mode 100644 index 000000000..5575369cc --- /dev/null +++ b/changelogs/unreleased/9420-Lyndon-Li @@ -0,0 +1 @@ +Fix issue #9194, add doc for GOMAXPROCS behavior change \ No newline at end of file diff --git a/site/content/docs/main/csi-snapshot-data-movement.md b/site/content/docs/main/csi-snapshot-data-movement.md index a83cbac49..cde862209 100644 --- a/site/content/docs/main/csi-snapshot-data-movement.md +++ b/site/content/docs/main/csi-snapshot-data-movement.md @@ -313,6 +313,12 @@ kubectl -n velero get datauploads -l velero.io/backup-name=YOUR_BACKUP_NAME -w kubectl -n velero get datadownloads -l velero.io/restore-name=YOUR_RESTORE_NAME -w ``` +For each volume, the parallelism is like below: +- If it is a file system mode volume, files in the volume are processed in parallel. You can use `--parallel-files-upload` backup flag or `--parallel-files-download` restore flag to control how many files are processed in parallel. Otherwise, if they are not set, Velero by default refers to the number of CPU cores in the node (where the backup/restore is running) for the parallelism. That is to say, the parallelism is not affected by the CPU request/limit set to the data mover pods. +- If it is a block mode volume, there is no parallelism, the block data is processed sequentially. + +Notice that Golang 1.25 and later respects the CPU limit set to the pods to decide the physical threads provisioned to the pod processes (see [Container-aware GOMAXPROCS][22] for more details), so for Velero 1.18 (which consumes Golang 1.25) and later, if you set a CPU limit to the data mover pods, you may not get the expected performance (e.g., backup/restore throughput) with the default parallelism. The outcome may or may not be obvious varying on your volume data. If it is required, you could customize `--parallel-files-upload` or `--parallel-files-download` according to the CPU limit set to the data mover pods. + ### Restart and resume When Velero server is restarted, if the resource backup/restore has completed, so the backup/restore has excceded `InProgress` status and is waiting for the completion of the data movements, Velero will recapture the status of the running data movements and resume the execution. When node-agent is restarted, Velero tries to recapture the status of the running data movements and resume the execution; if the resume fails, the data movements are canceled. @@ -420,5 +426,6 @@ Sometimes, `RestorePVC` needs to be configured to increase the performance of re [19]: data-movement-restore-pvc-configuration.md [20]: node-agent-prepare-queue-length.md [21]: data-movement-cache-volume.md +[22]: https://tip.golang.org/doc/go1.25#container-aware-gomaxprocs:~:text=Runtime%C2%B6-,Container%2Daware%20GOMAXPROCS,-%C2%B6 diff --git a/site/content/docs/main/file-system-backup.md b/site/content/docs/main/file-system-backup.md index f74571b4c..d78368da3 100644 --- a/site/content/docs/main/file-system-backup.md +++ b/site/content/docs/main/file-system-backup.md @@ -631,6 +631,10 @@ However, if you run a backup which aborts halfway(some internal snapshots are th By default, one `PodVolumeBackup`/`PodVolumeRestore` request is handled in a node at a time. You can configure more parallelism per node by [node-agent Concurrency Configuration][19]. By the meantime, one data mover pod is created for each volume to be backed up/restored, if there is no available concurrency quota, the data mover pod has to wait there. To make a control of the data mover pods, you can configure the [node-agent Prepare Queue Length][20]. +For each volume, files in the volume are processed in parallel. You can use `--parallel-files-upload` backup flag or `--parallel-files-download` restore flag to control how many files are processed in parallel. Otherwise, if they are not set, Velero by default refers to the number of CPU cores in the node (where the backup/restore is running) for the parallelism. That is to say, the parallelism is not affected by the CPU request/limit set to the data mover pods. + +Notice that Golang 1.25 and later respects the CPU limit set to the pods to decide the physical threads provisioned to the pod processes (see [Container-aware GOMAXPROCS][23] for more details), so for Velero 1.18 (which consumes Golang 1.25) and later, if you set a CPU limit to the data mover pods, you may not get the expected performance (e.g., backup/restore throughput) with the default parallelism. The outcome may or may not be obvious varying on your volume data. If it is required, you could customize `--parallel-files-upload` or `--parallel-files-download` according to the CPU limit set to the data mover pods. + ### Restart and resume When Velero server is restarted, the running backups/restores will be marked as `Failed`. The corresponding `PodVolumeBackup`/`PodVolumeRestore` will be canceled. When node-agent is restarted, the controller will try to recapture and resume the `PodVolumeBackup`/`PodVolumeRestore`. If the resume fails, the `PodVolumeBackup`/`PodVolumeRestore` will be canceled. @@ -701,16 +705,6 @@ Both the uploader and repository consume remarkable CPU/memory during the backup Velero node-agent uses [BestEffort as the QoS][14] for node-agent pods (so no CPU/memory request/limit is set), so that backups/restores wouldn't fail due to resource throttling in any cases. If you want to constraint the CPU/memory usage, you need to [customize the resource limits][15]. The CPU/memory consumption is always related to the scale of data to be backed up/restored, refer to [Performance Guidance][16] for more details, so it is highly recommended that you perform your own testing to find the best resource limits for your data. -Some memory is preserved by the node-agent to avoid frequent memory allocations, therefore, after you run a file-system backup/restore, you won't see node-agent releases all the memory until it restarts. There is a limit for the memory preservation, so the memory won't increase all the time. The limit varies from the number of CPU cores in the cluster nodes, as calculated below: -``` -preservedMemoryInOneNode = 128M + 24M * numOfCPUCores -``` -The memory perservation only happens in the nodes where backups/restores ever occur. Assuming file-system backups/restores occur in ever worker node and you have equal CPU cores in each node, the maximum possibly preserved memory in your cluster is: -``` -totalPreservedMemory = (128M + 24M * numOfCPUCores) * numOfWorkerNodes -``` -However, whether and when this limit is reached is related to the data you are backing up/restoring. - During the restore, the repository may also cache data/metadata so as to reduce the network footprint and speed up the restore. The repository uses its own policy to store and clean up the cache. For Kopia repository, by default, the cache is stored in the data mover pod's root file system. If your root file system space is limited, the data mover pods may be evicted due to running out of the ephemeral storage, which causes the restore fails. To cope with this problem, Velero allows you: - configure a limit of the cache size per backup repository, for more details, check [Backup Repository Configuration][18]. @@ -770,3 +764,4 @@ Velero still effectively manage restic repository, though you cannot write any n [20]: node-agent-prepare-queue-length.md [21]: data-movement-pod-resource-configuration.md [22]: data-movement-cache-volume.md +[23]: https://tip.golang.org/doc/go1.25#container-aware-gomaxprocs:~:text=Runtime%C2%B6-,Container%2Daware%20GOMAXPROCS,-%C2%B6 From 960a596e7b80ee4982e2de987f62e7038066cf1c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 02:44:43 +0000 Subject: [PATCH 099/104] Bump golang.org/x/crypto from 0.40.0 to 0.45.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.40.0 to 0.45.0. - [Commits](https://github.com/golang/crypto/compare/v0.40.0...v0.45.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.45.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- go.mod | 16 ++++++++-------- go.sum | 32 ++++++++++++++++---------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index d32340b2b..b06ccdd68 100644 --- a/go.mod +++ b/go.mod @@ -41,10 +41,10 @@ require ( github.com/stretchr/testify v1.10.0 github.com/vmware-tanzu/crash-diagnostics v0.3.7 go.uber.org/zap v1.27.0 - golang.org/x/mod v0.26.0 - golang.org/x/net v0.42.0 + golang.org/x/mod v0.29.0 + golang.org/x/net v0.47.0 golang.org/x/oauth2 v0.30.0 - golang.org/x/text v0.27.0 + golang.org/x/text v0.31.0 google.golang.org/api v0.241.0 google.golang.org/grpc v1.73.0 google.golang.org/protobuf v1.36.6 @@ -180,13 +180,13 @@ require ( go.opentelemetry.io/otel/trace v1.37.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.40.0 // indirect + golang.org/x/crypto v0.45.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.34.0 // indirect - golang.org/x/term v0.33.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/term v0.37.0 // indirect golang.org/x/time v0.12.0 // indirect - golang.org/x/tools v0.34.0 // indirect + golang.org/x/tools v0.38.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect diff --git a/go.sum b/go.sum index 84a94ed32..3d63289fc 100644 --- a/go.sum +++ b/go.sum @@ -794,8 +794,8 @@ golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= -golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -833,8 +833,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= -golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -880,8 +880,8 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= -golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -908,8 +908,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -973,14 +973,14 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= -golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -990,8 +990,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= -golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1051,8 +1051,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 99d87aae5b13038b4e3dbc90de9a57a478b47b13 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Mon, 24 Nov 2025 17:21:00 +0800 Subject: [PATCH 100/104] fix linter error Signed-off-by: Lyndon-Li --- pkg/plugin/framework/backup_item_action.go | 3 ++- pkg/plugin/framework/backup_item_action_client.go | 3 ++- pkg/plugin/framework/backup_item_action_server.go | 3 ++- pkg/plugin/framework/backupitemaction/v2/backup_item_action.go | 3 ++- .../framework/backupitemaction/v2/backup_item_action_client.go | 3 ++- .../framework/backupitemaction/v2/backup_item_action_server.go | 3 ++- pkg/plugin/framework/delete_item_action.go | 3 ++- pkg/plugin/framework/delete_item_action_client.go | 3 ++- pkg/plugin/framework/delete_item_action_server.go | 3 ++- pkg/plugin/framework/itemblockaction/v1/item_block_action.go | 3 ++- .../framework/itemblockaction/v1/item_block_action_client.go | 3 ++- .../framework/itemblockaction/v1/item_block_action_server.go | 3 ++- pkg/plugin/framework/object_store.go | 3 ++- pkg/plugin/framework/object_store_client.go | 3 ++- pkg/plugin/framework/object_store_server.go | 3 ++- pkg/plugin/framework/plugin_lister.go | 3 ++- pkg/plugin/framework/restore_item_action.go | 3 ++- pkg/plugin/framework/restore_item_action_client.go | 3 ++- pkg/plugin/framework/restore_item_action_server.go | 3 ++- .../framework/restoreitemaction/v2/restore_item_action.go | 3 ++- .../restoreitemaction/v2/restore_item_action_client.go | 3 ++- .../restoreitemaction/v2/restore_item_action_server.go | 3 ++- pkg/plugin/framework/volume_snapshotter.go | 3 ++- pkg/plugin/framework/volume_snapshotter_client.go | 3 ++- pkg/plugin/framework/volume_snapshotter_server.go | 3 ++- pkg/util/kube/periodical_enqueue_source_test.go | 3 ++- test/util/eks/eks.go | 3 ++- test/util/k8s/clusterrolebinding.go | 2 +- test/util/k8s/common.go | 3 ++- test/util/k8s/configmap.go | 3 ++- test/util/k8s/crd.go | 3 ++- test/util/k8s/deployment.go | 3 ++- test/util/k8s/secret.go | 3 ++- test/util/k8s/statefulset.go | 3 ++- test/util/kibishii/kibishii_utils.go | 3 ++- test/util/providers/aws_utils.go | 3 ++- test/util/providers/azure_utils.go | 3 ++- test/util/providers/gcloud_utils.go | 3 ++- 38 files changed, 75 insertions(+), 38 deletions(-) diff --git a/pkg/plugin/framework/backup_item_action.go b/pkg/plugin/framework/backup_item_action.go index 00f3cc0ea..9c1a5665d 100644 --- a/pkg/plugin/framework/backup_item_action.go +++ b/pkg/plugin/framework/backup_item_action.go @@ -17,8 +17,9 @@ limitations under the License. package framework import ( + "context" + plugin "github.com/hashicorp/go-plugin" - "golang.org/x/net/context" "google.golang.org/grpc" "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" diff --git a/pkg/plugin/framework/backup_item_action_client.go b/pkg/plugin/framework/backup_item_action_client.go index 948cb3492..724737d01 100644 --- a/pkg/plugin/framework/backup_item_action_client.go +++ b/pkg/plugin/framework/backup_item_action_client.go @@ -19,8 +19,9 @@ package framework import ( "encoding/json" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" diff --git a/pkg/plugin/framework/backup_item_action_server.go b/pkg/plugin/framework/backup_item_action_server.go index 6511591a9..7c18b4ef6 100644 --- a/pkg/plugin/framework/backup_item_action_server.go +++ b/pkg/plugin/framework/backup_item_action_server.go @@ -19,8 +19,9 @@ package framework import ( "encoding/json" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" diff --git a/pkg/plugin/framework/backupitemaction/v2/backup_item_action.go b/pkg/plugin/framework/backupitemaction/v2/backup_item_action.go index c1e2e5401..903ec378c 100644 --- a/pkg/plugin/framework/backupitemaction/v2/backup_item_action.go +++ b/pkg/plugin/framework/backupitemaction/v2/backup_item_action.go @@ -17,8 +17,9 @@ limitations under the License. package v2 import ( + "context" + plugin "github.com/hashicorp/go-plugin" - "golang.org/x/net/context" "google.golang.org/grpc" "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" diff --git a/pkg/plugin/framework/backupitemaction/v2/backup_item_action_client.go b/pkg/plugin/framework/backupitemaction/v2/backup_item_action_client.go index 52733de2d..64695dbe3 100644 --- a/pkg/plugin/framework/backupitemaction/v2/backup_item_action_client.go +++ b/pkg/plugin/framework/backupitemaction/v2/backup_item_action_client.go @@ -19,8 +19,9 @@ package v2 import ( "encoding/json" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" diff --git a/pkg/plugin/framework/backupitemaction/v2/backup_item_action_server.go b/pkg/plugin/framework/backupitemaction/v2/backup_item_action_server.go index c622490e7..f8c894eba 100644 --- a/pkg/plugin/framework/backupitemaction/v2/backup_item_action_server.go +++ b/pkg/plugin/framework/backupitemaction/v2/backup_item_action_server.go @@ -19,8 +19,9 @@ package v2 import ( "encoding/json" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/protobuf/types/known/emptypb" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" diff --git a/pkg/plugin/framework/delete_item_action.go b/pkg/plugin/framework/delete_item_action.go index afc5d548e..db4329b7f 100644 --- a/pkg/plugin/framework/delete_item_action.go +++ b/pkg/plugin/framework/delete_item_action.go @@ -17,8 +17,9 @@ limitations under the License. package framework import ( + "context" + plugin "github.com/hashicorp/go-plugin" - "golang.org/x/net/context" "google.golang.org/grpc" "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" diff --git a/pkg/plugin/framework/delete_item_action_client.go b/pkg/plugin/framework/delete_item_action_client.go index 088c42b51..bec5088db 100644 --- a/pkg/plugin/framework/delete_item_action_client.go +++ b/pkg/plugin/framework/delete_item_action_client.go @@ -19,8 +19,9 @@ package framework import ( "encoding/json" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" diff --git a/pkg/plugin/framework/delete_item_action_server.go b/pkg/plugin/framework/delete_item_action_server.go index e298969d1..01abe8dc3 100644 --- a/pkg/plugin/framework/delete_item_action_server.go +++ b/pkg/plugin/framework/delete_item_action_server.go @@ -19,8 +19,9 @@ package framework import ( "encoding/json" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" diff --git a/pkg/plugin/framework/itemblockaction/v1/item_block_action.go b/pkg/plugin/framework/itemblockaction/v1/item_block_action.go index 9fb8094ee..2115d2ecf 100644 --- a/pkg/plugin/framework/itemblockaction/v1/item_block_action.go +++ b/pkg/plugin/framework/itemblockaction/v1/item_block_action.go @@ -17,8 +17,9 @@ limitations under the License. package v1 import ( + "context" + plugin "github.com/hashicorp/go-plugin" - "golang.org/x/net/context" "google.golang.org/grpc" "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" diff --git a/pkg/plugin/framework/itemblockaction/v1/item_block_action_client.go b/pkg/plugin/framework/itemblockaction/v1/item_block_action_client.go index 612a14a6c..aa597c4af 100644 --- a/pkg/plugin/framework/itemblockaction/v1/item_block_action_client.go +++ b/pkg/plugin/framework/itemblockaction/v1/item_block_action_client.go @@ -19,8 +19,9 @@ package v1 import ( "encoding/json" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" diff --git a/pkg/plugin/framework/itemblockaction/v1/item_block_action_server.go b/pkg/plugin/framework/itemblockaction/v1/item_block_action_server.go index ab9ad7485..2d940550c 100644 --- a/pkg/plugin/framework/itemblockaction/v1/item_block_action_server.go +++ b/pkg/plugin/framework/itemblockaction/v1/item_block_action_server.go @@ -19,8 +19,9 @@ package v1 import ( "encoding/json" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" diff --git a/pkg/plugin/framework/object_store.go b/pkg/plugin/framework/object_store.go index d7c7b95e4..ea624da42 100644 --- a/pkg/plugin/framework/object_store.go +++ b/pkg/plugin/framework/object_store.go @@ -17,8 +17,9 @@ limitations under the License. package framework import ( + "context" + plugin "github.com/hashicorp/go-plugin" - "golang.org/x/net/context" "google.golang.org/grpc" "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" diff --git a/pkg/plugin/framework/object_store_client.go b/pkg/plugin/framework/object_store_client.go index 725f8e934..b59f3d1b0 100644 --- a/pkg/plugin/framework/object_store_client.go +++ b/pkg/plugin/framework/object_store_client.go @@ -20,8 +20,9 @@ import ( "io" "time" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" diff --git a/pkg/plugin/framework/object_store_server.go b/pkg/plugin/framework/object_store_server.go index 2d3ef3658..fbed21ecf 100644 --- a/pkg/plugin/framework/object_store_server.go +++ b/pkg/plugin/framework/object_store_server.go @@ -20,8 +20,9 @@ import ( "io" "time" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" proto "github.com/vmware-tanzu/velero/pkg/plugin/generated" diff --git a/pkg/plugin/framework/plugin_lister.go b/pkg/plugin/framework/plugin_lister.go index 19e349007..6db81c66d 100644 --- a/pkg/plugin/framework/plugin_lister.go +++ b/pkg/plugin/framework/plugin_lister.go @@ -17,9 +17,10 @@ limitations under the License. package framework import ( + "context" + plugin "github.com/hashicorp/go-plugin" "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" diff --git a/pkg/plugin/framework/restore_item_action.go b/pkg/plugin/framework/restore_item_action.go index 0aaf2b47e..26cef3728 100644 --- a/pkg/plugin/framework/restore_item_action.go +++ b/pkg/plugin/framework/restore_item_action.go @@ -17,8 +17,9 @@ limitations under the License. package framework import ( + "context" + plugin "github.com/hashicorp/go-plugin" - "golang.org/x/net/context" "google.golang.org/grpc" "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" diff --git a/pkg/plugin/framework/restore_item_action_client.go b/pkg/plugin/framework/restore_item_action_client.go index 8809e31c3..3a5a633f3 100644 --- a/pkg/plugin/framework/restore_item_action_client.go +++ b/pkg/plugin/framework/restore_item_action_client.go @@ -19,8 +19,9 @@ package framework import ( "encoding/json" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" diff --git a/pkg/plugin/framework/restore_item_action_server.go b/pkg/plugin/framework/restore_item_action_server.go index bdc149c48..175a941bd 100644 --- a/pkg/plugin/framework/restore_item_action_server.go +++ b/pkg/plugin/framework/restore_item_action_server.go @@ -19,8 +19,9 @@ package framework import ( "encoding/json" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" diff --git a/pkg/plugin/framework/restoreitemaction/v2/restore_item_action.go b/pkg/plugin/framework/restoreitemaction/v2/restore_item_action.go index 243e2fd67..00bb825b8 100644 --- a/pkg/plugin/framework/restoreitemaction/v2/restore_item_action.go +++ b/pkg/plugin/framework/restoreitemaction/v2/restore_item_action.go @@ -17,8 +17,9 @@ limitations under the License. package v2 import ( + "context" + plugin "github.com/hashicorp/go-plugin" - "golang.org/x/net/context" "google.golang.org/grpc" "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" diff --git a/pkg/plugin/framework/restoreitemaction/v2/restore_item_action_client.go b/pkg/plugin/framework/restoreitemaction/v2/restore_item_action_client.go index b1d61fb75..5e2f01c37 100644 --- a/pkg/plugin/framework/restoreitemaction/v2/restore_item_action_client.go +++ b/pkg/plugin/framework/restoreitemaction/v2/restore_item_action_client.go @@ -19,8 +19,9 @@ package v2 import ( "encoding/json" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" diff --git a/pkg/plugin/framework/restoreitemaction/v2/restore_item_action_server.go b/pkg/plugin/framework/restoreitemaction/v2/restore_item_action_server.go index 2795d787d..115961656 100644 --- a/pkg/plugin/framework/restoreitemaction/v2/restore_item_action_server.go +++ b/pkg/plugin/framework/restoreitemaction/v2/restore_item_action_server.go @@ -19,8 +19,9 @@ package v2 import ( "encoding/json" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/emptypb" "google.golang.org/protobuf/types/known/timestamppb" diff --git a/pkg/plugin/framework/volume_snapshotter.go b/pkg/plugin/framework/volume_snapshotter.go index 5eb6159eb..8cbb48fa4 100644 --- a/pkg/plugin/framework/volume_snapshotter.go +++ b/pkg/plugin/framework/volume_snapshotter.go @@ -17,8 +17,9 @@ limitations under the License. package framework import ( + "context" + plugin "github.com/hashicorp/go-plugin" - "golang.org/x/net/context" "google.golang.org/grpc" "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" diff --git a/pkg/plugin/framework/volume_snapshotter_client.go b/pkg/plugin/framework/volume_snapshotter_client.go index da66f2cea..f7af07ce4 100644 --- a/pkg/plugin/framework/volume_snapshotter_client.go +++ b/pkg/plugin/framework/volume_snapshotter_client.go @@ -19,8 +19,9 @@ package framework import ( "encoding/json" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" diff --git a/pkg/plugin/framework/volume_snapshotter_server.go b/pkg/plugin/framework/volume_snapshotter_server.go index 99bdea03a..de30c823f 100644 --- a/pkg/plugin/framework/volume_snapshotter_server.go +++ b/pkg/plugin/framework/volume_snapshotter_server.go @@ -19,8 +19,9 @@ package framework import ( "encoding/json" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "github.com/vmware-tanzu/velero/pkg/plugin/framework/common" diff --git a/pkg/util/kube/periodical_enqueue_source_test.go b/pkg/util/kube/periodical_enqueue_source_test.go index 677ec90e1..ee892b54b 100644 --- a/pkg/util/kube/periodical_enqueue_source_test.go +++ b/pkg/util/kube/periodical_enqueue_source_test.go @@ -20,9 +20,10 @@ import ( "testing" "time" + "context" + "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" - "golang.org/x/net/context" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" diff --git a/test/util/eks/eks.go b/test/util/eks/eks.go index ff3df3c31..f2e491c1f 100644 --- a/test/util/eks/eks.go +++ b/test/util/eks/eks.go @@ -22,7 +22,8 @@ import ( "strings" "time" - "golang.org/x/net/context" + "context" + "k8s.io/apimachinery/pkg/util/wait" veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec" diff --git a/test/util/k8s/clusterrolebinding.go b/test/util/k8s/clusterrolebinding.go index c7ce32e31..e682c0bdc 100644 --- a/test/util/k8s/clusterrolebinding.go +++ b/test/util/k8s/clusterrolebinding.go @@ -21,7 +21,7 @@ import ( "os/exec" "strings" - "golang.org/x/net/context" + "context" veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec" ) diff --git a/test/util/k8s/common.go b/test/util/k8s/common.go index 3e0c553ce..8869caab3 100644 --- a/test/util/k8s/common.go +++ b/test/util/k8s/common.go @@ -23,8 +23,9 @@ import ( "strings" "time" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" corev1api "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" diff --git a/test/util/k8s/configmap.go b/test/util/k8s/configmap.go index b03bcdb99..39bcb0907 100644 --- a/test/util/k8s/configmap.go +++ b/test/util/k8s/configmap.go @@ -20,9 +20,10 @@ import ( "fmt" "time" + "context" + "github.com/pkg/errors" "github.com/sirupsen/logrus" - "golang.org/x/net/context" corev1api "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/test/util/k8s/crd.go b/test/util/k8s/crd.go index 3b46ddbb0..fe17fb0ae 100644 --- a/test/util/k8s/crd.go +++ b/test/util/k8s/crd.go @@ -22,8 +22,9 @@ import ( "strings" "time" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec" ) diff --git a/test/util/k8s/deployment.go b/test/util/k8s/deployment.go index 9c570aee1..42e2d6ac7 100644 --- a/test/util/k8s/deployment.go +++ b/test/util/k8s/deployment.go @@ -21,7 +21,8 @@ import ( "path" "time" - "golang.org/x/net/context" + "context" + appsv1api "k8s.io/api/apps/v1" corev1api "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/test/util/k8s/secret.go b/test/util/k8s/secret.go index ed3eaf834..ea02f51d0 100644 --- a/test/util/k8s/secret.go +++ b/test/util/k8s/secret.go @@ -20,9 +20,10 @@ import ( "fmt" "time" + "context" + "github.com/pkg/errors" "github.com/sirupsen/logrus" - "golang.org/x/net/context" corev1api "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/test/util/k8s/statefulset.go b/test/util/k8s/statefulset.go index e9a1e564d..f0ac3a651 100644 --- a/test/util/k8s/statefulset.go +++ b/test/util/k8s/statefulset.go @@ -20,8 +20,9 @@ import ( "fmt" "os/exec" + "context" + "github.com/pkg/errors" - "golang.org/x/net/context" veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec" ) diff --git a/test/util/kibishii/kibishii_utils.go b/test/util/kibishii/kibishii_utils.go index 81be36cff..5948a2c7b 100644 --- a/test/util/kibishii/kibishii_utils.go +++ b/test/util/kibishii/kibishii_utils.go @@ -26,9 +26,10 @@ import ( "strings" "time" + "context" + . "github.com/onsi/ginkgo/v2" "github.com/pkg/errors" - "golang.org/x/net/context" appsv1api "k8s.io/api/apps/v1" corev1api "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/wait" diff --git a/test/util/providers/aws_utils.go b/test/util/providers/aws_utils.go index d40a2bec2..7b8916cef 100644 --- a/test/util/providers/aws_utils.go +++ b/test/util/providers/aws_utils.go @@ -26,6 +26,8 @@ import ( "os" "strings" + "context" + "github.com/aws/aws-sdk-go-v2/aws" awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" "github.com/aws/aws-sdk-go-v2/config" @@ -35,7 +37,6 @@ import ( "github.com/aws/aws-sdk-go-v2/service/s3" s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/pkg/errors" - "golang.org/x/net/context" "github.com/vmware-tanzu/velero/pkg/cmd/util/flag" "github.com/vmware-tanzu/velero/test" diff --git a/test/util/providers/azure_utils.go b/test/util/providers/azure_utils.go index 439c1e9e7..468dbfe40 100644 --- a/test/util/providers/azure_utils.go +++ b/test/util/providers/azure_utils.go @@ -23,6 +23,8 @@ import ( "os" "strings" + "context" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" @@ -36,7 +38,6 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container" "github.com/joho/godotenv" "github.com/pkg/errors" - "golang.org/x/net/context" "github.com/vmware-tanzu/velero/pkg/cmd/util/flag" . "github.com/vmware-tanzu/velero/test" diff --git a/test/util/providers/gcloud_utils.go b/test/util/providers/gcloud_utils.go index 99e60a61e..022d92ff2 100644 --- a/test/util/providers/gcloud_utils.go +++ b/test/util/providers/gcloud_utils.go @@ -23,9 +23,10 @@ import ( "os" "strings" + "context" + "cloud.google.com/go/storage" "github.com/pkg/errors" - "golang.org/x/net/context" "golang.org/x/oauth2/google" "google.golang.org/api/compute/v1" "google.golang.org/api/iterator" From e63486b677eb9a9aeccebb6bc0b68274d2446333 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Mon, 24 Nov 2025 17:26:59 +0800 Subject: [PATCH 101/104] fix-linter-error Signed-off-by: Lyndon-Li --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index b06ccdd68..28009e8fc 100644 --- a/go.mod +++ b/go.mod @@ -42,7 +42,6 @@ require ( github.com/vmware-tanzu/crash-diagnostics v0.3.7 go.uber.org/zap v1.27.0 golang.org/x/mod v0.29.0 - golang.org/x/net v0.47.0 golang.org/x/oauth2 v0.30.0 golang.org/x/text v0.31.0 google.golang.org/api v0.241.0 @@ -182,6 +181,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.45.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/net v0.47.0 // indirect golang.org/x/sync v0.18.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/term v0.37.0 // indirect From 981b29b4cb8836e06dfed062313be8fd09fabd9d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Nov 2025 19:25:51 +0000 Subject: [PATCH 102/104] Bump actions/checkout from 5 to 6 Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/e2e-test-kind.yaml | 4 ++-- .github/workflows/get-go-version.yaml | 2 +- .github/workflows/nightly-trivy-scan.yml | 2 +- .github/workflows/pr-changelog-check.yml | 2 +- .github/workflows/pr-ci-check.yml | 2 +- .github/workflows/pr-codespell.yml | 2 +- .github/workflows/pr-containers.yml | 2 +- .github/workflows/pr-goreleaser.yml | 2 +- .github/workflows/pr-linter-check.yml | 2 +- .github/workflows/push-builder.yml | 2 +- .github/workflows/push.yml | 2 +- .github/workflows/rebase.yml | 2 +- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/e2e-test-kind.yaml b/.github/workflows/e2e-test-kind.yaml index db774e409..033e93370 100644 --- a/.github/workflows/e2e-test-kind.yaml +++ b/.github/workflows/e2e-test-kind.yaml @@ -21,7 +21,7 @@ jobs: minio-dockerfile-sha: ${{ steps.minio-version.outputs.dockerfile_sha }} steps: - name: Check out the code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up Go version uses: actions/setup-go@v6 @@ -112,7 +112,7 @@ jobs: fail-fast: false steps: - name: Check out the code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up Go version uses: actions/setup-go@v6 diff --git a/.github/workflows/get-go-version.yaml b/.github/workflows/get-go-version.yaml index 3bc3f8e53..4f14a352c 100644 --- a/.github/workflows/get-go-version.yaml +++ b/.github/workflows/get-go-version.yaml @@ -17,7 +17,7 @@ jobs: version: ${{ steps.pick-version.outputs.version }} steps: - name: Check out the code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - id: pick-version run: | diff --git a/.github/workflows/nightly-trivy-scan.yml b/.github/workflows/nightly-trivy-scan.yml index dc8363e39..0f5fe0a68 100644 --- a/.github/workflows/nightly-trivy-scan.yml +++ b/.github/workflows/nightly-trivy-scan.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master diff --git a/.github/workflows/pr-changelog-check.yml b/.github/workflows/pr-changelog-check.yml index 6cda5a63e..0f296853a 100644 --- a/.github/workflows/pr-changelog-check.yml +++ b/.github/workflows/pr-changelog-check.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Check out the code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Changelog check if: ${{ !(contains(github.event.pull_request.labels.*.name, 'kind/changelog-not-required') || contains(github.event.pull_request.labels.*.name, 'Design') || contains(github.event.pull_request.labels.*.name, 'Website') || contains(github.event.pull_request.labels.*.name, 'Documentation'))}} diff --git a/.github/workflows/pr-ci-check.yml b/.github/workflows/pr-ci-check.yml index c97f216b4..aea136329 100644 --- a/.github/workflows/pr-ci-check.yml +++ b/.github/workflows/pr-ci-check.yml @@ -14,7 +14,7 @@ jobs: fail-fast: false steps: - name: Check out the code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up Go version uses: actions/setup-go@v6 diff --git a/.github/workflows/pr-codespell.yml b/.github/workflows/pr-codespell.yml index 9f8e44825..65d2a1885 100644 --- a/.github/workflows/pr-codespell.yml +++ b/.github/workflows/pr-codespell.yml @@ -8,7 +8,7 @@ jobs: steps: - name: Check out the code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Codespell uses: codespell-project/actions-codespell@master diff --git a/.github/workflows/pr-containers.yml b/.github/workflows/pr-containers.yml index 0f1823f8a..6f839a166 100644 --- a/.github/workflows/pr-containers.yml +++ b/.github/workflows/pr-containers.yml @@ -13,7 +13,7 @@ jobs: name: Build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 name: Checkout - name: Set up QEMU diff --git a/.github/workflows/pr-goreleaser.yml b/.github/workflows/pr-goreleaser.yml index 2fdc5bc6e..5215a5bfb 100644 --- a/.github/workflows/pr-goreleaser.yml +++ b/.github/workflows/pr-goreleaser.yml @@ -14,7 +14,7 @@ jobs: name: Build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 name: Checkout - name: Verify .goreleaser.yml and try a dryrun release. diff --git a/.github/workflows/pr-linter-check.yml b/.github/workflows/pr-linter-check.yml index 6ff4a0367..13205bcd8 100644 --- a/.github/workflows/pr-linter-check.yml +++ b/.github/workflows/pr-linter-check.yml @@ -18,7 +18,7 @@ jobs: needs: get-go-version steps: - name: Check out the code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up Go version uses: actions/setup-go@v6 diff --git a/.github/workflows/push-builder.yml b/.github/workflows/push-builder.yml index 0663ffd2f..2272ee3f1 100644 --- a/.github/workflows/push-builder.yml +++ b/.github/workflows/push-builder.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: # The default value is "1" which fetches only a single commit. If we merge PR without squash or rebase, # there are at least two commits: the first one is the merge commit and the second one is the real commit diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index c82689cc6..e0c32e189 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -20,7 +20,7 @@ jobs: needs: get-go-version steps: - name: Check out the code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up Go version uses: actions/setup-go@v6 diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml index e7cd1fccb..07c86b534 100644 --- a/.github/workflows/rebase.yml +++ b/.github/workflows/rebase.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the latest code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 - name: Automatic Rebase From 758f6a48475bc154dae281f64e62305be855b698 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Mon, 24 Nov 2025 18:58:05 +0800 Subject: [PATCH 103/104] Bump Golang version from 1.24-bookworm to 1.25-bookworm Bump golangci-lint to v1.25.0, because golangci-lint start to support Golang v1.25 since v1.24.0, and v1.26.x was not stable yet. Align action pr-linter-check's golangci-lint version to v1.25.0 Signed-off-by: Xun Jiang --- .github/workflows/pr-linter-check.yml | 2 +- Dockerfile | 4 ++-- Dockerfile-Windows | 2 +- Tiltfile | 2 +- go.mod | 2 +- hack/build-image/Dockerfile | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/pr-linter-check.yml b/.github/workflows/pr-linter-check.yml index 13205bcd8..79d7918b2 100644 --- a/.github/workflows/pr-linter-check.yml +++ b/.github/workflows/pr-linter-check.yml @@ -28,5 +28,5 @@ jobs: - name: Linter check uses: golangci/golangci-lint-action@v9 with: - version: v2.1.1 + version: v2.5.0 args: --verbose diff --git a/Dockerfile b/Dockerfile index 94d7ceb9c..6ce46ca3b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,7 @@ # limitations under the License. # Velero binary build section -FROM --platform=$BUILDPLATFORM golang:1.24-bookworm AS velero-builder +FROM --platform=$BUILDPLATFORM golang:1.25-bookworm AS velero-builder ARG GOPROXY ARG BIN @@ -49,7 +49,7 @@ RUN mkdir -p /output/usr/bin && \ go clean -modcache -cache # Restic binary build section -FROM --platform=$BUILDPLATFORM golang:1.24-bookworm AS restic-builder +FROM --platform=$BUILDPLATFORM golang:1.25-bookworm AS restic-builder ARG GOPROXY ARG BIN diff --git a/Dockerfile-Windows b/Dockerfile-Windows index d20ab7748..ac22531dc 100644 --- a/Dockerfile-Windows +++ b/Dockerfile-Windows @@ -15,7 +15,7 @@ ARG OS_VERSION=1809 # Velero binary build section -FROM --platform=$BUILDPLATFORM golang:1.24-bookworm AS velero-builder +FROM --platform=$BUILDPLATFORM golang:1.25-bookworm AS velero-builder ARG GOPROXY ARG BIN diff --git a/Tiltfile b/Tiltfile index fd0879cd4..7f2029f6d 100644 --- a/Tiltfile +++ b/Tiltfile @@ -52,7 +52,7 @@ git_sha = str(local("git rev-parse HEAD", quiet = True, echo_off = True)).strip( tilt_helper_dockerfile_header = """ # Tilt image -FROM golang:1.24 as tilt-helper +FROM golang:1.25 as tilt-helper # Support live reloading with Tilt RUN wget --output-document /restart.sh --quiet https://raw.githubusercontent.com/windmilleng/rerun-process-wrapper/master/restart.sh && \ diff --git a/go.mod b/go.mod index 28009e8fc..0dccd1af3 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/vmware-tanzu/velero -go 1.24.0 +go 1.25.0 require ( cloud.google.com/go/storage v1.55.0 diff --git a/hack/build-image/Dockerfile b/hack/build-image/Dockerfile index 9e8153e73..68a34fbf0 100644 --- a/hack/build-image/Dockerfile +++ b/hack/build-image/Dockerfile @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM --platform=$TARGETPLATFORM golang:1.24-bookworm +FROM --platform=$TARGETPLATFORM golang:1.25-bookworm ARG GOPROXY @@ -94,7 +94,7 @@ RUN ARCH=$(go env GOARCH) && \ chmod +x /usr/bin/goreleaser # get golangci-lint -RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.1.1 +RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.5.0 # install kubectl RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/$(go env GOARCH)/kubectl From 64e3643006025df9483115e79e53574a96eb80d3 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Tue, 25 Nov 2025 01:01:49 +0800 Subject: [PATCH 104/104] Fix linter error reported. Signed-off-by: Xun Jiang --- pkg/cmd/cli/backup/delete_test.go | 2 +- pkg/cmd/cli/backup/describe_test.go | 2 +- pkg/cmd/cli/backup/download_test.go | 2 +- pkg/cmd/cli/backup/get_test.go | 4 ++-- pkg/cmd/cli/backuplocation/delete_test.go | 2 +- pkg/cmd/cli/backuplocation/get_test.go | 2 +- pkg/cmd/cli/backuplocation/set_test.go | 2 +- pkg/cmd/cli/bug/bug.go | 10 ++++++---- pkg/cmd/cli/restore/delete_test.go | 2 +- pkg/cmd/cli/restore/describe_test.go | 2 +- pkg/cmd/cli/restore/get_test.go | 2 +- pkg/install/import_test.go | 3 ++- pkg/plugin/clientmgmt/process/client_builder.go | 3 ++- pkg/plugin/clientmgmt/process/client_builder_test.go | 6 ++++-- pkg/plugin/framework/import_test.go | 3 ++- pkg/restic/command.go | 2 +- test/e2e/migration/migration.go | 1 + test/e2e/upgrade/upgrade.go | 5 ++++- test/util/common/common.go | 2 +- test/util/velero/velero_utils.go | 6 +++--- 20 files changed, 37 insertions(+), 26 deletions(-) diff --git a/pkg/cmd/cli/backup/delete_test.go b/pkg/cmd/cli/backup/delete_test.go index 85718541c..3278e8153 100644 --- a/pkg/cmd/cli/backup/delete_test.go +++ b/pkg/cmd/cli/backup/delete_test.go @@ -75,7 +75,7 @@ func TestDeleteCommand(t *testing.T) { return } - cmd := exec.Command(os.Args[0], []string{"-test.run=TestDeleteCommand"}...) + cmd := exec.CommandContext(t.Context(), os.Args[0], []string{"-test.run=TestDeleteCommand"}...) cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", cmdtest.CaptureFlag)) stdout, _, err := veleroexec.RunCommand(cmd) if err != nil { diff --git a/pkg/cmd/cli/backup/describe_test.go b/pkg/cmd/cli/backup/describe_test.go index 7ca12ae3e..5d5486473 100644 --- a/pkg/cmd/cli/backup/describe_test.go +++ b/pkg/cmd/cli/backup/describe_test.go @@ -63,7 +63,7 @@ func TestNewDescribeCommand(t *testing.T) { if os.Getenv(cmdtest.CaptureFlag) == "1" { return } - cmd := exec.Command(os.Args[0], []string{"-test.run=TestNewDescribeCommand"}...) + cmd := exec.CommandContext(t.Context(), os.Args[0], []string{"-test.run=TestNewDescribeCommand"}...) cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", cmdtest.CaptureFlag)) stdout, _, err := veleroexec.RunCommand(cmd) diff --git a/pkg/cmd/cli/backup/download_test.go b/pkg/cmd/cli/backup/download_test.go index aaada0db3..999799ff3 100644 --- a/pkg/cmd/cli/backup/download_test.go +++ b/pkg/cmd/cli/backup/download_test.go @@ -91,7 +91,7 @@ func TestNewDownloadCommand(t *testing.T) { assert.NoError(t, e) return } - cmd := exec.Command(os.Args[0], []string{"-test.run=TestNewDownloadCommand"}...) + cmd := exec.CommandContext(t.Context(), os.Args[0], []string{"-test.run=TestNewDownloadCommand"}...) cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", cmdtest.CaptureFlag)) _, stderr, err := veleroexec.RunCommand(cmd) diff --git a/pkg/cmd/cli/backup/get_test.go b/pkg/cmd/cli/backup/get_test.go index 511c33f51..28c41a6de 100644 --- a/pkg/cmd/cli/backup/get_test.go +++ b/pkg/cmd/cli/backup/get_test.go @@ -63,7 +63,7 @@ func TestNewGetCommand(t *testing.T) { return } - cmd := exec.Command(os.Args[0], []string{"-test.run=TestNewGetCommand"}...) + cmd := exec.CommandContext(t.Context(), os.Args[0], []string{"-test.run=TestNewGetCommand"}...) cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", cmdtest.CaptureFlag)) stdout, _, err := veleroexec.RunCommand(cmd) require.NoError(t, err) @@ -84,7 +84,7 @@ func TestNewGetCommand(t *testing.T) { e = d.Execute() require.NoError(t, e) - cmd = exec.Command(os.Args[0], []string{"-test.run=TestNewGetCommand"}...) + cmd = exec.CommandContext(t.Context(), os.Args[0], []string{"-test.run=TestNewGetCommand"}...) cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", cmdtest.CaptureFlag)) stdout, _, err = veleroexec.RunCommand(cmd) require.NoError(t, err) diff --git a/pkg/cmd/cli/backuplocation/delete_test.go b/pkg/cmd/cli/backuplocation/delete_test.go index cbc09c514..70ff7568b 100644 --- a/pkg/cmd/cli/backuplocation/delete_test.go +++ b/pkg/cmd/cli/backuplocation/delete_test.go @@ -66,7 +66,7 @@ func TestNewDeleteCommand(t *testing.T) { return } - cmd := exec.Command(os.Args[0], []string{"-test.run=TestNewDeleteCommand"}...) + cmd := exec.CommandContext(t.Context(), os.Args[0], []string{"-test.run=TestNewDeleteCommand"}...) cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", cmdtest.CaptureFlag)) stdout, _, err := veleroexec.RunCommand(cmd) diff --git a/pkg/cmd/cli/backuplocation/get_test.go b/pkg/cmd/cli/backuplocation/get_test.go index 2e4c5510c..d45231fce 100644 --- a/pkg/cmd/cli/backuplocation/get_test.go +++ b/pkg/cmd/cli/backuplocation/get_test.go @@ -50,7 +50,7 @@ func TestNewGetCommand(t *testing.T) { c.Execute() return } - cmd := exec.Command(os.Args[0], []string{"-test.run=TestNewGetCommand"}...) + cmd := exec.CommandContext(t.Context(), os.Args[0], []string{"-test.run=TestNewGetCommand"}...) cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", cmdtest.CaptureFlag)) _, stderr, err := veleroexec.RunCommand(cmd) diff --git a/pkg/cmd/cli/backuplocation/set_test.go b/pkg/cmd/cli/backuplocation/set_test.go index 4b35693af..0ebf8a8d3 100644 --- a/pkg/cmd/cli/backuplocation/set_test.go +++ b/pkg/cmd/cli/backuplocation/set_test.go @@ -99,7 +99,7 @@ func TestSetCommand_Execute(t *testing.T) { return } - cmd := exec.Command(os.Args[0], []string{"-test.run=TestSetCommand_Execute"}...) + cmd := exec.CommandContext(t.Context(), os.Args[0], []string{"-test.run=TestSetCommand_Execute"}...) cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", cmdtest.CaptureFlag)) _, stderr, err := veleroexec.RunCommand(cmd) diff --git a/pkg/cmd/cli/bug/bug.go b/pkg/cmd/cli/bug/bug.go index 9f87e3f5a..33fbb38b7 100644 --- a/pkg/cmd/cli/bug/bug.go +++ b/pkg/cmd/cli/bug/bug.go @@ -18,6 +18,7 @@ package bug import ( "bytes" + "context" "errors" "fmt" "net/url" @@ -147,7 +148,7 @@ func getKubectlVersion() (string, error) { return "", errors.New("kubectl not found on PATH") } - kubectlCmd := exec.Command("kubectl", "version") + kubectlCmd := exec.CommandContext(context.Background(), "kubectl", "version") var outbuf bytes.Buffer kubectlCmd.Stdout = &outbuf if err := kubectlCmd.Start(); err != nil { @@ -207,16 +208,17 @@ func renderToString(bugInfo *VeleroBugInfo) (string, error) { // a platform specific binary. func showIssueInBrowser(body string) error { url := issueURL + "?body=" + url.QueryEscape(body) + ctx := context.Background() switch runtime.GOOS { case "darwin": - return exec.Command("open", url).Start() + return exec.CommandContext(ctx, "open", url).Start() case "linux": if cmdExistsOnPath("xdg-open") { - return exec.Command("xdg-open", url).Start() + return exec.CommandContext(ctx, "xdg-open", url).Start() } return fmt.Errorf("velero can't open a browser window using the command '%s'", "xdg-open") case "windows": - return exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start() + return exec.CommandContext(ctx, "rundll32", "url.dll,FileProtocolHandler", url).Start() default: return fmt.Errorf("velero can't open a browser window on platform %s", runtime.GOOS) } diff --git a/pkg/cmd/cli/restore/delete_test.go b/pkg/cmd/cli/restore/delete_test.go index 9085e4cd9..e98f9b804 100644 --- a/pkg/cmd/cli/restore/delete_test.go +++ b/pkg/cmd/cli/restore/delete_test.go @@ -75,7 +75,7 @@ func TestDeleteCommand(t *testing.T) { return } - cmd := exec.Command(os.Args[0], []string{"-test.run=TestDeleteCommand"}...) + cmd := exec.CommandContext(t.Context(), os.Args[0], []string{"-test.run=TestDeleteCommand"}...) cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", cmdtest.CaptureFlag)) stdout, _, err := veleroexec.RunCommand(cmd) if err != nil { diff --git a/pkg/cmd/cli/restore/describe_test.go b/pkg/cmd/cli/restore/describe_test.go index 717fe2b7c..7c2ffe5f8 100644 --- a/pkg/cmd/cli/restore/describe_test.go +++ b/pkg/cmd/cli/restore/describe_test.go @@ -63,7 +63,7 @@ func TestNewDescribeCommand(t *testing.T) { if os.Getenv(cmdtest.CaptureFlag) == "1" { return } - cmd := exec.Command(os.Args[0], []string{"-test.run=TestNewDescribeCommand"}...) + cmd := exec.CommandContext(t.Context(), os.Args[0], []string{"-test.run=TestNewDescribeCommand"}...) cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", cmdtest.CaptureFlag)) stdout, _, err := veleroexec.RunCommand(cmd) diff --git a/pkg/cmd/cli/restore/get_test.go b/pkg/cmd/cli/restore/get_test.go index df2c25488..22b10e152 100644 --- a/pkg/cmd/cli/restore/get_test.go +++ b/pkg/cmd/cli/restore/get_test.go @@ -62,7 +62,7 @@ func TestNewGetCommand(t *testing.T) { return } - cmd := exec.Command(os.Args[0], []string{"-test.run=TestNewGetCommand"}...) + cmd := exec.CommandContext(t.Context(), os.Args[0], []string{"-test.run=TestNewGetCommand"}...) cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", cmdtest.CaptureFlag)) stdout, _, err := veleroexec.RunCommand(cmd) require.NoError(t, err) diff --git a/pkg/install/import_test.go b/pkg/install/import_test.go index ae5e8b41d..e77befe46 100644 --- a/pkg/install/import_test.go +++ b/pkg/install/import_test.go @@ -22,7 +22,8 @@ func TestPkgImportNoCloudProvider(t *testing.T) { t.Logf("Current test file path: %s", filename) t.Logf("Current test directory: %s", filepath.Dir(filename)) // should be this package name // go list -f {{.Deps}} ./ - cmd := exec.Command( + cmd := exec.CommandContext( + t.Context(), "go", "list", "-f", diff --git a/pkg/plugin/clientmgmt/process/client_builder.go b/pkg/plugin/clientmgmt/process/client_builder.go index 5bffa5259..ceeac8db7 100644 --- a/pkg/plugin/clientmgmt/process/client_builder.go +++ b/pkg/plugin/clientmgmt/process/client_builder.go @@ -18,6 +18,7 @@ limitations under the License. package process import ( + "context" "os" "os/exec" @@ -78,7 +79,7 @@ func (b *clientBuilder) clientConfig() *hcplugin.ClientConfig { string(common.PluginKindItemBlockAction): ibav1.NewItemBlockActionPlugin(common.ClientLogger(b.clientLogger)), }, Logger: b.pluginLogger, - Cmd: exec.Command(b.commandName, b.commandArgs...), //nolint:gosec // Internal call. No need to check the command line. + Cmd: exec.CommandContext(context.Background(), b.commandName, b.commandArgs...), //nolint:gosec // Internal call. No need to check the command line. } } diff --git a/pkg/plugin/clientmgmt/process/client_builder_test.go b/pkg/plugin/clientmgmt/process/client_builder_test.go index d92addf76..14278ae8f 100644 --- a/pkg/plugin/clientmgmt/process/client_builder_test.go +++ b/pkg/plugin/clientmgmt/process/client_builder_test.go @@ -65,9 +65,11 @@ func TestClientConfig(t *testing.T) { string(common.PluginKindItemBlockAction): ibav1.NewItemBlockActionPlugin(common.ClientLogger(logger)), }, Logger: cb.pluginLogger, - Cmd: exec.Command(cb.commandName, cb.commandArgs...), + Cmd: exec.CommandContext(t.Context(), cb.commandName, cb.commandArgs...), } cc := cb.clientConfig() - assert.Equal(t, expected, cc) + assert.Equal(t, expected.HandshakeConfig, cc.HandshakeConfig) + assert.Equal(t, expected.AllowedProtocols, cc.AllowedProtocols) + assert.Equal(t, expected.Plugins, cc.Plugins) } diff --git a/pkg/plugin/framework/import_test.go b/pkg/plugin/framework/import_test.go index 29be81122..ee1439329 100644 --- a/pkg/plugin/framework/import_test.go +++ b/pkg/plugin/framework/import_test.go @@ -22,7 +22,8 @@ func TestPkgImportNoCloudProvider(t *testing.T) { t.Logf("Current test file path: %s", filename) t.Logf("Current test directory: %s", filepath.Dir(filename)) // should be this package name // go list -f {{.Deps}} ./ - cmd := exec.Command( + cmd := exec.CommandContext( + t.Context(), "go", "list", "-f", diff --git a/pkg/restic/command.go b/pkg/restic/command.go index ef0ba5655..feb41642d 100644 --- a/pkg/restic/command.go +++ b/pkg/restic/command.go @@ -77,7 +77,7 @@ func (c *Command) String() string { // Cmd returns an exec.Cmd for the command. func (c *Command) Cmd() *exec.Cmd { parts := c.StringSlice() - cmd := exec.Command(parts[0], parts[1:]...) //nolint:gosec // Internal call. No need to check the parameter. + cmd := exec.Command(parts[0], parts[1:]...) //nolint:gosec,noctx // Internal call. No need to check the parameter. No to add context for deprecated Restic. cmd.Dir = c.Dir if len(c.Env) > 0 { diff --git a/test/e2e/migration/migration.go b/test/e2e/migration/migration.go index f91bcffff..08f1bac00 100644 --- a/test/e2e/migration/migration.go +++ b/test/e2e/migration/migration.go @@ -142,6 +142,7 @@ func (m *migrationE2E) Backup() error { "Fail to set images for the migrate-from Velero installation.") m.veleroCLI2Version.VeleroCLI, err = veleroutil.InstallVeleroCLI( + m.Ctx, m.veleroCLI2Version.VeleroVersion) Expect(err).To(Succeed()) } diff --git a/test/e2e/upgrade/upgrade.go b/test/e2e/upgrade/upgrade.go index 6832c160c..6d081f1c1 100644 --- a/test/e2e/upgrade/upgrade.go +++ b/test/e2e/upgrade/upgrade.go @@ -115,7 +115,10 @@ func BackupUpgradeRestoreTest(useVolumeSnapshots bool, veleroCLI2Version VeleroC //Download velero CLI if it's empty according to velero CLI version By(fmt.Sprintf("Install the expected old version Velero CLI (%s) for installing Velero", veleroCLI2Version.VeleroVersion), func() { - veleroCLI2Version.VeleroCLI, err = InstallVeleroCLI(veleroCLI2Version.VeleroVersion) + veleroCLI2Version.VeleroCLI, err = InstallVeleroCLI( + oneHourTimeout, + veleroCLI2Version.VeleroVersion, + ) Expect(err).To(Succeed()) }) } diff --git a/test/util/common/common.go b/test/util/common/common.go index b49c61e50..561f75040 100644 --- a/test/util/common/common.go +++ b/test/util/common/common.go @@ -33,7 +33,7 @@ func GetListByCmdPipes(ctx context.Context, cmdLines []*OsCommandLine) ([]string var cmds []*exec.Cmd for _, cmdline := range cmdLines { - cmd := exec.Command(cmdline.Cmd, cmdline.Args...) + cmd := exec.CommandContext(ctx, cmdline.Cmd, cmdline.Args...) cmds = append(cmds, cmd) } fmt.Println(cmds) diff --git a/test/util/velero/velero_utils.go b/test/util/velero/velero_utils.go index 65f56bf03..8dbcbb2bd 100644 --- a/test/util/velero/velero_utils.go +++ b/test/util/velero/velero_utils.go @@ -915,12 +915,12 @@ func CheckVeleroVersion(ctx context.Context, veleroCLI string, expectedVer strin return nil } -func InstallVeleroCLI(version string) (string, error) { +func InstallVeleroCLI(ctx context.Context, version string) (string, error) { var tempVeleroCliDir string name := "velero-" + version + "-" + runtime.GOOS + "-" + runtime.GOARCH postfix := ".tar.gz" tarball := name + postfix - err := wait.PollImmediate(time.Second*5, time.Minute*5, func() (bool, error) { + err := wait.PollUntilContextTimeout(ctx, time.Second*5, time.Minute*5, true, func(ctx context.Context) (bool, error) { tempFile, err := getVeleroCliTarball("https://github.com/vmware-tanzu/velero/releases/download/" + version + "/" + tarball) if err != nil { return false, errors.WithMessagef(err, "failed to get Velero CLI tarball") @@ -930,7 +930,7 @@ func InstallVeleroCLI(version string) (string, error) { return false, errors.WithMessagef(err, "failed to create temp dir for tarball extraction") } - cmd := exec.Command("tar", "-xvf", tempFile.Name(), "-C", tempVeleroCliDir) + cmd := exec.CommandContext(ctx, "tar", "-xvf", tempFile.Name(), "-C", tempVeleroCliDir) defer os.Remove(tempFile.Name()) if _, err := cmd.Output(); err != nil {

    AjI(EJ}}d3T-=| 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�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