Blame alembic/versions/f16ab75e4d32_sshkeys.py

Patrick Uiterwijk 9b237b
"""Migrate SSH keys to the new format.
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
Revision ID: f16ab75e4d32
Patrick Uiterwijk 9b237b
Revises: 0a8f99c161e2
Patrick Uiterwijk 9b237b
Create Date: 2018-09-24 16:11:21.297620
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
"""
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
# revision identifiers, used by Alembic.
Patrick Uiterwijk 9b237b
revision = "f16ab75e4d32"
Patrick Uiterwijk 9b237b
down_revision = "0a8f99c161e2"
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
import datetime
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
from alembic import op
Patrick Uiterwijk 9b237b
import sqlalchemy as sa
Patrick Uiterwijk 9b237b
Pierre-Yves Chibon 930073
from pagure.lib.query import is_valid_ssh_key
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
def upgrade():
Patrick Uiterwijk 9b237b
    """ Upgrade the database model for the way we store user's public ssh
Patrick Uiterwijk 9b237b
    keys.
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
    For this we leverage the existing ``deploykeys`` table.
Patrick Uiterwijk 9b237b
    It gets renamed to ``sshkeys``, we add the user_id foreign key as now
Patrick Uiterwijk 9b237b
    ssh keys stored in this table can be linked to an user.
Patrick Uiterwijk 9b237b
    Then we convert the existing ssh keys to this database model.
Patrick Uiterwijk 9b237b
    Finally, we drop the ``public_ssh_key`` column from the ``users`` table.
Patrick Uiterwijk 9b237b
    """
Patrick Uiterwijk 9b237b
    users_table = sa.sql.table(
Patrick Uiterwijk 9b237b
        "users",
Patrick Uiterwijk 9b237b
        sa.sql.column("id", sa.Integer),
Patrick Uiterwijk 9b237b
        sa.sql.column("public_ssh_key", sa.TEXT()),
Patrick Uiterwijk 9b237b
    )
Patrick Uiterwijk 9b237b
    sshkey_table = sa.sql.table(
Patrick Uiterwijk 9b237b
        "sshkeys",
Patrick Uiterwijk 9b237b
        sa.sql.column("id", sa.Integer),
Patrick Uiterwijk 9b237b
        sa.sql.column("user_id", sa.Integer),
Patrick Uiterwijk 9b237b
        sa.sql.column("public_ssh_key", sa.TEXT()),
Patrick Uiterwijk 9b237b
        sa.sql.column("ssh_short_key", sa.TEXT()),
Patrick Uiterwijk 9b237b
        sa.sql.column("ssh_search_key", sa.TEXT()),
Patrick Uiterwijk 9b237b
        sa.sql.column("creator_user_id", sa.Integer),
Patrick Uiterwijk 9b237b
        sa.sql.column("pushaccess", sa.Boolean),
Patrick Uiterwijk 9b237b
        sa.sql.column("date_created", sa.DateTime),
Patrick Uiterwijk 9b237b
    )
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
    op.rename_table("deploykeys", "sshkeys")
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
    op.add_column("sshkeys", sa.Column("user_id", sa.Integer(), nullable=True))
Patrick Uiterwijk 9b237b
    op.create_index(
Patrick Uiterwijk 9b237b
        op.f("ix_sshkeys_sshkeys_user_id"),
Patrick Uiterwijk 9b237b
        "sshkeys",
Patrick Uiterwijk 9b237b
        ["user_id"],
Patrick Uiterwijk 9b237b
        unique=False,
Patrick Uiterwijk 9b237b
    )
Patrick Uiterwijk 9b237b
    op.create_foreign_key(
Patrick Uiterwijk 9b237b
        op.f("sshkeys_user_id_fkey"),
Patrick Uiterwijk 9b237b
        "sshkeys",
Patrick Uiterwijk 9b237b
        "users",
Patrick Uiterwijk 9b237b
        ["user_id"],
Patrick Uiterwijk 9b237b
        ["id"],
Patrick Uiterwijk 9b237b
        onupdate=u"CASCADE",
Patrick Uiterwijk 9b237b
    )
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
    print("Convert existing ssh keys to the new format")
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 91e2c5
    seen = []
