Giter VIP home page Giter VIP logo

pyaptly's Introduction

Pyaptly

Automates the creation and managment of aptly mirrors and snapshots based on toml input files.

Important: Currently under heavy development:

Why & How

Aptly is great tool for creating Debian repositories. But as soon as it's required to maintain repositories for different environments it gets very complicated fast.

This is where Pyaptly comes in. First of all, a single config.toml can be used to define mirrors, snapshots and publishes instead of using command line arguments. The definition includes exactly how the entities are created and updated.

Secondly, aptly isn't really layed out to have retention policies. Updating a snapshot will lose the information of the previous state. That means it's hard to roll back to a previous state if required. This problem is fixed by using fix timestamps in snapshot names. That behaviour also allows to define a fixed update spacing. It's possible to say for example "only update this snapshot once a week".

Follow the Tutorial

Example commands

Initialize a new aptly server.

pyaptly mirror mirrors.toml create
pyaptly mirror mirrors.toml update
pyaptly snapshot mirrors.toml create
pyaptly publish mirrors.toml create

Update mirrors and snapshots and switch publish endpoints with automatic-update: true to the new snapshots.

pyaptly mirror mirrors.toml update
pyaptly snapshot mirrors.toml create
pyaptly publish mirrors.toml create
pyaptly publish mirrors.toml update

Manually trigger a switch to the new snapshots for the publish endpoint ubuntu/stable.

pyaptly publish mirrors.toml update -n ubuntu/stable

Debugging

The most interesting mode for users is not --debug but --info which shows all commands executed.

> pyaptly legacy -- --info --config pyaptly/tests/repo.toml repo create
Command call
  cmd:         gpg --no-default-keyring --keyring trustedkeys.gpg --list-keys --with-colons -> 0
  stdout:     'tru::1:1709575833:0:3:1:5
               pub:-:255:22:2841988729C7F3FF:1701882080:::-:::scESC:::::ed25519:::0:
               fpr:::::::::6380C07FF6496016E01CF4522841988729C7F3FF:
               uid:-::::1701882080::5BBE9C7E7AA5EEE3538F66274125D69FA727FD1E::Pyaptly Test 01 <[email protected]>::::::::::0:
               sub:-:255:18:0A1CBEF26FE4F36E:1701882080::::::e:::::cv25519::
               fpr:::::::::9EE64E40A5E3530D3E18A97C0A1CBEF26FE4F36E:
               pub:-:255:22:EC54D33E5B5EBE98:1701882297:::-:::scESC:::::ed25519:::0:
               fpr:::::::::660D45228AB6B59CCE48AFB3EC54D33E5B5EBE98:
               uid:-::::1701882297::F3EF71B78669C0FC259A4078151BDC5815A6015D::Pyaptly Test 02 <[email protected]>::::::::::0:
               sub:-:255:18:042FE0F5BB743B60:1701882297::::::e:::::cv25519::
               fpr:::::::::AE58B62134E02AF8E5D55FF4042FE0F5BB743B60:'
Command call
  cmd:         aptly repo list -raw -> 0
  stderr:     'Config file not found, creating default config at /root/.aptly.conf'
Command call
  cmd:         aptly mirror list -raw -> 0
Command call
  cmd:         aptly snapshot list -raw -> 0
Command call
  cmd:         aptly publish list -raw -> 0
Command call
  cmd:         aptly repo -architectures=amd64,i386 -distribution=stable -component=main create centrify -> 0
  stdout:     'Local repo [centrify] successfully added.
               You can run 'aptly repo add centrify ...' to add packages to repository.'

Commands that fail are always displayed in red on a tty, but that actually only happens if something is broken.

pyaptly's People

Contributors

karras avatar melkor333 avatar msabramo avatar tongpu avatar winged avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyaptly's Issues

Ubuntu repo empty?

I recently found your project while struggling to sanely implement aptly with weekly snapshots for different environments. However, while trying to install it on ubuntu (xenial), I came to realize that the repo is actually empty. I am saddened greatly.

Cleanup snapshots when snapshot filter feature in aptly is ready

Rotated snapshots are not needed and could be cleaned up. Repositories (e.g. Ubuntu) include all packages so a cleanup of snapshots wouldn't really help as the newest snapshot would still include all packages. Hence the aptly filter (only latest package) would need to be implemented.

