├── .coveragerc
├── .gitignore
├── .gitreview
├── .pre-commit-config.yaml
├── .pylintrc
├── .stestr.conf
├── .zuul.yaml
├── CREDITS.rst
├── FAQ.rst
├── HACKING.rst
├── LICENSE
├── README.rst
├── bindep.txt
├── devstack
├── README.rst
├── gate_hook.sh
├── lib
│ └── freezer
├── local.conf.example
├── plugin.sh
└── settings
├── doc
├── .gitignore
├── README.rst
├── requirements.txt
└── source
│ ├── admin
│ ├── agent-scheduler-install.rst
│ ├── complete-install.rst
│ ├── freezer-api-install.rst
│ ├── freezer-web-ui-install.rst
│ ├── index.rst
│ ├── installation.rst
│ └── operation.rst
│ ├── cli
│ ├── freezer-agent.rst
│ ├── freezer-scheduler.rst
│ └── index.rst
│ ├── conf.py
│ ├── contributor
│ ├── actions.rst
│ ├── api_documents.rst
│ ├── api_routes.rst
│ ├── client_structure.rst
│ ├── index.rst
│ ├── jobs.rst
│ ├── metadata_structure.rst
│ └── sessions.rst
│ ├── images
│ └── admin
│ │ ├── Service_Architecture_02.png
│ │ ├── freezer_agent_backup.png
│ │ ├── freezer_agent_backup_api.png
│ │ ├── freezer_dashboard.png
│ │ ├── freezer_scheduler_api.png
│ │ ├── freezer_scheduler_api_scale.png
│ │ └── job_session.png
│ ├── index.rst
│ ├── install
│ ├── common_configure.rst
│ ├── common_prerequisites.rst
│ ├── db-install.rst
│ ├── devstack_plugin.rst
│ ├── get_started.rst
│ ├── index.rst
│ ├── install-obs.rst
│ ├── install-rdo.rst
│ ├── install-ubuntu.rst
│ ├── install.rst
│ ├── install_agent.rst
│ ├── next-steps.rst
│ └── verify.rst
│ ├── reference
│ └── index.rst
│ └── user
│ ├── freezer-agent.rst
│ ├── freezer-scheduler.rst
│ ├── freezer-web-ui.rst
│ ├── index.rst
│ └── installation.rst
├── etc
├── config-generator.conf
└── scheduler.conf.sample
├── freezer
├── __init__.py
├── common
│ ├── __init__.py
│ ├── client_manager.py
│ └── config.py
├── engine
│ ├── __init__.py
│ ├── engine.py
│ ├── glance
│ │ ├── __init__.py
│ │ └── glance.py
│ ├── manager.py
│ ├── nova
│ │ ├── __init__.py
│ │ └── nova.py
│ ├── osbrick
│ │ ├── __init__.py
│ │ ├── brick_utils.py
│ │ ├── client.py
│ │ ├── osbrick.py
│ │ └── volume_actions.py
│ ├── rsync
│ │ ├── __init__.py
│ │ ├── pyrsync.py
│ │ └── rsync.py
│ ├── rsyncv2
│ │ ├── __init__.py
│ │ ├── pyrsync.py
│ │ └── rsyncv2.py
│ └── tar
│ │ ├── __init__.py
│ │ ├── tar.py
│ │ └── tar_builders.py
├── exceptions
│ ├── __init__.py
│ ├── engine.py
│ └── utils.py
├── job.py
├── lib
│ ├── __init__.py
│ └── pep3143daemon
│ │ ├── __init__.py
│ │ ├── daemon.py
│ │ └── pidfile.py
├── main.py
├── mode
│ ├── __init__.py
│ ├── cinder.py
│ ├── cindernative.py
│ ├── fs.py
│ ├── glance.py
│ ├── mode.py
│ ├── mongo.py
│ ├── mysql.py
│ ├── nova.py
│ └── sqlserver.py
├── openstack
│ ├── __init__.py
│ ├── admin.py
│ ├── backup.py
│ ├── osclients.py
│ └── restore.py
├── scheduler
│ ├── __init__.py
│ ├── arguments.py
│ ├── daemon.py
│ ├── freezer_scheduler.py
│ ├── scheduler_job.py
│ ├── utils.py
│ ├── win_daemon.py
│ └── win_service.py
├── scripts
│ └── vss.ps1
├── snapshot
│ ├── __init__.py
│ ├── lvm.py
│ ├── snapshot.py
│ └── vss.py
├── storage
│ ├── __init__.py
│ ├── base.py
│ ├── exceptions.py
│ ├── fslike.py
│ ├── ftp.py
│ ├── local.py
│ ├── multiple.py
│ ├── physical.py
│ ├── s3.py
│ ├── ssh.py
│ └── swift.py
├── tests
│ ├── __init__.py
│ ├── commons.py
│ ├── integration
│ │ ├── __init__.py
│ │ ├── common.py
│ │ ├── test_agent.py
│ │ ├── test_rsync_backup.py
│ │ └── test_version.py
│ └── unit
│ │ ├── __init__.py
│ │ ├── engines
│ │ ├── __init__.py
│ │ ├── nova
│ │ │ ├── __init__.py
│ │ │ └── test_nova.py
│ │ ├── rsync
│ │ │ ├── __init__.py
│ │ │ ├── test_pyrsync.py
│ │ │ └── test_rsync.py
│ │ └── tar
│ │ │ ├── __init__.py
│ │ │ └── test_tar_builders.py
│ │ ├── openstack
│ │ ├── __init__.py
│ │ ├── test_admin.py
│ │ ├── test_backup.py
│ │ ├── test_osclients.py
│ │ └── test_restore.py
│ │ ├── scheduler
│ │ ├── __init__.py
│ │ ├── commons.py
│ │ ├── test_freezer_scheduler.py
│ │ ├── test_scheduler_daemon.py
│ │ ├── test_scheduler_job.py
│ │ └── test_utils.py
│ │ ├── snapshot
│ │ ├── __init__.py
│ │ ├── test_lvm.py
│ │ └── test_vss.py
│ │ ├── storages
│ │ ├── __init__.py
│ │ ├── test_ftp.py
│ │ └── test_local.py
│ │ ├── test_job.py
│ │ └── utils
│ │ ├── __init__.py
│ │ ├── test_checksum.py
│ │ ├── test_config.py
│ │ ├── test_crypt.py
│ │ ├── test_exec_cmd.py
│ │ ├── test_streaming.py
│ │ ├── test_utils.py
│ │ └── test_winutils.py
└── utils
│ ├── __init__.py
│ ├── checksum.py
│ ├── compress.py
│ ├── config.py
│ ├── crypt.py
│ ├── exec_cmd.py
│ ├── streaming.py
│ ├── utils.py
│ └── winutils.py
├── freezer_logo.jpg
├── releasenotes
├── notes
│ ├── drop-py-2-7-a76d53b7a12bcff2.yaml
│ ├── os-brick-engine-c47834de156dfa27.yaml
│ ├── s3-driver-support-02d0a19b99cfe2c5.yaml
│ └── volume-boot-nova-instance-backup-support-3c8d090370518f43.yaml
└── source
│ ├── 2023.1.rst
│ ├── 2023.2.rst
│ ├── 2025.1.rst
│ ├── _static
│ └── .placeholder
│ ├── _templates
│ └── .placeholder
│ ├── conf.py
│ ├── index.rst
│ ├── newton.rst
│ ├── ocata.rst
│ ├── pike.rst
│ ├── queens.rst
│ ├── stein.rst
│ ├── train.rst
│ ├── unreleased.rst
│ ├── ussuri.rst
│ ├── victoria.rst
│ ├── wallaby.rst
│ ├── yoga.rst
│ └── zed.rst
├── requirements.txt
├── setup.cfg
├── setup.py
├── test-requirements.txt
└── tox.ini
/.coveragerc:
--------------------------------------------------------------------------------
1 | # .coveragerc to control coverage.py
2 | [run]
3 | branch = True
4 | omit = freezer/tests/*
5 |
6 | [path]
7 | source = freezer/freezer
8 |
9 | [html]
10 | directory = term
11 |
12 | [report]
13 | ignore_errors = True
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__
2 | dist
3 | build
4 | .venv
5 | tests/scenario/.vagrant
6 | .idea
7 | .autogenerated
8 | .coverage
9 | cover/
10 | coverage.xml
11 | *.sw?
12 | .tox
13 | *.egg
14 | *.egg-info
15 | *.py[co]
16 | .DS_Store
17 | *.log
18 | .stestr/
19 | subunit.log
20 | .eggs
21 | AUTHORS
22 | ChangeLog
23 |
24 | # Django files that get created during the test runs
25 | .secret_key_store
26 | *.lock
27 |
28 | # Eclipse generates these
29 | .project
30 | .pydevproject
31 |
32 | # Coverage data
33 | .coverage.*
34 | releasenotes/build
35 | doc/source/_static/*.sample
36 |
--------------------------------------------------------------------------------
/.gitreview:
--------------------------------------------------------------------------------
1 | [gerrit]
2 | host=review.opendev.org
3 | port=29418
4 | project=openstack/freezer.git
5 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | default_language_version:
3 | # force all unspecified python hooks to run python3
4 | python: python3
5 | repos:
6 | - repo: https://github.com/pre-commit/pre-commit-hooks
7 | rev: v3.4.0
8 | hooks:
9 | - id: trailing-whitespace
10 | - id: mixed-line-ending
11 | args: ['--fix', 'lf']
12 | exclude: '.*\.(svg)$'
13 | - id: check-byte-order-marker
14 | - id: check-executables-have-shebangs
15 | - id: check-merge-conflict
16 | - id: debug-statements
17 | - id: check-yaml
18 | files: .*\.(yaml|yml)$
19 | - repo: local
20 | hooks:
21 | - id: flake8
22 | name: flake8
23 | additional_dependencies:
24 | - hacking>=3.0.1,<3.1.0
25 | language: python
26 | entry: flake8
27 | files: '^.*\.py$'
28 | exclude: '^(doc|releasenotes|tools)/.*$'
29 |
--------------------------------------------------------------------------------
/.stestr.conf:
--------------------------------------------------------------------------------
1 | [DEFAULT]
2 | test_path=${OS_TEST_PATH:-./freezer/tests/unit}
3 | top_dir=./
4 |
--------------------------------------------------------------------------------
/.zuul.yaml:
--------------------------------------------------------------------------------
1 | - project:
2 | queue: freezer
3 | templates:
4 | - check-requirements
5 | - publish-openstack-docs-pti
6 | - release-notes-jobs-python3
7 | - openstack-python3-jobs
8 | check:
9 | jobs:
10 | - openstack-tox-pylint
11 | - freezer-tempest-agent
12 | - freezer-tempest-scheduler
13 | - freezer-ubuntu
14 | - freezer-centos-9-stream
15 | gate:
16 | jobs:
17 | - openstack-tox-pylint
18 | - freezer-tempest-agent
19 | - freezer-tempest-scheduler
20 | - freezer-ubuntu
21 | - freezer-centos-9-stream
22 |
23 | - job:
24 | name: freezer-base
25 | parent: freezer-tempest-basic
26 | vars:
27 | tempest_test_regex: '^(freezer_tempest_plugin.tests.freezer)'
28 |
29 | - job:
30 | name: freezer-ubuntu
31 | parent: freezer-base
32 |
33 | - job:
34 | name: freezer-centos-9-stream
35 | parent: freezer-base
36 | nodeset: centos-9-stream
37 |
--------------------------------------------------------------------------------
/CREDITS.rst:
--------------------------------------------------------------------------------
1 | Authors
2 | =======
3 |
4 | - Fausto Marzi
5 | - Ryszard Chojnacki
6 | - Emil Dimitrov
7 |
8 | Maintainers
9 | ===========
10 |
11 | - Fausto Marzi
12 | - Ryszard Chojnacki
13 | - Emil Dimitrov
14 | - Geng changcai
15 | - Gecong
16 | - Carl Caihui
17 |
18 | Contributors
19 | ============
20 |
21 | - Duncan Thomas
22 | - Coleman Corrigan
23 | - Guillermo Ramirez Garcia
24 | - Zahari Zahariev
25 | - Eldar Nugaev
26 | - Saad Zaher
27 | - Samuel Bartel
28 | - Jonas Pfannschmidt
29 | - Deklan Dieterly
30 | - Pierre Mathieu
31 | - Dmitriy Rabotyagov
32 | - Volodymyr Mevsha
33 | - Ivan Anfimov
34 | - Dmitriy Chubinidze
35 |
36 | Credits
37 | =======
38 |
39 | - Davide Guerri
40 | - Jim West
41 | - Lars Noldan
42 | - Stephen Pearson
43 | - Sneha Mini
44 | - Chris Delaney
45 | - James Bishop
46 | - Matt Joyce
47 | - Anupriya Ramraj
48 | - HP OpsAuto Team
49 | - Jon Otero Fernández (logo)
50 | - ZTE TECS Team
51 | - Advanced Hosters B.V.
52 | - Napa Labs
53 |
--------------------------------------------------------------------------------
/FAQ.rst:
--------------------------------------------------------------------------------
1 | ===
2 | FAQ
3 | ===
4 |
5 | 1) **What is freezer?**
6 | Is a tool to automate data backup and restore
7 | process using OpenStack Swift and/or other media storage.
8 |
9 | 2) **Does freezer support incremental backup?**
10 | Yes. Incremental backup are done using GNU tar incremental features.
11 |
12 | 3) **Does freezer check the file contents to establish if a file was modified?**
13 | Freezer check for changes at mtime and ctime in
14 | every file inode to evaluate if a file changed or not.
15 |
16 | 4) **Why GNU tar rather than rsync?**
17 | Both approaches are good. Rsync check
18 | the file content, while tar check the file inode. In our
19 | environment, we need to backup directories with size > 400GB and
20 | hundreds of thousands of files. Rsync approach is effective but slow.
21 | Tar is fast as it needs to check only the file inodes, rather than
22 | the full file content. Rsync backup type will be added pretty soon.
23 |
24 | 5) *Does freezer support encrypted backup?*
25 | Yes. Freezer encrypt data using OpenSSL (AES-256-CFB).
26 |
27 | 6) **Does freezer execute point-in-time backup?**
28 | Yes. For point in time backup LVM snapshot feature used.
29 |
30 | 7) **Can I use freezer on OSX or other OS where GNU Tar is not installed
31 | by default?**
32 | Yes. For OSX and \*BSD, just install gtar and freezer
33 | automatically will use gtar to execute backup. OS other then Linux,
34 | OSX and \*BSD are currently not supported.
35 |
36 | 8) **What Application backup does freezer support currently?**
37 | MongoDB, MySQL to have a higher level of data consistency, while
38 | any application is supported for crash consistent data integrity.
39 |
40 | 9) **How does the MongoDB backup happens?**
41 | Freezer required journal enabled in Mongo and lvm volume to execute backup.
42 | It checks if the Mongo instance is the master and create lvm snapshot to have
43 | consistent data.
44 |
45 | 10) **Does freezer manage sparse files efficiently?**
46 | Yes. Zeroed/null data is not backed up. So less space and bandwidth will be used.
47 |
48 | 11) **Does freezer remove automatically backup after some time?**
49 | Yes. From command line the option --remove-older-than (days) can be used to
50 | remove objects older then (days).
51 |
52 | 12) **Does freezer support MySQL Backup?**
53 | Yes.
54 |
55 | 13) **What storage media are currently supported?**
56 | Current support media storage are:
57 | a. Swift
58 | b. Store files on a remote host file system using ssh
59 | c. Directory in the local host (i.e. NFS/CIFS mounted volumes)
60 |
61 | 14) **Does freezer has any Web UI or API?**
62 | Yes. Freezer has REST API and a Web UI integrated with Horizon.
63 |
64 | 15) **Does Freezer detect removed files between incremental executions?**
65 | Yes.
66 |
67 | 16) **Will Freezer be included as official project in OpenStack?**
68 | Yes.
69 |
70 | 17) **Does freezer support Windows?**
71 | Yes. The freezer agent and scheduler can be executed on Windows.
72 |
73 | 18) **What is being used on Windows to execute file system snapshots?**
74 | Currently VSS are used to support point in time snapshots.
75 |
76 | 19) **What applications are supported in Windows for consistent backups?**
77 | SQL Server (--mode sqlserver).
78 |
79 | 20) **Are there examples of OpenStack projects that use Freezer that I can look at?**
80 | Not currently.
81 |
82 | 21) **My service has it's own task scheduler. What is the recommended way to schedule Freezer runs?**
83 | If you want to use the freezer-api and freezer-web-ui in horizon, you need to use the
84 | freezer-scheduler.
85 | If you do not need the api and web ui, you can just execute the freezer-agent from crontab or
86 | any other scheduler.
87 |
88 | 22) **What are the benefits of using the API and Web UI?**
89 | - You can start backup and restore jobs on any node from the Web UI
90 | - Backup jobs can be synchronized across multiple nodes
91 | - The UI provides metrics and other info
92 |
93 | 23) **How can I run user-defined scripts before and after a backup run?**
94 | A simple solution is to implement your own script locally and execute
95 | freezer-agent from it.
96 | We recommend instead creating "exec"-type jobs in the UI and set up job
97 | dependencies.
98 |
99 | 24) **What are the options for backing up MySQL/Percona?**
100 | a. Make use of filesystem snapshots (LVM) using the "--mode mysql" option. It's supported
101 | natively by Freezer and suitable for large databases.
102 | This instructs freezer to execute the following steps:
103 | - flush tables and lock the DB
104 | - take an LVM snapshot
105 | - release the DB (so it's usable again very quiclky)
106 | - backup the consistent DB image from the snapshot
107 | - release the snapshot
108 | b. Manual process - It does not require LVM and provides incremental backup.
109 | - manually flush tables and lock the DB: "flush tables with read lock"
110 | - backup the DB folder, usually /var/lib/mysql (--mode fs --path-to-backup /var/lib/mysql --max-level 14)
111 | - manually unlock the DB
112 | Using mysqldump is not recommended for speed and reliability reasons.
113 |
--------------------------------------------------------------------------------
/HACKING.rst:
--------------------------------------------------------------------------------
1 | Freezer Style Commandments
2 | ===========================
3 |
4 | - Step 1: Read the OpenStack Style Commandments
5 | https://docs.openstack.org/hacking/latest/
6 | - Step 2: Read on
7 |
8 | Freezer Specific Commandments
9 | ------------------------------
10 |
11 |
12 | Logging
13 | -------
14 |
15 | Use the common logging module, and ensure you ``getLogger``::
16 |
17 | from oslo_log import log
18 |
19 | LOG = log.getLogger(__name__)
20 |
21 | LOG.debug('Foobar')
22 |
23 |
24 | oslo.config
25 | -----------
26 |
27 | - All configuration options for freezer-scheduler should be in the following file ::
28 |
29 | freezer/scheduler/arguments.py
30 |
31 | - After adding new options to freezer-scheduler please use the following command to update the sample configuration file::
32 |
33 | oslo-config-generator --config-file etc/config-generator.conf
34 |
35 | - If you added support for a new oslo library, you have to edit the following file adding a new namespace for the new oslo library:
36 | for example adding oslo.db::
37 |
38 | # edit etc/config-generator.conf
39 | [DEFAULT]
40 | output_file = etc/scheduler.conf.sample
41 | wrap_width = 79
42 | namespace = scheduler
43 | namespace = oslo.log
44 | namespace = oslo.db
45 |
46 | This will add oslo.db options to your configuration file.
47 |
48 | Agent Options
49 | -------------
50 | - All configuration options for freezer-agent should be in the following file ::
51 |
52 | freezer/common/config.py
53 |
54 | - To list options available in freezer-agent use the following command::
55 |
56 | oslo-config-generator --namespace freezer --namespace oslo.log
57 |
58 |
59 | Release Notes
60 | -------------
61 |
62 | - When a new feature is committed we should have a new release notes page that
63 | highlights the changes made. These release notes will be used for deployers,
64 | users, and developers. There are a few steps that need to be taken in order.
65 |
66 | * Generate a release notes page
67 | 1. tox -e venv -- reno new {my-new-feature}
68 | 2. https://docs.openstack.org/reno/latest/user/usage.html#creating-new-release-notes
69 |
70 | * Update/Edit an existing release note
71 | 1. https://docs.openstack.org/reno/latest/user/usage.html#editing-a-release-note
72 |
73 |
74 | - Building release notes::
75 |
76 | tox -e releasenotes
77 |
78 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | =================
2 | OpenStack Freezer
3 | =================
4 |
5 | .. image:: freezer_logo.jpg
6 |
7 | Freezer is a Backup and Restore Service platform that helps you to automate
8 | the data backup and restore process.
9 |
10 | The following features are available:
11 |
12 | - Backup file system using point-in-time snapshot
13 | - Strong encryption supported: AES-256-CFB
14 | - Backup file system tree directly (without volume snapshot)
15 | - Backup journalled MongoDB directory tree using lvm snapshot to Swift
16 | - Backup MySQL with lvm snapshot
17 | - Restore data from a specific date automatically to file system
18 | - Low storage consumption as the backup are uploaded as a stream
19 | - Flexible backup policy (incremental and differential)
20 | - Data is archived in GNU Tar format for file based incremental
21 | - Multiple compression algorithm support (zlib, bzip2, xz)
22 | - Remove old backup automatically according to the provided parameters
23 | - Multiple storage media support (Swift, local file system, or ssh)
24 | - Flush kernel buffered memory to disk
25 | - Multi-platform (Linux, Windows, \*BSD, OSX)
26 | - Manage multiple jobs (I.e., multiple backups on the same node)
27 | - Synchronize backups and restore on multiple nodes
28 | - Web user interface integrated with OpenStack Horizon
29 | - Execute scripts/commands before or after a job execution
30 | - More ...
31 |
32 | To learn how to use Freezer's API, consult the documentation available online
33 | at:
34 |
35 | - `Backup API Reference `__
36 | - `Freezer API `__
37 |
38 | Freezer Horizon plugin:
39 | - `Freezer Web UI `__
40 |
41 | For more information on OpenStack APIs, SDKs and CLIs in general, refer to:
42 |
43 | - `OpenStack for App Developers `__
44 | - `Development resources for OpenStack clouds
45 | `__
46 |
47 | Operators
48 | ---------
49 |
50 | To learn how to deploy and configure OpenStack Freezer, consult the
51 | documentation available online at:
52 |
53 | - `OpenStack Freezer `__
54 |
55 | In the unfortunate event that bugs are discovered, they should be reported to
56 | the appropriate bug tracker. If you obtained the software from a 3rd party
57 | operating system vendor, it is often wise to use their own bug tracker for
58 | reporting problems. In all other cases use the master OpenStack bug tracker,
59 | available at:
60 |
61 | - `Bug Tracker `__
62 |
63 | Troubleshooting
64 | ---------------
65 |
66 | When errors occure, these are good places to check:
67 |
68 | * freezer-api log: `$HOME/log/freezer-api.log`
69 | `/var/log/apache2/freezer-api.log`
70 | * freezer-agent log: `$HOME/.freezer/freezer.log`
71 | * freezer-scheduler log:`/var/log/freezer/scheduler.log`
72 |
73 | Developers
74 | ----------
75 |
76 | Any new code must follow the development guidelines detailed in the HACKING.rst
77 | file and OpenStack general development guidelines, and pass all unit tests.
78 |
79 | Further developer focused documentation is available at:
80 |
81 | - `Official Freezer Documentation `__
82 | - `Official Client Documentation
83 | `__
84 |
85 | Contributors are encouraged to join IRC (``#openstack-freezer`` on OFTC):
86 |
87 | - `IRC `__
88 |
89 | Other Information
90 | -----------------
91 |
92 | Release notes for the project can be found at:
93 |
94 | - `Release notes
95 | `__
96 |
97 | During each `Summit`_ and `Project Team Gathering`_, we agree on what the whole
98 | community wants to focus on for the upcoming release. The plans for freezer can
99 | be found at:
100 |
101 | - `Freezer Specs `__
102 |
103 | .. _Summit: https://openinfra.org/summit/
104 | .. _Project Team Gathering: https://openinfra.org/ptg/
105 |
--------------------------------------------------------------------------------
/bindep.txt:
--------------------------------------------------------------------------------
1 | # A build time dependency
2 | libffi-dev [platform:dpkg test]
3 | libffi-devel [platform:rpm test]
4 | libssl-dev [platform:dpkg test]
5 | openssl-devel [platform:rpm test]
6 | # these are needed to compile Python dependencies from sources
7 | python3-all-dev [platform:dpkg !platform:ubuntu-precise test]
8 | python3-devel [platform:rpm test]
9 | build-essential [platform:dpkg test]
10 | # these are needed by infra for python-* jobs
11 | mariadb [platform:rpm test]
12 | mariadb-server [platform:rpm test]
13 | mysql-client [platform:dpkg test]
14 | mysql-server [platform:dpkg test]
15 |
--------------------------------------------------------------------------------
/devstack/README.rst:
--------------------------------------------------------------------------------
1 | ============================
2 | Enabling Freezer in Devstack
3 | ============================
4 |
5 | This directory contains the Freezer DevStack plugin.
6 |
7 | Download Devstack::
8 |
9 | git clone https://git.openstack.org/openstack-dev/devstack
10 | cd devstack
11 |
12 | To configure the Freezer scheduler and agent with DevStack, you will need to
13 | enable this plugin by adding one line to the [[local|localrc]]
14 | section of your ``local.conf`` file.
15 |
16 | To enable the plugin, add a line of the form::
17 |
18 | [[local|localrc]]
19 | enable_plugin freezer [GITREF]
20 |
21 | where::
22 |
23 | is the URL of a freezer repository
24 | [GITREF] is an optional git ref (branch/ref/tag). The default is master.
25 |
26 | For example::
27 |
28 | enable_plugin freezer https://git.openstack.org/openstack/freezer master
29 |
30 | Then run devstack normally::
31 |
32 | cd $DEVICE_DIR
33 | ./stack.sh
34 |
35 | This is a sample ``local.conf`` file for freezer developer::
36 |
37 | [[local|localrc]]
38 | ADMIN_PASSWORD=stack
39 | DATABASE_PASSWORD=stack
40 | RABBIT_PASSWORD=stack
41 | SERVICE_PASSWORD=$ADMIN_PASSWORD
42 |
43 | DEST=/opt/stack
44 | LOGFILE=$DEST/logs/stack.sh.log
45 |
46 | # only install keystone/horizon/swift in devstack
47 | # disable_all_services
48 | # enable_service key mysql s-proxy s-object s-container s-account horizon
49 |
50 | enable_plugin freezer http://git.openstack.org/openstack/freezer master
51 | enable_plugin freezer-api http://git.openstack.org/openstack/freezer-api.git master
52 | enable_plugin freezer-tempest-plugin http://git.openstack.org/openstack/freezer-tempest-plugin.git master
53 | enable_plugin freezer-web-ui http://git.openstack.org/openstack/freezer-web-ui.git master
54 |
55 | export FREEZER_BACKEND='sqlalchemy'
56 |
57 | For more information, see:
58 | https://docs.openstack.org/devstack/latest/index.html
59 |
--------------------------------------------------------------------------------
/devstack/gate_hook.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 | # not use this file except in compliance with the License. You may obtain
6 | # a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | # License for the specific language governing permissions and limitations
14 | # under the License.
15 |
16 | # set -ex
17 |
18 | echo "Start Gate Hook"
19 | # Link the log file so it will be collected by the CI system
20 | if [ -n "$BASE" ] && [ -d "$BASE/logs" ]; then
21 | sudo ln -sf /home/tempest/.freezer/freezer.log $BASE/logs/freezer.log
22 | sudo ln -sf $BASE/logs/freezer-scheduler.log $BASE/logs/freezersch.log
23 | fi
24 |
25 |
26 |
27 | #export DEVSTACK_LOCAL_CONFIG="enable_plugin freezer https://git.openstack.org/openstack/freezer"
28 | # export DEVSTACK_LOCAL_CONFIG+=$'\n'"enable_plugin freezer-api https://git.openstack.org/openstack/freezer-api"
29 | # Swift is needed for some of the integration tests
30 | export DEVSTACK_LOCAL_CONFIG+=$'\n'"enable_service s-proxy s-object s-container s-account"
31 |
32 | export DEVSTACK_GATE_TEMPEST_REGEX="freezer_tempest_plugin"
33 |
34 | # $BASE/new/devstack-gate/devstack-vm-gate.sh
35 |
36 | echo "End Gate Hook"
37 |
--------------------------------------------------------------------------------
/devstack/lib/freezer:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | # Install and start Freezer service
18 |
19 | # add the following to localrc:
20 | # enable_service freezer
21 | #
22 | # Dependencies:
23 | # - functions
24 | # - OS_AUTH_URL for auth in api
25 | # - DEST set to the destination directory
26 | # - SERVICE_PASSWORD, SERVICE_TENANT_NAME for auth in api
27 | # - STACK_USER service user
28 |
29 | # functions called by the plugin.sh script
30 | # source plugin.sh [phase]
31 | # ---------
32 | # -
33 | # - [pre-install]
34 | # - [install]
35 | # - install_freezer
36 | # - [extra]
37 | # - init_freezer_scheduler
38 | # - start_freezer_scheduler
39 | # -
40 | # - stop_freezer_scheduler
41 | # -
42 | # - cleanup_freezer_scheduler
43 |
44 | # Save trace setting
45 | XTRACE=$(set +o | grep xtrace)
46 | set +o xtrace
47 |
48 |
49 | # Functions
50 | # ---------
51 |
52 | function is_freezer_enabled {
53 | [[ ,${ENABLED_SERVICES} =~ ,"freezer" ]] && return 0
54 | }
55 |
56 |
57 | # executed during: stack install
58 | function install_freezer {
59 |
60 | git_clone $FREEZER_REPO $FREEZER_DIR $FREEZER_BRANCH
61 | setup_develop $FREEZER_DIR
62 | if [[ "$GLOBAL_VENV" == "True" ]]; then
63 | sudo ln -sf /opt/stack/data/venv/bin/freezer /usr/local/bin
64 | sudo ln -sf /opt/stack/data/venv/bin/freezer-agent /usr/local/bin
65 | sudo ln -sf /opt/stack/data/venv/bin/freezer-scheduler /usr/local/bin
66 | fi
67 | }
68 |
69 | # executed during: stack post-config
70 | function configure_freezer_scheduler {
71 |
72 | [ ! -d $FREEZER_CONF_DIR ] && sudo mkdir -m 755 -p $FREEZER_CONF_DIR
73 | sudo cp -p $FREEZER_DIR/etc/scheduler.conf.sample $FREEZER_CONF_FILE
74 | sudo chown $STACK_USER $FREEZER_CONF_DIR
75 |
76 | # enable debug
77 | #iniset $FREEZER_CONF_FILE 'DEFAULT' debug True
78 |
79 | [ ! -d $FREEZER_JOBS_DIR ] && sudo mkdir -m 755 -p $FREEZER_JOBS_DIR
80 | sudo chown $STACK_USER $FREEZER_JOBS_DIR
81 | [ ! -d $FREEZER_LOG_DIR ] && sudo mkdir -m 755 -p $FREEZER_LOG_DIR
82 | sudo chown $STACK_USER $FREEZER_LOG_DIR
83 | sudo ls -lh $DEST
84 | sudo ls -lh $DEST/logs
85 |
86 |
87 | }
88 |
89 |
90 | # executed during: stack extra
91 | function init_freezer_scheduler {
92 | # Add scheduler settings here
93 | :
94 | }
95 |
96 |
97 | # executed during: stack extra
98 | function start_freezer_scheduler {
99 | # Add scheduler starts here
100 | :
101 | }
102 |
103 |
104 | # executed during: stop
105 | function stop_freezer_scheduler {
106 | stop_process freezer-scheduler
107 | }
108 |
109 |
110 | # utility function
111 | function get_id {
112 | echo `"$@" | awk '/ id / { print $4 }'`
113 | }
114 |
115 | # Restore xtrace
116 | $XTRACE
117 |
--------------------------------------------------------------------------------
/devstack/local.conf.example:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | [[local|localrc]]
16 | disable_all_services
17 |
18 | enable_plugin freezer https://git.openstack.org/openstack/freezer master
19 | # To use a specific branch:
20 | # enable_plugin freezer https://git.openstack.org/openstack/freezer \
21 | # stable/
22 |
23 | enable_service rabbit mysql key
24 |
25 | # This is to keep the token small for testing
26 | KEYSTONE_TOKEN_FORMAT=UUID
27 |
28 | # Modify passwords as needed
29 | DATABASE_PASSWORD=secretdatabase
30 | RABBIT_PASSWORD=secretrabbit
31 | ADMIN_PASSWORD=secretadmin
32 | SERVICE_PASSWORD=secretservice
33 | SERVICE_TOKEN=111222333444
34 |
35 |
--------------------------------------------------------------------------------
/devstack/plugin.sh:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | # check for service enabled
16 | if is_service_enabled freezer; then
17 | if [[ "$1" == "source" || "`type -t install_freezer`" != 'function' ]]; then
18 | # Initial source
19 | source $FREEZER_DIR/devstack/lib/freezer
20 | fi
21 |
22 | if [[ "$1" == "stack" && "$2" == "install" ]]; then
23 | echo_summary "Installing Freezer"
24 | install_freezer
25 | elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then
26 | echo_summary "Configuring Freezer"
27 | configure_freezer_scheduler
28 | elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
29 | echo_summary "Initializing Freezer Scheduler"
30 | init_freezer_scheduler
31 | start_freezer_scheduler
32 | fi
33 |
34 | if [[ "$1" == "unstack" ]]; then
35 | stop_freezer_scheduler
36 | fi
37 | fi
38 |
--------------------------------------------------------------------------------
/devstack/settings:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | # Defaults
16 | # --------
17 |
18 | # Set up default directories
19 | FREEZER_DIR=$DEST/freezer
20 | FREEZER_CONF_DIR=${FREEZER_CONF_DIR:-/etc/freezer}
21 | FREEZER_JOBS_DIR=${FREEZER_JOBS_DIR:-/etc/freezer/scheduler/conf.d}
22 | FREEZER_CONF_FILE=$FREEZER_CONF_DIR/scheduler.conf
23 | FREEZER_LOG_DIR=$DEST/logs
24 |
25 | # Freezer API repository
26 | FREEZER_REPO=${FREEZER_REPO:-${GIT_BASE}/openstack/freezer.git}
27 | FREEZER_BRANCH=${FREEZER_BRANCH:-master}
28 |
29 | enable_service freezer
30 |
--------------------------------------------------------------------------------
/doc/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | source/reference/api/
--------------------------------------------------------------------------------
/doc/requirements.txt:
--------------------------------------------------------------------------------
1 | # The order of packages is significant, because pip processes them in the order
2 | # of appearance. Changing the order has an impact on the overall integration
3 | # process, which may cause wedges in the gate later.
4 |
5 | sphinx>=2.0.0,!=2.1.0 # BSD
6 | sphinxcontrib-apidoc>=0.2.0 # BSD
7 | openstackdocstheme>=2.2.1 # Apache-2.0
8 | reno>=3.1.0 # Apache-2.0
9 | mock>=2.0.0 # BSD
10 | ddt>=1.0.1 # MIT
11 | testtools>=2.2.0 # MIT
12 | tempest>=17.1.0 # Apache-2.0
13 |
--------------------------------------------------------------------------------
/doc/source/admin/agent-scheduler-install.rst:
--------------------------------------------------------------------------------
1 | Installation
2 | ============
3 |
4 | Before Installation
5 | -------------------
6 |
7 | - You will be required to install Freezer Agent before installing Freezer API
8 | or Freezer Web UI
9 | - Install Freezer Agent from source. Do not use pip!
10 | - Use this guide to install Freezer Agent to OpenStack Controller node
11 | (Where you have installed Horizon and Keystone)
12 | - Use corresponding release to your OpenStack version. For example;
13 | If your OpenStack version is Liberty, user stable/Liberty branch.
14 |
15 | Requirements
16 | ------------
17 |
18 | - python
19 | - python-dev
20 | - git
21 | - Development Tools (gcc)
22 | - libffi
23 | - GNU Tar >= 1.26
24 | - gzip, bzip2, xz
25 | - OpenSSL
26 | - OpenSSL Development
27 | - python-swiftclient
28 | - python-keystoneclient
29 | - libmysqlclient-dev
30 | - sync
31 |
32 | You can check up to date required packages from "requirements.txt"
33 |
34 | Ubuntu / Debian Installation
35 | ----------------------------
36 |
37 | **Follow these instructions if your OpenStack controller nodes are installed
38 | on Ubuntu or Debian based Linux distros**
39 |
40 | Install required packages first:
41 |
42 | .. code:: bash
43 |
44 | sudo apt-get install python-dev python-pip git openssl gcc make automake
45 |
46 | Clone proper branch of Freezer Client with git:
47 |
48 | .. code:: bash
49 |
50 | git clone -b [branch] https://github.com/openstack/freezer.git
51 |
52 | Install requirements with pip:
53 |
54 | .. code:: bash
55 |
56 | cd freezer/
57 |
58 | sudo pip install -r requirements.txt
59 |
60 | Install freezer from source:
61 |
62 | .. code:: bash
63 |
64 | sudo python setup.py install
65 |
--------------------------------------------------------------------------------
/doc/source/admin/complete-install.rst:
--------------------------------------------------------------------------------
1 | Installation
2 | ============
3 |
4 | Before Installation
5 | -------------------
6 |
7 | Requirements
8 | ------------
9 |
10 | Ubuntu / Debian Installation
11 | ----------------------------
12 |
--------------------------------------------------------------------------------
/doc/source/admin/freezer-api-install.rst:
--------------------------------------------------------------------------------
1 | Installation
2 | ============
3 |
4 | This guide will help you install Freezer API framework in one of your OpenStack
5 | controller node. You can install Freezer API in stand alone virtual or bare
6 | metal server but it is strongly suggested install in controller node.
7 |
8 | Before Installation
9 | -------------------
10 |
11 | - Freezer Agent must be installed
12 | - Use this guide to install Freezer Agent to OpenStack Controller node
13 | (Where you have installed Horizon and Keystone)
14 | - Use corresponding release to your OpenStack version. For example;
15 | If your OpenStack version is Liberty, user stable/Liberty branch.
16 | - Do not forget to register Keystone API endpoint and service
17 | - Elasticsearch must be installed
18 |
19 | Requirements
20 | ------------
21 | - elasticsearch>=1.3.0,<2.0 # Apache-2.0
22 | - falcon>=0.1.6 # Apache-2.0
23 | - jsonschema>=2.0.0,<3.0.0,!=2.5.0 # MIT
24 | - keystonemiddleware>=4.0.0 # Apache-2.0
25 | - oslo.config>=3.2.0 # Apache-2.0
26 | - oslo.i18n>=1.5.0 # Apache-2.0
27 | - Freezer Agent & Scheduler installed from source
28 |
29 | Ubuntu / Debian Installation
30 | ----------------------------
31 |
32 | **Follow these instructions if your OpenStack controller nodes are installed
33 | on Ubuntu or Debian based Linux distros**
34 |
35 | Install required packages first:
36 | (If you have installed Freezer Agent from source, following packages are already installed.)
37 |
38 | .. code:: bash
39 |
40 | sudo apt-get install python-dev python-pip git openssl gcc make automake
41 |
42 | Clone proper branch of Freezer API with git:
43 |
44 | .. code:: bash
45 |
46 | git clone -b [branch] https://github.com/openstack/freezer-api.git
47 |
48 | Install requirements with pip:
49 |
50 | .. code:: bash
51 |
52 | cd freezer-api/
53 |
54 | sudo pip install -r requirements.txt
55 |
56 | Install Freezer API from source:
57 |
58 | .. code:: bash
59 |
60 | sudo python setup.py install
61 |
62 | Copy config file:
63 |
64 | .. code:: bash
65 |
66 | sudo cp etc/freezer-api.conf /etc/freezer-api.conf
67 |
68 | Edit config file:
69 |
70 | .. code:: bash
71 |
72 | sudo nano /etc/freezer-api.conf
73 |
74 | # change log file location
75 | log_file = /var/log/freezer-api.log
76 |
77 | # configure Keystone authentication
78 |
79 | [keystone_authtoken]
80 | auth_protocol = http
81 | auth_host = [keystone_host_ip_or_hostname]
82 | auth_port = 5000
83 | admin_user = [freezer admin user] # admin or user with admin priviliges
84 | admin_password = [admin password]
85 | admin_tenant_name = [admin tenan] # usually admin
86 | include_service_catalog = False
87 | delay_auth_decision = False
88 |
89 | [storage]
90 | # supported db engine. currently elasticsearch only
91 | db=elasticsearch
92 | hosts='http://[elasticsearch host address]:9200'
93 | # freezer-manage db sync/update uses the following parameter to set the number of replicas
94 | number_of_replicas=1
95 |
96 |
97 | Follow this instructions to install Elasticsearch 1.7.5:
98 |
99 | .. code:: bash
100 |
101 | https://goo.gl/bwDcNK
102 |
103 | service elasticsearch start
104 |
105 | ***You must install Elasticsearch 1.7.5 for Freezer API to work correctly***
106 |
107 | Elasticsearch needs to know what type of data each document's field contains.
108 | This information is contained in the "mapping", or schema definition.
109 |
110 | Elasticsearch will use dynamic mapping to try to guess the field type from the
111 | basic datatypes available in JSON, but some field's properties have to be
112 | explicitly declared to tune the indexing engine.
113 |
114 | Let's initialize database:
115 |
116 | .. code:: bash
117 |
118 | freezer-manage db sync
119 |
120 | Run Freezer API:
121 |
122 | .. code:: bash
123 |
124 | freezer-api 0.0.0.0
125 |
126 | There is not any Freezer API Deamon. If you need to run Freezer API in
127 | backgroun, user following commend:
128 |
129 | .. code:: bash
130 |
131 | freezer-api 0.0.0.0 >/dev/null 2>&1
132 |
133 | Keystone API v2.0 endpoint registration:
134 |
135 | .. code:: bash
136 |
137 | keystone service-create --name freezer --type backup \
138 | --description "Freezer Backup Service"
139 |
140 | # use public IP address or hostname because Freezer Scheduler must be able
141 | to reach API from public IP or hostname.
142 |
143 | # default port is 9090. If you have changed in freezer-api.conf you must
144 | change it here too.
145 |
146 | keystone endpoint-create \
147 | --service-id $(keystone service-list | awk '/ backup / {print $2}') \
148 | --publicurl http://[freezer_api_publicurl]:[port] \
149 | --internalurl http://[freezer_api_internalurl]:[port] \
150 | --adminurl http://[freezer_api_adminurl]:[port] \
151 | --region regionOne
152 |
153 | Keystone API v3 endpoint registration:
154 |
155 | .. code:: bash
156 |
157 | # With OpenStack Liberty, Keystone API v2.0 is depreciated and you will not
158 | able to use "keystone-client" commend instead user "openstack" commend
159 |
160 | openstack service create --name freezer \
161 | --description "Freezer Backup Service" backup
162 |
163 | # use public IP address or hostname because Freezer Scheduler must be able
164 | to reach API from public IP or hostname.
165 |
166 | # default port is 9090. If you have changed in freezer-api.conf you must
167 | change it here too.
168 |
169 | openstack endpoint create --publicurl http://176.53.94.101:9090 \
170 | --internalurl http://192.168.0.4:9090 \
171 | --adminurl http://176.53.94.101:9090 \
172 | --region RegionOne backup
173 |
--------------------------------------------------------------------------------
/doc/source/admin/freezer-web-ui-install.rst:
--------------------------------------------------------------------------------
1 | Installation
2 | ============
3 |
4 | Before Installation
5 | -------------------
6 |
7 | Requirements
8 | ------------
9 |
10 | Ubuntu / Debian Installation
11 | ----------------------------
12 |
--------------------------------------------------------------------------------
/doc/source/admin/index.rst:
--------------------------------------------------------------------------------
1 | Admin Guide
2 | ===========
3 |
4 | Table of Contents:
5 |
6 | .. toctree::
7 | :maxdepth: 2
8 |
9 | installation
10 | operation
11 |
--------------------------------------------------------------------------------
/doc/source/admin/installation.rst:
--------------------------------------------------------------------------------
1 | Installation
2 | ============
3 |
4 |
5 | Agent & Scheduler Installation:
6 | -------------------------------
7 |
8 | .. toctree::
9 | :maxdepth: 2
10 |
11 | agent-scheduler-install
12 |
13 | Freezer API Installation
14 | ------------------------
15 |
16 | .. toctree::
17 | :maxdepth: 2
18 |
19 | freezer-api-install
20 |
21 | Web UI Installation
22 | -------------------
23 |
24 | .. toctree::
25 | :maxdepth: 2
26 |
27 | freezer-web-ui-install
28 |
29 | Backup as a Service Platform Installation
30 | -----------------------------------------
31 |
32 | .. toctree::
33 | :maxdepth: 2
34 |
35 | complete-install
36 |
--------------------------------------------------------------------------------
/doc/source/admin/operation.rst:
--------------------------------------------------------------------------------
1 | Operation
2 | =========
3 |
4 | Here goes operation guides...
5 |
--------------------------------------------------------------------------------
/doc/source/cli/index.rst:
--------------------------------------------------------------------------------
1 | CLI Guide
2 | =========
3 |
4 | .. toctree::
5 | :maxdepth: 2
6 |
7 | freezer-agent
8 | freezer-scheduler
9 |
10 |
11 | This chapter assumes a working setup of OpenStack following the
12 | `OpenStack Installation Tutorial
13 | `_.
14 |
--------------------------------------------------------------------------------
/doc/source/contributor/actions.rst:
--------------------------------------------------------------------------------
1 | Actions
2 | =======
3 |
4 | Actions are stored only to facilitate the assembling of different actions into jobs in the web UI.
5 | They are not directly used by the scheduler.
6 | They are stored in this structure
7 |
8 | .. code-block:: none
9 |
10 |
11 | {
12 |
13 | "freezer_action": {
14 | "action": string,
15 | "backup_name": string,
16 | ....
17 | },
18 | "mandatory": bool,
19 | "max_retries": int,
20 | "max_retries_interval": int
21 |
22 | "action_id": string,
23 | "user_id": string
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/doc/source/contributor/api_documents.rst:
--------------------------------------------------------------------------------
1 | API Documents
2 | =============
3 |
4 | Freezer has different types of documents as follow:
5 |
6 | .. toctree::
7 |
8 | jobs.rst
9 | actions.rst
10 | sessions.rst
11 |
--------------------------------------------------------------------------------
/doc/source/contributor/client_structure.rst:
--------------------------------------------------------------------------------
1 | Freezer Client document structure
2 | =================================
3 |
4 | Identifies a freezer client for the purpose of sending action
5 |
6 | client_info document contains information relevant for client identification
7 |
8 | .. code-block:: none
9 |
10 | client_info:
11 | {
12 | "client_id": string actually a concatenation "tenant-id_hostname"
13 | "hostname": string
14 | "description": string
15 | "uuid":
16 | }
17 |
18 |
19 | client_type document embeds the client_info and adds user_id
20 |
21 | .. code-block:: none
22 |
23 | client_type :
24 | {
25 | "client" : client_info document,
26 | "user_id": string, # owner of the information (OS X-User-Id, keystone provided, added by api)
27 | }
28 |
--------------------------------------------------------------------------------
/doc/source/contributor/index.rst:
--------------------------------------------------------------------------------
1 | Developer Guide
2 | ===============
3 |
4 | .. toctree::
5 | :maxdepth: 2
6 |
7 | api_routes
8 | metadata_structure
9 | client_structure
10 | api_documents
11 |
12 |
--------------------------------------------------------------------------------
/doc/source/contributor/metadata_structure.rst:
--------------------------------------------------------------------------------
1 | Backup metadata structure
2 | =========================
3 |
4 | .. note::
5 | sizes are in MB
6 |
7 | .. code-block:: none
8 |
9 | backup_metadata:=
10 | {
11 | "container": string,
12 | "host_name": string, # fqdn, client has to provide consistent information here !
13 | "backup_name": string,
14 | "time_stamp": int,
15 | "level": int,
16 | "max_level": int,
17 | "mode" : string, (fs mongo mysql)
18 | "fs_real_path": string,
19 | "vol_snap_path": string,
20 | "total_broken_links" : int,
21 | "total_fs_files" : int,
22 | "total_directories" : int,
23 | "backup_size_uncompressed" : int,
24 | "backup_size_compressed" : int,
25 | "compression_alg": string, (gzip bzip xz)
26 | "encrypted": bool,
27 | "client_os": string
28 | "broken_links" : [string, string, string],
29 | "excluded_files" : [string, string, string]
30 | "cli": string, equivalent cli used when executing the backup ?
31 | "version": string
32 | }
33 |
34 |
35 | The api wraps backup_metadata dictionary with some additional information.
36 | It stores and returns the information provided in this form
37 |
38 | .. code-block:: none
39 |
40 | {
41 | "backup_id": string # backup UUID
42 | "user_id": string, # owner of the backup metadata (OS X-User-Id, keystone provided)
43 | "user_name": string # owner of the backup metadata (OS X-User-Name, keystone provided)
44 |
45 | "backup_metadata": { #--- actual backup_metadata provided
46 | "container": string,
47 | "host_name": string,
48 | "backup_name": string,
49 | "timestamp": int,
50 | ...
51 | }
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/doc/source/contributor/sessions.rst:
--------------------------------------------------------------------------------
1 | Sessions
2 | ========
3 |
4 | A session is a group of jobs which share the same scheduling time. A session is identified
5 | by its **session_id** and has a numeric tag (**session_tag**) which is incremented each time that a new session
6 | is started.
7 | The purpose of the *session_tag* is that of identifying a group of jobs which have been executed
8 | together and which therefore represent a snapshot of a distributed system.
9 |
10 | When a job is added to a session, the scheduling time of the session is copied into the
11 | job data structure, so that any job belonging to the same session will start at the same time.
12 |
13 |
14 | Session Data Structure
15 | ----------------------
16 |
17 | .. code-block:: none
18 |
19 | session =
20 | {
21 | "session_id": string,
22 | "session_tag": int,
23 | "description": string,
24 | "hold_off": int (seconds),
25 | "schedule": { scheduling information, same as jobs },
26 | "jobs": { 'job_id_1': {
27 | "client_id": string,
28 | "status": string,
29 | "result": string
30 | "time_started": int (timestamp),
31 | "time_ended": int (timestamp),
32 | },
33 | 'job_id_2': {
34 | "client_id": string,
35 | "status": string,
36 | "result": string
37 | "time_started": int (timestamp),
38 | "time_ended": int (timestamp),
39 | }
40 | }
41 | "time_start": int timestamp,
42 | "time_end": int timestamp,
43 | "time_started": int (timestamp),
44 | "time_ended": int (timestamp),
45 | "status": string "completed" "running",
46 | "result": string "success" "fail",
47 | "user_id": string
48 | }
49 |
50 | Session actions
51 | ---------------
52 |
53 | When the freezer scheduler running on a node wants to start a session,
54 | it sends a POST request to the following endpoint:
55 |
56 | .. code-block:: none
57 |
58 | POST /v1/sessions/{sessions_id}/action
59 |
60 | The body of the request bears the action and parameters
61 |
62 | Session START action
63 | --------------------
64 |
65 | .. code-block:: none
66 |
67 | {
68 | "start": {
69 | "job_id": "JOB_ID_HERE",
70 | "current_tag": 22
71 | }
72 | }
73 |
74 | Example of a successful response
75 |
76 | .. code-block:: none
77 |
78 | {
79 | 'result': 'success',
80 | 'session_tag': 23
81 | }
82 |
83 | Session STOP action
84 | -------------------
85 |
86 | .. code-block:: none
87 |
88 | {
89 | "end": {
90 | "job_id": "JOB_ID_HERE",
91 | "current_tag": 23,
92 | "result": "success|fail"
93 | }
94 | }
95 |
96 | Session-Job association
97 | -----------------------
98 |
99 | .. code-block:: rest
100 |
101 | PUT /v1/sessions/{sessions_id}/jobs/{job_id} adds the job to the session
102 | DELETE /v1/sessions/{sessions_id}/jobs/{job_id} adds the job to the session
103 |
--------------------------------------------------------------------------------
/doc/source/images/admin/Service_Architecture_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/doc/source/images/admin/Service_Architecture_02.png
--------------------------------------------------------------------------------
/doc/source/images/admin/freezer_agent_backup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/doc/source/images/admin/freezer_agent_backup.png
--------------------------------------------------------------------------------
/doc/source/images/admin/freezer_agent_backup_api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/doc/source/images/admin/freezer_agent_backup_api.png
--------------------------------------------------------------------------------
/doc/source/images/admin/freezer_dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/doc/source/images/admin/freezer_dashboard.png
--------------------------------------------------------------------------------
/doc/source/images/admin/freezer_scheduler_api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/doc/source/images/admin/freezer_scheduler_api.png
--------------------------------------------------------------------------------
/doc/source/images/admin/freezer_scheduler_api_scale.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/doc/source/images/admin/freezer_scheduler_api_scale.png
--------------------------------------------------------------------------------
/doc/source/images/admin/job_session.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/doc/source/images/admin/job_session.png
--------------------------------------------------------------------------------
/doc/source/install/common_prerequisites.rst:
--------------------------------------------------------------------------------
1 | Prerequisites
2 | -------------
3 |
4 | #. Source the ``admin`` credentials to gain access to
5 | admin-only CLI commands:
6 |
7 | .. code-block:: console
8 |
9 | $ . admin-openrc
10 |
11 | #. To create the service credentials, complete these steps:
12 |
13 | * Create the ``freezer`` user:
14 |
15 | .. code-block:: console
16 |
17 | $ openstack user create --domain default --password-prompt freezer
18 |
19 | * Add the ``admin`` role to the ``freezer`` user:
20 |
21 | .. code-block:: console
22 |
23 | $ openstack role add --project service --user freezer admin
24 |
25 | * Create the freezer service entities:
26 |
27 | .. code-block:: console
28 |
29 | $ openstack service create --name freezer --description "Backup" backup
30 |
31 | #. Create the Backup service API endpoints:
32 |
33 | .. code-block:: console
34 |
35 | $ openstack endpoint create --region RegionOne \
36 | backup public http://controller:9090/
37 | $ openstack endpoint create --region RegionOne \
38 | backup internal http://controller:9090/
39 | $ openstack endpoint create --region RegionOne \
40 | backup admin http://controller:9090/
41 |
--------------------------------------------------------------------------------
/doc/source/install/db-install.rst:
--------------------------------------------------------------------------------
1 | Install and configure database
2 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 |
4 | Before you install and configure the Backup/Restore service,
5 | you must install the database.
6 |
7 | #. To install elasticsearch on Ubuntu, complete these steps:
8 |
9 | * Install java prerequisites:
10 |
11 | .. code-block:: console
12 |
13 | $ sudo apt-get install default-jre-headless
14 |
15 | * Download ``elasticsearch`` version 2.3.0
16 |
17 | .. code-block:: console
18 |
19 | $ wget https://download.elasticsearch.org/elasticsearch/release/org/elasticsearch/distribution/deb/elasticsearch/2.3.0/elasticsearch-2.3.0.deb
20 |
21 | * Install ``elasticsearch``
22 |
23 | .. code-block:: console
24 |
25 | $ sudo dpkg -i elasticsearch-2.3.0.deb
26 | $ sudo update-rc.d elasticsearch defaults 95 10
27 |
28 |
29 |
30 | #. To install elasticsearch on Fedora, complete these steps:
31 |
32 | * Install java prerequisites:
33 |
34 | .. code-block:: console
35 |
36 | $ sudo yum install java-1.8.0-openjdk-headless
37 |
38 | * Download ``elasticsearch`` version 2.3.0
39 |
40 | .. code-block:: console
41 |
42 | $ wget https://download.elasticsearch.org/elasticsearch/release/org/elasticsearch/distribution/rpm/elasticsearch/2.3.0/elasticsearch-2.3.0.rpm
43 |
44 | * Install ``elasticsearch``
45 |
46 | .. code-block:: console
47 |
48 | $ sudo yum install elasticsearch-2.3.0.rpm
49 |
--------------------------------------------------------------------------------
/doc/source/install/devstack_plugin.rst:
--------------------------------------------------------------------------------
1 | Devstack Plugin
2 | ===============
3 |
4 | Edit local.conf
5 | ---------------
6 |
7 | To configure the Freezer API with DevStack, you will need to enable the
8 | freezer-api plugin by adding one line to the [[local|localrc]] section
9 | of your local.conf file:
10 |
11 | .. code-block:: ini
12 |
13 | enable_plugin freezer-api [GITREF]
14 | enable_plugin freezer [GITREF]
15 | enable_plugin freezer-web-ui [GITREF]
16 |
17 | where
18 |
19 | .. code-block:: none
20 |
21 | is the URL of a freezer-api, freezer, freezer-web-ui repository
22 | [GITREF] is an optional git ref (branch/ref/tag). The default is master.
23 |
24 | For example
25 |
26 | .. code-block:: ini
27 |
28 | enable_plugin freezer-api https://git.openstack.org/openstack/freezer-api.git master
29 | enable_plugin freezer https://git.openstack.org/openstack/freezer.git master
30 | enable_plugin freezer-web-ui https://git.openstack.org/openstack/freezer-web-ui.git master
31 |
32 | Plugin Options
33 | --------------
34 |
35 | The plugin makes use of apache2 by default.
36 | To use the *uwsgi* server set the following environment variable
37 |
38 | .. code-block:: bash
39 |
40 | export FREEZER_API_SERVER_TYPE=uwsgi
41 |
42 | The default port is *9090*. To configure the api to listen on a different port
43 | set the variable `FREEZER_API_PORT`.
44 | For example to make use of port 19090 instead of 9090 use
45 |
46 | .. code-block:: bash
47 |
48 | export FREEZER_API_PORT=19090
49 |
50 | For more information, see `openstack_devstack_plugins_install `_
51 |
--------------------------------------------------------------------------------
/doc/source/install/get_started.rst:
--------------------------------------------------------------------------------
1 | Backup/Restore service overview
2 | ===============================
3 | The Backup/Restore service provides an easy way to backup and restore
4 | your OpenStack workloads to different storage.
5 |
6 | The Backup and restore service consists of the following components:
7 | - freezer-api
8 | - freezer-agent
9 | - freezer-scheduler
10 |
11 | The service features a RESTful API, which can be used to maintain the status of
12 | your jobs, backups and metadata.
13 |
14 | This chapter assumes a working setup of OpenStack following the base
15 | Installation Guide.
16 |
17 |
18 | Concepts and definitions
19 | ========================
20 |
21 |
22 | ``freezer-api`` service
23 | Accepts and responds to end user API calls.
24 | ``freezer-api`` service documentation can be found here:
25 | `Freezer API `_
26 |
27 |
28 | ``freezer-scheduler`` service
29 | Does API calls to ``freezer-api`` to schedule, fetch, update or Delete backup
30 | jobs.
31 |
32 |
33 | ``freezer-agent`` service
34 | Python application run on the same node like ``freezer-scheduler`` and it
35 | gets called by ``freezer-scheduler`` to execute backups/restore operations.
36 |
37 |
38 | *hostname* is _probably_ going to be the host fqdn.
39 |
40 | *backup_id* defined as UUID of a backup.
41 |
--------------------------------------------------------------------------------
/doc/source/install/index.rst:
--------------------------------------------------------------------------------
1 | Backup/Restore service
2 | ======================
3 |
4 | .. toctree::
5 | :maxdepth: 2
6 |
7 | get_started
8 | install
9 | verify
10 | next-steps
11 |
12 | This chapter assumes a working setup of OpenStack following the
13 | `OpenStack Installation Tutorial
14 | `_.
15 |
--------------------------------------------------------------------------------
/doc/source/install/install-obs.rst:
--------------------------------------------------------------------------------
1 | Install and configure for openSUSE and SUSE Linux Enterprise
2 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 |
4 | This section describes how to install and configure the Backup service
5 | for openSUSE Leap 42.1 and SUSE Linux Enterprise Server 12 SP1.
6 |
7 | .. include:: common_prerequisites.rst
8 |
9 | Install and configure components
10 | --------------------------------
11 |
12 | #. Install the packages:
13 |
14 | .. code-block:: console
15 |
16 | zypper --quiet --non-interactive install python-dev python-pip
17 |
18 | .. include:: common_configure.rst
19 |
20 |
21 | Finalize installation
22 | ---------------------
23 |
24 | Start the Backup services and configure them to start when
25 | the system boots:
26 |
27 | .. code-block:: console
28 |
29 | # systemctl enable openstack-freezer-api.service
30 |
31 | # systemctl start openstack-freezer-api.service
32 |
--------------------------------------------------------------------------------
/doc/source/install/install-rdo.rst:
--------------------------------------------------------------------------------
1 | Install and configure for Red Hat Enterprise Linux and CentOS
2 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 |
4 |
5 | This section describes how to install and configure the Backup service
6 | for Red Hat Enterprise Linux 9 and CentOS Stream 9.
7 |
8 | .. include:: common_prerequisites.rst
9 |
10 | Install and configure components
11 | --------------------------------
12 |
13 | #. Install the packages:
14 |
15 | .. code-block:: console
16 |
17 | $ sudo dnf install python3-devel python3-pip
18 |
19 | .. include:: common_configure.rst
20 |
21 | Finalize installation
22 | ---------------------
23 |
24 | Start the Backup services and configure them to start when
25 | the system boots:
26 |
27 | .. code-block:: console
28 |
29 | $ sudo systemctl enable openstack-freezer-api.service
30 |
31 | $ sudo systemctl start openstack-freezer-api.service
32 |
--------------------------------------------------------------------------------
/doc/source/install/install-ubuntu.rst:
--------------------------------------------------------------------------------
1 | Install and configure for Ubuntu
2 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 |
4 | This section describes how to install and configure the Backup
5 | service for Ubuntu 16.04 (LTS).
6 |
7 | .. include:: common_prerequisites.rst
8 |
9 | Install and configure components
10 | --------------------------------
11 |
12 | #. Install the packages:
13 |
14 | .. code-block:: console
15 |
16 | $ sudo apt-get update
17 |
18 | $ sudo apt-get install python-dev python-pip
19 |
20 | .. note:: To list all missing packages needed to install freezer
21 | in your system use provided ``bindep.txt`` file with `bindep utility.
22 | `_
23 |
24 |
25 | .. include:: common_configure.rst
26 |
27 | Finalize installation
28 | ---------------------
29 |
30 | Restart the Backup services:
31 |
32 | .. code-block:: console
33 |
34 | $ sudo service openstack-freezer-api restart
35 |
--------------------------------------------------------------------------------
/doc/source/install/install.rst:
--------------------------------------------------------------------------------
1 | Install and configure
2 | ~~~~~~~~~~~~~~~~~~~~~
3 |
4 | This section describes how to install and configure the
5 | Backup service, code-named freezer-api, on the controller node.
6 |
7 | This section assumes that you already have a working OpenStack
8 | environment with at least the following components installed:
9 | .. Keystone
10 |
11 | Note that installation and configuration vary by distribution.
12 |
13 | .. toctree::
14 | :maxdepth: 2
15 |
16 | db-install
17 | install-obs
18 | install-rdo
19 | install-ubuntu
20 |
21 | .. code-block:: console
22 |
23 | $ git clone https://opendev.org/openstack/freezer-api.git
24 | $ cd freezer-api
25 | $ pip install ./
26 |
27 |
28 | .. toctree::
29 |
30 | devstack_plugin.rst
31 |
--------------------------------------------------------------------------------
/doc/source/install/install_agent.rst:
--------------------------------------------------------------------------------
1 | This section describes how to install and configure freezer-scheduler and
2 | freezer-agent, on any node in the cloud or any vm inside the cloud.
3 |
4 | This section assumes that you already have a working OpenStack
5 | environment with at least the following components installed:
6 | - Keystone
7 | - Swift
8 |
9 | .. code-block:: bash
10 |
11 | git clone https://git.openstack.org/openstack/freezer.git
12 | cd freezer
13 | pip install ./
14 |
15 |
16 | Configure the scheduler
17 | -----------------------
18 |
19 | 1. Copy the configuration files to ``/etc/freezer/``:
20 |
21 |
22 | .. code-block:: console
23 |
24 | $ sudo cp etc/scheduler.conf.sample /etc/freezer/scheduler.conf
25 |
26 |
27 | 2. Edit the ``/etc/freezer/scheduler.conf`` file and complete the following
28 | actions:
29 |
30 | There are two kinds of api interface, v1 and v2.
31 |
32 | There are two kinds of configurations:
33 |
34 | ``notes:``
35 |
36 | Default configuration is freezer api v2.
37 |
38 | ``Configuration1``: freezer-api is started by v1 interface:
39 |
40 | * In the ``[DEFAULT]`` section, configure database access:
41 |
42 | The ``client_id`` has to be set to the hostname of the machine. It will be
43 | used as an identifier for this node to fetch its scheduled backups
44 |
45 | .. code-block:: ini
46 |
47 | [DEFAULT]
48 | ...
49 | client_id = hostname_of_machine
50 | jobs_dir = /etc/freezer/scheduler/conf.d
51 | enable_v1_api = True
52 |
53 | ``Configuration2``: freezer-api is started by v2 interface:
54 |
55 | * In the ``[DEFAULT]`` section, configure database access:
56 |
57 | The ``client_id`` has to be set to the hostname of the machine. It will be
58 | used as an identifier for this node to fetch its scheduled backups
59 |
60 | .. code-block:: ini
61 |
62 | [DEFAULT]
63 | ...
64 | client_id = hostname_of_machine
65 | jobs_dir = /etc/freezer/scheduler/conf.d
66 | #enable_v1_api = False
67 |
68 |
69 | 3. Start ``freezer-scheduler``
70 |
71 | .. code-block:: console
72 |
73 | $ . admin-openrc
74 | $ sudo freezer-scheduler --config-file /etc/freezer/scheduler.conf start
75 |
76 |
--------------------------------------------------------------------------------
/doc/source/install/next-steps.rst:
--------------------------------------------------------------------------------
1 | Next steps
2 | ~~~~~~~~~~
3 |
4 | Your OpenStack environment now includes the freezer-api service.
5 |
6 | To add additional services, see
7 | https://docs.openstack.org/install/
8 |
--------------------------------------------------------------------------------
/doc/source/install/verify.rst:
--------------------------------------------------------------------------------
1 | Verify operation
2 | ~~~~~~~~~~~~~~~~
3 |
4 | Verify operation of the Backup service.
5 |
6 | .. note::
7 |
8 | Perform these commands on the controller node.
9 |
10 | #. Source the ``admin`` project credentials to gain access to
11 | admin-only CLI commands:
12 |
13 | .. code-block:: console
14 |
15 | $ . admin-openrc
16 |
17 | #. List service components to verify successful launch and registration
18 | of each process:
19 |
20 | .. code-block:: console
21 |
22 | $ openstack endpoint list
23 |
24 | #. List available backup jobs for current node:
25 |
26 | .. code-block:: console
27 |
28 | $ freezer job-list
29 |
--------------------------------------------------------------------------------
/doc/source/reference/index.rst:
--------------------------------------------------------------------------------
1 | Reference
2 | =========
3 |
4 | .. toctree::
5 | :maxdepth: 2
6 |
7 | api/modules
8 |
--------------------------------------------------------------------------------
/doc/source/user/freezer-scheduler.rst:
--------------------------------------------------------------------------------
1 | Scheduler User Guide
2 | ====================
3 |
4 | Here goes the guide...
5 |
--------------------------------------------------------------------------------
/doc/source/user/freezer-web-ui.rst:
--------------------------------------------------------------------------------
1 | Web User Interface User Guide
2 | =============================
3 |
4 | Here goes the guide...
5 |
--------------------------------------------------------------------------------
/doc/source/user/index.rst:
--------------------------------------------------------------------------------
1 | User Guide
2 | ==========
3 |
4 | .. toctree::
5 | :maxdepth: 2
6 |
7 | installation
8 | freezer-agent
9 | freezer-scheduler
10 | freezer-web-ui
11 |
--------------------------------------------------------------------------------
/etc/config-generator.conf:
--------------------------------------------------------------------------------
1 | [DEFAULT]
2 | output_file = etc/scheduler.conf.sample
3 | wrap_width = 79
4 | namespace = freezer-scheduler
5 | namespace = oslo.log
6 |
7 |
--------------------------------------------------------------------------------
/freezer/__init__.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | # Freezer Versions
16 |
17 | import pbr.version
18 |
19 |
20 | __version__ = pbr.version.VersionInfo('freezer').version_string()
21 | version_info = pbr.version.VersionInfo('freezer')
22 |
--------------------------------------------------------------------------------
/freezer/common/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/common/__init__.py
--------------------------------------------------------------------------------
/freezer/common/client_manager.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2016 Hewlett-Packard Development Enterprise, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | from freezer.openstack import osclients
17 | from freezer.utils import config
18 | from oslo_config import cfg
19 | from oslo_log import log
20 |
21 | CONF = cfg.CONF
22 | LOG = log.getLogger(__name__)
23 |
24 |
25 | def parse_osrc(file_name):
26 | with open(file_name, 'r') as osrc_file:
27 | return config.osrc_parse(osrc_file.read())
28 |
29 |
30 | def get_client_manager(backup_args):
31 | if "osrc" in backup_args:
32 | options = osclients.OpenstackOpts.create_from_dict(
33 | parse_osrc(backup_args['osrc']))
34 | else:
35 | options = osclients.OpenstackOpts.create_from_env().get_opts_dicts()
36 | if backup_args['project_id']:
37 | options['project_name'] = None
38 | options['project_id'] = backup_args['project_id']
39 | client_manager = osclients.OSClientManager(
40 | auth_url=options.pop('auth_url', None),
41 | auth_method=options.pop('auth_method', 'password'),
42 | dry_run=backup_args.get('dry_run', None),
43 | **options
44 | )
45 | return client_manager
46 |
--------------------------------------------------------------------------------
/freezer/engine/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/engine/__init__.py
--------------------------------------------------------------------------------
/freezer/engine/glance/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/engine/glance/__init__.py
--------------------------------------------------------------------------------
/freezer/engine/manager.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2016 Hewlett-Packard Development Enterprise, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | import os
17 | from oslo_config import cfg
18 | from oslo_log import log
19 | from oslo_utils import importutils
20 |
21 | from freezer.exceptions import engine as engine_exceptions
22 |
23 | CONF = cfg.CONF
24 | LOG = log.getLogger(__name__)
25 |
26 |
27 | class EngineManager(object):
28 | """
29 | EngineManager, this class handles engines.
30 | Lists all available engines
31 | Checks if an engine does exists or not
32 | Load an engine
33 | """
34 | def __init__(self):
35 | """
36 | This function does some initialization for the engine manager and
37 | register some variables from the CONF variable into the local class
38 | """
39 | self.engine_name = CONF.engine_name
40 | self.engine_store = os.path.abspath(os.path.dirname(__file__))
41 | self.engines = self.list_engines()
42 |
43 | def load_engine(self, **kwargs):
44 | """ Check if the engine exists or not. If not raise EngineNotFound
45 | Error. If the engine exists then try to get an instance of this engine.
46 | """
47 | if not self._check_engine_exists():
48 | raise engine_exceptions.EngineNotFound(
49 | "Engine {0} not found".format(self.engine_name)
50 | )
51 | return importutils.import_object(
52 | "freezer.engine.{0}.{0}.{1}Engine".format(
53 | self.engine_name,
54 | self.engine_name.capitalize()
55 | ),
56 | **kwargs
57 | )
58 |
59 | def _check_engine_exists(self):
60 | if self.engine_name not in self.engines:
61 | return False
62 | return True
63 |
64 | def list_engines(self):
65 | """
66 | Lists all engines in the engine directory
67 | :return:
68 | """
69 | engines = [
70 | name for name in os.listdir(self.engine_store) if
71 | os.path.isdir(os.path.join(self.engine_store, name))
72 | ]
73 | return engines
74 |
--------------------------------------------------------------------------------
/freezer/engine/nova/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/engine/nova/__init__.py
--------------------------------------------------------------------------------
/freezer/engine/osbrick/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/engine/osbrick/__init__.py
--------------------------------------------------------------------------------
/freezer/engine/osbrick/brick_utils.py:
--------------------------------------------------------------------------------
1 |
2 | # Copyright 2011-2014 OpenStack Foundation
3 | # All Rights Reserved.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 | # not use this file except in compliance with the License. You may obtain
7 | # a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 | # License for the specific language governing permissions and limitations
15 | # under the License.
16 |
17 | import os
18 | import socket
19 |
20 | from cinderclient import exceptions
21 | from oslo_concurrency import processutils
22 |
23 |
24 | def get_my_ip():
25 | try:
26 | csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
27 | csock.connect(('8.8.8.8', 80))
28 | (addr, port) = csock.getsockname()
29 | csock.close()
30 | return addr
31 | except socket.error:
32 | return None
33 |
34 |
35 | def get_root_helper():
36 | # NOTE (e0ne): We don't use rootwrap now
37 | return 'sudo'
38 |
39 |
40 | def require_root(f):
41 | def wrapper(*args, **kwargs):
42 | if os.getuid() != 0:
43 | raise exceptions.CommandError(
44 | "This command requires root permissions.")
45 | return f(*args, **kwargs)
46 | return wrapper
47 |
48 |
49 | def safe_execute(cmd):
50 | try:
51 | processutils.execute(*cmd, root_helper=get_root_helper(),
52 | run_as_root=True)
53 | except processutils.ProcessExecutionError as e:
54 | print('Command "{0}" execution returned {1} exit code:'.format(
55 | e.cmd, e.exit_code))
56 | print('Stderr: {0}'.format(e.stderr))
57 | print('Stdout: {0}'.format(e.stdout))
58 |
--------------------------------------------------------------------------------
/freezer/engine/osbrick/volume_actions.py:
--------------------------------------------------------------------------------
1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
2 | # not use this file except in compliance with the License. You may obtain
3 | # a copy of the License at
4 | #
5 | # http://www.apache.org/licenses/LICENSE-2.0
6 | #
7 | # Unless required by applicable law or agreed to in writing, software
8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 | # License for the specific language governing permissions and limitations
11 | # under the License.
12 |
13 | from os_brick import exception
14 | from os_brick import initiator
15 |
16 |
17 | class VolumeAction(object):
18 | def __init__(self, volumes_client, volume_id):
19 | self.volumes_client = volumes_client
20 | self.volume_id = volume_id
21 |
22 | def __enter__(self):
23 | return self
24 |
25 | def __exit__(self, type, value, traceback):
26 | if traceback:
27 | self.volumes_client.volumes.unreserve(self.volume_id)
28 | return False
29 | return True
30 |
31 |
32 | class Reserve(VolumeAction):
33 | def reserve(self):
34 | self.volumes_client.volumes.reserve(self.volume_id)
35 |
36 |
37 | class InitializeConnection(VolumeAction):
38 | def initialize(self, brick_client, multipath, enforce_multipath):
39 | conn_prop = brick_client.get_connector(multipath, enforce_multipath)
40 | return self.volumes_client.volumes.initialize_connection(
41 | self.volume_id, conn_prop)
42 |
43 |
44 | class VerifyProtocol(VolumeAction):
45 | # NOTE(e0ne): Only iSCSI and RBD based drivers are supported. NFS doesn't
46 | # work. Drivers with other protocols are not tested yet.
47 | SUPPORTED_PROCOTOLS = [initiator.ISCSI, initiator.RBD]
48 |
49 | def verify(self, protocol):
50 | protocol = protocol.upper()
51 |
52 | # NOTE(e0ne): iSCSI drivers works without issues, RBD and NFS don't
53 | # work. Drivers with other protocols are not tested yet.
54 | if protocol not in VerifyProtocol.SUPPORTED_PROCOTOLS:
55 | raise exception.ProtocolNotSupported(protocol=protocol)
56 |
57 |
58 | class ConnectVolume(VolumeAction):
59 | def connect(self, brick_connector, connection_data,
60 | mountpoint, mode, hostname):
61 | device_info = brick_connector.connect_volume(connection_data)
62 |
63 | self.volumes_client.volumes.attach(self.volume_id, instance_uuid=None,
64 | mountpoint=mountpoint,
65 | mode=mode,
66 | host_name=hostname)
67 | return device_info
68 |
69 |
70 | class VolumeDetachAction(VolumeAction):
71 | def __exit__(self, type, value, traceback):
72 | if traceback:
73 | self.volumes_client.volumes.roll_detaching(self.volume_id)
74 | return False
75 | return True
76 |
77 |
78 | class BeginDetach(VolumeDetachAction):
79 | def reserve(self):
80 | self.volumes_client.volumes.begin_detaching(self.volume_id)
81 |
82 |
83 | class InitializeConnectionForDetach(InitializeConnection, VolumeDetachAction):
84 | pass
85 |
86 |
87 | class DisconnectVolume(VolumeDetachAction):
88 | def disconnect(self, brick_connector, connection_data, device_info):
89 | device_info = device_info or {}
90 |
91 | brick_connector.disconnect_volume(connection_data, device_info)
92 |
93 |
94 | class DetachVolume(VolumeDetachAction):
95 | def detach(self, brick_client,
96 | attachment_uuid, multipath, enforce_multipath):
97 | conn_prop = brick_client.get_connector(multipath, enforce_multipath)
98 |
99 | self.volumes_client.volumes.terminate_connection(self.volume_id,
100 | conn_prop)
101 | self.volumes_client.volumes.detach(self.volume_id, attachment_uuid)
102 |
--------------------------------------------------------------------------------
/freezer/engine/rsync/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/engine/rsync/__init__.py
--------------------------------------------------------------------------------
/freezer/engine/rsyncv2/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/engine/rsyncv2/__init__.py
--------------------------------------------------------------------------------
/freezer/engine/rsyncv2/pyrsync.py:
--------------------------------------------------------------------------------
1 | # Licensed under the Apache License, Version 2.0 (the "License");
2 | # you may not use this file except in compliance with the License.
3 | # You may obtain a copy of the License at
4 | #
5 | # http://www.apache.org/licenses/LICENSE-2.0
6 | #
7 | # Unless required by applicable law or agreed to in writing, software
8 | # distributed under the License is distributed on an "AS IS" BASIS,
9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | # See the License for the specific language governing permissions and
11 | # limitations under the License.
12 |
13 |
14 | import hashlib
15 | import zlib
16 |
17 |
18 | _BASE = 65521 # largest prime smaller than 65536
19 |
20 |
21 | def adler32fast(data):
22 | return zlib.adler32(data) & 0xffffffff
23 |
24 |
25 | def adler32(data):
26 | checksum = zlib.adler32(data)
27 | s2, s1 = (checksum >> 16) & 0xffff, checksum & 0xffff
28 | return checksum & 0xffffffff, s1, s2
29 |
30 |
31 | def adler32rolling(removed, new, s1, s2, blocksize=4096):
32 | r = ord(removed)
33 | n = ord(new)
34 | s1 = (s1 + n - r) % _BASE
35 | s2 = (s2 + s1 - blocksize * r - 1) % _BASE
36 | return ((s2 << 16) | s1) & 0xffffffff, s1, s2
37 |
38 |
39 | def blockchecksums(args):
40 | """
41 | Returns a list of weak and strong hashes for each block of the
42 | defined size for the given data stream.
43 | """
44 | path, blocksize = args
45 | weakhashes = []
46 | stronghashes = []
47 | weak_append = weakhashes.append
48 | strong_append = stronghashes.append
49 |
50 | with open(path, 'rb') as instream:
51 | instream_read = instream.read
52 | read = instream_read(blocksize)
53 |
54 | while read:
55 | weak_append(adler32fast(read))
56 | strong_append(hashlib.sha1(read).hexdigest())
57 | read = instream_read(blocksize)
58 |
59 | return weakhashes, stronghashes
60 |
61 |
62 | def rsyncdelta_fast(datastream, remotesignatures, blocksize=4096):
63 | rem_weak, rem_strong = remotesignatures
64 | data_block = datastream.read(blocksize)
65 | index = 0
66 | while data_block:
67 | try:
68 | if adler32fast(data_block) == rem_weak[index] and hashlib.sha1(
69 | data_block).hexdigest() == rem_strong[index]:
70 | yield index
71 | else:
72 | yield data_block
73 | except IndexError:
74 | yield data_block
75 |
76 | index += 1
77 | data_block = datastream.read(blocksize)
78 |
--------------------------------------------------------------------------------
/freezer/engine/tar/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/engine/tar/__init__.py
--------------------------------------------------------------------------------
/freezer/exceptions/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/exceptions/__init__.py
--------------------------------------------------------------------------------
/freezer/exceptions/engine.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2016 Hewlett-Packard Development Enterprise, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | class EngineException(Exception):
17 | msg = "An unknown error occurred."
18 |
19 | def __init__(self, message=None, **kwargs):
20 | if not message:
21 | message = self.msg
22 | super(EngineException, self).__init__(message, kwargs)
23 |
24 |
25 | class EngineNotFound(EngineException):
26 |
27 | def __init__(self, message):
28 | super(EngineNotFound, self).__init__(message)
29 |
--------------------------------------------------------------------------------
/freezer/exceptions/utils.py:
--------------------------------------------------------------------------------
1 | class TimeoutException(Exception):
2 | msg = "Timeout has been occurred."
3 |
4 | def __init__(self, message=None, **kwargs):
5 | if not message:
6 | message = self.msg
7 | super(TimeoutException, self).__init__(message, kwargs)
8 |
--------------------------------------------------------------------------------
/freezer/lib/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/lib/__init__.py
--------------------------------------------------------------------------------
/freezer/lib/pep3143daemon/__init__.py:
--------------------------------------------------------------------------------
1 | # flake8: noqa
2 | #
3 | # Copyright (c) 2014, Stephan Schultchen.
4 | #
5 | # License: MIT (see LICENSE for details)
6 |
7 |
8 | """
9 | pep3143daemon is a implementation of the PEP 3143, describing a well behaving
10 | Unix daemon, as documented in Stevens 'Unix Network Programming'
11 | """
12 |
13 | from freezer.lib.pep3143daemon.daemon import DaemonContext, DaemonError
14 | from freezer.lib.pep3143daemon.pidfile import PidFile
15 |
16 |
17 | __all__ = [
18 | "DaemonContext",
19 | "DaemonError",
20 | "PidFile",
21 | ]
22 |
--------------------------------------------------------------------------------
/freezer/lib/pep3143daemon/pidfile.py:
--------------------------------------------------------------------------------
1 | # flake8: noqa
2 | # The MIT License (MIT)
3 | #
4 | # Copyright (c) 2014 Stephan Schultchen
5 | #
6 | # Permission is hereby granted, free of charge, to any person obtaining a copy
7 | # of this software and associated documentation files (the "Software"), to deal
8 | # in the Software without restriction, including without limitation the rights
9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | # copies of the Software, and to permit persons to whom the Software is
11 | # furnished to do so, subject to the following conditions:
12 | #
13 | # The above copyright notice and this permission notice shall be included in
14 | # all copies or substantial portions of the Software.
15 | #
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | # THE SOFTWARE.
23 | # -*- coding: utf-8 -*-
24 | """
25 | Simple PidFile Module for a pep3143 daemon implementation.
26 |
27 | """
28 | __author__ = 'schlitzer'
29 |
30 |
31 | import atexit
32 | import fcntl
33 | import os
34 |
35 |
36 | class PidFile(object):
37 | """
38 | PidFile implementation for PEP 3143 Daemon.
39 |
40 | This Class can also be used with pythons 'with'
41 | statement.
42 |
43 | :param pidfile:
44 | filename to be used as pidfile, including path
45 | :type pidfile: str
46 | """
47 |
48 | def __init__(self, pidfile):
49 | """
50 | Create a new instance
51 | """
52 | self._pidfile = pidfile
53 | self.pidfile = None
54 |
55 | def __enter__(self):
56 | self.acquire()
57 | return self
58 |
59 | def __exit__(self, exc_type, exc_value, exc_tb):
60 | if exc_type is not None:
61 | self.release()
62 | return False
63 | self.release()
64 | return True
65 |
66 | def acquire(self):
67 | """Acquire the pidfile.
68 |
69 | Create the pidfile, lock it, write the pid into it
70 | and register the release with atexit.
71 |
72 |
73 | :return: None
74 | :raise: SystemExit
75 | """
76 | try:
77 | pidfile = open(self._pidfile, "a")
78 | except IOError as err:
79 | raise SystemExit(err)
80 | try:
81 | fcntl.flock(pidfile.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
82 | except IOError:
83 | raise SystemExit('Already running according to ' + self._pidfile)
84 | pidfile.seek(0)
85 | pidfile.truncate()
86 | pidfile.write(str(os.getpid()) + '\n')
87 | pidfile.flush()
88 | self.pidfile = pidfile
89 | atexit.register(self.release)
90 |
91 | def release(self):
92 | """Release the pidfile.
93 |
94 | Close and delete the Pidfile.
95 |
96 |
97 | :return: None
98 | """
99 | try:
100 | self.pidfile.close()
101 | os.remove(self._pidfile)
102 | except OSError as err:
103 | if err.errno != 2:
104 | raise
105 |
--------------------------------------------------------------------------------
/freezer/mode/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/mode/__init__.py
--------------------------------------------------------------------------------
/freezer/mode/cinder.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2016 Hewlett-Packard Enterprise Development , L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from freezer.mode import mode
16 |
17 |
18 | class CinderMode(mode.Mode):
19 | """
20 | Execute a cinder backup
21 | """
22 | def __init__(self, conf):
23 | self.conf = conf
24 |
25 | @property
26 | def name(self):
27 | return "cinder"
28 |
29 | @property
30 | def version(self):
31 | return "1.0"
32 |
33 | def release(self):
34 | pass
35 |
36 | def prepare(self):
37 | pass
38 |
--------------------------------------------------------------------------------
/freezer/mode/cindernative.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2016 Hewlett-Packard Enterprise Development , L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from freezer.mode import mode
16 |
17 |
18 | class CindernativeMode(mode.Mode):
19 | """
20 | Execute a cinder-volume native backup/restore
21 | """
22 | def __init__(self, conf):
23 | self.conf = conf
24 |
25 | @property
26 | def name(self):
27 | return "cindernative"
28 |
29 | @property
30 | def version(self):
31 | return "1.0"
32 |
33 | def release(self):
34 | pass
35 |
36 | def prepare(self):
37 | pass
38 |
--------------------------------------------------------------------------------
/freezer/mode/fs.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2015,2016 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from freezer.mode import mode
16 |
17 |
18 | class FsMode(mode.Mode):
19 |
20 | def __init__(self, conf):
21 | pass
22 |
23 | @property
24 | def name(self):
25 | return "fs"
26 |
27 | @property
28 | def version(self):
29 | return "1.0"
30 |
31 | def release(self):
32 | pass
33 |
34 | def prepare(self):
35 | pass
36 |
--------------------------------------------------------------------------------
/freezer/mode/glance.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2019 ZTE Corporation..
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from freezer.mode import mode
16 |
17 |
18 | class GlanceMode(mode.Mode):
19 | """
20 | Execute a glance backup/restore
21 | """
22 | def __init__(self, conf):
23 | self.conf = conf
24 |
25 | @property
26 | def name(self):
27 | return "glance"
28 |
29 | @property
30 | def version(self):
31 | return "1.0"
32 |
33 | def release(self):
34 | pass
35 |
36 | def prepare(self):
37 | pass
38 |
--------------------------------------------------------------------------------
/freezer/mode/mode.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2015,2016 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import abc
16 |
17 |
18 | class Mode(metaclass=abc.ABCMeta):
19 | @property
20 | @abc.abstractmethod
21 | def name(self):
22 | pass
23 |
24 | @property
25 | @abc.abstractmethod
26 | def version(self):
27 | pass
28 |
29 | @abc.abstractmethod
30 | def prepare(self):
31 | pass
32 |
33 | @abc.abstractmethod
34 | def release(self):
35 | pass
36 |
--------------------------------------------------------------------------------
/freezer/mode/mongo.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2015,2016 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from oslo_log import log
16 |
17 | from freezer.mode import mode
18 |
19 | LOG = log.getLogger(__name__)
20 |
21 |
22 | class MongoMode(mode.Mode):
23 | """
24 | Execute the necessary tasks for file system backup mode
25 | """
26 |
27 | @property
28 | def name(self):
29 | return "mongo"
30 |
31 | @property
32 | def version(self):
33 | return "1.0"
34 |
35 | def release(self):
36 | pass
37 |
38 | def prepare(self):
39 | pass
40 |
41 | def __init__(self, conf):
42 | try:
43 | import pymongo
44 | except ImportError:
45 | raise ImportError('please install pymongo module')
46 |
47 | LOG.info('MongoDB backup is being executed...')
48 | LOG.info('Checking is the localhost is Master/Primary...')
49 | # todo unhardcode this
50 | mongodb_port = '27017'
51 | local_hostname = conf.hostname
52 | db_host_port = '{0}:{1}'.format(local_hostname, mongodb_port)
53 | mongo_client = pymongo.MongoClient(db_host_port)
54 | master_dict = dict(mongo_client.admin.command("isMaster"))
55 | if master_dict['me'] != master_dict['primary']:
56 | raise Exception('localhost {0} is not Master/Primary,\
57 | exiting...'.format(local_hostname))
58 |
--------------------------------------------------------------------------------
/freezer/mode/mysql.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2015,2016 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from freezer.mode import mode
16 | from freezer.utils import config
17 |
18 |
19 | class MysqlMode(mode.Mode):
20 | """
21 | Execute a MySQL DB backup. currently only backup with lvm snapshots
22 | are supported. This mean, just before the lvm snap vol is created,
23 | the db tables will be flushed and locked for read, then the lvm create
24 | command will be executed and after that, the table will be unlocked and
25 | the backup will be executed. It is important to have the available in
26 | backup_args.mysql_conf the file where the database host, name, user,
27 | password and port are set.
28 | """
29 |
30 | @property
31 | def name(self):
32 | return "mysql"
33 |
34 | @property
35 | def version(self):
36 | return "1.0"
37 |
38 | def release(self):
39 | if not self.released:
40 | self.released = True
41 | self.cursor.execute('UNLOCK TABLES')
42 | self.mysql_db_inst.commit()
43 | self.cursor.close()
44 | self.mysql_db_inst.close()
45 |
46 | def prepare(self):
47 | self.released = False
48 | self.cursor = self.mysql_db_inst.cursor()
49 | self.cursor.execute('FLUSH TABLES WITH READ LOCK')
50 | self.mysql_db_inst.commit()
51 |
52 | def __init__(self, conf):
53 | try:
54 | import pymysql as MySQLdb
55 | except ImportError:
56 | raise ImportError('Please install PyMySQL module')
57 |
58 | with open(conf.mysql_conf, 'r') as mysql_file_fd:
59 | parsed_config = config.ini_parse(mysql_file_fd)
60 | # Initialize the DB object and connect to the db according to
61 | # the db mysql backup file config
62 | self.released = False
63 | try:
64 | self.mysql_db_inst = MySQLdb.connect(
65 | host=parsed_config.get("host", False),
66 | port=int(parsed_config.get("port", 3306)),
67 | user=parsed_config.get("user", False),
68 | passwd=parsed_config.get("password", False))
69 | self.cursor = None
70 | except Exception as error:
71 | raise Exception('MySQL: {0}'.format(error))
72 |
--------------------------------------------------------------------------------
/freezer/mode/nova.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2016 Hewlett-Packard Enterprise Development , L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from freezer.mode import mode
16 |
17 |
18 | class NovaMode(mode.Mode):
19 | """
20 | Execute a nova backup/restore
21 | """
22 | def __init__(self, conf):
23 | self.conf = conf
24 |
25 | @property
26 | def name(self):
27 | return "nova"
28 |
29 | @property
30 | def version(self):
31 | return "1.0"
32 |
33 | def release(self):
34 | pass
35 |
36 | def prepare(self):
37 | pass
38 |
--------------------------------------------------------------------------------
/freezer/mode/sqlserver.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2015,2016 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | from oslo_log import log
17 |
18 | from freezer.mode import mode
19 | from freezer.utils import config
20 | from freezer.utils import utils
21 | from freezer.utils import winutils
22 |
23 | LOG = log.getLogger(__name__)
24 |
25 |
26 | class SqlserverMode(mode.Mode):
27 | """
28 | Execute a SQL Server DB backup. Currently only backups with shadow
29 | copy are supported. This mean, as soon as the shadow copy is created
30 | the db writes will be blocked and a checkpoint will be created, as soon
31 | as the backup finish the db will be unlocked and the backup will be
32 | uploaded. A sql_server.conf_file is required for this operation.
33 | """
34 | def __init__(self, conf):
35 | self.released = False
36 | with open(conf.sql_server_conf, 'r') as sql_conf_file_fd:
37 | self.sql_server_instance = \
38 | config.ini_parse(sql_conf_file_fd)["instance"]
39 |
40 | @property
41 | def name(self):
42 | return "sqlserver"
43 |
44 | @property
45 | def version(self):
46 | return "1.0"
47 |
48 | def stop_sql_server(self):
49 | """ Stop a SQL Server instance to
50 | perform the backup of the db files """
51 |
52 | LOG.info('Stopping SQL Server for backup')
53 | with winutils.DisableFileSystemRedirection():
54 | cmd = 'net stop "SQL Server ({0})"'\
55 | .format(self.sql_server_instance)
56 | (out, err) = utils.create_subprocess(cmd)
57 | if err != '':
58 | raise Exception('Error while stopping SQL Server,'
59 | ', error {0}'.format(err))
60 |
61 | def start_sql_server(self):
62 | """ Start the SQL Server instance after the backup is completed """
63 |
64 | with winutils.DisableFileSystemRedirection():
65 | cmd = 'net start "SQL Server ({0})"'.format(
66 | self.sql_server_instance)
67 | (out, err) = utils.create_subprocess(cmd)
68 | if err != '':
69 | raise Exception('Error while starting SQL Server'
70 | ', error {0}'.format(err))
71 | LOG.info('SQL Server back to normal')
72 |
73 | def prepare(self):
74 | self.stop_sql_server()
75 | self.released = False
76 |
77 | def release(self):
78 | if not self.released:
79 | self.released = True
80 | self.start_sql_server()
81 |
--------------------------------------------------------------------------------
/freezer/openstack/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/openstack/__init__.py
--------------------------------------------------------------------------------
/freezer/openstack/backup.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | """
17 | Freezer Backup modes related functions
18 | """
19 |
20 | from oslo_config import cfg
21 | from oslo_log import log
22 |
23 | from freezer.utils import utils
24 |
25 | CONF = cfg.CONF
26 | LOG = log.getLogger(__name__)
27 |
28 |
29 | class BackupOs(object):
30 |
31 | def __init__(self, client_manager, container, storage):
32 | """
33 |
34 | :param client_manager:
35 | :param container:
36 | :param storage:
37 | :type storage: freezer.swift.SwiftStorage
38 | :return:
39 | """
40 | self.client_manager = client_manager
41 | self.container = container
42 | self.storage = storage
43 |
44 | def backup_cinder_by_glance(self, volume_id):
45 | """
46 | Implements cinder backup:
47 | 1) Gets a stream of the image from glance
48 | 2) Stores resulted image to the swift as multipart object
49 |
50 | :param volume_id: id of volume for backup
51 | """
52 | client_manager = self.client_manager
53 | cinder = client_manager.get_cinder()
54 |
55 | volume = cinder.volumes.get(volume_id)
56 | LOG.debug("Creation temporary snapshot")
57 | snapshot = client_manager.provide_snapshot(
58 | volume, "backup_snapshot_for_volume_%s" % volume_id)
59 | LOG.debug("Creation temporary volume")
60 | copied_volume = client_manager.do_copy_volume(snapshot)
61 | LOG.debug("Creation temporary glance image")
62 | image = client_manager.make_glance_image(copied_volume.id,
63 | copied_volume)
64 | LOG.debug("Download temporary glance image {0}".format(image.id))
65 | stream = client_manager.download_image(image)
66 | package = "{0}/{1}".format(volume_id, utils.DateTime.now().timestamp)
67 | LOG.debug("Saving image to {0}".format(self.storage.type))
68 | if volume.name is None:
69 | name = volume_id
70 | else:
71 | name = volume.name
72 | headers = {'x-object-meta-length': str(len(stream)),
73 | 'volume_name': name,
74 | 'availability_zone': volume.availability_zone
75 | }
76 | attachments = volume._info['attachments']
77 | if attachments:
78 | headers['server'] = attachments[0]['server_id']
79 | self.storage.add_stream(stream, package, headers=headers)
80 | LOG.debug("Deleting temporary snapshot")
81 | client_manager.clean_snapshot(snapshot)
82 | LOG.debug("Deleting temporary volume")
83 | cinder.volumes.delete(copied_volume)
84 | LOG.debug("Deleting temporary image")
85 | client_manager.get_glance().images.delete(image.id)
86 |
87 | def backup_cinder(self, volume_id, name=None, description=None,
88 | incremental=False):
89 | client_manager = self.client_manager
90 | cinder = client_manager.get_cinder()
91 | container = "{0}/{1}/{2}".format(self.container, volume_id,
92 | utils.DateTime.now().timestamp)
93 | if incremental:
94 | search_opts = {
95 | 'volume_id': volume_id,
96 | 'status': 'available'
97 | }
98 | backups = cinder.backups.list(search_opts=search_opts)
99 | if len(backups) <= 0:
100 | cinder.backups.create(volume_id, container, name, description,
101 | incremental=False, force=True)
102 | else:
103 | cinder.backups.create(volume_id, container, name, description,
104 | incremental=incremental, force=True)
105 | else:
106 | cinder.backups.create(volume_id, container, name, description,
107 | incremental=incremental, force=True)
108 |
--------------------------------------------------------------------------------
/freezer/scheduler/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/scheduler/__init__.py
--------------------------------------------------------------------------------
/freezer/scheduler/utils.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015 Hewlett-Packard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | import os
17 | import signal
18 | import socket
19 |
20 | from freezerclient import exceptions
21 | from oslo_config import cfg
22 | from oslo_log import log
23 | from oslo_serialization import jsonutils as json
24 | from oslo_utils import uuidutils
25 | import psutil
26 |
27 |
28 | CONF = cfg.CONF
29 | LOG = log.getLogger(__name__)
30 |
31 | CONFIG_FILE_EXT = '.conf'
32 |
33 |
34 | def do_register(client, args=None):
35 | if client:
36 | client_info = {
37 | "client_id": client.client_id,
38 | "hostname": socket.gethostname(),
39 | "supported_actions": CONF.capabilities.supported_actions,
40 | "supported_modes": CONF.capabilities.supported_modes,
41 | "supported_storages": CONF.capabilities.supported_storages,
42 | "supported_engines": CONF.capabilities.supported_engines,
43 | }
44 | try:
45 | client.clients.create(client_info)
46 | except exceptions.ApiClientException as e:
47 | if e.status_code == 409:
48 | print("Client already registered")
49 | return 73 # os.EX_CANTCREAT
50 | return 0 # os.EX_OK
51 |
52 |
53 | def find_config_files(path):
54 | expanded_path = os.path.expanduser(path)
55 | if os.path.isfile(expanded_path):
56 | return [expanded_path]
57 | file_list = []
58 | if os.path.isdir(expanded_path):
59 | for fname in next(os.walk(expanded_path))[2]:
60 | if CONFIG_FILE_EXT.upper() == os.path.splitext(fname)[1].upper():
61 | file_list.append('{0}/{1}'.format(expanded_path, fname))
62 | return file_list
63 | raise Exception("unable to find job files at the provided path "
64 | "{0}".format(path))
65 |
66 |
67 | def load_doc_from_json_file(fname, debug=False):
68 | with open(fname, 'rb') as fd:
69 | try:
70 | doc = json.load(fd)
71 | except Exception as e:
72 | raise Exception("Unable to load conf file. {0}".format(e))
73 | if debug:
74 | print("File {0} loaded: ".format(fname))
75 | return doc
76 |
77 |
78 | def save_doc_to_json_file(doc, fname, debug=False):
79 | with open(fname, 'w') as fd:
80 | json.dump(doc, fd, indent=4)
81 | if debug:
82 | print('Saved doc to file: {0}'.format(fname))
83 |
84 |
85 | def get_jobs_from_disk(path):
86 | job_doc_list = [
87 | load_doc_from_json_file(f) for f in find_config_files(path)]
88 | for job_doc in job_doc_list:
89 | if job_doc:
90 | job_doc['job_id'] = job_doc.get('job_id', uuidutils.generate_uuid(
91 | dashed=False))
92 | return [x for x in job_doc_list if x]
93 |
94 |
95 | def save_jobs_to_disk(job_doc_list, path):
96 | for doc in job_doc_list:
97 | fname = os.path.normpath('{0}/job_{1}.conf'.
98 | format(path, doc['job_id']))
99 | save_doc_to_json_file(doc, fname)
100 |
101 |
102 | def get_active_jobs_from_api(client):
103 | # might raise
104 | search = {"match_not": [{"status": "completed"}]}
105 | job_list, offset = [], 0
106 | while True:
107 | jobs = client.jobs.list(limit=10, offset=offset, search=search)
108 | job_list.extend(jobs)
109 | if len(jobs) < 10:
110 | break
111 | offset += len(jobs)
112 | return job_list
113 |
114 |
115 | def terminate_subprocess(pid, name):
116 | try:
117 | process = psutil.Process(pid)
118 | if process.name.startswith(name):
119 | os.kill(pid, signal.SIGTERM)
120 | else:
121 | LOG.warning('The name {} does not match the pid {}'.format(
122 | name, pid))
123 | except Exception:
124 | LOG.debug('Process {} does not exists anymore'.format(pid))
125 |
--------------------------------------------------------------------------------
/freezer/scheduler/win_service.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014 Hewlett-Packard
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import os
16 | import servicemanager
17 | import sys
18 | import win32event
19 | import win32service
20 | import win32serviceutil
21 |
22 | from freezer.utils import winutils
23 |
24 |
25 | class PySvc(win32serviceutil.ServiceFramework):
26 | _svc_name_ = "FreezerService"
27 | _svc_display_name_ = "Freezer Service"
28 | _svc_description_ = "Freezer Service"
29 |
30 | def __init__(self, args):
31 | win32serviceutil.ServiceFramework.__init__(self, args)
32 | # create an event to listen for stop requests on
33 | self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
34 | self.home = r'C:\.freezer'
35 | self.insecure = False
36 |
37 | def SvcDoRun(self):
38 | """Run the windows service and start the scheduler in the background
39 | """
40 | rc = None
41 |
42 | self.main()
43 |
44 | # if the stop event hasn't been fired keep looping
45 | while rc != win32event.WAIT_OBJECT_0:
46 | # block for 5 seconds and listen for a stop event
47 | rc = win32event.WaitForSingleObject(self.hWaitStop, 5000)
48 |
49 | def SvcStop(self):
50 | """Stop the windows service and stop the scheduler instance
51 | """
52 | # tell the SCM we're shutting down
53 | self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
54 |
55 | # fire the stop event
56 | servicemanager.LogInfoMsg("freezer-scheduler stopped")
57 | win32event.SetEvent(self.hWaitStop)
58 |
59 | def main(self):
60 | from freezer.scheduler.freezer_scheduler import FreezerScheduler
61 | from freezerclient.v1.client import Client
62 |
63 | servicemanager.LogMsg(
64 | servicemanager.EVENTLOG_INFORMATION_TYPE,
65 | servicemanager.PYS_SERVICE_STARTED,
66 | (self._svc_name_, ''))
67 |
68 | winutils.set_environment(self.home)
69 |
70 | if os.environ.get('SERVICE_INSECURE'):
71 | self.insecure = True
72 |
73 | # only support for keystone v3
74 | credentials = {}
75 | # if os.environ['OS_IDENTITY_API_VERSION'] == 3:
76 | credentials = {
77 | 'username': os.environ['OS_USERNAME'],
78 | 'password': os.environ['OS_PASSWORD'],
79 | 'auth_url': os.environ['OS_AUTH_URL'],
80 | 'endpoint': os.environ['OS_BACKUP_URL'],
81 | 'project_name': os.environ['OS_PROJECT_NAME'],
82 | 'user_domain_name': os.environ['OS_USER_DOMAIN_NAME'],
83 | 'project_domain_name': os.environ['OS_PROJECT_DOMAIN_NAME'],
84 | 'insecure': self.insecure
85 | }
86 |
87 | client = Client(**credentials)
88 |
89 | scheduler = FreezerScheduler(
90 | apiclient=client, interval=int(os.environ['SERVICE_INTERVAL']),
91 | job_path=os.environ['SERVICE_JOB_PATH'],
92 | concurrent_jobs=int(os.environ['SERVICE_CONCURRENT_JOBS']))
93 |
94 | scheduler.start()
95 |
96 |
97 | if __name__ == '__main__':
98 | if len(sys.argv) == 1:
99 | servicemanager.Initialize()
100 | servicemanager.PrepareToHostSingle(PySvc)
101 | servicemanager.StartServiceCtrlDispatcher()
102 | else:
103 | win32serviceutil.HandleCommandLine(PySvc)
104 |
--------------------------------------------------------------------------------
/freezer/scripts/vss.ps1:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | param([String]$volume="")
16 |
17 | $shadow = get-wmiobject win32_shadowcopy
18 |
19 | # get static method
20 | $class=[WMICLASS]"root\cimv2:win32_shadowcopy"
21 |
22 | # create a new shadow copy
23 | $s1 = $class.create($volume, "ClientAccessible")
24 |
25 | # get shadow ID
26 | $s2 = gwmi Win32_ShadowCopy | ? { $_.ID -eq $s1.ShadowID }
27 |
28 | $d = $s2.DeviceObject + "\"
29 |
30 | # create a symlink for the shadow path
31 | cmd /c mklink /d $volume\freezer_shadowcopy "$d"
32 |
33 | echo "shadow id:" $s2
--------------------------------------------------------------------------------
/freezer/snapshot/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/snapshot/__init__.py
--------------------------------------------------------------------------------
/freezer/snapshot/snapshot.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | """
17 | Freezer Backup modes related functions
18 | """
19 |
20 | from freezer.snapshot import lvm
21 | from freezer.snapshot import vss
22 | from freezer.utils import winutils
23 |
24 |
25 | def snapshot_create(backup_opt_dict):
26 | """
27 | Calls the code to take fs snapshots, depending on the platform
28 |
29 | :param backup_opt_dict:
30 | :return: boolean value, True if snapshot has been taken, false otherwise
31 | """
32 | if not backup_opt_dict.snapshot:
33 | return False
34 |
35 | if winutils.is_windows():
36 | if backup_opt_dict.snapshot:
37 | # Create a shadow copy.
38 | backup_opt_dict.shadow_path, backup_opt_dict.shadow = \
39 | vss.vss_create_shadow_copy(backup_opt_dict.windows_volume)
40 |
41 | backup_opt_dict.path_to_backup = winutils.use_shadow(
42 | backup_opt_dict.path_to_backup,
43 | backup_opt_dict.windows_volume)
44 | return True
45 | return False
46 | else:
47 | return lvm.lvm_snap(backup_opt_dict)
48 |
49 |
50 | def snapshot_remove(backup_opt_dict, shadow, windows_volume):
51 | if winutils.is_windows():
52 | # Delete the shadow copy after the backup
53 | vss.vss_delete_shadow_copy(shadow, windows_volume)
54 | else:
55 | # Unmount and remove lvm snapshot volume
56 | lvm.lvm_snap_remove(backup_opt_dict)
57 |
--------------------------------------------------------------------------------
/freezer/snapshot/vss.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import os
16 |
17 | from oslo_log import log
18 |
19 | from freezer.utils import utils
20 | from freezer.utils import winutils
21 |
22 | LOG = log.getLogger(__name__)
23 |
24 |
25 | def vss_create_shadow_copy(windows_volume):
26 | """
27 | Create a new shadow copy for the specified volume
28 |
29 | Windows registry path for vssadmin:
30 | HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VSS\Settings
31 |
32 | MaxShadowCopies
33 | Windows is limited in how many shadow copies can create per volume.
34 | The default amount of shadow copies is 64, the minimum is 1 and the maxi-
35 | mum is 512, if you want to change the default value you need to add/edit
36 | the key MaxShadowCopies and set the amount of shadow copies per volume.
37 |
38 | MinDiffAreaFileSize
39 | The minimum size of the shadow copy storage area is a per-computer setting
40 | that can be specified by using the MinDiffAreaFileSize registry value.
41 |
42 | If the MinDiffAreaFileSize registry value is not set, the minimum size of
43 | the shadow copy storage area is 32 MB for volumes that are smaller than
44 | 500 MB and 320 MB for volumes that are larger than 500 MB.
45 |
46 | If you have not set a maximum size, there is no limit to the amount
47 | of space that can be used.
48 |
49 | If the MinDiffAreaFileSize registry value does not exist, the backup
50 | application can create it under the following registry key:
51 |
52 | HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VolSnap
53 |
54 |
55 | Freezer create a shadow copy for each time the client runs it's been
56 | removed after the backup is complete.
57 |
58 | :param volume: The letter of the windows volume e.g. c:\\
59 | :return: shadow_id: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
60 | :return: shadow_path: shadow copy path
61 | """
62 | shadow_path = None
63 | shadow_id = None
64 |
65 | vss_delete_symlink(windows_volume)
66 |
67 | with winutils.DisableFileSystemRedirection():
68 | path = os.path.dirname(os.path.abspath(__file__))
69 | script = '{0}\\scripts\\vss.ps1'.format(path)
70 | (out, err) = utils.create_subprocess(
71 | ['powershell.exe', '-executionpolicy', 'unrestricted',
72 | '-command', script, '-volume', windows_volume])
73 | if err != '':
74 | raise Exception('Error creating a new shadow copy on {0}'
75 | ', error {1}' .format(windows_volume, err))
76 |
77 | for line in out.split('\n'):
78 | if 'symbolic' in line:
79 | shadow_path = line.split('>>')[1].strip()
80 | if '__RELPATH' in line:
81 | shadow_id = line.split('=')[1].strip().lower() + '}'
82 | shadow_id = shadow_id[1:]
83 |
84 | LOG.info('Created shadow copy {0}'.format(shadow_id))
85 |
86 | return shadow_path, shadow_id
87 |
88 |
89 | def vss_delete_shadow_copy(shadow_id, windows_volume):
90 | """
91 | Delete a shadow copy from the volume with the given shadow_id
92 | :param shadow_id: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
93 | :return: bool
94 | """
95 |
96 | with winutils.DisableFileSystemRedirection():
97 | cmd = ['vssadmin', 'delete', 'shadows',
98 | '/shadow={0}'.format(shadow_id), '/quiet']
99 | (out, err) = utils.create_subprocess(cmd)
100 | if err != '':
101 | raise Exception('Error deleting shadow copy with id {0}'
102 | ', error {1}' .format(shadow_id, err))
103 |
104 | vss_delete_symlink(windows_volume)
105 |
106 | LOG.info('Deleting shadow copy {0}'.format(shadow_id))
107 |
108 | return True
109 |
110 |
111 | def vss_delete_symlink(windows_volume):
112 | """Delete shadow copy symlink on the file system"""
113 | path = os.path.join(windows_volume, 'freezer_shadowcopy')
114 | try:
115 | if os.path.exists(path):
116 | os.rmdir(path)
117 | except Exception:
118 | LOG.error('Failed to delete shadow copy symlink {0}'.
119 | format(os.path.join(windows_volume,
120 | 'freezer_shadowcopy')))
121 |
--------------------------------------------------------------------------------
/freezer/storage/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/storage/__init__.py
--------------------------------------------------------------------------------
/freezer/storage/exceptions.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2016 Hewlett-Packard Enterprise Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | class StorageException(Exception):
17 |
18 | def __init__(self, message):
19 | super(StorageException, self).__init__(message)
20 |
--------------------------------------------------------------------------------
/freezer/storage/fslike.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import abc
16 |
17 | from oslo_serialization import jsonutils as json
18 |
19 | from freezer.storage import physical
20 |
21 |
22 | class FsLikeStorage(physical.PhysicalStorage, metaclass=abc.ABCMeta):
23 | _type = 'fslike'
24 |
25 | def __init__(self, storage_path,
26 | max_segment_size, skip_prepare=False):
27 | super(FsLikeStorage, self).__init__(
28 | storage_path=storage_path,
29 | max_segment_size=max_segment_size,
30 | skip_prepare=skip_prepare)
31 |
32 | def prepare(self):
33 | self.create_dirs(self.storage_path)
34 |
35 | def info(self):
36 | pass
37 |
38 | def write_backup(self, rich_queue, backup):
39 | """
40 | Stores backup in storage
41 | :type rich_queue: freezer.utils.streaming.RichQueue
42 | :type backup: freezer.storage.base.Backup
43 | """
44 | backup = backup.copy(storage=self)
45 | path = backup.data_path
46 | self.create_dirs(path.rsplit('/', 1)[0])
47 |
48 | with self.open(path, mode='wb') as \
49 | b_file:
50 | for message in rich_queue.get_messages():
51 | b_file.write(message)
52 |
53 | def backup_blocks(self, backup):
54 | """
55 |
56 | :param backup:
57 | :type backup: freezer.storage.base.Backup
58 | :return:
59 | """
60 | with self.open(backup.data_path, 'rb') as backup_file:
61 | while True:
62 | chunk = backup_file.read(self.max_segment_size)
63 | if len(chunk):
64 | yield chunk
65 | else:
66 | break
67 |
68 | @abc.abstractmethod
69 | def open(self, filename, mode):
70 | """
71 | :type filename: str
72 | :param filename:
73 | :type mode: str
74 | :param mode:
75 | :return:
76 | """
77 | pass
78 |
79 | def add_stream(self, stream, package_name, headers=None):
80 | """
81 | :param stream: data
82 | :param package_name: path
83 | :param headers: backup metadata information
84 | :return:
85 | """
86 | split = package_name.rsplit('/', 1)
87 | # create backup_basedir
88 | backup_basedir = "{0}/{1}".format(self.storage_path,
89 | package_name)
90 | self.create_dirs(backup_basedir)
91 | # define backup_data_name
92 | backup_basepath = "{0}/{1}".format(backup_basedir,
93 | split[0])
94 | backup_metadata = "%s/metadata" % backup_basedir
95 | # write backup to backup_basepath
96 | with self.open(backup_basepath, 'wb') as backup_file:
97 | for el in stream:
98 | backup_file.write(el)
99 | # write data matadata to backup_metadata
100 | with self.open(backup_metadata, 'wb') as backup_meta:
101 | backup_meta.write(json.dumps(headers))
102 |
--------------------------------------------------------------------------------
/freezer/storage/local.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | import io
17 | import os
18 | import shutil
19 |
20 | from freezer.storage import fslike
21 | from freezer.utils import utils
22 |
23 |
24 | class LocalStorage(fslike.FsLikeStorage):
25 | _type = 'local'
26 |
27 | def get_file(self, from_path, to_path):
28 | shutil.copyfile(from_path, to_path)
29 |
30 | def put_file(self, from_path, to_path):
31 | shutil.copyfile(from_path, to_path)
32 |
33 | def listdir(self, directory):
34 | try:
35 | return os.listdir(directory)
36 | except OSError:
37 | return list()
38 |
39 | def create_dirs(self, path):
40 | utils.create_dir_tree(path)
41 |
42 | def rmtree(self, path):
43 | shutil.rmtree(path)
44 |
45 | def open(self, filename, mode):
46 | return io.open(filename, mode)
47 |
--------------------------------------------------------------------------------
/freezer/storage/physical.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2016 Hewlett-Packard Enterprise Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | import abc
17 | import os
18 |
19 |
20 | from freezer.storage import base
21 | from freezer.utils import utils
22 |
23 |
24 | class PhysicalStorage(base.Storage, metaclass=abc.ABCMeta):
25 | """
26 | Backup like Swift, SSH or Local. Something that represents real storage.
27 | For example MultipleStorage is not physical.
28 | """
29 |
30 | def __init__(self, storage_path, max_segment_size,
31 | skip_prepare=False):
32 | self.storage_path = storage_path
33 | self.max_segment_size = max_segment_size
34 | super(PhysicalStorage, self).__init__(skip_prepare=skip_prepare)
35 |
36 | def metadata_path(self, engine, hostname_backup_name):
37 | return utils.path_join(self.storage_path, "metadata", engine.name,
38 | hostname_backup_name)
39 |
40 | def get_level_zero(self,
41 | engine,
42 | hostname_backup_name,
43 | recent_to_date=None):
44 | """
45 | Gets backups by backup_name and hostname
46 |
47 | :type engine: freezer.engine.engine.BackupEngine
48 | :param engine: Search for backups made by specified engine
49 | :type hostname_backup_name: str
50 | :param hostname_backup_name: Search for backup with specified name
51 | :type recent_to_date: int
52 | :param recent_to_date:
53 | :rtype: list[freezer.storage.base.Backup]
54 | :return: dictionary of level zero timestamps with attached storage
55 | """
56 |
57 | path = self.metadata_path(
58 | engine=engine,
59 | hostname_backup_name=hostname_backup_name)
60 |
61 | zeros = [base.Backup(
62 | storage=self,
63 | engine=engine,
64 | hostname_backup_name=hostname_backup_name,
65 | level_zero_timestamp=int(t),
66 | timestamp=int(t),
67 | level=0) for t in self.listdir(path)]
68 | if recent_to_date:
69 | zeros = [zero for zero in zeros
70 | if zero.timestamp <= recent_to_date]
71 | return zeros
72 |
73 | @abc.abstractmethod
74 | def backup_blocks(self, backup):
75 | """
76 | :param backup:
77 | :type backup: freezer.storage.base.Backup
78 | :return:
79 | """
80 | pass
81 |
82 | @abc.abstractmethod
83 | def listdir(self, path):
84 | """
85 | :type path: str
86 | :param path:
87 | :rtype: collections.Iterable[str]
88 | """
89 | pass
90 |
91 | def put_metadata(self,
92 | engine_metadata_path,
93 | freezer_metadata_path,
94 | backup):
95 | """
96 | :param engine_metadata_path:
97 | :param freezer_metadata_path:
98 | :type backup: freezer.storage.base.Backup
99 | :param backup:
100 | :return:
101 | """
102 | backup = backup.copy(self)
103 | self.put_file(engine_metadata_path, backup.engine_metadata_path)
104 | self.create_dirs(os.path.dirname(backup.metadata_path))
105 | self.put_file(freezer_metadata_path, backup.metadata_path)
106 |
107 | @abc.abstractmethod
108 | def rmtree(self, path):
109 | pass
110 |
--------------------------------------------------------------------------------
/freezer/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/tests/__init__.py
--------------------------------------------------------------------------------
/freezer/tests/integration/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/tests/integration/__init__.py
--------------------------------------------------------------------------------
/freezer/tests/integration/test_version.py:
--------------------------------------------------------------------------------
1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development Company LP
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | import subprocess
16 |
17 | from tempest.lib import decorators
18 |
19 | from freezer import __version__ as freezer_version
20 | from freezer.tests.integration import common
21 |
22 |
23 | class TestFreezerVersion(common.TestFS):
24 |
25 | @decorators.attr(type="gate")
26 | def test_version(self):
27 |
28 | version = subprocess.check_output(['freezer-agent', '--version'],
29 | stderr=subprocess.STDOUT)
30 | self.assertEqual(freezer_version, version.strip())
31 |
--------------------------------------------------------------------------------
/freezer/tests/unit/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/tests/unit/__init__.py
--------------------------------------------------------------------------------
/freezer/tests/unit/engines/__init__.py:
--------------------------------------------------------------------------------
1 | __author__ = 'reldan'
2 |
--------------------------------------------------------------------------------
/freezer/tests/unit/engines/nova/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/tests/unit/engines/nova/__init__.py
--------------------------------------------------------------------------------
/freezer/tests/unit/engines/rsync/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/tests/unit/engines/rsync/__init__.py
--------------------------------------------------------------------------------
/freezer/tests/unit/engines/rsync/test_pyrsync.py:
--------------------------------------------------------------------------------
1 | # (C) Copyright 2016 Mirantis, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import unittest
16 |
17 | import io
18 |
19 | from freezer.engine.rsync import pyrsync
20 |
21 |
22 | class TestPyrsync(unittest.TestCase):
23 | def test_blockcheksum(self):
24 | instream = io.BytesIO(b'aae9dd83aa45f906'
25 | b'a4629f42e97eac99'
26 | b'b9882284dc7030ca'
27 | b'427ad365fedd2a55')
28 | weak, strong = pyrsync.blockchecksums(instream, 16)
29 | exp_weak = [736756931, 616825970, 577963056, 633341072]
30 | exp_strong = ['0f923c37c14f648de4065d4666c2429231a923bc',
31 | '9f043572d40922cc45545bd6ec8a650ca095ab84',
32 | '3a0c39d59a6f49975c2be24bc6b37d80a6680dce',
33 | '81487d7e87190cfbbf4f74acc40094c0a6f6ce8a']
34 | self.assertEqual((weak, strong), (exp_weak, exp_strong))
35 |
36 | def test_rsyncdelta(self):
37 | datastream = io.BytesIO(b'addc830058f917ae'
38 | b'a1be5ab4d899b570'
39 | b'85c9534c64d8d71c'
40 | b'1f32cde9c71e5b6d')
41 |
42 | old_weak = [675087508, 698025105, 579470394, 667092162]
43 | old_strong = ['e72251cb70a1b918ee43876896ebb4c8a7225f78',
44 | '3bf6d2483425e8925df06c01ee490e386a9a707a',
45 | '0ba97d95cc49b1ee2863b7dec3d49911502111c2',
46 | '8b92d9f3f6679e1c8ce2f20e2a6217fd7f351f8f']
47 |
48 | changed_indexes = []
49 | cur_index = 0
50 | for block_index in pyrsync.rsyncdelta(datastream,
51 | (old_weak, old_strong), 16):
52 | if not isinstance(block_index, int):
53 | changed_indexes.append(cur_index)
54 | cur_index += 1
55 | exp_changed_indexes = [0, 2]
56 | self.assertEqual(changed_indexes[:-1], exp_changed_indexes)
57 |
--------------------------------------------------------------------------------
/freezer/tests/unit/engines/tar/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/tests/unit/engines/tar/__init__.py
--------------------------------------------------------------------------------
/freezer/tests/unit/engines/tar/test_tar_builders.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import unittest
16 |
17 | from freezer.engine.tar import tar_builders
18 | from freezer.utils import utils
19 |
20 |
21 | class TestTarCommandBuilder(unittest.TestCase):
22 | def setUp(self):
23 | self.builder = tar_builders.TarCommandBuilder(".", "gzip", False,
24 | "gnutar")
25 |
26 | def test_build(self):
27 | self.assertEqual(
28 | self.builder.build(),
29 | "gnutar --create -z --warning=none --no-check-device "
30 | "--one-file-system --preserve-permissions "
31 | "--same-owner --seek --ignore-failed-read .")
32 |
33 | def test_build_listed(self):
34 | self.builder.set_listed_incremental("listed-file.tar")
35 | self.assertEqual(
36 | self.builder.build(),
37 | "gnutar --create -z --warning=none --no-check-device "
38 | "--one-file-system --preserve-permissions --same-owner --seek "
39 | "--ignore-failed-read --listed-incremental=listed-file.tar .")
40 |
41 | def test_build_every_arg(self):
42 | self.builder.set_listed_incremental("listed-file.tar")
43 | self.builder.set_encryption("encrypt_pass_file", "openssl")
44 | self.builder.set_dereference("hard")
45 | self.builder.set_exclude("excluded_files")
46 | self.assertEqual(
47 | self.builder.build(),
48 | "gnutar --create -z --warning=none --no-check-device "
49 | "--one-file-system --preserve-permissions --same-owner "
50 | "--seek --ignore-failed-read --hard-dereference "
51 | "--listed-incremental=listed-file.tar "
52 | "--exclude=\"excluded_files\" . | openssl enc -aes-256-cfb -pass "
53 | "file:encrypt_pass_file && exit ${PIPESTATUS[0]}")
54 |
55 | def test_build_every_arg_windows(self):
56 | self.builder = tar_builders.TarCommandBuilder(".", "gzip", True,
57 | "gnutar")
58 | self.builder.set_listed_incremental("listed-file.tar")
59 | self.builder.set_encryption("encrypt_pass_file", "openssl")
60 | self.builder.set_dereference("hard")
61 | self.builder.set_exclude("excluded_files")
62 | self.assertEqual(
63 | self.builder.build(),
64 | 'gnutar -c -z --incremental --unlink-first --ignore-zeros '
65 | '--hard-dereference --listed-incremental=listed-file.tar '
66 | '--exclude="excluded_files" . '
67 | '| openssl enc -aes-256-cfb -pass file:encrypt_pass_file '
68 | '&& exit ${PIPESTATUS[0]}')
69 |
70 |
71 | class TestTarCommandRestoreBuilder(unittest.TestCase):
72 | def setUp(self):
73 | self.builder = tar_builders.TarCommandRestoreBuilder(
74 | "restore_path", "gzip", False, "gnutar")
75 |
76 | def test(self):
77 | self.assertEqual(
78 | self.builder.build(),
79 | "gnutar -z --incremental --extract --ignore-zeros "
80 | "--warning=none --overwrite --directory restore_path")
81 |
82 | def test_dry_run(self):
83 | self.builder.set_dry_run()
84 | self.assertEqual(
85 | self.builder.build(),
86 | "gnutar -z --incremental --list --ignore-zeros --warning=none")
87 |
88 | def test_all_args(self):
89 | self.builder.set_encryption("encrypt_pass_file", "openssl")
90 | self.assertEqual(
91 | self.builder.build(),
92 | "openssl enc -d -aes-256-cfb -pass file:encrypt_pass_file | "
93 | "gnutar -z --incremental --extract --ignore-zeros"
94 | " --warning=none --overwrite --directory restore_path "
95 | "&& exit ${PIPESTATUS[0]}")
96 |
97 | def test_all_args_windows(self):
98 | self.builder = tar_builders.TarCommandRestoreBuilder(
99 | "restore_path", "gzip", True, "gnutar")
100 | self.builder.set_encryption("encrypt_pass_file", "openssl")
101 | self.assertEqual(
102 | self.builder.build(),
103 | 'openssl enc -d -aes-256-cfb -pass file:encrypt_pass_file '
104 | '| gnutar -x -z --incremental --unlink-first --ignore-zeros '
105 | '&& exit ${PIPESTATUS[0]}')
106 |
107 | def test_get_tar_flag_from_algo(self):
108 | assert tar_builders.get_tar_flag_from_algo('gzip') == '-z'
109 | assert tar_builders.get_tar_flag_from_algo('bzip2') == '-j'
110 | if not utils.is_bsd():
111 | assert tar_builders.get_tar_flag_from_algo('xz') == '-J'
112 |
--------------------------------------------------------------------------------
/freezer/tests/unit/openstack/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/tests/unit/openstack/__init__.py
--------------------------------------------------------------------------------
/freezer/tests/unit/openstack/test_admin.py:
--------------------------------------------------------------------------------
1 | """Freezer admin.py related tests
2 |
3 | (c) Copyright 2018 ZTE Corporation.
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | """
17 |
18 | from freezer.openstack import admin
19 | from freezer.tests import commons
20 |
21 |
22 | class TestAdmin(commons.FreezerBaseTestCase):
23 | def setUp(self):
24 | super(TestAdmin, self).setUp()
25 | self.backup_opt = commons.BackupOpt1()
26 | self.admin_os = admin.AdminOs(self.backup_opt.client_manager)
27 | self.client_manager = self.backup_opt.client_manager
28 |
29 | def test_del_cinderbackup_and_dependend_incremental(self):
30 | self.admin_os.del_cinderbackup_and_dependend_incremental(1)
31 | try:
32 | self.admin_os.del_cinderbackup_and_dependend_incremental(1023)
33 | except Exception as e:
34 | msg = "Delete backup 1023 failed, the status of backup is error."
35 | self.assertEqual(msg, str(e))
36 |
37 | try:
38 | self.admin_os.del_cinderbackup_and_dependend_incremental(1024)
39 | except Exception as e:
40 | msg = "Delete backup 1024 failed due to timeout over 120s," \
41 | " the status of backup is deleting."
42 | self.assertEqual(msg, str(e))
43 |
44 | def test_del_off_limit_fullbackup_keep(self):
45 | self.admin_os.del_off_limit_fullbackup('2', 1)
46 |
47 | def test_del_off_limit_fullbackup_keep_two(self):
48 | self.admin_os.del_off_limit_fullbackup('2', 2)
49 |
50 | def test_remove_cinderbackup_older_than(self):
51 | self.admin_os.remove_cinderbackup_older_than(35, 1463896546.0)
52 | try:
53 | self.admin_os.remove_cinderbackup_older_than(1023, 1463896546.0)
54 | except Exception as e:
55 | msg = "Delete backup 1023 failed, the status of backup is error."
56 | self.assertEqual(msg, str(e))
57 |
58 | try:
59 | self.admin_os.remove_cinderbackup_older_than(1024, 1463896546.0)
60 | except Exception as e:
61 | msg = "Delete backup 1024 failed due to timeout over 120s," \
62 | " the status of backup is deleting."
63 | self.assertEqual(msg, str(e))
64 |
--------------------------------------------------------------------------------
/freezer/tests/unit/openstack/test_backup.py:
--------------------------------------------------------------------------------
1 | """Freezer backup.py related tests
2 |
3 | (c) Copyright 2018 ZTE Corporation.
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 | """
17 |
18 | from freezer.openstack import backup
19 | from freezer.tests import commons
20 |
21 |
22 | class TestBackup(commons.FreezerBaseTestCase):
23 | def setUp(self):
24 | super(TestBackup, self).setUp()
25 | self.backup_opt = commons.BackupOpt1()
26 | self.bakup_os = backup.BackupOs(self.backup_opt.client_manager,
27 | self.backup_opt.container,
28 | self.backup_opt.storage)
29 |
30 | def test_backup_cinder_by_glance(self):
31 | self.bakup_os.backup_cinder_by_glance(35)
32 |
33 | def test_backup_cinder_by_glance_none_name(self):
34 | self.bakup_os.backup_cinder_by_glance(10230)
35 |
36 | def test_backup_cinder_with_incremental(self):
37 | self.bakup_os.backup_cinder(35, incremental=True)
38 |
39 | def test_backup_cinder_without_incremental(self):
40 | self.bakup_os.backup_cinder(35, incremental=False)
41 |
42 | def test_backup_cinder_with_none(self):
43 | self.bakup_os.backup_cinder(10240, incremental=True)
44 |
--------------------------------------------------------------------------------
/freezer/tests/unit/openstack/test_osclients.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | # (c) Copyright 2016 Hewlett-Packard Enterprise Development Company, L.P.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | import unittest
17 | from unittest import mock
18 |
19 | from freezer.openstack import osclients
20 |
21 |
22 | class TestOsClients(unittest.TestCase):
23 | def setUp(self):
24 | self.opts = osclients.OpenstackOpts(
25 | username="user", project_name="project",
26 | auth_url="url/v3", password="password", identity_api_version="3",
27 | insecure=False, cacert='cert', user_domain_name='Default',
28 | project_domain_name='Default').get_opts_dicts()
29 | self.client_manager = osclients.OSClientManager(**self.opts)
30 |
31 | def test_init(self):
32 | self.client_manager.get_cinder()
33 |
34 | def test_create_cinder(self):
35 | self.client_manager.create_cinder()
36 |
37 | def test_create_swift(self):
38 | self.client_manager.create_swift()
39 |
40 | def test_create_nova(self):
41 | self.client_manager.create_nova()
42 |
43 | def test_create_neutron(self):
44 | self.client_manager.create_neutron()
45 |
46 | def test_dry_run(self):
47 | osclients.DryRunSwiftclientConnectionWrapper(mock.Mock())
48 |
49 | def test_get_cinder(self):
50 | self.client_manager.get_cinder()
51 |
52 | def test_get_swift(self):
53 | self.client_manager.get_swift()
54 |
55 | def test_get_glance(self):
56 | self.client_manager.get_glance()
57 |
58 | def test_get_nova(self):
59 | self.client_manager.get_nova()
60 |
61 | def test_get_neutron(self):
62 | self.client_manager.get_neutron()
63 |
--------------------------------------------------------------------------------
/freezer/tests/unit/scheduler/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/tests/unit/scheduler/__init__.py
--------------------------------------------------------------------------------
/freezer/tests/unit/scheduler/commons.py:
--------------------------------------------------------------------------------
1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
2 | # not use this file except in compliance with the License. You may obtain
3 | # a copy of the License at
4 | #
5 | # http://www.apache.org/licenses/LICENSE-2.0
6 | #
7 | # Unless required by applicable law or agreed to in writing, software
8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 | # License for the specific language governing permissions and limitations
11 | # under the License.
12 |
13 | from freezer.scheduler import arguments
14 | from oslo_config import cfg
15 |
16 | CONF = cfg.CONF
17 |
18 |
19 | def set_test_capabilities():
20 | arguments.configure_capabilities_options()
21 | CONF.capabilities.supported_actions = ['backup']
22 | CONF.capabilities.supported_modes = ['cindernative']
23 | CONF.capabilities.supported_storages = ['swift']
24 | CONF.capabilities.supported_engines = []
25 |
26 |
27 | def set_default_capabilities():
28 | CONF.capabilities.supported_actions = arguments.DEFAULT_SUPPORTED_ACTIONS
29 | CONF.capabilities.supported_modes = arguments.DEFAULT_SUPPORTED_MODES
30 | CONF.capabilities.supported_storages = arguments.DEFAULT_SUPPORTED_STORAGES
31 | CONF.capabilities.supported_engines = arguments.DEFAULT_SUPPORTED_ENGINES
32 |
--------------------------------------------------------------------------------
/freezer/tests/unit/scheduler/test_freezer_scheduler.py:
--------------------------------------------------------------------------------
1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
2 | # not use this file except in compliance with the License. You may obtain
3 | # a copy of the License at
4 | #
5 | # http://www.apache.org/licenses/LICENSE-2.0
6 | #
7 | # Unless required by applicable law or agreed to in writing, software
8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 | # License for the specific language governing permissions and limitations
11 | # under the License.
12 |
13 | import unittest
14 | from unittest import mock
15 |
16 | from freezer.scheduler.freezer_scheduler import FreezerScheduler
17 | from freezer.tests.unit.scheduler.commons import set_default_capabilities
18 | from freezer.tests.unit.scheduler.commons import set_test_capabilities
19 |
20 | SUPPORTED_JOB = {
21 | 'job_id': 'test2',
22 | 'job_schedule': {},
23 | 'job_actions': [
24 | {'freezer_action': {'action': 'backup'}},
25 | ],
26 | }
27 | UNSUPPORTED_JOB = {
28 | 'job_id': 'test1',
29 | 'job_schedule': {},
30 | 'job_actions': [
31 | {'freezer_action': {'action': 'exec'}},
32 | ],
33 | }
34 |
35 |
36 | class TestFreezerScheduler(unittest.TestCase):
37 | def setUp(self):
38 | self.scheduler = FreezerScheduler(
39 | apiclient=mock.MagicMock(),
40 | interval=1,
41 | job_path='/tmp/test',
42 | )
43 | set_test_capabilities()
44 |
45 | def tearDown(self):
46 | set_default_capabilities()
47 |
48 | def test_filter_jobs(self):
49 | job_doc_list = [
50 | SUPPORTED_JOB,
51 | UNSUPPORTED_JOB,
52 | ]
53 | expected_jobs = [SUPPORTED_JOB]
54 | filtered_jobs = self.scheduler.filter_jobs(job_doc_list)
55 | self.assertListEqual(filtered_jobs, expected_jobs)
56 |
--------------------------------------------------------------------------------
/freezer/tests/unit/scheduler/test_utils.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2019 ZTE Corporation.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import os
16 | import shutil
17 | import tempfile
18 | import unittest
19 | from unittest import mock
20 | from unittest.mock import patch
21 |
22 | from freezer.scheduler import utils
23 |
24 | job_list = [{"job_id": "test"}]
25 |
26 |
27 | class TestUtils(unittest.TestCase):
28 | def setUp(self):
29 | self.client = mock.Mock()
30 | self.client.clients.create = mock.Mock(return_value='test')
31 | self.client.jobs.list = mock.Mock(return_value=job_list)
32 | self.client.client_id = "test"
33 |
34 | def test_do_register(self):
35 | ret = utils.do_register(self.client, args=None)
36 | self.assertEqual(0, ret)
37 |
38 | def test_del_register_error(self):
39 | self.client.clients.delete = mock.Mock(side_effect=Exception(
40 | 'delete client error: bad request'))
41 | with self.assertRaises(Exception) as cm: # noqa
42 | utils.del_register(self.client)
43 | the_exception = cm.exception
44 | self.assertIn('delete client error', str(the_exception))
45 |
46 | def test_find_config_files(self):
47 | temp = tempfile.NamedTemporaryFile('wb', delete=True,
48 | suffix='.conf')
49 | ret = utils.find_config_files(temp.name)
50 | self.assertEqual([temp.name], ret)
51 | temp.close()
52 | self.assertFalse(os.path.exists(temp.name))
53 |
54 | def test_find_config_files_path(self):
55 | temp = tempfile.NamedTemporaryFile('wb', delete=True,
56 | suffix='.conf')
57 | temp_path = os.path.dirname(temp.name)
58 | ret = utils.find_config_files(temp_path)
59 | self.assertEqual([temp.name], ret)
60 | temp.close()
61 | self.assertFalse(os.path.exists(temp.name))
62 |
63 | @patch('oslo_serialization.jsonutils.load')
64 | def test_load_doc_from_json_file(self, mock_load):
65 | os.mknod("/tmp/test_freezer.conf")
66 | mock_load.side_effect = Exception('error')
67 | try:
68 | utils.load_doc_from_json_file("/tmp/test_freezer.conf")
69 | except Exception as e:
70 | self.assertIn("Unable to load conf file", str(e))
71 | os.remove("/tmp/test_freezer.conf")
72 |
73 | def test_get_jobs_from_disk(self):
74 | temp = tempfile.mkdtemp()
75 | file = '/'.join([temp, "test.conf"])
76 | data = b'{"job_id": "test"}'
77 | with open(file, 'wb') as f:
78 | f.write(data)
79 | ret = utils.get_jobs_from_disk(temp)
80 | self.assertEqual(job_list, ret)
81 | shutil.rmtree(temp)
82 | self.assertFalse(os.path.exists(file))
83 |
84 | def test_save_jobs_to_disk(self):
85 | job_doc_list = job_list
86 | tmpdir = tempfile.mkdtemp()
87 | utils.save_jobs_to_disk(job_doc_list, tmpdir)
88 | file = '/'.join([tmpdir, "job_test.conf"])
89 | self.assertTrue(os.path.exists(file))
90 | shutil.rmtree(tmpdir)
91 |
92 | def test_get_active_jobs_from_api(self):
93 | ret = utils.get_active_jobs_from_api(self.client)
94 | self.assertEqual(job_list, ret)
95 |
96 | @patch('os.kill')
97 | @patch('psutil.Process')
98 | def test_terminate_subprocess1(self, mock_process, mock_oskill):
99 | mock_pro = mock.MagicMock()
100 | mock_pro.name.startswith.return_value = False
101 | mock_process.return_value = mock_pro
102 | result = utils.terminate_subprocess(35, 'test')
103 | self.assertIsNone(result)
104 | mock_pro.name.startswith.return_value = True
105 | mock_oskill.side_effect = Exception("error")
106 | result = utils.terminate_subprocess(35, 'test')
107 | self.assertIsNone(result)
108 |
109 | @patch('psutil.Process')
110 | def test_terminate_subprocess(self, mock_process_constructor):
111 | mock_pro = mock_process_constructor.return_value
112 | seffect = mock.Mock(
113 | side_effect=Exception('Process 35 does not exists anymore'))
114 | mock_pro.raiseError.side_effect = seffect
115 | with self.assertRaises(Exception) as cm: # noqa
116 | utils.terminate_subprocess(35, "test")
117 | the_exception = cm.exception
118 | self.assertIn('does not exists anymore',
119 | str(the_exception))
120 |
--------------------------------------------------------------------------------
/freezer/tests/unit/snapshot/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/tests/unit/snapshot/__init__.py
--------------------------------------------------------------------------------
/freezer/tests/unit/snapshot/test_vss.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import unittest
16 |
17 | from unittest import mock
18 |
19 | from freezer.tests.commons import FakeDisableFileSystemRedirection
20 |
21 |
22 | class TestVss(unittest.TestCase):
23 | def mock_process(self, process):
24 | fakesubprocesspopen = process.Popen()
25 | mock.patch('subprocess.Popen.communicate',
26 | new_callable=fakesubprocesspopen.communicate).start()
27 | mock.patch('subprocess.Popen',
28 | new_callable=fakesubprocesspopen.start())
29 |
30 | def mock_winutils(self):
31 | fake_disable_redirection = FakeDisableFileSystemRedirection()
32 | mock.patch('winutils.DisableFileSystemRedirection.__enter__',
33 | new_callable=fake_disable_redirection.__enter__,
34 | )
35 | mock.patch('winutils.DisableFileSystemRedirection.__exit__',
36 | new_callable=fake_disable_redirection.__exit__,
37 | )
38 |
39 | # def test_vss_create_shadow_copy(self):
40 | # self.mock_process(FakeSubProcess())
41 | # self.mock_winutils()
42 | # assert vss.vss_create_shadow_copy('C:\\') is not False
43 | # self.mock_process(FakeSubProcess3())
44 | # self.assertRaises(Exception, vss.vss_create_shadow_copy('C:\\'))
45 | #
46 | # def test_vss_delete_shadow_copy(self):
47 | # self.mock_winutils()
48 | # self.mock_process(FakeSubProcess6())
49 | # self.assertRaises(Exception, vss.vss_delete_shadow_copy('', ''))
50 | # self.mock_process(FakeSubProcess3())
51 | # self.assertRaises(Exception, vss.vss_delete_shadow_copy('shadow_id',
52 | # 'C:\\'))
53 | # self.mock_process(FakeSubProcess())
54 | # assert vss.vss_delete_shadow_copy('shadow_id', 'C:\\') is True
55 |
--------------------------------------------------------------------------------
/freezer/tests/unit/storages/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/tests/unit/storages/__init__.py
--------------------------------------------------------------------------------
/freezer/tests/unit/storages/test_local.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import shutil
16 | import tempfile
17 | import unittest
18 |
19 | from freezer.storage import local
20 | from freezer.utils import utils
21 |
22 |
23 | class TestLocalStorage(unittest.TestCase):
24 | BACKUP_DIR_PREFIX = "freezer_test_backup_dir"
25 | FILES_DIR_PREFIX = "freezer_test_files_dir"
26 | WORK_DIR_PREFIX = "freezer_work_dir"
27 | HELLO = "Hello World!\n"
28 | temp = True
29 |
30 | def create_content(self, files_dir, file_name="file_1", text=HELLO):
31 | f = open(files_dir + "/" + file_name, 'w')
32 | f.write(text)
33 | f.close()
34 |
35 | def create_dirs(self):
36 | tmpdir = tempfile.mkdtemp()
37 | if self.temp:
38 | backup_dir = tempfile.mkdtemp(
39 | dir=tmpdir, prefix=self.BACKUP_DIR_PREFIX)
40 | files_dir = tempfile.mkdtemp(
41 | dir=tmpdir, prefix=self.FILES_DIR_PREFIX)
42 | work_dir = tempfile.mkdtemp(
43 | dir=tmpdir, prefix=self.WORK_DIR_PREFIX)
44 | else:
45 | backup_dir = tmpdir + self.BACKUP_DIR_PREFIX
46 | files_dir = tmpdir + self.FILES_DIR_PREFIX
47 | work_dir = tmpdir + self.WORK_DIR_PREFIX
48 | utils.create_dir(backup_dir)
49 | utils.create_dir(work_dir)
50 | utils.create_dir(files_dir)
51 | self.create_content(files_dir)
52 | return backup_dir, files_dir, work_dir
53 |
54 | def remove_dirs(self, work_dir, files_dir, backup_dir):
55 | if self.temp:
56 | shutil.rmtree(work_dir)
57 | shutil.rmtree(files_dir)
58 | shutil.rmtree(backup_dir, ignore_errors=True)
59 |
60 | def remove_storage(self, backup_dir):
61 | shutil.rmtree(backup_dir)
62 |
63 | def test_prepare(self):
64 | backup_dir, files_dir, work_dir = self.create_dirs()
65 | storage = local.LocalStorage(backup_dir,
66 | work_dir,
67 | 10000)
68 | storage.prepare()
69 |
70 | def test_info(self):
71 | backup_dir, files_dir, work_dir = self.create_dirs()
72 | storage = local.LocalStorage(backup_dir, work_dir, 10000)
73 | storage.info()
74 |
--------------------------------------------------------------------------------
/freezer/tests/unit/test_job.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | """
17 | Freezer main.py related tests
18 | """
19 |
20 | from unittest import mock
21 | from unittest.mock import patch
22 |
23 | from freezer import job as jobs
24 | from freezer.tests import commons
25 |
26 |
27 | class TestJob(commons.FreezerBaseTestCase):
28 | def setUp(self):
29 | super(TestJob, self).setUp()
30 |
31 | def test_execute(self):
32 | opt = commons.BackupOpt1()
33 | job = jobs.InfoJob(opt, opt.storage)
34 | assert job.execute() is not None
35 |
36 |
37 | class TestInfoJob(TestJob):
38 |
39 | def test_execute_nothing_to_do(self):
40 | backup_opt = commons.BackupOpt1()
41 | job = jobs.InfoJob(backup_opt, backup_opt.storage)
42 | job.execute()
43 |
44 | def test_execute_list_containers(self):
45 | backup_opt = commons.BackupOpt1()
46 | job = jobs.InfoJob(backup_opt, backup_opt.storage)
47 | job.execute()
48 |
49 |
50 | class TestBackupJob(TestJob):
51 | def setUp(self):
52 | super(TestBackupJob, self).setUp()
53 |
54 | def test_execute_backup_fs_no_incremental_and_backup_level_raise(self):
55 | backup_opt = commons.BackupOpt1()
56 | backup_opt.mode = 'default'
57 | backup_opt.no_incremental = True
58 | backup_opt.max_level = None
59 | backup_opt.always_level = None
60 | job = jobs.BackupJob(backup_opt, backup_opt.storage)
61 | self.assertRaises(Exception, job.execute) # noqa
62 |
63 |
64 | class TestAdminJob(TestJob):
65 | def setUp(self):
66 | super(TestAdminJob, self).setUp()
67 |
68 | def test_execute(self):
69 | backup_opt = commons.BackupOpt1()
70 | jobs.AdminJob(backup_opt, backup_opt.storage).execute()
71 |
72 |
73 | class TestExecJob(TestJob):
74 | def setUp(self):
75 | super(TestExecJob, self).setUp()
76 | # init mock_popen
77 | self.popen = patch('freezer.utils.exec_cmd.subprocess.Popen')
78 | self.mock_popen = self.popen.start()
79 | self.mock_popen.return_value = mock.Mock()
80 | self.mock_popen.return_value.communicate = mock.Mock()
81 | self.mock_popen.return_value.communicate.return_value = ['some stderr']
82 |
83 | def tearDown(self):
84 | super(TestExecJob, self).tearDown()
85 | self.popen.stop()
86 |
87 | def test_execute_nothing_to_do(self):
88 | self.mock_popen.return_value.returncode = 0
89 | backup_opt = commons.BackupOpt1()
90 | backup_opt.command = 'ls '
91 | jobs.ExecJob(backup_opt, backup_opt.storage).execute()
92 |
93 | def test_execute_script(self):
94 | self.mock_popen.return_value.returncode = 0
95 | backup_opt = commons.BackupOpt1()
96 | backup_opt.command = 'echo test'
97 | jobs.ExecJob(backup_opt, backup_opt.storage).execute()
98 |
99 | def test_execute_raise(self):
100 | self.popen = patch('freezer.utils.exec_cmd.subprocess.Popen')
101 | self.mock_popen = self.popen.start()
102 | self.mock_popen.return_value.returncode = 1
103 | backup_opt = commons.BackupOpt1()
104 | backup_opt.command = 'echo test'
105 | job = jobs.ExecJob(backup_opt, backup_opt.storage)
106 | self.assertRaises(Exception, job.execute) # noqa
107 |
--------------------------------------------------------------------------------
/freezer/tests/unit/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/tests/unit/utils/__init__.py
--------------------------------------------------------------------------------
/freezer/tests/unit/utils/test_config.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import io
16 | import unittest
17 |
18 | from freezer.utils import config
19 |
20 |
21 | class TestConfig(unittest.TestCase):
22 | def test_export(self):
23 | string = """unset OS_DOMAIN_NAME
24 | export OS_AUTH_URL="http://abracadabra/v3"
25 | export OS_PROJECT_NAME=abracadabra_project
26 | export OS_USERNAME=abracadabra_username
27 | export OS_PASSWORD=abracadabra_password
28 | export OS_PROJECT_DOMAIN_NAME=Default
29 | export OS_USER_DOMAIN_NAME=Default
30 | export OS_IDENTITY_API_VERSION=3
31 | export OS_AUTH_VERSION=3
32 | export OS_CACERT=/etc/ssl/certs/ca-certificates.crt
33 | export OS_ENDPOINT_TYPE=internalURL"""
34 |
35 | res = config.osrc_parse(string)
36 | self.assertEqual("http://abracadabra/v3", res["OS_AUTH_URL"])
37 |
38 | def test_ini(self):
39 | string = """[default]
40 | # This is a comment line
41 | #
42 | host = 127.0.0.1
43 | port = 3306
44 | user = openstack
45 | password = 'aNiceQuotedPassword'
46 | password2 = "aNiceQuotedPassword"
47 | spaced = value"""
48 |
49 | fd = io.StringIO(string)
50 | res = config.ini_parse(fd)
51 | self.assertEqual('127.0.0.1', res['host'])
52 | self.assertEqual('openstack', res['user'])
53 | self.assertEqual('3306', res['port'])
54 |
55 | # python 3.4 tests will fail because aNiceQuatedPassword will
56 | # be quoted like "'aNiceQuotedPassword'" and '"aNiceQuotedPassword"'.
57 | # Solution for now is to strip the inside quotation marks.
58 | self.assertEqual('aNiceQuotedPassword', res['password'].strip("\"")
59 | .strip('\''))
60 | self.assertEqual('aNiceQuotedPassword', res['password2'].strip("\"")
61 | .strip('\''))
62 |
63 | self.assertEqual('value', res['spaced'])
64 |
--------------------------------------------------------------------------------
/freezer/tests/unit/utils/test_crypt.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2018 ZTE Corporation.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import shutil
16 | import tempfile
17 | import unittest
18 |
19 | # from unittest import mock
20 | # from mock import patch
21 |
22 | from freezer.utils import crypt
23 |
24 |
25 | class AESCipherTestCase(unittest.TestCase):
26 |
27 | def setUp(self):
28 | super(AESCipherTestCase, self).setUp()
29 | self.passwd_test_file_dir = None
30 | self.passwd_test_file_name = None
31 | self.create_pass_test_file()
32 |
33 | def tearDown(self):
34 | super(AESCipherTestCase, self).tearDown()
35 | self.delete_pass_test_file()
36 |
37 | def create_pass_test_file(self):
38 | if self.passwd_test_file_name:
39 | return
40 | tmpdir = tempfile.mkdtemp()
41 | FILES_DIR_PREFIX = "freezer_passwd_dir"
42 | files_dir = tempfile.mkdtemp(dir=tmpdir, prefix=FILES_DIR_PREFIX)
43 | file_name = "passwd_test"
44 | self.passwd_test_file_dir = files_dir
45 | text = '78f40f2c57eee727a4be179049cecf89'
46 | filehandle = open(files_dir + "/" + file_name, 'w')
47 | if filehandle:
48 | filehandle.write(text)
49 | filehandle.close()
50 | self.passwd_test_file_name = files_dir + "/" + file_name
51 |
52 | def delete_pass_test_file(self):
53 | if self.passwd_test_file_name:
54 | files_dir = self.passwd_test_file_dir
55 | shutil.rmtree(files_dir)
56 | self.passwd_test_file_name = None
57 | self.passwd_test_file_dir = None
58 |
59 | def test_get_pass_from_file(self):
60 | pfile = self.passwd_test_file_name
61 | passwd = crypt.AESCipher._get_pass_from_file(pfile)
62 | self.assertEqual(passwd, '78f40f2c57eee727a4be179049cecf89')
63 |
64 | # @unittest.skipIf(sys.version_info.major == 3,
65 | # 'Not supported on python v 3.x')
66 | def test_derive_key_and_iv(self):
67 | passwd = b'ababab'
68 | salt = b'a'
69 | ret1, ret2 = crypt.AESCipher._derive_key_and_iv(password=passwd,
70 | salt=salt,
71 | key_length=10,
72 | iv_length=5)
73 | expect1 = b'\xb3J5\xce\xd4b\x87\xce\xe0:'
74 | expect2 = b'\x93\xc9\x9d\x03\x00'
75 | self.assertEqual(ret1, expect1)
76 | self.assertEqual(ret2, expect2)
77 |
--------------------------------------------------------------------------------
/freezer/tests/unit/utils/test_exec_cmd.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import subprocess
16 | import unittest
17 | from unittest import mock
18 | from unittest.mock import patch
19 |
20 | from freezer.utils import exec_cmd
21 |
22 |
23 | class TestExec(unittest.TestCase):
24 | def test_exec_cmd(self):
25 | cmd = "echo test > test.txt"
26 | popen = patch('freezer.utils.exec_cmd.subprocess.Popen')
27 | mock_popen = popen.start()
28 | mock_popen.return_value = mock.Mock()
29 | mock_popen.return_value.communicate = mock.Mock()
30 | mock_popen.return_value.communicate.return_value = ['some stderr']
31 | mock_popen.return_value.returncode = 0
32 | exec_cmd.execute(cmd)
33 | assert (mock_popen.call_count == 1)
34 | mock_popen.assert_called_with(['echo', 'test', '>', 'test.txt'],
35 | shell=False,
36 | stderr=subprocess.PIPE,
37 | stdout=subprocess.PIPE)
38 | popen.stop()
39 |
40 | def test__exec_cmd_with_pipe(self):
41 | cmd = "echo test|wc -l"
42 | popen = patch('freezer.utils.exec_cmd.subprocess.Popen')
43 | mock_popen = popen.start()
44 | mock_popen.return_value = mock.Mock()
45 | mock_popen.return_value.communicate = mock.Mock()
46 | mock_popen.return_value.communicate.return_value = ['some stderr']
47 | mock_popen.return_value.returncode = 0
48 | exec_cmd.execute(cmd)
49 | assert (mock_popen.call_count == 2)
50 | popen.stop()
51 |
--------------------------------------------------------------------------------
/freezer/tests/unit/utils/test_streaming.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2020 ZTE Corporation.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import queue
16 | import unittest
17 |
18 | from freezer.utils import streaming
19 |
20 |
21 | class StreamingTestCase(unittest.TestCase):
22 |
23 | def create_fifo(self, size):
24 | input_queue = streaming.RichQueue(size)
25 | read_except_queue = queue.Queue()
26 | write_except_queue = queue.Queue()
27 |
28 | read_stream = streaming.QueuedThread(self.backup_stream,
29 | input_queue,
30 | read_except_queue)
31 |
32 | write_stream = streaming.QueuedThread(self.write_stream,
33 | input_queue,
34 | write_except_queue)
35 |
36 | read_stream.daemon = True
37 | write_stream.daemon = True
38 | read_stream.start()
39 | write_stream.start()
40 | read_stream.join()
41 | write_stream.join()
42 |
43 | return input_queue
44 |
45 | def backup_stream(self, rich_queue):
46 | rich_queue.put_messages('ancd')
47 |
48 | def write_stream(self, rich_queue):
49 | for message in rich_queue.get_messages():
50 | pass
51 |
52 | def test_stream_1(self):
53 | input_queue = self.create_fifo(1)
54 | assert input_queue.finish_transmission is True
55 |
56 | def test_stream_2(self):
57 | input_queue = self.create_fifo(2)
58 | assert input_queue.finish_transmission is True
59 |
60 | def test_stream_3(self):
61 | input_queue = self.create_fifo(3)
62 | assert input_queue.finish_transmission is True
63 |
64 | def test_stream_4(self):
65 | input_queue = self.create_fifo(4)
66 | assert input_queue.finish_transmission is True
67 |
68 | def test_stream_5(self):
69 | input_queue = self.create_fifo(5)
70 | assert input_queue.finish_transmission is True
71 |
--------------------------------------------------------------------------------
/freezer/tests/unit/utils/test_winutils.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import os
16 | import unittest
17 | from unittest import mock
18 |
19 | from freezer.tests import commons
20 | from freezer.utils import winutils
21 |
22 |
23 | class TestWinutils(unittest.TestCase):
24 |
25 | def mock_process(self, process):
26 | fakesubprocesspopen = process.Popen()
27 | mock.patch('subprocess.Popen.communicate',
28 | new_callable=fakesubprocesspopen.communicate).start()
29 | mock.patch('subprocess.Popen', new_callable=fakesubprocesspopen)\
30 | .start()
31 |
32 | def mock_winutils(self):
33 | fake_disable_redirection = commons.FakeDisableFileSystemRedirection()
34 | mock.patch('winutils.DisableFileSystemRedirection.__enter__',
35 | new_callable=fake_disable_redirection.__enter__)
36 | mock.patch('winutils.DisableFileSystemRedirection.__exit__',
37 | new_callable=fake_disable_redirection.__exit__)
38 |
39 | def test_is_windows(self):
40 | fake_os = commons.Os()
41 | os.name = fake_os
42 | assert winutils.is_windows() is False
43 |
44 | def test_use_shadow(self):
45 | test_volume = 'C:'
46 | test_volume2 = 'C:\\'
47 | path = 'C:\\Users\\Test'
48 | expected = 'C:\\freezer_shadowcopy\\Users\\Test'
49 | assert winutils.use_shadow(path, test_volume2) == expected
50 |
51 | # test if the volume format is incorrect
52 | self.assertRaises(Exception,
53 | winutils.use_shadow(path, test_volume)) # noqa
54 |
55 | # def test_start_sql_server(self):
56 | # backup_opt = BackupOpt1()
57 | # self.mock_process(FakeSubProcess())
58 | # self.mock_winutils()
59 | #
60 | # assert winutils.start_sql_server(
61 | # backup_opt.sql_server_instance) is not False
62 | #
63 | # self.mock_process(FakeSubProcess3())
64 | # self.assertRaises(
65 | # Exception,
66 | # winutils.start_sql_server(backup_opt.sql_server_instance))
67 | #
68 | # def test_stop_sql_server(self):
69 | # backup_opt = BackupOpt1()
70 | # self.mock_process(FakeSubProcess())
71 | # self.mock_winutils()
72 | #
73 | # assert winutils.start_sql_server(
74 | # backup_opt.sql_server_instance) is not False
75 | #
76 | # self.mock_process(FakeSubProcess3())
77 | #
78 | # self.assertRaises(Exception, winutils.stop_sql_server(
79 | # backup_opt.sql_server_instance))
80 |
--------------------------------------------------------------------------------
/freezer/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer/utils/__init__.py
--------------------------------------------------------------------------------
/freezer/utils/compress.py:
--------------------------------------------------------------------------------
1 | # (C) Copyright 2016 Mirantis, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | GZIP = 'zlib'
16 | BZIP2 = 'bz2'
17 | XZ = 'lzma'
18 |
19 | COMPRESS_METHOD = 'compress'
20 | DECOMPRESS_METHOD = 'decompress'
21 |
22 |
23 | def get_compression_algo(compression_algo):
24 | algo = {
25 | 'gzip': GZIP,
26 | 'bzip2': BZIP2,
27 | 'xz': XZ,
28 | }
29 | return algo.get(compression_algo)
30 |
31 |
32 | def one_shot_compress(compression_algo, data):
33 | compression_module = __import__(get_compression_algo(compression_algo))
34 | return getattr(compression_module, COMPRESS_METHOD)(data)
35 |
36 |
37 | def one_shot_decompress(compression_algo, data):
38 | compression_module = __import__(get_compression_algo(compression_algo))
39 | return getattr(compression_module, DECOMPRESS_METHOD)(data)
40 |
41 |
42 | class BaseCompressor(object):
43 | """
44 | Base class for compress/decompress activities.
45 | """
46 |
47 | def __init__(self, compression_algo):
48 | # TODO(raliev): lzma module exists in stdlib since Py3 only
49 | if compression_algo == 'xz':
50 | raise NotImplementedError('XZ compression not implemented yet')
51 | self.algo = get_compression_algo(compression_algo)
52 | self.module = __import__(self.algo)
53 |
54 |
55 | class Compressor(BaseCompressor):
56 | """
57 | Compress chucks of data.
58 | """
59 |
60 | MAX_COMPRESS_LEVEL = 9
61 |
62 | def __init__(self, compression_algo):
63 | super(Compressor, self).__init__(compression_algo)
64 | self.compressobj = self.create_compressobj(compression_algo)
65 |
66 | def create_compressobj(self, compression_algo):
67 | def get_obj_name():
68 | names = {
69 | 'gzip': 'compressobj',
70 | 'bzip2': 'BZ2Compressor',
71 | 'xz': 'compressobj',
72 | }
73 | return names.get(compression_algo)
74 |
75 | obj_name = get_obj_name()
76 | return getattr(self.module, obj_name)(self.MAX_COMPRESS_LEVEL)
77 |
78 | def compress(self, data):
79 | return self.compressobj.compress(data)
80 |
81 | def flush(self):
82 | return self.compressobj.flush()
83 |
84 |
85 | class Decompressor(BaseCompressor):
86 | """
87 | Decompress chucks of data.
88 | """
89 |
90 | def __init__(self, compression_algo):
91 | super(Decompressor, self).__init__(compression_algo)
92 | self.decompressobj = self.create_decompressobj(compression_algo)
93 |
94 | def create_decompressobj(self, compression_algo):
95 | def get_obj_name():
96 | names = {
97 | 'gzip': 'decompressobj',
98 | 'bzip2': 'BZ2Decompressor',
99 | 'xz': 'decompressobj',
100 | }
101 | return names.get(compression_algo)
102 |
103 | obj_name = get_obj_name()
104 | return getattr(self.module, obj_name)()
105 |
106 | def decompress(self, data):
107 | return self.decompressobj.decompress(data)
108 |
109 | def flush(self):
110 | return self.decompressobj.flush()
111 |
--------------------------------------------------------------------------------
/freezer/utils/config.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import configparser
16 | import os
17 | import re
18 |
19 | from oslo_log import log
20 |
21 | from freezer.utils import utils
22 |
23 | LOG = log.getLogger(__name__)
24 |
25 |
26 | EXPORT = re.compile(r"^\s*export\s+([^=^#^\s]+)\s*=\s*([^#^\n]*)\s*$",
27 | re.MULTILINE)
28 |
29 | INI = re.compile(r"^\s*([^=#\s]+)\s*=[\t]*([^#\n]*)\s*$", re.MULTILINE)
30 |
31 |
32 | class Config(object):
33 |
34 | @staticmethod
35 | def parse(config_path):
36 | if config_path:
37 | if not os.path.exists(config_path):
38 | LOG.error("Critical Error: Configuration file {0} not"
39 | " found".format(config_path))
40 | raise Exception("Configuration file {0} not found !".format(
41 | config_path))
42 | # SafeConfigParser was deprecated in Python 3.2
43 | config = configparser.ConfigParser()
44 | config.read([config_path])
45 | sections = config.sections()
46 | storages = []
47 | default_options = {}
48 | for section in sections:
49 | dict = {}
50 | for option in config.options(section):
51 | option_value = config.get(section, option)
52 | if option_value in ('False', 'false', 'None'):
53 | option_value = False
54 | elif option_value in ('True', 'true'):
55 | option_value = True
56 | dict[option] = option_value
57 | if section.startswith("storage:"):
58 | storages.append(dict)
59 | else:
60 | default_options.update(dict)
61 | return Config(default_options, storages)
62 |
63 | def __init__(self, default, storages):
64 | """
65 | :param default:
66 | :type default: dict
67 | :param storages:
68 | :type storages: list[dict]
69 | :return:
70 | """
71 | self.default = default
72 | self.storages = storages
73 |
74 |
75 | def osrc_parse(lines):
76 | """
77 | :param lines:
78 | :type lines: str
79 | :return:
80 | """
81 | return find_all(EXPORT, lines)
82 |
83 |
84 | def ini_parse(fd):
85 | """
86 | :param fd:
87 | :type fd: file_descriptor
88 | :return:
89 | """
90 | parser = configparser.ConfigParser()
91 | parser.read_file(fd)
92 | return dict(parser.items('default'))
93 |
94 |
95 | def find_all(regex, lines):
96 | return dict([(k.strip(), utils.dequote(v.strip())) for k, v in
97 | regex.findall(lines)])
98 |
--------------------------------------------------------------------------------
/freezer/utils/crypt.py:
--------------------------------------------------------------------------------
1 | # (C) Copyright 2016 Mirantis, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 | # not use this file except in compliance with the License. You may obtain
5 | # a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations
13 | # under the License.
14 |
15 | import hashlib
16 |
17 | from cryptography.hazmat.backends import default_backend
18 | from cryptography.hazmat.primitives.ciphers import algorithms
19 | from cryptography.hazmat.primitives.ciphers import Cipher
20 | from cryptography.hazmat.primitives.ciphers import modes
21 | from os import urandom
22 |
23 | SALT_HEADER = 'Salted__'
24 | AES256_KEY_LENGTH = 32
25 | BS = 16 # static 16 bytes, 128 bits for AES
26 |
27 |
28 | class AESCipher(object):
29 | """
30 | Base class for encrypt/decrypt activities.
31 | """
32 |
33 | def __init__(self, pass_file):
34 | self._password = self._get_pass_from_file(pass_file)
35 | self._salt = None
36 | self.cipher = None
37 |
38 | @staticmethod
39 | def _get_pass_from_file(pass_file):
40 | with open(pass_file) as p_file:
41 | password = p_file.readline()
42 | return password
43 |
44 | @staticmethod
45 | def _derive_key_and_iv(password, salt, key_length, iv_length):
46 | d = d_i = b''
47 | while len(d) < key_length + iv_length:
48 | md5_str = d_i + password + salt
49 | d_i = hashlib.md5(md5_str).digest()
50 | d += d_i
51 | return d[:key_length], d[key_length:key_length + iv_length]
52 |
53 |
54 | class AESEncrypt(AESCipher):
55 | """
56 | Encrypts chucks of data using AES-256 algorithm.
57 | OpenSSL compatible.
58 | """
59 |
60 | def __init__(self, pass_file):
61 | super(AESEncrypt, self).__init__(pass_file)
62 | self._salt = urandom(BS - len(SALT_HEADER))
63 | key, iv = self._derive_key_and_iv(self._password,
64 | self._salt,
65 | AES256_KEY_LENGTH,
66 | BS)
67 | self.cipher = Cipher(algorithms.AES(key),
68 | modes.CFB(iv),
69 | backend=default_backend())
70 |
71 | def generate_header(self):
72 | return SALT_HEADER + self._salt
73 |
74 | def encrypt(self, data):
75 | encryptor = self.cipher.encryptor()
76 | return encryptor.update(data) + encryptor.finalize()
77 |
78 |
79 | class AESDecrypt(AESCipher):
80 | """
81 | Decrypts chucks of data using AES-256 algorithm.
82 | OpenSSL compatible.
83 | """
84 |
85 | def __init__(self, pass_file, salt):
86 | super(AESDecrypt, self).__init__(pass_file)
87 | self._salt = self._prepare_salt(salt)
88 | key, iv = self._derive_key_and_iv(self._password,
89 | self._salt,
90 | AES256_KEY_LENGTH,
91 | BS)
92 | self.cipher = Cipher(algorithms.AES(key),
93 | modes.CFB(iv),
94 | backend=default_backend())
95 |
96 | @staticmethod
97 | def _prepare_salt(salt):
98 | return salt[len(SALT_HEADER):]
99 |
100 | def decrypt(self, data):
101 | decryptor = self.cipher.decryptor()
102 | return decryptor.update(data) + decryptor.finalize()
103 |
--------------------------------------------------------------------------------
/freezer/utils/exec_cmd.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import subprocess
16 |
17 |
18 | def execute(cmd):
19 | """
20 | Split a command specified as function arguments into separate sub commands
21 | executed separately
22 | """
23 | cmds = cmd.split('|')
24 | nb_process = len(cmds)
25 | index = 1
26 | process = None
27 | for sub_cmd in cmds:
28 | is_last_process = (index == nb_process)
29 | process = popen_call(sub_cmd.split(' '), process, is_last_process)
30 | index += 1
31 |
32 |
33 | def popen_call(sub_cmd, input, is_last_process):
34 | """
35 | Execute a command specified as function arguments using the given input
36 | """
37 | if not input:
38 | process = subprocess.Popen(sub_cmd,
39 | stdout=subprocess.PIPE,
40 | stderr=subprocess.PIPE, shell=False)
41 | else:
42 | process = subprocess.Popen(sub_cmd,
43 | stdout=subprocess.PIPE, stdin=input.stdout,
44 | stderr=subprocess.PIPE, shell=False)
45 | input.stdout.close()
46 | if (is_last_process):
47 | process.communicate()[0]
48 | rc = process.returncode
49 | if rc != 0:
50 | raise Exception('Error: while executing script '
51 | '%s return code was %d instead of 0'
52 | % (''.join(sub_cmd), rc))
53 | return process
54 |
--------------------------------------------------------------------------------
/freezer/utils/streaming.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | # (c) Copyright 2016 Hewlett-Packard Enterprise Development Company, L.P.
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | """
17 | Freezer general utils functions
18 | """
19 |
20 | import threading
21 |
22 | from oslo_log import log
23 | import queue
24 |
25 |
26 | LOG = log.getLogger(__name__)
27 |
28 |
29 | class Wait(Exception):
30 | pass
31 |
32 |
33 | class RichQueue(object):
34 | """
35 | :type data_queue: Queue.Queue
36 | """
37 | def __init__(self, size=2):
38 | """
39 | :type size: int
40 | :return:
41 | """
42 | self.data_queue = queue.Queue(maxsize=size)
43 | # transmission changes in atomic way so no synchronization needed
44 | self.finish_transmission = False
45 | self.is_force_stop = False
46 |
47 | def finish(self):
48 | self.finish_transmission = True
49 |
50 | def force_stop(self):
51 | self.is_force_stop = True
52 |
53 | def empty(self):
54 | return self.data_queue.empty()
55 |
56 | def get(self):
57 | try:
58 | res = self.data_queue.get(timeout=1)
59 | self.data_queue.task_done()
60 | return res
61 | except queue.Empty:
62 | raise Wait()
63 |
64 | def check_stop(self):
65 | if self.is_force_stop:
66 | raise Exception("Forced stop")
67 |
68 | def put_messages(self, messages):
69 | for message in messages:
70 | self.put(message)
71 | self.finish()
72 |
73 | def has_more(self):
74 | self.check_stop()
75 | return not self.finish_transmission or not self.data_queue.empty()
76 |
77 | def put(self, message):
78 | while True:
79 | try:
80 | self.data_queue.put(message, timeout=1)
81 | break
82 | except queue.Full:
83 | self.check_stop()
84 |
85 | def get_messages(self):
86 | while self.has_more():
87 | try:
88 | yield self.get()
89 | except Wait:
90 | self.check_stop()
91 |
92 |
93 | class QueuedThread(threading.Thread):
94 | def __init__(self, target, rich_queue, exception_queue,
95 | args=(), kwargs=None):
96 | """
97 | :type args: collections.Iterable
98 | :type kwargs: dict
99 | :type target: () -> ()
100 | :type rich_queue: RichQueue
101 | """
102 | self.args = args
103 | kwargs = kwargs or {}
104 | self.rich_queue = rich_queue
105 | self._exception_queue = exception_queue
106 | kwargs["rich_queue"] = rich_queue
107 | super(QueuedThread, self).__init__(target=target, args=args,
108 | kwargs=kwargs)
109 |
110 | def run(self):
111 | try:
112 | super(QueuedThread, self).run()
113 | except Exception as e:
114 | LOG.exception(e)
115 | self._exception_queue.put_nowait(e)
116 | self.rich_queue.force_stop()
117 | # Thread will exit at this point.
118 | # @todo print the error using traceback.print_exc(file=sys.stdout)
119 | raise
120 |
--------------------------------------------------------------------------------
/freezer/utils/winutils.py:
--------------------------------------------------------------------------------
1 | # (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import ctypes
16 | import os
17 | import sys
18 |
19 | from oslo_serialization import jsonutils as json
20 |
21 |
22 | def is_windows():
23 | """
24 | :return: True if the running platform is windows
25 | """
26 | return True if sys.platform == 'win32' else False
27 |
28 |
29 | class DisableFileSystemRedirection(object):
30 | """
31 | When a 32 bit program runs on a 64 bit operating system the paths
32 | to C:/Windows/System32 automatically get redirected to the 32 bit
33 | version (C:/Windows/SysWow64), if you really do need to access the
34 | contents of System32, you need to disable the file system redirector first.
35 | """
36 |
37 | def __init__(self):
38 | if is_windows():
39 | self._disable = (ctypes.windll.kernel32.
40 | Wow64DisableWow64FsRedirection)
41 | self._revert = (ctypes.windll.kernel32.
42 | Wow64RevertWow64FsRedirection)
43 | else:
44 | raise Exception("Useless if not windows")
45 |
46 | def __enter__(self):
47 | self.old_value = ctypes.c_long()
48 | self.success = self._disable(ctypes.byref(self.old_value))
49 |
50 | def __exit__(self, type, value, traceback):
51 | if self.success:
52 | self._revert(self.old_value)
53 |
54 |
55 | def use_shadow(to_backup, windows_volume):
56 | """ add the shadow path to the backup directory """
57 | return to_backup.replace(windows_volume, '{0}freezer_shadowcopy\\'
58 | .format(windows_volume))
59 |
60 |
61 | def save_environment(home):
62 | """Read the environment from the terminal where the scheduler is
63 | initialized and save the environment variables to be reused within the
64 | windows service
65 | """
66 | env_path = os.path.join(home, 'env.json')
67 | with open(env_path, 'wb') as tmp:
68 | json.dump(os.environ.copy(), tmp)
69 |
70 |
71 | def set_environment(home):
72 | """Read the environment variables saved by the win_daemon and restore it
73 | here for the windows service
74 | """
75 | json_env = os.path.join(home, 'env.json')
76 | with open(json_env, 'rb') as fp:
77 | env = json.loads(fp.read())
78 | for k, v in env.items():
79 | os.environ[str(k).strip()] = str(v).strip()
80 |
--------------------------------------------------------------------------------
/freezer_logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/freezer_logo.jpg
--------------------------------------------------------------------------------
/releasenotes/notes/drop-py-2-7-a76d53b7a12bcff2.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | Python 2.7 support has been dropped. Last release of freezer
5 | to support py2.7 is OpenStack Train. The minimum version of Python now
6 | supported by freezer is Python 3.6.
7 |
--------------------------------------------------------------------------------
/releasenotes/notes/os-brick-engine-c47834de156dfa27.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | prelude: >
3 | Currently Freezer provides basic features to execute Cinder volumes backup.
4 | The current approach present significant challenges,
5 | due mainly to the difficulty of downloading Cinder Volumes without passing
6 | through Glance. This can be an issue for time and scalability reasons,
7 | (i.e. volumes of few hundreds GB size, potential error probability increase,
8 | as more services are part of the process, unailability of cinder-backup).
9 |
10 | features:
11 | - |
12 | Added new backup engine called 'os-brick' which allows to backup and
13 | restore the content of cinder volumes attaching it directly to localhost
14 | using functionality of os-brick library.
15 |
16 | issues:
17 | - |
18 | There are could be a read/write file permisson issues if freezer-agent
19 | don't have appropriate right to read\write files to mounted FS.
20 |
--------------------------------------------------------------------------------
/releasenotes/notes/s3-driver-support-02d0a19b99cfe2c5.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | prelude: >
3 | Currently, freezer can only store backup data to swift compatible object
4 | storage (except local and ssh), so we should increase support for other
5 | storage driver. S3 compatible object storage is a valid choice, which is
6 | used by many individuals and companies in the public or private clouds.
7 |
8 | features:
9 | - |
10 | Added new storage type called 's3' which allows to store the backup data
11 | to S3 compatible object storage and restore from it with using botocore
12 | library.
13 |
--------------------------------------------------------------------------------
/releasenotes/notes/volume-boot-nova-instance-backup-support-3c8d090370518f43.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | prelude: >
3 | Currently, when using 'freezer-agent --action backup --engine nova
4 | --nova-inst-id xxx --mode nova --no-incremental true' to backup instance
5 | that boot from volume or snapshot, it gives us the result of successful
6 | backup. But when we restore the nova instance from the backup data and
7 | launch the restored instance, it will fail with 'no boot device error'
8 | message. This can be an issue.
9 |
10 | fixes:
11 | - |
12 | With the above issue, freezer can not support the backup and restore of
13 | instance that boot from volume or snapshot correctly. With this fix, when
14 | using backup, freezer will create an image from the volume, and then
15 | store the image data to storage media. After this fix, users can backup
16 | and restore the nova instance no matter what type of the instance is.
17 |
--------------------------------------------------------------------------------
/releasenotes/source/2023.1.rst:
--------------------------------------------------------------------------------
1 | ===========================
2 | 2023.1 Series Release Notes
3 | ===========================
4 |
5 | .. release-notes::
6 | :branch: stable/2023.1
7 |
--------------------------------------------------------------------------------
/releasenotes/source/2023.2.rst:
--------------------------------------------------------------------------------
1 | ===========================
2 | 2023.2 Series Release Notes
3 | ===========================
4 |
5 | .. release-notes::
6 | :branch: stable/2023.2
7 |
--------------------------------------------------------------------------------
/releasenotes/source/2025.1.rst:
--------------------------------------------------------------------------------
1 | ===========================
2 | 2025.1 Series Release Notes
3 | ===========================
4 |
5 | .. release-notes::
6 | :branch: stable/2025.1
7 |
--------------------------------------------------------------------------------
/releasenotes/source/_static/.placeholder:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/releasenotes/source/_static/.placeholder
--------------------------------------------------------------------------------
/releasenotes/source/_templates/.placeholder:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/freezer/f0e435038467d1fe284ec4b8e87f70bfaa41f490/releasenotes/source/_templates/.placeholder
--------------------------------------------------------------------------------
/releasenotes/source/index.rst:
--------------------------------------------------------------------------------
1 | ..
2 | Licensed under the Apache License, Version 2.0 (the "License"); you may
3 | not use this file except in compliance with the License. You may obtain
4 | a copy of the License at
5 |
6 | http://www.apache.org/licenses/LICENSE-2.0
7 |
8 | Unless required by applicable law or agreed to in writing, software
9 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11 | License for the specific language governing permissions and limitations
12 | under the License.
13 |
14 | =====================================================
15 | Welcome to Freezer Agent Release Notes documentation!
16 | =====================================================
17 |
18 | Contents
19 | ========
20 |
21 | .. toctree::
22 | :maxdepth: 2
23 |
24 | unreleased
25 | 2025.1
26 | 2023.2
27 | 2023.1
28 | zed
29 | yoga
30 | wallaby
31 | victoria
32 | ussuri
33 | train
34 | stein
35 | queens
36 | pike
37 | ocata
38 | newton
39 |
40 | Indices and tables
41 | ==================
42 |
43 | * :ref:`genindex`
44 | * :ref:`search`
45 |
--------------------------------------------------------------------------------
/releasenotes/source/newton.rst:
--------------------------------------------------------------------------------
1 | ============================
2 | Newton Series Release Notes
3 | ============================
4 |
5 | .. release-notes::
6 | :branch: stable/newton
7 |
--------------------------------------------------------------------------------
/releasenotes/source/ocata.rst:
--------------------------------------------------------------------------------
1 | ===================================
2 | Ocata Series Release Notes
3 | ===================================
4 |
5 | .. release-notes::
6 | :branch: origin/stable/ocata
7 |
--------------------------------------------------------------------------------
/releasenotes/source/pike.rst:
--------------------------------------------------------------------------------
1 | ===================================
2 | Pike Series Release Notes
3 | ===================================
4 |
5 | .. release-notes::
6 | :branch: stable/pike
7 |
--------------------------------------------------------------------------------
/releasenotes/source/queens.rst:
--------------------------------------------------------------------------------
1 | ===================================
2 | Queens Series Release Notes
3 | ===================================
4 |
5 | .. release-notes::
6 | :branch: stable/queens
7 |
--------------------------------------------------------------------------------
/releasenotes/source/stein.rst:
--------------------------------------------------------------------------------
1 | ===================================
2 | Stein Series Release Notes
3 | ===================================
4 |
5 | .. release-notes::
6 | :branch: stable/stein
7 |
--------------------------------------------------------------------------------
/releasenotes/source/train.rst:
--------------------------------------------------------------------------------
1 | ==========================
2 | Train Series Release Notes
3 | ==========================
4 |
5 | .. release-notes::
6 | :branch: stable/train
7 |
--------------------------------------------------------------------------------
/releasenotes/source/unreleased.rst:
--------------------------------------------------------------------------------
1 | ============================
2 | Current Series Release Notes
3 | ============================
4 |
5 | .. release-notes::
6 |
--------------------------------------------------------------------------------
/releasenotes/source/ussuri.rst:
--------------------------------------------------------------------------------
1 | ===========================
2 | Ussuri Series Release Notes
3 | ===========================
4 |
5 | .. release-notes::
6 | :branch: stable/ussuri
7 |
--------------------------------------------------------------------------------
/releasenotes/source/victoria.rst:
--------------------------------------------------------------------------------
1 | =============================
2 | Victoria Series Release Notes
3 | =============================
4 |
5 | .. release-notes::
6 | :branch: stable/victoria
7 |
--------------------------------------------------------------------------------
/releasenotes/source/wallaby.rst:
--------------------------------------------------------------------------------
1 | ============================
2 | Wallaby Series Release Notes
3 | ============================
4 |
5 | .. release-notes::
6 | :branch: stable/wallaby
7 |
--------------------------------------------------------------------------------
/releasenotes/source/yoga.rst:
--------------------------------------------------------------------------------
1 | =========================
2 | Yoga Series Release Notes
3 | =========================
4 |
5 | .. release-notes::
6 | :branch: unmaintained/yoga
7 |
--------------------------------------------------------------------------------
/releasenotes/source/zed.rst:
--------------------------------------------------------------------------------
1 | ========================
2 | Zed Series Release Notes
3 | ========================
4 |
5 | .. release-notes::
6 | :branch: unmaintained/zed
7 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | # Requirements lower bounds listed here are our best effort to keep them up to
2 | # date but we do not test them so no guarantee of having them all correct. If
3 | # you find any incorrect lower bounds, let us know or propose a fix.
4 | pbr>=4.0.0 # Apache-2.0
5 |
6 | botocore>=1.5.1 # Apache-2.0
7 | setuptools!=24.0.0,!=34.0.0,!=34.0.1,!=34.0.2,!=34.0.3,!=34.1.0,!=34.1.1,!=34.2.0,!=34.3.0,!=34.3.1,!=34.3.2,!=36.2.0,>=21.0.0 # PSF/ZPL
8 | python-swiftclient>=3.2.0 # Apache-2.0
9 | python-cinderclient>=3.3.0 # Apache-2.0
10 | python-glanceclient>=2.8.0 # Apache-2.0
11 | python-keystoneclient>=3.8.0 # Apache-2.0
12 | python-novaclient>=9.1.0 # Apache-2.0
13 | python-neutronclient>=6.7.0 # Apache-2.0
14 | python-freezerclient>=2.0.0 # Apache-2.0
15 | oslo.serialization>=5.5.0 # Apache-2.0
16 | oslo.utils>=7.3.0 # Apache-2.0
17 | oslo.log>=5.3.0 # Apache-2.0
18 | oslo.config>=9.4.0 # Apache-2.0
19 | oslo.service!=1.28.1,>=1.24.0 # Apache-2.0
20 | keystoneauth1>=3.14.0 # Apache-2.0
21 | os-brick>=2.2.0 # Apache-2.0
22 |
23 | cryptography>=2.5 # Apache-2.0
24 | PyMySQL>=0.7.6 # MIT License
25 | pymongo!=3.1,>=3.0.2 # Apache-2.0
26 | paramiko>=2.7.1 # LGPLv2.1+
27 |
28 | apscheduler>=3.0.5 # MIT License
29 | psutil>=3.2.2 # BSD
30 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [metadata]
2 | name = freezer
3 | author = OpenStack
4 | author_email = openstack-discuss@lists.openstack.org
5 | summary = The OpenStack Backup and Restore as a Service Platform
6 | description_file = README.rst
7 | description-content-type = text/x-rst
8 | home_page = https://docs.openstack.org/freezer/latest/
9 | license = Apache-2
10 | python_requires = >=3.9
11 | classifier =
12 | Programming Language :: Python
13 | Programming Language :: Python :: Implementation :: CPython
14 | Programming Language :: Python :: 3 :: Only
15 | Programming Language :: Python :: 3
16 | Programming Language :: Python :: 3.9
17 | Programming Language :: Python :: 3.10
18 | Programming Language :: Python :: 3.11
19 | Programming Language :: Python :: 3.12
20 | Development Status :: 5 - Production/Stable
21 | Natural Language :: English
22 | Environment :: OpenStack
23 | Intended Audience :: Developers
24 | Intended Audience :: Information Technology
25 | Intended Audience :: System Administrators
26 | License :: OSI Approved :: Apache Software License
27 | Operating System :: MacOS
28 | Operating System :: POSIX :: BSD :: FreeBSD
29 | Operating System :: POSIX :: BSD :: NetBSD
30 | Operating System :: POSIX :: BSD :: OpenBSD
31 | Operating System :: POSIX :: Linux
32 | Operating System :: Microsoft :: Windows
33 | Operating System :: Unix
34 | Topic :: System :: Archiving :: Backup
35 | Topic :: System :: Archiving :: Compression
36 | Topic :: System :: Archiving
37 | keywords =
38 | freezer
39 | backup
40 | openstack
41 | restore
42 | lvm
43 | snapshot
44 | mongodb
45 | mysql
46 |
47 | [global]
48 | setup_hooks =
49 | pbr.hooks.setup_hook
50 |
51 | [files]
52 | packages =
53 | freezer
54 | data_files =
55 | freezer/scripts = freezer/scripts/vss.ps1
56 |
57 | [entry_points]
58 | oslo.config.opts =
59 | freezer-agent = freezer.common.config:list_opts
60 | freezer-scheduler = freezer.scheduler.arguments:list_opts
61 | console_scripts =
62 | freezer-scheduler = freezer.scheduler.freezer_scheduler:main
63 | freezer-agent = freezer.main:main
64 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12 | # implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | import setuptools
17 |
18 | setuptools.setup(
19 | setup_requires=['pbr>=2.0.0'],
20 | pbr=True)
21 |
--------------------------------------------------------------------------------
/test-requirements.txt:
--------------------------------------------------------------------------------
1 | # The order of packages is significant, because pip processes them in the order
2 | # of appearance. Changing the order has an impact on the overall integration
3 | # process, which may cause wedges in the gate later.
4 |
5 | hacking>=3.0.1,<3.1.0 # Apache-2.0
6 | coverage>=4.5.1 # Apache-2.0
7 | ddt>=1.0.1 # MIT
8 | #pylint==1.9.2 # GPLv2
9 | stestr>=2.0.0 # Apache-2.0
10 | testtools>=2.2.0 # MIT
11 | #astroid==1.6.5 # LGPLv2.1
12 |
13 | # Tempest Plugin
14 | tempest>=17.1.0 # Apache-2.0
15 |
16 | # Used in integration tests
17 | python-openstackclient>=3.12.0 # Apache-2.0
18 |
19 | # Used in doc8 check
20 | doc8>=0.6.0 # Apache-2.0
21 | Pygments>=2.2.0 # BSD license
22 | # astroid<=2.5.0;python_version>="3.0" # LGPLv2.1
23 | pylint>=2.6.0 # GPLv2
24 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | envlist = py3,pep8,pylint,docs
3 | skipsdist = True
4 |
5 | [testenv]
6 | usedevelop = True
7 | deps =
8 | -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
9 | -r{toxinidir}/requirements.txt
10 | -r{toxinidir}/test-requirements.txt
11 |
12 | passenv =
13 | FREEZER_TEST_SSH_KEY
14 | FREEZER_TEST_SSH_USERNAME
15 | FREEZER_TEST_SSH_HOST
16 | FREEZER_TEST_CONTAINER
17 | FREEZER_TEST_OS_PROJECT_NAME
18 | FREEZER_TEST_OS_USERNAME
19 | FREEZER_TEST_OS_REGION_NAME
20 | FREEZER_TEST_OS_PASSWORD
21 | FREEZER_TEST_OS_AUTH_URL
22 | FREEZER_TEST_NO_LVM
23 | http_proxy
24 | HTTP_PROXY
25 | https_proxy
26 | HTTPS_PROXY
27 | no_proxy
28 | NO_PROXY
29 |
30 | install_command = pip3 install {opts} {packages}
31 | setenv =
32 | VIRTUAL_ENV={envdir}
33 | OS_TEST_PATH = ./freezer/tests/unit
34 | PYTHON=coverage run --source freezer --parallel-mode
35 | commands =
36 | find . -type f -name "*.pyc" -delete
37 | stestr run {posargs}
38 | coverage combine
39 | coverage html -d cover
40 | coverage xml -o cover/coverage.xml
41 | coverage report -m
42 | rm -f .coverage
43 | rm -rf .testrepository
44 |
45 | allowlist_externals =
46 | find
47 | coverage
48 | rm
49 |
50 | python_files = test_*.py
51 | norecursedirs = .tox .venv
52 |
53 | [testenv:venv]
54 | commands = {posargs}
55 |
56 | [testenv:py39]
57 | basepython = python3.9
58 |
59 | [testenv:py312]
60 | basepython = python3.12
61 |
62 | [testenv:docs]
63 | deps =
64 | -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
65 | -r{toxinidir}/doc/requirements.txt
66 | allowlist_externals = rm
67 | commands =
68 | rm -rf doc/build/
69 | sphinx-build --keep-going -b html doc/source doc/build/html
70 |
71 |
72 | [testenv:pep8]
73 | commands =
74 | flake8 freezer
75 | doc8 {posargs}
76 |
77 | [testenv:pylint]
78 | commands = pylint --rcfile .pylintrc freezer
79 |
80 | [flake8]
81 | # W504 line break after binary operator
82 | # W605 invalid escape sequence
83 |
84 | ignore = H405,H404,H403,H401,W504,W605
85 | show-source = True
86 | enable-extensions = H203,H106
87 | exclude = .venv,.tox,dist,doc,test,*egg,releasenotes
88 |
89 | [doc8]
90 | ignore = D000,D001
91 | ignore-path = .venv,.git,.tox,.tmp,*freezer/locale*,*lib/python*,freezer.egg*,doc/build,releasenotes/*,doc/source/contributor/api
92 |
93 | [testenv:releasenotes]:
94 | deps =
95 | -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
96 | -r{toxinidir}/doc/requirements.txt
97 | allowlist_externals = rm
98 | commands =
99 | rm -rf releasenotes/build
100 | sphinx-build -a -E -d releasenotes/build/doctrees --keep-going -b html releasenotes/source releasenotes/build/html
101 |
--------------------------------------------------------------------------------