Patrick Uiterwijk 9b237b
    conn = op.get_bind()
Patrick Uiterwijk 9b237b
    for key in conn.execute(sshkey_table.select()):
Patrick Uiterwijk 9b237b
        ssh_short_key = is_valid_ssh_key(key.public_ssh_key).strip()
Patrick Uiterwijk 9b237b
        ssh_search_key = ssh_short_key.split(" ")[1]
Patrick Uiterwijk 91e2c5
        # There is no chance of dupes in the deploykeys alone
Patrick Uiterwijk 91e2c5
        seen.append(ssh_search_key)
Patrick Uiterwijk 9b237b
        op.execute(
Patrick Uiterwijk 9b237b
            sshkey_table.update()
Patrick Uiterwijk 9b237b
            .where(sshkey_table.c.id == key.id)
Patrick Uiterwijk 9b237b
            .values({
Patrick Uiterwijk 9b237b
                "ssh_short_key": ssh_short_key,
Patrick Uiterwijk 9b237b
                "ssh_search_key": ssh_search_key,
Patrick Uiterwijk 9b237b
            })
Patrick Uiterwijk 9b237b
        )
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
    data = []
Patrick Uiterwijk 9b237b
    for user in conn.execute(users_table.select()):
Patrick Uiterwijk 9b237b
        if not user.public_ssh_key:
Patrick Uiterwijk 9b237b
            continue
Patrick Uiterwijk 9b237b
        for key in user.public_ssh_key.split("\n"):
Patrick Uiterwijk 9b237b
            if key in (None, False) or not key.strip():
Patrick Uiterwijk 9b237b
                print("Skipping one key")
Patrick Uiterwijk 9b237b
                continue
Pierre-Yves Chibon 6764e6
            ssh_short_key = is_valid_ssh_key(key)
Pierre-Yves Chibon 6764e6
            if not ssh_short_key:
Pierre-Yves Chibon 6764e6
                continue
Pierre-Yves Chibon 6764e6
            ssh_short_key = ssh_short_key.strip()
Patrick Uiterwijk 9b237b
            ssh_search_key = ssh_short_key.split(" ")[1]
Patrick Uiterwijk 91e2c5
            if ssh_search_key in seen:
Patrick Uiterwijk 91e2c5
                print("Skipping previously seen key")
Patrick Uiterwijk 91e2c5
                continue
Patrick Uiterwijk 91e2c5
            seen.append(ssh_search_key)
Patrick Uiterwijk 9b237b
            print("Key:    %s" % key)
Patrick Uiterwijk 9b237b
            print("Short:  %s" % ssh_short_key)
Patrick Uiterwijk 9b237b
            print("Search: %s" % ssh_search_key)
Patrick Uiterwijk 9b237b
            tmp = {}
Patrick Uiterwijk 9b237b
            tmp["user_id"] = user.id
Patrick Uiterwijk 9b237b
            tmp["creator_user_id"] = user.id
Patrick Uiterwijk 9b237b
            tmp["public_ssh_key"] = key
Patrick Uiterwijk 9b237b
            tmp["ssh_search_key"] = ssh_search_key
Patrick Uiterwijk 9b237b
            tmp["ssh_short_key"] = ssh_short_key
Patrick Uiterwijk 9b237b
            tmp["pushaccess"] = True
Patrick Uiterwijk 9b237b
            tmp['date_created'] = datetime.datetime.utcnow()