Once this is implemented and snapshots are also cleaned up a aptly db cleanup would remove packages which are not references anymore.

Issue in aptly to be completed: adfinis-forks/aptly#28

Tasks to be implemented in pyaptly:

  • Using new filter option in mirror filter
  • Delete snapshots which are not current

read_snapshot_map is slow

When many snapshots (e.g. 1200) are present in aptly read_snapshot_map takes long time to process the data.

Add ability to redirect output into a file

It would be nice to have a command line parameter to redirect the (debug) output of pyaptly / aptly into a separate file. Example:

$ pyaptly --debug --log output.log -c trusty.yml snapshot update

What do you think?

publish update fails for configs with direct published repos (without snapshot)

The snapshot update command fails when having publish endpoints, which get published directly (without snapshot), configured:

$ pyaptly -c trusty.yml snapshot update
Traceback (most recent call last):
  File "/usr/local/bin/pyaptly", line 1794, in <module>
    main()
  File "/usr/local/bin/pyaptly", line 775, in main
    args.func(cfg, args)
  File "/usr/local/bin/pyaptly", line 1284, in snapshot
    for cmd in cmd_snapshot(cfg, snapshot_name, snapshot_config)
  File "/usr/local/bin/pyaptly", line 1534, in cmd_snapshot_update
    if is_publish_affected(publish_name, publish_conf_entry)
  File "/usr/local/bin/pyaptly", line 1519, in is_publish_affected
    for snap in publish['snapshots']:
KeyError: 'snapshots'

Example publish endpoint where the repo is published directly:

  icaclient:
    -
      distribution: "stable"
      origin: "icaclient"
      architectures: ["amd64", "i386"]
      components: "main"
      repo: "icaclient"
      automatic-update: true

How to publish to specific local endpoint ?

Hello,

I need to setup some repositories, but for some reason I need to publish by example docker mirrors, like this:

aptly publish -gpg-key="<GPG_KEY_IDENTIFIER>" snapshot docker-bookworm-<date> docker/bookworm
aptly publish -gpg-key="<GPG_KEY_IDENTIFIER>" snapshot docker-bullseye-<date> docker/bullseye

Note

Because component stable is in snapshots docker-bookworm and docker-bullseye, is it considered as duplicate for some packages identically. (Idk why)

There is no documentation for the project or to be more precise since docs.adfinis-sygroup.ch stopped, probably.
Can you port documentation on Github ?

Or please, can you help me to configure the local publish endpoint ?

[publish]
# Bookworm
[[publish.bookworm-main]]
gpg-key = "<GPG_KEY>"
skip-contents = true
automatic-update = true
components = "main"
distribution = "bookworm"
[[publish.bookworm.snapshots]]
name = "bookworm-main-%T"
timestamp = "current"
archive-on-update = "archived-bookworm-main-%T"

[[publish.bookworm-updates]]
gpg-key = "<GPG_KEY>"
automatic-update = true
components = "main"
distribution = "bookworm-updates"
[[publish.bookworm-updates.snapshots]]
name = "bookworm-updates-%T"
timestamp = "current"
archive-on-update = "archived-bookworm-updates-%T"

[[publish.bookworm-security]]
gpg-key = "<GPG_KEY>"
automatic-update = true
components = "main"
distribution = "bookworm-security"
[[publish.bookworm-security.snapshots]]
name = "bookworm-security-%T"
timestamp = "current"
archive-on-update = "archived-bookworm-security-%T"

[[publish.docker-bookworm]]
gpg-key = "<GPG_KEY>"
automatic-update = true
components = "stable"
distribution = "bookworm"
[[publish.docker-bookworm.snapshots]]
name = "docker-bookworm-%T"
timestamp = "current"
archive-on-update = "archived-docker-bookworm-%T"

[[publish.php-bookworm]]
gpg-key = "<GPG_KEY>"
automatic-update = true
components = "main"
distribution = "bookworm"
[[publish.php-bookworm.snapshots]]
name = "php-bookworm-%T"
timestamp = "current"
archive-on-update = "archived-php-bookworm-%T"

[[publish.postgres-bookworm]]
gpg-key = "<GPG_KEY>"
automatic-update = true
components = "main"
distribution = "bookworm-pgdg"
[[publish.postgres-bookworm.snapshots]]
name = "postgres-bookworm-%T"
timestamp = "current"
archive-on-update = "archived-postgres-bookworm-%T"

