Ansible role that installs Wallabag, a read-it-later web service
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
taha@asks2 284c689b35 mysql tasks now use socket auth instead of password auth 3 weeks ago
defaults mysql tasks now use socket auth instead of password auth 3 weeks ago
docs mysql tasks now use socket auth instead of password auth 3 weeks ago
files Working Wallabag installation from prebuilt tarballs 2 months ago
handlers Added support for mysql database backend. Fixed weird bug in handlers 1 month ago
meta mysql tasks now use socket auth instead of password auth 3 weeks ago
tasks mysql tasks now use socket auth instead of password auth 3 weeks ago
templates mysql tasks now use socket auth instead of password auth 3 weeks ago
vars Added support for mysql database backend. Fixed weird bug in handlers 1 month ago
.gitignore Added support for mysql database backend. Fixed weird bug in handlers 1 month ago
LICENSE Added support for mysql database backend. Fixed weird bug in handlers 1 month ago
README.md Working on the mysql->pgsql migration, which is not working yet 2 months ago

README.md

Wallabag

This Ansible role installs Wallabag, either from precompiled tarballs or from source.

This role can handle part of the upgrade process, and has so far been tested successfully for an upgrade from v2.3.8 to v2.4.2.

I originally wrote this role to help me migrate my Wallabag instance from a bare-metal host to an LXD container, while also switching database backend from MySQL to PostgreSQL, followed by upgrading from 2.3.8 to 2.4.2.

How I used this role to migrate and upgrade Wallabag

First, I setup the LXD server and the container shanghai using my luxor playbook:

ansible-playbook playbook-host.yml --ask-become-pass --ask-vault-pass -v --tags "lxd-server"

Then I provisioned the LXD container shanghai using my containers playbook (which includes this role) with wlbg_install_from_source: yes and wlbg_version: 2.3.8:

ansible-playbook playbook-containers.yml --ask-become-pass --ask-vault-pass

At this point we had a default (empty) Wallabag v2.3.8 installation on the LXD container, so I commented out the lines for the import_tasks: import-pgloader.yml in this role's tasks/main.yml, and re-ran the playbook only for those tasks:

ansible-playbook playbook-containers.yml --ask-become-pass --ask-vault-pass --tags "wlbg_sshtunnel_import_pgloader"

That imported my old Wallabag database (which used MySQL) into the new container's PostgreSQL database. It was important to use matching Wallabag versions for the migration to succeed. At this point, the migration was complete. Huzzah!

Since Wallabag v2.3.8 has become outdated, the final step was to upgrade to the latest release v2.4.2.

So I ran the playbook again (with wlbg_url_tarball set to latest):

ansible-playbook playbook-containers.yml --ask-become-pass --ask-vault-pass -vv --tags "upgrade-wallabag"

https://doc.wallabag.org/en/admin/query-upgrade-23-24.html Finally, we had to manually run these PostgreSQL queries:

ALTER TABLE wallabag_entry ADD archived_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL;

ALTER TABLE "wallabag_user" ADD googleAuthenticatorSecret VARCHAR(191) DEFAULT NULL;
ALTER TABLE "wallabag_user" RENAME COLUMN twofactorauthentication TO emailTwoFactor;
ALTER TABLE "wallabag_user" DROP trusted;
ALTER TABLE "wallabag_user" ADD backupCodes TEXT DEFAULT NULL;

ALTER TABLE wallabag_site_credential ADD updated_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL;

ALTER TABLE wallabag_entry ADD hashed_url TEXT DEFAULT NULL;
CREATE INDEX hashed_url_user_id ON wallabag_entry (user_id, hashed_url);

ALTER TABLE "wallabag_config" RENAME COLUMN rss_token TO feed_token;
ALTER TABLE "wallabag_config" RENAME COLUMN rss_limit TO feed_limit;

ALTER TABLE "wallabag_oauth2_access_tokens" DROP CONSTRAINT FK_368A4209A76ED395;
ALTER TABLE "wallabag_oauth2_access_tokens" ADD CONSTRAINT FK_368A4209A76ED395 FOREIGN KEY (user_id) REFERENCES "wallabag_user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;
ALTER TABLE "wallabag_oauth2_clients" DROP CONSTRAINT idx_user_oauth_client;
ALTER TABLE "wallabag_oauth2_clients" ADD CONSTRAINT FK_635D765EA76ED395 FOREIGN KEY (user_id) REFERENCES "wallabag_user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE;
ALTER TABLE "wallabag_oauth2_refresh_tokens" DROP CONSTRAINT FK_20C9FB24A76ED395;
ALTER TABLE "wallabag_oauth2_refresh_tokens" ADD CONSTRAINT FK_20C9FB24A76ED395 FOREIGN KEY (user_id) REFERENCES "wallabag_user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;
ALTER TABLE "wallabag_oauth2_auth_codes" DROP CONSTRAINT FK_EE52E3FAA76ED395;
ALTER TABLE "wallabag_oauth2_auth_codes" ADD CONSTRAINT FK_EE52E3FAA76ED395 FOREIGN KEY (user_id) REFERENCES "wallabag_user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;