Patrick Uiterwijk 9b237b
            data.append(tmp)
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
    op.bulk_insert(sshkey_table, data)
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
    op.drop_column("users", "public_ssh_key")
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
def downgrade():
Patrick Uiterwijk 9b237b
    """ Downgrade the database model for the way we store user's public ssh
Patrick Uiterwijk 9b237b
    keys.
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
    For this we bring back the keys present in the ``sshkeys`` table and
Patrick Uiterwijk 9b237b
    put them back into the ``public_ssh_key`` column of the ``users`` table.
Patrick Uiterwijk 9b237b
    """
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
    users_table = sa.sql.table(
Patrick Uiterwijk 9b237b
        "users",
Patrick Uiterwijk 9b237b
        sa.sql.column("id", sa.Integer),
Patrick Uiterwijk 9b237b
        sa.sql.column("public_ssh_key", sa.TEXT()),
Patrick Uiterwijk 9b237b
    )
Patrick Uiterwijk 9b237b
    sshkey_table = sa.sql.table(
Patrick Uiterwijk 9b237b
        "sshkeys",
Patrick Uiterwijk 9b237b
        sa.sql.column("user_id", sa.Integer),
Patrick Uiterwijk 9b237b
        sa.sql.column("public_ssh_key", sa.TEXT()),
Patrick Uiterwijk 9b237b
        sa.sql.column("ssh_short_key", sa.TEXT()),
Patrick Uiterwijk 9b237b
        sa.sql.column("ssh_search_key", sa.TEXT()),
Patrick Uiterwijk 9b237b
        sa.sql.column("creator_user_id", sa.Integer),
Patrick Uiterwijk 9b237b
        sa.sql.column("pushaccess", sa.Boolean),
Patrick Uiterwijk 9b237b
        sa.sql.column("date_created", sa.DateTime),
Patrick Uiterwijk 9b237b
    )
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
    op.add_column(
Patrick Uiterwijk 9b237b
        "users", sa.Column("public_ssh_key", sa.TEXT(), nullable=True)
Patrick Uiterwijk 9b237b
    )
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
    print("Convert existing ssh keys to the old format")
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
    conn = op.get_bind()
Patrick Uiterwijk 9b237b
    data = []
Patrick Uiterwijk 9b237b
    for key in conn.execute(sshkey_table.select()):
Patrick Uiterwijk 9b237b
        if not key.user_id:
Patrick Uiterwijk 9b237b
            continue
Patrick Uiterwijk 9b237b
        user = [
Patrick Uiterwijk 9b237b
            u
Patrick Uiterwijk 9b237b
            for u in conn.execute(
Patrick Uiterwijk 9b237b
                users_table.select().where(users_table.c.id == key.user_id)
Patrick Uiterwijk 9b237b
            )
Patrick Uiterwijk 9b237b
        ]
Patrick Uiterwijk 9b237b
        user = user[0]
Patrick Uiterwijk 9b237b
        ssh_key = ""
Patrick Uiterwijk 9b237b
        if user.public_ssh_key:
Patrick Uiterwijk 9b237b
            ssh_key = user.public_ssh_key + "\n"
Patrick Uiterwijk 9b237b
        ssh_key += key.public_ssh_key
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
        op.execute(
Patrick Uiterwijk 9b237b
            users_table.update()
Patrick Uiterwijk 9b237b
            .where(users_table.c.id == key.user_id)
Patrick Uiterwijk 9b237b
            .values({"public_ssh_key": ssh_key})
Patrick Uiterwijk 9b237b
        )
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
    print("Remove the keys associated with users since we moved them")
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
    op.execute(
Patrick Uiterwijk 9b237b
        sshkey_table.delete()
Patrick Uiterwijk 9b237b
        .where(sshkey_table.c.user_id != None)
Patrick Uiterwijk 9b237b
    )
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
    op.drop_constraint(
Patrick Uiterwijk 9b237b
        op.f("sshkeys_user_id_fkey"), "sshkeys", type_="foreignkey"
Patrick Uiterwijk 9b237b
    )
Patrick Uiterwijk 9b237b
    op.drop_index(op.f("ix_sshkeys_sshkeys_user_id"), table_name="sshkeys")
Patrick Uiterwijk 9b237b
    op.drop_column("sshkeys", "user_id")
Patrick Uiterwijk 9b237b
Patrick Uiterwijk 9b237b
    op.rename_table("sshkeys", "deploykeys")