Internals

The goal of this document is to describe Software Factory’s internals.

Organisation

The project is divided into many repositories, available on the https://softwarefactory-project.io gerrit software-factory/ namespace, and replicated on github at https://github.com/softwarefactory-project

* sf-release: The release rpm to install the repository
* sf-config: The configuration/upgrade process
* sf-docs: The documentation
* sf-ci: The SF testing framework
* sf-elements: Diskimage builder elements
* sfinfo: The rpm distribution informations
* ...

All the components are packaged using distgit repositories.

The components

Below is an overview of all the components integration (shown as dashed boxes) and services along with their connections to each others.

digraph {
    nodesep = 0.75
    node [shape=doublecircle,color=orange,fontsize=10,width=1.0]
    edge [fontsize=10];

    "User" [shape=box];
    "LDAP" [color=gray];
    "LaunchPad" [color=gray];
    "Github" [color=gray label="Github\n(OAuth)"];
    "LocalAuth" [color=gray];

    subgraph cluster_agenda {
        style=invis;

        node [fontsize=0 width=0 style=invis]

        {rank=same; h1; h2;}
        h1 -> h2 [label="HTTP" color="blue" dir=none];

        {rank=same; s1; s2;}
        s1 -> s2 [label="SSH" color="red" dir=none];

        {rank=same; m1; m2;}
        m1 -> m2 [label="MySQL" color="orange" dir=none];

        {rank=same; i1; i2;}
        i1 -> i2 [label="internal" color="gray" dir=none];

        {rank=same; l1; l2;}
        l1 -> l2 [label="LDAP" color="green" dir=none];
    }

    subgraph cluster_gerrit {
        style = dashed;
        label="Gerrit";
        "Gerrit";
        "GerritApache" [label="Apache"];
    }

    subgraph cluster_jenkins {
        style = dashed;
        label="Jenkins";
        "master" [label="Jenkins"];
        "JenkinsApache" [label="Apache"];
        "Zuul";
        "Nodepool";
    }

    subgraph cluster_mysql {
        style = dashed;
        label="Mysql";
        "MySQL";
    }

    subgraph cluster_slave {
        style = dashed;
        label="Jenkins slave";
        "slave" [label="Jenkins"];
    }

    subgraph cluster_managesf {
        style = dashed;
        label="Managesf";
        "Apache";
        "Etherpad";
        "Paste";
        "managesf";
        "cauth";
        "LocalAuth";
    }

    edge [color=blue];
    "User" -> "Apache";
    "Apache" -> "Etherpad";
    "Apache" -> "Paste";
    "Apache" -> "GerritApache";
    "Apache" -> "JenkinsApache";
    "GerritApache" -> "Gerrit";
    "JenkinsApache" -> "master";
    "slave" -> "master" [constraint=False];
    "master" -> "slave" [style=invis];
    "cauth" -> "Github";
    "cauth" -> "Gerrit";
    "managesf" -> "Gerrit";
    "cauth" -> "managesf";

    edge [color=red];
    "User" -> "Gerrit";

    edge [color=orange];
    "Gerrit" -> "MySQL";
    "Etherpad" -> "MySQL";
    "Paste" -> "MySQL";
    "managesf" -> "LocalAuth";

    edge [color=gray];
    "Apache" -> "cauth";
    "Apache" -> "managesf";
    "master" -> "Zuul" [constraint=False];
    "Zuul" -> "Gerrit";

    edge [color=green];
    "cauth" -> "LDAP";
    "cauth" -> "LaunchPad";

    MySQL -> m1 [style=invis];
}

The SSO mechanism

Below is the sequence diagram of the SSO mechanism.

