{"id":41363510,"url":"https://github.com/platform9/express","last_synced_at":"2026-01-23T08:10:28.942Z","repository":{"id":44865062,"uuid":"58567787","full_name":"platform9/express","owner":"platform9","description":"Platform9's on-boarding / automation toolkit","archived":false,"fork":false,"pushed_at":"2025-08-01T07:23:38.000Z","size":82671,"stargazers_count":13,"open_issues_count":71,"forks_count":10,"subscribers_count":37,"default_branch":"master","last_synced_at":"2025-08-01T09:46:10.341Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Jinja","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/platform9.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2016-05-11T17:52:13.000Z","updated_at":"2025-07-19T18:05:23.000Z","dependencies_parsed_at":"2024-07-16T17:22:14.186Z","dependency_job_id":"7b623069-7f3e-4c8f-8c59-5eefa14f23d4","html_url":"https://github.com/platform9/express","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/platform9/express","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/platform9%2Fexpress","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/platform9%2Fexpress/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/platform9%2Fexpress/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/platform9%2Fexpress/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/platform9","download_url":"https://codeload.github.com/platform9/express/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/platform9%2Fexpress/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28684015,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-23T05:48:07.525Z","status":"ssl_error","status_checked_at":"2026-01-23T05:48:07.129Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-23T08:10:28.120Z","updated_at":"2026-01-23T08:10:28.934Z","avatar_url":"https://github.com/platform9.png","language":"Jinja","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Platform9 Express\nPlatform9 Express (pf9-express) is a Customer Success developed tool for bringing hosts under management by a Platform9 management plane.  It can bring a host to the point where it shows up in the Clarity UI as a host waiting to be authorized, or it can (optionally) perform Platform9 role deployments for both OpenStack and Kubernetes.  Platform9 Express includes a CLI and can be installed on a CentOS or Ubuntu control host.\n\n## Prerequisites\nPlatform9 Express must be installed on a control host with IP connectivity to the hosts to be brought under management. CentOS 7.8+, Ubuntu 22.04 or Rocky 9.x are supported. Onboarding hosts with Ubuntu 18.04, 20.04 can also be done, howerver the pf9-express cannot be executed from these OS due to some package/software dependency. Before installing Platform9 Express, you'll need administrator credentials for the Platform9 management plane. If a proxy is required for HTTP/HTTPS traffic, you'll need the URL for the proxy.\n\nThe systems should have minumum 2 network interfaces with IP configured on them. Default gateway will be on one of those interfaces.\n\n### Python3\n\nPython3 is now required for playbook execution and will be installed automatically on the control host.\nIf you have a specific version of python that should be executed on the _remote_ hosts, you can set these two lines accordingly.\n\n```\n[defaults]\n### Set the following two lines if you have python2 installed\ninterpreter_python=/bin/python3\nansible_python_interpreter=/bin/python3\n###\n```\n\n## Installation\nPerform the following steps to install Platform9 Express:\n\n1. Login as root (or a user with sudo access) on the host that you plan to install Platform9 Express on.\n\n2. Install git\n```\nyum install git # CentOS\n\napt update \u0026\u0026 apt install git # Ubuntu\n\ndnf install git # Rocky\n```\n\n3. Clone the Platform9 Express repository.\n\n```\ngit clone https://github.com/platform9/express.git /opt/pf9-express \u0026\u0026 cd /opt/pf9-express\n```\n**NOTE:** In this example, the installation directory is /opt/pf9-express, but any directory can be used.\n\n## Configure Access to the Management Plane (CLI Only)\nTo configure the Platform9 Express CLI to communicate with the Platform9 management plane, run the following command (a sample session is included):\n\n```\n# ./pf9-express -s\nNOTE: to enter a NULL value for prompt, enter '-'\n\nPF9 Management Plane URL [https://company.platform9.net]:\n--\u003e accepted: https://company.platform9.net\n\nAdmin Username [user@company.com]:\n--\u003e accepted: user@company.com\n\nAdmin Password [********]:\n--\u003e accepted: ********\n\nRegion [Sunnyvale]:\n--\u003e accepted: Sunnyvale\n\nTenant [service]:\n--\u003e accepted: service\n\nManage Hostname [true false] [false]:\n--\u003e accepted: false\n\nManage DNS Resolver [true false] [false]:\n--\u003e accepted: false\n\nDNS Resolver 1 [8.8.8.8]:\n--\u003e accepted: 8.8.8.8\n\nDNS Resolver 2 [8.8.4.4]:\n--\u003e accepted: 8.8.4.4\n\nProxy URL:\n--\u003e accepted: -\n```\n\n## Install Prerequisite Packages\nTo install prerequisite packages on the Platform9 Express control host, run the following command (a sample session is included):\n\n```\n[root@rocky94 pf9-express]# ./pf9-express -i\nFound release 9.4 on platform rocky\n--\u003e Installing Prerequisites\n--\u003e Installation Log: ./log/pf9-express.2025-07-22_11:05:30.log\n--\u003e Validating package dependencies: sshpass epel-release python3-devel python3-pip python3-virtualenv jq ansible==8.0.0 openstacksdk==4.0.0 docker-py pyopenssl \n\n[root@rocky94 pf9-express]# \n```\n\n**NOTE:** As you can see, python3 based stack will be installed. If your system already has python2, you will need to refer to [the Python3](#python3) section above.\n\n## Configuration Inventory (CLI Only)\nPlatform9 Express uses Ansible to execute commands on the hosts to be taken under management.  In order to configure Ansible to run remote commands on the managed hosts, the Ansible Inventory file must be configured.\n\n**NOTE:** A sample template is installed in the previous command (\"./pf9-express -s\").\nThis file is located in `/opt/pf9-express/inventory/hosts`.\n\nA breakdown of the Inventory File is below:\n\n## Sample Inventory File Part 1 - Authentication Portion\nThis is where you enter the credentials for your control host to log into the target VM hosts to be managed by the Platform9 management plane (through either a password or SSH key, comment out any password lines if using SSH authentication and vice versa as needed)\n```\n##\n## Ansible Inventory\n##\n[all]\n[all:vars]\n# The remote user ansible will use for ssh execution\nansible_user=ubuntu\nansible_sudo_pass=winterwonderland\nansible_ssh_pass=winterwonderland\n# The ssh key for the ssh connection to the `ansible_user` on the remote host\nansible_ssh_private_key_file=~/.ssh/id_rsa\n```\n\n## Sample Inventory File Part 2 - Network Portion\nThis is where you can configure optional network settings to create a bond with single or multiple interfaces.\n```\n################################################################################################\n## Optional Settings\n################################################################################################\nmanage_network=True\nbond_ifname=bond0\nbond_mode=1\nbond_mtu=9000\n\n## network bond configuration implemented if manage_network=True\n[bond_config]\n## for single interface bond configuration\nhv01 bond_members='eth1' bond_sub_interfaces='[{\"vlanid\":\"100\",\"ip\":\"10.0.0.11\",\"mask\":\"255.255.255.0\"}]'\n\n## for multiple interface bond configuration\nhv02 bond_members='[\"eth1\",\"eth2\"]' bond_sub_interfaces='[{\"vlanid\":\"100\",\"ip\":\"10.0.0.12\",\"mask\":\"255.255.255.0\"}]'\nhv03 bond_members='[\"eth1\",\"eth2\"]' bond_sub_interfaces='[{\"vlanid\":\"100\",\"ip\":\"10.0.0.13\",\"mask\":\"255.255.255.0\"}]'\ncv01 bond_members='[\"eth1\",\"eth2\"]' bond_sub_interfaces='[{\"vlanid\":\"100\",\"ip\":\"10.0.0.15\",\"mask\":\"255.255.255.0\"}]'\n```\nNOTE:\n 1. On systems where there is NO bond configured, simply set `bond_ifname` to the respective interface name like `ens3` or `eth1` , etc.\n 2. The interface configured against `bond_ifname` should NOT have default gateway configured against it. As the `br-pf9` bridge gets created on top of it, the connectivity like ssh via that interface is lost if that is the interface/Iface with the default gateway.\n\n## Sample Inventory File Part 3 - OpenStack Portion\nYou can configure the OpenStack hosts and their pertinent roles (Hypervisor, Image Host, Storage Host, DNS Host)\n```\n################################################################################################\n## OpenStack Groups\n################################################################################################\n[pmo:children]\nhypervisors\nglance\ncinder\n\n## global variables defined in group_vars/hypervisors.yml\n## note: if the following variables are not defined, the value of ansible_host will be inherited\n##   - vm_console_ip\n##   - ha_cluster_ip\n##   - tunnel_ip\n[hypervisors]\nhv01 ansible_host=10.0.0.11 vm_console_ip=10.0.0.11 ha_cluster_ip=10.0.1.11 tunnel_ip=10.0.2.11 dhcp=on snat=on\nhv02 ansible_host=10.0.0.12 vm_console_ip=10.0.0.12 tunnel_ip=10.0.2.12 dhcp=on snat=on\nhv03 ansible_host=10.0.0.13 vm_console_ip=10.0.0.13 tunnel_ip=10.0.2.13\nhv04 ansible_host=10.0.0.14\n\n## global variables defined in group_vars/glance.yml\n## note: if the following variables are not defined, the value of ansible_host will be inherited\n##   - glance_ip\n[glance]\nhv01 glance_ip=10.0.3.11 glance_public_endpoint=True\nhv02 glance_ip=10.0.3.12\n\n## global variables defined in group_vars/cinder.yml\n## note: if the following variables are not defined, the value of ansible_host will be inherited\n##   - cinder_ip\n[cinder]\nhv02 cinder_ip=10.0.4.14 pvs=[\"/dev/sdb\",\"/dev/sdc\",\"/dev/sdd\",\"/dev/sde\"]\n\n## global variables defined in group_vars/designate.yml\n## note: this role must be enabled by Platform9 Customer Success before using\n[designate]\n#hv01\n```\n\n## Sample Inventory File Part 4 - Kubernetes Portion\nThis is where you can configure your Kubernetes cluster members under their own roles (either master or worker). For a worker, you can optionally add it into a running cluster using the \"cluster_uuid\" variable. For any new workers, you can omit this variable assignment.\n```\n################################################################################################\n## Kubernetes Groups\n################################################################################################\n[pmk:children]\nk8s_master\nk8s_worker\n\n## global variables defined in group_vars/containervisors.yml\n## note: if the following variables are not defined, their tasks will be skipped\n##   - cluster_uuid\n[k8s_master]\ncv01 ansible_host=10.0.0.15\ncv02 ansible_host=10.0.0.16\ncv03 ansible_host=10.0.0.17\n\n[k8s_worker]\ncv04 ansible_host=10.0.0.18 cluster_uuid=7273706d-afd5-44ea-8fbf-901ceb6bef27\ncv05 ansible_host=10.0.0.19 cluster_uuid=7273706d-afd5-44ea-8fbf-901ceb6bef27\n```\n\n## CSV Import\nInstead of manually configuring the inventory file, you can use the '-f \u003ccsvFile\u003e' option to auto-configure it from a CSV definition file.\n\nHere's a sample CSV definition file:\n```\nhostname,username,key,ip,dhcp,snat,glance,glance-public,nic1,nic2,mgmtvlan,mgmtip,mgmtnetmask,Storagevlan,storageip,storagenetmask,tunnelvlan,tunnelip,tunnelnetmask\nfake01,centos,~/.ssh/id_rsa,172.16.7.182,TRUE,TRUE,TRUE,TRUE,ens160,,243,172.16.243.11,255.255.255.0,244,172.16.244.11,255.255.255.0,245,172.16.245.11,255.255.255.0\nfake02,ubuntu,~/.ssh/id_rsa,172.16.7.47,TRUE,FALSE,FALSE,FALSE,ens192,,243,172.16.243.12,255.255.255.0,244,172.16.244.12,255.255.255.0,245,172.16.245.12,255.255.255.0\n```\n\n## Controlling UID/GID for the Platform9 Host Agent\nIf you want to control the UID and GID values for the Platform9 service account (pf9/pf9group), set the following inventory variables:\n* pf9_uid\n* pf9_gid\n\nIf these variables are not defined, the Host Agent Installer will allow the system to auto-assign the UID and GID.\n\nNOTE: This feature is not idempotent.  If the 'pf9' user had not been created yet, Platform9 Express will create the 'pf9' user and 'pf9group' group based on the values of pf9_uid and pf9_gid.  If the 'pf9' user already exists, Platform9 Express will skip the user/group management section; it will not attempt to alter the UID/GID settings.\n\n## Running Platform9 Express\nThe basic syntax for starting Platform9 Express includes a target (host group, individual host, comma-delimited list of hosts, or \"all\" to run all groups) and an optional flag ('-a') that instructs it to perform role deployment.\n\nHere's an example of invoking Platform9 Express against a number of hosts without registering them automatically to the management plane:\n\n```\n[root@pf9-express]# ./pf9-express -g -a -b centos03\nFound release 7.9.2009 on platform centos\n################################################################\n# Platform9 Express Utility\n################################################################\n\n[Executing: ansible-playbook ./pf9-express.yml]\nansible-playbook-3 2.9.27\n  config file = /opt/pf9-express/ansible.cfg\n  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']\n  ansible python module location = /usr/lib/python3.6/site-packages/ansible\n  executable location = /bin/ansible-playbook-3\n  python version = 3.6.8 (default, Nov 16 2020, 16:55:22) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]\nUsing /opt/pf9-express/ansible.cfg as config file\nhost_list declined parsing /opt/pf9-express/inventory/hosts as it did not pass its verify_file() method\nscript declined parsing /opt/pf9-express/inventory/hosts as it did not pass its verify_file() method\n```\n\nHere's an example of invoking Platform9 Express against a number of hosts without registering them automatically to the management plane:\n\n```\n# ./pf9-express -g -a -b hv01,hv02,hv03\n################################################################\n# Platform9 Express Utility\n################################################################\n--\u003e Installation Log: ./log/pf9-express.2018-05-22_11:47:22.log\n--\u003e Validating package dependencies: epel-release ntp nginx gcc python-devel python2-pip bc shade docker-py ansible setupd\n--\u003e Updating setupd libraries: pf9_master_setup.py pf9_utils.py pf9_mgmt_setup.py attach-node add-cluster\n--\u003e ansible_version = 2.5\n\n[Executing: ansible-playbook ./pf9-express.yml]\n.\n.\n.\n```\n\nHere's an example of invoking Platform9 Express against a single host group (host groups are either \"pmo\" for OpenStack and \"pmk\" for Kubernetes), performing role deployments (based on metadata defined in /opt/pf9-express/inventory/hosts), and registering them automatically to the management plane\n```\n# ./pf9-express -a pmk\n################################################################\n# Platform9 Express Utility\n################################################################\n--\u003e Installation Log: ./log/pf9-express.2018-05-22_16:29:01.log\n--\u003e Validating package dependencies: epel-release ntp nginx gcc python-devel python2-pip bc shade docker-py ansible setupd\n--\u003e Updating setupd libraries: pf9_master_setup.py pf9_utils.py pf9_mgmt_setup.py attach-node add-cluster\n--\u003e ansible_version = 2.5\n\n[Executing: ansible-playbook ./pf9-express.yml]\n.\n.\n.\n```\nHere's an example of invoking Platform9 Express against all host groups and performing role deployments (based on metadata defined in /opt/pf9-express/inventory/hosts):\n```\n# ./pf9-express -a all\n################################################################\n# Platform9 Express Utility\n################################################################\n--\u003e Installation Log: ./log/pf9-express.2018-05-22_16:29:01.log\n--\u003e Validating package dependencies: epel-release ntp nginx gcc python-devel python2-pip bc shade docker-py ansible setupd\n--\u003e Updating setupd libraries: pf9_master_setup.py pf9_utils.py pf9_mgmt_setup.py attach-node add-cluster\n--\u003e ansible_version = 2.5\n\n[Executing: ansible-playbook ./pf9-express.yml]\n.\n.\n.\n```\nHere's the usage statement showing all command-line options:\n```\n# ./pf9-express\nUsage: ./pf9-express [Args] \u003ctarget\u003e\n\nArgs (Optional):\n\n-a|--autoRegister          : auto-register host with management plane\n-i|--installPrereqs        : install pre-requisites and exit\n-s|--setup                 : run setup and exit\n-o|--oscli                 : install OpenStack CLI\n-c|--config \u003cconfigFile\u003e   : use custom configuration file\n-e|--extra-vars \u003cstring\u003e   : ansible extra-vars \u003cname=val,...\u003e\n-b|--bypassPrereqs         : bypass pre-requisites\n-d|--deauth                : de-authorize host\n-l|--log                   : Log output file. Assumes parent directory already exists.\n-u|--upgradeK8s            : upgrade Kubernetes nodes\n-v|--inventory \u003cfile\u003e      : use alternate inventory file for Ansible\n-g|--debug                 : use extra ansible verbosity for debugging\n-f|--csvFile \u003cfile\u003e        : import CSV file\n-t|--tag \u003ctag[,\u003ctag\u003e]\u003e     : available tags = [live-migration, image-import]\n-h|--help                  : display this message\n```\n\n## Managing Multiple Cloud Management Regions (DUs)\nIf you have more than one Platform9 region to manage, you can create a configuration file for each one (using pf9-express.conf as a template) and start pf9-express with the '-c' flag:\n\n```\n./pf9-express -c ~/pf9-site1.conf -a hv01\n```\n\n## Overriding Inventory Variables\nIf you want to override an Ansible variable defined in Inventory or dynamically within playbooks, you can invoke pf9-express with the '-e' flag:\n\n```\n./pf9-express -c ~/pf9-express.conf -a -e \"proxy_url=https://proxy1.platform9.net\" hv01\n```\nNOTE: Variables passed as extra-vars have the highest precedence.\n\n\n## Troubleshooting\n\n**Issue:**\n\n```\n[root@sn-n1 express]# ./pf9-express -i\nFound release 7.9.2009 on platform centos\n--\u003e Installing Prerequisites\n--\u003e Installation Log: ./log/pf9-express.2023-06-07_10:14:56.log\n--\u003e Validating package dependencies: sshpass epel-release gcc python3-devel python3-pip jq ansible==2.9.27 openstacksdk==0.62.0\nERROR: failed to install ansible==2.9.27 openstacksdk==0.62.0 - here's the last 10 lines of the log:\n\n    return self._prepare_linked_requirement(req, parallel_builds)\n  File \"/usr/local/lib/python3.6/site-packages/pip/_internal/operations/prepare.py\", line 528, in _prepare_linked_requirement\n    link, req.source_dir, self._download, self.download_dir, hashes\n  File \"/usr/local/lib/python3.6/site-packages/pip/_internal/operations/prepare.py\", line 223, in unpack_url\n    unpack_file(file.path, location, file.content_type)\n  File \"/usr/local/lib/python3.6/site-packages/pip/_internal/utils/unpacking.py\", line 247, in unpack_file\n    untar_file(filename, location)\n  File \"/usr/local/lib/python3.6/site-packages/pip/_internal/utils/unpacking.py\", line 218, in untar_file\n    with open(path, \"wb\") as destfp:\nUnicodeEncodeError: 'ascii' codec can't encode character '\\xe9' in position 112: ordinal not in range(128)\n```\n\n**Fix:**\n\nCreate `/etc/profile.d/my-custom.lang.sh` Add following lines to it. Then `chmod a+x /etc/profile.d/my-custom.lang.sh ; source /etc/profile.d/my-custom.lang.sh`\n\n```\nexport LANG=en_US.UTF-8\nexport LANGUAGE=en_US.UTF-8\nexport LC_COLLATE=C\nexport LC_CTYPE=en_US.UTF-8\n```\n\nOn Rocky Linux 9.1 you may need to install `langpacks-en glibc-all-langpacks` first. Verify that locale en_US.UTF-8 is installed.\n\n```\n# localectl set-locale LANG=en_US.UTF-8\nFailed to issue method call: Locale en_US.UTF-8 not installed, refusing.\n```\n\nIn such event install the locale by running\n\n```\n# dnf install langpacks-en glibc-all-langpacks -y\n```\n\n## License\n\nApache 2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplatform9%2Fexpress","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fplatform9%2Fexpress","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplatform9%2Fexpress/lists"}