# Bullseye
[[publish.bullseye-main]]
gpg-key = "<GPG_KEY>"
skip-contents = true
automatic-update = true
components = "main"
distribution = "bullseye"
[[publish.bullseye.snapshots]]
name = "bullseye-main-%T"
timestamp = "current"
archive-on-update = "archived-bullseye-main-%T"

[[publish.bullseye-updates]]
gpg-key = "<GPG_KEY>"
automatic-update = true
components = "main"
distribution = "bullseye-updates"
[[publish.bullseye-updates.snapshots]]
name = "bullseye-updates-%T"
timestamp = "current"
archive-on-update = "archived-bullseye-updates-%T"

[[publish.bullseye-security]]
gpg-key = "<GPG_KEY>"
automatic-update = true
components = "main"
distribution = "bullseye-security"
[[publish.bullseye-security.snapshots]]
name = "bullseye-security-%T"
timestamp = "current"
archive-on-update = "archived-bullseye-security-%T"

[[publish.docker-bullseye]]
gpg-key = "<GPG_KEY>"
automatic-update = true
components = "stable"
distribution = "bullseye"
[[publish.docker-bullseye.snapshots]]
name = "docker-bullseye-%T"
timestamp = "current"
archive-on-update = "archived-docker-bullseye-%T"

[[publish.php-bullseye]]
gpg-key = "<GPG_KEY>"
automatic-update = true
components = "main"
distribution = "bullseye"
[[publish.php-bullseye.snapshots]]
name = "php-bullseye-%T"
timestamp = "current"
archive-on-update = "archived-php-bullseye-%T"

[[publish.postgres-bullseye]]
gpg-key = "<GPG_KEY>"
automatic-update = true
components = "main"
distribution = "bullseye-pgdg"
[[publish.postgres-bullseye.snapshots]]
name = "postgres-bullseye-%T"
timestamp = "current"
archive-on-update = "archived-postgres-bullseye-%T"

Add proper failure messages for common failures

If the configuration file is "wrong", it leads to seemingly fatal crashes, like the following when the configuration doesn't have any snapshots defined:

# pyaptly publish config.toml create
ERROR: snapshot
               Wrote traceback to: /tmp/tmpwpp159mr

For better UX, it should explain what is missing/wrong... I assume that's something which exists in various places.

bootstrap, cannot create ubuntu/stable publish point missing previous week snapshots

Currently when setting up the aptly lastest/next-stable/stable system we cannot bootstrap all these publish point at once.

When calling the following commands:

release=bionic
  pyaptly -c /etc/pyaptly/${release}_rlc.yml repo create
  echo "Creating mirror..."
  pyaptly -c /etc/pyaptly/${release}_rlc.yml mirror create
  echo "Updating mirror..."
  pyaptly -c /etc/pyaptly/${release}_rlc.yml mirror update
  echo "Working on: ${release}"
  echo "Creating snapshot..."
  pyaptly -c /etc/pyaptly/${release}_rlc.yml snapshot create
  pyaptly -c /etc/pyaptly/${release}_rlc.yml publish create
  echo "Creating stable snapshot..."
  pyaptly -c /etc/pyaptly/${release}_rlc.yml publish create ubuntu/stable

The configuration looks like

...
      distribution: "bionic"
      origin: "Ubuntu"
      architectures: ["amd64", "i386", "source"]
      components: ["main", "restricted", "universe", "multiverse"]
      snapshots:
        - name: "bionic-main_foo-keyring-stable-%T"
          timestamp: "previous"
          archive-on-update: "archived-bionic-main_foo-keyring-stable-%T"
        - name: "bionic-restricted-stable-%T"
          timestamp: "previous"
          archive-on-update: "archived-bionic-restricted-stable-%T"
        - name: "bionic-universe-stable-%T"
          timestamp: "previous"
          archive-on-update: "archived-bionic-universe-stable-%T"
        - name: "bionic-multiverse-stable-%T"
          timestamp: "previous"
          archive-on-update: "archived-bionic-multiverse-stable-%T"
      automatic-update: false