ALTER TABLE wallabag_entry ADD given_url TEXT DEFAULT NULL;
ALTER TABLE wallabag_entry ADD hashed_given_url TEXT DEFAULT NULL;
CREATE INDEX hashed_given_url_user_id ON wallabag_entry (user_id, hashed_given_url);

UPDATE wallabag_config SET reading_speed = reading_speed*200;

ALTER TABLE "wallabag_entry" ALTER language TYPE VARCHAR(20);
CREATE INDEX user_language ON "wallabag_entry" (language, user_id);
CREATE INDEX user_archived ON "wallabag_entry" (user_id, is_archived, archived_at);
CREATE INDEX user_created ON "wallabag_entry" (user_id, created_at);
CREATE INDEX user_starred ON "wallabag_entry" (user_id, is_starred, starred_at);
CREATE INDEX tag_label ON "wallabag_tag" (label);
CREATE INDEX config_feed_token ON "wallabag_config" (feed_token);

ALTER TABLE "wallabag_craue_config_setting" RENAME TO "wallabag_internal_setting";

CREATE SEQUENCE ignore_origin_user_rule_id_seq INCREMENT BY 1 MINVALUE 1 START 1;
CREATE SEQUENCE ignore_origin_instance_rule_id_seq INCREMENT BY 1 MINVALUE 1 START 1;
CREATE TABLE wallabag_ignore_origin_user_rule (id SERIAL NOT NULL, config_id INT NOT NULL, rule VARCHAR(255) NOT NULL, PRIMARY KEY(id));
CREATE INDEX idx_config ON wallabag_ignore_origin_user_rule (config_id);
CREATE TABLE wallabag_ignore_origin_instance_rule (id SERIAL NOT NULL, rule VARCHAR(255) NOT NULL, PRIMARY KEY(id));
ALTER TABLE wallabag_ignore_origin_user_rule ADD CONSTRAINT fk_config FOREIGN KEY (config_id) REFERENCES "wallabag_config" (id) NOT DEFERRABLE INITIALLY IMMEDIATE;

UPDATE wallabag_internal_setting SET name = 'matomo_enabled' where name = 'piwik_enabled';
UPDATE wallabag_internal_setting SET name = 'matomo_host' where name = 'piwik_host';
UPDATE wallabag_internal_setting SET name = 'matomo_site_id' where name = 'piwik_site_id';

For good measure, restart Apache (not necessary).

Upgrade to v2.4.2 succeeded!

Would it be possible to switch from precompiled to source during an upgrade?

In essence, is it possible to "switch tracks" for an existing Wallabag install? Here's the report of my attempt. In the end, it failed.

Re-ran the full containers playbook after setting wlbg_install_from_source: yes (this installed Composer, and installed the latest Wallabag release from source).

The playbook completes OK (v2.4.2 installed), but the make update command fails spectacularly. Makes me think switching from precompiled to source is not possible. I posed the question on the Wallabag Gitter.

taha@shanghai:~/public/wallabag/2.4.2
((2.4.2)) $ sudo -u www-data make update
HEAD is now at 919d7da5 Merge pull request #5155 from wallabag/release/2.4.2
Installing dependencies from lock file
Verifying lock file contents can be installed on current platform.
Nothing to install, update or remove
Generating optimized autoload files
composer/package-versions-deprecated: Generating version class...
composer/package-versions-deprecated: ...done generating version class
> Incenteev\ParameterHandler\ScriptHandler::buildParameters
Updating the "app/config/parameters.yml" file
> Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::buildBootstrap
> Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::clearCache

 // Clearing the cache for the prod environment with debug                      
 // false                                                                       

 [OK] Cache for the "prod" environment (debug=false) was successfully cleared.  

> Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::installAssets

 Trying to install assets as relative symbolic links.

 --- ------------------------ ------------------ 
      Bundle                   Method / Error    
 --- ------------------------ ------------------ 
  ✔   NelmioApiDocBundle       relative symlink  
  ✔   CraueConfigBundle        relative symlink  
  ✔   BabDevPagerfantaBundle   relative symlink  
  ✔   FOSJsRoutingBundle       relative symlink  
 --- ------------------------ ------------------ 
                                                                                
 [OK] All assets were successfully installed.                                   

> Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::installRequirementsFile

                    Application Migrations

Migrating up to 20200428072628 from 0

  ++ migrating 20160401000000

Migration 20160401000000 failed during Execution. Error An exception occurred while executing 'SELECT quote_ident(r.conname) as conname, pg_catalog.pg_get_constraintdef(r.oid, true) as condef
                  FROM pg_catalog.pg_constraint r
                  WHERE r.conrelid =
                  (
                      SELECT c.oid
                      FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n
                      WHERE n.nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast') AND c.relname = 'migration_versions' AND n.nspname = ANY(current_schemas(false)) AND n.oid = c.relnamespace
                  )
                  AND r.contype = 'f'':

