Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CPDEV-93171] - do not export kubernetes resources by default #553

Merged
merged 2 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions documentation/Maintenance.md
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ The `upgrade` procedure executes the following sequence of tasks:
The backup procedure automatically saves the following entities:
* ETCD snapshot
* Files and configs from cluster nodes
* Kubernetes resources
* Kubernetes resources (if it's configured in procedure.yaml)

As a result of the procedure, you receive an archive with all the stored objects inside. The archive has approximately the following structure inside:

Expand Down Expand Up @@ -585,7 +585,7 @@ backup_plan:

#### kubernetes Parameter

The procedure exports all available Kubernetes resources from the cluster to yaml files. There are two types of resources - namespaced and non-namespaced. If you need to restrict resources for export, you can specify which ones you need.
The procedure can export any available Kubernetes resources from the cluster to yaml files. There are two types of resources - namespaced and non-namespaced. If you need to export resources, you can specify which ones you need. By default, **no** resources from **all** namespaces are exported.

**Note**: If the specified resource is missing, it is skipped without an error.

Expand Down Expand Up @@ -630,6 +630,16 @@ backup_plan:
nonnamespaced_resources: all
```

If you do not specify `backup_plan.kubernetes`, the following configuration will be used:
```yaml
backup_plan:
kubernetes:
namespaced_resources:
namespaces: all
resources: []
nonnamespaced_resources: []
```

### Backup Procedure Tasks Tree

The `backup` procedure executes the following sequence of tasks:
Expand Down
8 changes: 6 additions & 2 deletions kubemarine/procedures/backup.py
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,10 @@ def run(self) -> None:
if task is None:
break

# Skip task with empty resource list
if not task.resources:
continue

random = uuid.uuid4().hex
temp_local_filepath = os.path.join(self.backup_directory, random)
self._download(task, temp_local_filepath)
Expand Down Expand Up @@ -585,12 +589,12 @@ def export_kubernetes(cluster: KubernetesCluster) -> None:

logger.debug('Loading namespaced resource types:')
loaded_resources = _load_resources(logger, control_plane, True)
proposed_resources = backup_kubernetes.get('namespaced_resources', {}).get('resources', 'all')
proposed_resources = backup_kubernetes.get('namespaced_resources', {}).get('resources', [])
namespaced_resources = _filter_resources_by_proposed(logger, loaded_resources, proposed_resources, 'resource')

logger.debug('Loading non-namespaced resource types:')
loaded_resources = _load_resources(logger, control_plane, False)
proposed_resources = backup_kubernetes.get('nonnamespaced_resources', 'all')
proposed_resources = backup_kubernetes.get('nonnamespaced_resources', [])
nonnamespaced_resources = _filter_resources_by_proposed(logger, loaded_resources, proposed_resources, 'resource')

logger.debug('Loading resources:')
Expand Down
2 changes: 1 addition & 1 deletion kubemarine/resources/schemas/backup.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"ListOrEverything": {
"oneOf": [
{"type": "string", "enum": ["all"], "default": "all"},
{"$ref": "definitions/common/utils.json#/definitions/NonEmptySetOfStrings"}
{"$ref": "definitions/common/utils.json#/definitions/SetOfStrings"}
]
}
}
Expand Down
32 changes: 28 additions & 4 deletions test/unit/test_backup.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,27 @@ def tearDown(self):
h.close()
self.tmpdir.cleanup()

def _run(self):
def _run(self, procedure_inventory: dict):
self.resources = demo.FakeResources(self.context, self.inventory,
procedure_inventory=demo.generate_procedure_inventory('backup'),
procedure_inventory=procedure_inventory,
nodes_context=demo.generate_nodes_context(self.inventory),
fake_shell=self.fake_shell)

flow.run_actions(self.resources, [backup.BackupAction()])

def test_export_kubernetes(self):
def test_export_whole_kubernetes(self):
self.args['tasks'] = 'export.kubernetes'
self._stub_load_namespaces()
self._stub_load_resources()

backup_all_procedure = demo.generate_procedure_inventory('backup')
backup_all_procedure.setdefault('backup_plan', {}).setdefault('kubernetes', {})\
.setdefault('namespaced_resources', {}).setdefault('resources', 'all')
backup_all_procedure.setdefault('backup_plan', {}).setdefault('kubernetes', {}) \
.setdefault('nonnamespaced_resources', 'all')

with self._mock_manifest_processor_enrich():
self._run()
self._run(backup_all_procedure)

descriptor = self.resources.last_cluster.context['backup_descriptor']['kubernetes']['resources']
self.assertEqual({'kube-system': ['configmaps', 'configmaps.example.com', 'roles.rbac.authorization.k8s.io']},
Expand Down Expand Up @@ -172,6 +179,23 @@ def test_export_kubernetes(self):
self.assertEqual(expected_context, actual_content,
f"Data in file 'kube-system/roles.rbac.authorization.k8s.io.yaml' is not expected")

def test_export_default_kubernetes(self):
self.args['tasks'] = 'export.kubernetes'
self._stub_load_namespaces()
self._stub_load_resources()

backup_all_procedure = demo.generate_procedure_inventory('backup')

with self._mock_manifest_processor_enrich():
self._run(backup_all_procedure)

descriptor = self.resources.last_cluster.context['backup_descriptor']['kubernetes']['resources']
self.assertEqual({}, descriptor, "Not expected resulting list of resources")

resources_path = Path(self.tmpdir.name) / 'dump' / 'backup' / 'kubernetes_resources'
actual_files = {str(p.relative_to(resources_path)) for p in resources_path.glob("**/*.yaml")}
self.assertFalse(actual_files, "List of files is not empty")

def _parse_yaml(self, data: str):
return utils.yaml_structure_preserver().load(data)

Expand Down