...
Creating snapshot...
Creating stable snapshot...
ERROR: unable to publish: snapshot with name bionic-main_foo-keyring-stable-20180825T0000Z not found
Traceback (most recent call last):
  File "/usr/local/bin/pyaptly", line 1842, in <module>
    main()
  File "/usr/local/bin/pyaptly", line 803, in main
    args.func(cfg, args)
  File "/usr/local/bin/pyaptly", line 1289, in publish
    cmd.execute()
  File "/usr/local/bin/pyaptly", line 267, in execute
    self._finished = subprocess.check_call(self.cmd)
  File "/usr/lib/python2.7/subprocess.py", line 190, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['aptly', 'publish', '-origin=Ubuntu', '-component=main,restricted,universe,multiverse', '-distribution=bionic', '-architectures=amd64,i386,source', 'snapshot', 'bionic-main_foo-keyring-stable-20180825T0000Z', 'bionic-restricted-stable-20180825T0000Z', 'bionic-universe-stable-20180825T0000Z', 'bionic-multiverse-stable-20180825T0000Z', 'ubuntu/stable']' returned non-zero exit status 1

extend docs

  • Generally there is not enough docs
  • Reenable generated dev-docs
  • Here are some ideas how to extend the docs in this merged PR

timestamp in publish/snapshot not being applied correctly

In my configuration I have two publish endpoints, one with a snapshot and timestamp: current and another one with timestamp: previous, but after an update they both publish the same snapshot.

mirror:
  trusty-main:
    archive: "http://ch.archive.ubuntu.com/ubuntu/"
snapshot:
  trusty-main-%T:
    mirror: "trusty-main"
    timestamp: {"time": "00:00"}
publish:
  ubuntu/latest:
    - distribution: "trusty"
      snapshots:
        - {"name": "trusty-main-%T", "timestamp": "current"}
  ubuntu/stable:
    - distribution: "trusty"
      snapshots:
        - {"name": "trusty-main-%T", "timestamp": "previous"}

Expected result:

  * trusty/latest [amd64] publishes {main: [trusty-main-20160613T0000Z]: Snapshot from mirror [trusty-main]: http://ch.archive.ubuntu.com/ubuntu/ trusty}
  * trusty/stable [amd64] publishes {main: [trusty-main-20160612T0000Z]: Snapshot from mirror [trusty-main]: http://ch.archive.ubuntu.com/ubuntu/ trusty}

Actual result:

  * trusty/latest [amd64] publishes {main: [trusty-main-20160613T0000Z]: Snapshot from mirror [trusty-main]: http://ch.archive.ubuntu.com/ubuntu/ trusty}
  * trusty/stable [amd64] publishes {main: [trusty-main-20160613T0000Z]: Snapshot from mirror [trusty-main]: http://ch.archive.ubuntu.com/ubuntu/ trusty}

pretend doesn't work with mirrors

Mirror creation/updating is still done when --pretend is used. It's because the mirror code currently doesn't use the Command feature but runs commands directly. I'm not sure if the solution is to unify the code and also use a Command for the mirroring (though there might be implications, not sure). Or if we should just propagate the config option to mirrors and check if pretend mode is activated.

@ganwell I don't know the pytest suite very well, but it already seems like we're generating tests. Is it possible to generate test cases that run with --pretend twice and make sure the output is exactly the same both times?

And since we're already at it, I'd propose renaming pretend to dryrun, it's much more popular.

Reflect TOML modifications in aptly

Currently modifications in the yaml file are ignored. If possible pyaptly should updated the aptly setup once modifications are done.

Maybe add a special cmdline flag to trigger an update?

E.g.: Remove the i386 architecture from a mirror should also remove it in the aptly mirror (if requested).

Currently such changes have to be done manually;

aptly mirror edit -architectures="amd64" google-chrome

Thanks @erickeller for reporting the issue.

config nestedness, yaml and toml

I switched to toml, because I had an issue with the nestedness of the config and because I wanted to get rid of C-extensions in pyaptly. I did not find an acceptable pure python yaml parser.

While the converter from yaml to toml did an ok job for the configs we use in our tests. It made a complete mess on the existing productions configs. Currently I think, there is a nice config that is correct toml, but the converter is just messing it up.

What I am going to do:

  • Try to fix the converter

Questions:

  • Is manual cleanup acceptable if we can't fix the converter?
  • Do we really need to get rid of C-extensions?
  • Should we just support toml and yaml?
  • Forget toml completely?
  • Should the nestedness be fixed in the data-structure?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.