digraph {
    nodesep = 1.0;
    node [fontsize=10,width=0.9,shape=doublecircle,color=orange];
    edge [fontsize=10];

    "User" [shape=box];
    "Apache";
    "cauth";
    "Github" [color=gray];

    "User" -> "Apache" [style=invis];
    "Apache" -> "cauth" [style=invis];
    "cauth" -> "Github" [style=invis];

    {rank=same; User; Apache; cauth; Github; }

    node [fontsize=10,width=0.0,shape=point];

    edge [dir=none, color=gray, style=dashed]
    "User" -> u1 -> u2 -> u3 -> u4 -> u5 -> u6 -> u7 -> u8 -> u9 -> u10;
    "Github" -> g5 -> g6;
    "Apache" -> a1 -> a2 -> a9 -> a10;
    "cauth" -> c3 -> c4 -> c7 -> c8;

    edge [dir=forward, color=black, style=solid];

    u1 -> a1 [label="1. Request"]; {rank=same; u1; a1;}

    a2 -> u2 [label="2. Redirect to login Form", constraint=False]; {rank=same;u2; a2;}

    u3 -> c3 [label="3. Select Github authentication"]; {rank=same;u3; c3;}

    c4 -> u4 [label=" 4. Redirect to Github", constraint=False]; {rank=same; c4; u4;}

    u5 -> g5 [label="5. Request"]; {rank=same; u5; g5;}

    g5 -> g6 [label=" 6. Authenticate", constraint=False];

    g6 -> u6 [label=" 7. Redirect to cauth with token", constraint=False]; {rank=same; u6; g6;}

    u7 -> c7 [label="8. Request with token"]; {rank=same;u7; c7;}

    c7 -> c8 [label=" 9. Verify token", constraint=False];

    c8 -> u8 [label=" 10. Redirect to Apache with cookie", constraint=False]; {rank=same; u6; g6;}

    u9 -> a9 [label="11. Request with cookie"]; {rank=same; u9; a9;}

    a9 -> a10 [label=" 12. Verify cookie", constraint=False];

    a10 -> u10 [label="13. Final response with content", constraint=False]; {rank=same;u10; a10;}

}

Ansible usage

The arch.yaml file describes what roles should run on which instances. Then based on this information, the sfconfig process generates all the necessary playbooks to configure and maintain the deployment:

  • The sf_setup.yml playbook runs the install, setup, config_update tasks to deploy the services on a fresh instance.
  • The sf_configrepo_update.yml playbook applies the config project configuration, it is the playbook executed by the config-update job.
  • The sf_backup.yml playbook collects all the services’ data in /var/lib/software-factory/backup
  • The get_logs.yml playbook collects all the services’ logs, it’s mostly used for sf-ci logs collections.
  • The sf_erase.yml playbook disables and can remove all the services’ data, it is used to un-install the services.

The system configuration

The sfconfig script drives the system configuration. This script does the following actions:

  • Generates secrets such as internal passwords, ssh keys and tls certificats,
  • Ensures configuration files are up-to-date, this script checks for missing section and makes sure the defaults value are present. This is particularly useful when after an upgrade, a new component configuration has been added
  • Generates Ansible inventory and configuration playbook based on the arch.yaml file.
  • Generates and execute an Ansible playbook based on the action (e.g. setup, recover, upgrade, …)
  • Waits for ssh access to all instances
  • Run testinfra tests
  • All the generated data is written in /var/lib/software-factory:
    • ansible/ contains the playbooks and the group_vars.
    • bootstrap-data/ contains file secrets such as tls certificats or ssh keys.
    • sql/ contains database creation scripts.

That system configuration process is re-entrant and needs to be executed everytime the settings are changed.

Then SF is meant to be a self-service system, thus project configuration is done through the config-repo.

The config-repo

Once SF is up and running, the user configuration of Software Factory happens via the config-repo:

  • zuul3/: Zuul3 configuration
  • nodepoolV3/: Nodepool3 configuration
  • gerritbot/: IRC notification for gerrit event configuration,
  • gerrit/: Gerrit replication endpoint configuration, and
  • mirrors/: mirror2swift configuration.
  • resources/: Platform wide groups, projects, repositories definitions.
  • dashboard/: Custom Gerrit dashboard configuration
  • repoxplorer/: RepoXplorer additional definitions (idents, groups, …)
  • policies/: ManageSF API ACLs definition

Deprecated configuration: * jobs/: Jenkins jobs jjb configuration, * jobs-zuul/: Zuul-launcher jobs jjb configuration, * zuul/: CI gating zuul yaml configuration, * nodepool/: Slave configuration with images and labels definitions,

This is actually managed through SF CI system, thanks to the config-update job. This job is actually an ansible playbook that will:

  • Reload zuul configuration (hot reload without losing in-progress tasks),
  • Reload nodepool, gerritbot and gerrit replication, and
  • Set mirror2swift configuration for manual or next periodic update.
  • Apply resources definitions (create repositories, update groups, …)