SQLSTATE[21000]: Cardinality violation: 7 ERROR:  more than one row returned by a subquery used as an expression
00:29:23 ERROR     [console] Error thrown while running command "doctrine:migrations:migrate --no-interaction --env=prod". Message: "An exception occurred while executing 'SELECT quote_ident(r.conname) as conname, pg_catalog.pg_get_constraintdef(r.oid, true) as condef
                  FROM pg_catalog.pg_constraint r
                  WHERE r.conrelid =
                  (
                      SELECT c.oid
                      FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n
                      WHERE n.nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast') AND c.relname = 'migration_versions' AND n.nspname = ANY(current_schemas(false)) AND n.oid = c.relnamespace
                  )
                  AND r.contype = 'f'':

SQLSTATE[21000]: Cardinality violation: 7 ERROR:  more than one row returned by a subquery used as an expression" ["exception" => Doctrine\DBAL\Exception\DriverException { …},"command" => "doctrine:migrations:migrate --no-interaction --env=prod","message" => """  An exception occurred while executing 'SELECT quote_ident(r.conname) as conname, pg_catalog.pg_get_constraintdef(r.oid, true) as condef\n                    FROM pg_catalog.pg_constraint r\n                    WHERE r.conrelid =\n                    (\n                        SELECT c.oid\n                        FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n\n                        WHERE n.nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast') AND c.relname = 'migration_versions' AND n.nspname = ANY(current_schemas(false)) AND n.oid = c.relnamespace\n                    )\n                    AND r.contype = 'f'':\n  \n  SQLSTATE[21000]: Cardinality violation: 7 ERROR:  more than one row returned by a subquery used as an expression  """]

In AbstractPostgreSQLDriver.php line 89:
                               
  An exception occurred while executing 'SELECT quote_ident(r.conname) as conname, pg_catalog.pg_get_constraintdef(r.oid, true) as condef         
                    FROM pg_catalog.pg_constraint r  
                    WHERE r.conrelid =               
                    (
                        SELECT c.oid
                        FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n
                        WHERE n.nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast') AND c.relname = 'migration_versions' AND n.nspname = ANY(current_schemas(false)) AND n.oid = c.relnamespace
                    )                                                                                             
                    AND r.contype = 'f'':
                                
  SQLSTATE[21000]: Cardinality violation: 7 ERROR:  more than one row returned by a subquery used as an expression

In PDOConnection.php line 91:
  SQLSTATE[21000]: Cardinality violation: 7 ERROR:  more than one row returned by a subquery used as an expression  

In PDOConnection.php line 86:
  SQLSTATE[21000]: Cardinality violation: 7 ERROR:  more than one row returned by a subquery used as an expression  

Wallabag requirements

  • PHP>=7.2, but perhaps not 7.4
  • Composer, at least version 1.8.0 (if installing from source)
  • PHP extensions:
    • php-session
    • php-ctype
    • php-dom
    • php-hash
    • php-simplexml
    • php-json
    • php-gd
    • php-mbstring
    • php-xml
    • php-tidy
    • php-iconv
    • php-curl
    • php-gettext
    • php-tokenizer
    • php-bcmath
    • php-intl
    • php-fpm
    • php-pgsql
  • MySQL, SQLite, or PostgreSQL

https://doc.wallabag.org/en/admin/installation/requirements.html

Some notes on other Wallabag installation options

Wallabag with Docker Compose

The Wallabag Docker image is in effect a wrapper around an Ansible playbook.

Ansible playbooks/roles for installation of Wallabag

Container technologies other than Docker?

A list compiled by a complete beginner.

LXC

If using Ubuntu, we recommend you use Ubuntu 18.04 LTS as your container host. LXC bugfix releases are available directly in the distribution package repository shortly after release and those offer a clean (unpatched) upstream experience. Ubuntu is also one of the few (if not only) Linux distributions to come by default with everything that's needed for safe, unprivileged LXC containers. https://linuxcontainers.org/lxc/getting-started/

LXD

Ansible support for LXD? Yes, at least two community modules:

From what I can understand, it seems lxd init is usually executed interactively (not part of Ansible role). But may be possible to automate, with some work.

By default LXD server is not accessible from the network as it only listens on a local unix socket. https://linuxcontainers.org/lxd/docs/stable-4.0/

This suits me fine, as I intend to run a TLS-terminating reverse proxy on the host machine.

By default, all Ubuntu LXD images for containers are set up with PasswordAuthentication no in their SSH configuration. https://askubuntu.com/questions/1106369/how-to-ssh-into-a-lxd-guest

SSH into LXD container should work as for any other host. To pre-populate your pubkey into the LXD container, you can put it in your LXD profile. https://gist.github.com/jeanlouisferey/15be1f421eb9f9a66f1c74d410de2675

Podman

Podman provides a Docker (and Docker Compose) compatible CLI environment. So essentially it's Docker, but not from Docker Inc.

Running containers as systemd services with Podman

Refs