diff --git a/.zuul.yaml b/.zuul.yaml index 7f39baa7d0..9c8e3a07fe 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -1011,6 +1011,32 @@ - playbooks/roles/zuul-preview/ - testinfra/test_zuul_preview.py +- job: + name: system-config-run-review-dev + parent: system-config-run + description: | + Run the playbook for gerrit (in a container). + nodeset: + nodes: + - name: bridge.openstack.org + label: ubuntu-bionic + - name: review-dev01.openstack.org + label: ubuntu-bionic + vars: + run_playbooks: + - playbooks/service-review-dev.yaml + host-vars: + review-dev01.openstack.org: + host_copy_output: + '/home/gerrit2/review_site/etc': logs + '/home/gerrit2/review_site/logs': logs + files: + - playbooks/group_vars/review-dev.yaml + - ^playbooks/host_vars/review-dev\d+.opendev.org.yaml + - playbooks/zuul/templates/group_vars/review.yaml.j2 + - playbooks/roles/gerrit/ + - testinfra/test_gerrit.py + - job: name: infra-prod-playbook description: | @@ -1068,6 +1094,7 @@ soft: true - name: system-config-build-image-haproxy-statsd soft: true + - system-config-run-review-dev - system-config-run-zuul-preview - system-config-run-letsencrypt - system-config-build-image-bazel @@ -1127,6 +1154,7 @@ soft: true - name: system-config-upload-image-haproxy-statsd soft: true + - system-config-run-review-dev - system-config-run-zuul-preview - system-config-run-letsencrypt - system-config-upload-image-bazel diff --git a/modules/openstack_project/files/gerrit/web_server.py b/modules/openstack_project/files/gerrit/web_server.py deleted file mode 100755 index 8c61a122b6..0000000000 --- a/modules/openstack_project/files/gerrit/web_server.py +++ /dev/null @@ -1,178 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -This is a simple test server that serves up the web content locally -as if it was a working remote server. It also proxies all the live -date/*.json files into the local test server, so that the Ajax async -loading works without hitting Cross Site Scripting violations. -""" - -import argparse -import BaseHTTPServer -import os.path -import urllib2 - -import requests - -# Values for these set via cli defaults -GERRIT_UPSTREAM = "" -ZUUL_UPSTREAM = "" - - -def replace_urls(line, port): - line = line.replace( - GERRIT_UPSTREAM, - "http://localhost:%s" % port) - line = line.replace( - ZUUL_UPSTREAM, - "http://localhost:%s" % port) - return line - - -class GerritHandler(BaseHTTPServer.BaseHTTPRequestHandler): - """A request handler to create a magic local Gerrit server""" - - def do_POST(self): - data = self.rfile.read(int(self.headers['content-length'])) - headers = {} - # we need to trim some of the local headers in order for this - # request to remain valid. - for header in self.headers: - if header not in ("host", "origin", "connection"): - headers[header] = self.headers[header] - resp = requests.post("%s%s" % - (GERRIT_UPSTREAM, self.path), - headers=headers, - data=data) - - # Process request back to client - self.send_response(resp.status_code) - for header in resp.headers: - # Requests has now decoded the response so it's no longer - # a gzip stream, which also means content-length is - # wrong. So we remove content-encoding, then drop - # content-length because if provided Gerrit strictly uses - # it for reads. We also drop all the keep-alive related - # headers, our server doesn't do that. - if header not in ("connection", "content-length", - "keep-alive", "content-encoding"): - self.send_header(header, resp.headers[header]) - self.end_headers() - self.wfile.write(resp.text) - - def do_GET(self): - # possible local file path - local_path = self.path.replace('/static/', '').split('?')[0] - - # if the file exists locally, we'll serve it up directly - if os.path.isfile(local_path): - self.send_response(200, "Success") - self.end_headers() - with open(local_path) as f: - for line in f.readlines(): - line = replace_urls(line, self.server.server_port) - self.wfile.write(line) - print "Loaded from local override" - return - - # First we'll look for a zuul status call, /status doesn't map - # to gerrit so we can overload the localhost server for this. - if self.path.startswith("/status"): - try: - zuul_url = "%s%s" % (ZUUL_UPSTREAM, self.path) - # BUG(sdague): for some reason SSL connections to zuul - # from python 2.7 blow up with an SSL exception - zuul_url = zuul_url.replace('https', 'http') - response = urllib2.urlopen(zuul_url) - self.send_response(200, "Success") - for header in response.info(): - # need to reset content-length otherwise jquery complains - if header not in ("connection", "content-length", - "keep-alive", "content-encoding"): - self.send_header(header, response.info()[header]) - self.end_headers() - - for line in response.readlines(): - line = replace_urls(line, self.server.server_port) - self.wfile.write(line) - return - except urllib2.HTTPError as e: - self.send_response(e.code) - self.end_headers() - self.wfile.write(e.read()) - return - except urllib2.URLError as e: - print "URLError on %s" % (zuul_url) - print e - - # If you've not built local data to test with, instead grab - # the data off the production server on the fly and serve it - # up from our server. - try: - response = urllib2.urlopen("%s%s" % - (GERRIT_UPSTREAM, self.path)) - self.send_response(200, "Success") - for header in response.info(): - self.send_header(header, response.info()[header]) - self.end_headers() - - for line in response.readlines(): - line = replace_urls(line, self.server.server_port) - self.wfile.write(line) - except urllib2.HTTPError as e: - self.send_response(e.code) - self.end_headers() - self.wfile.write(e.read()) - - -def parse_opts(): - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument('-p', '--port', - help='port to bind to [default: 8001]', - type=int, - default=8001) - parser.add_argument('-z', '--zuul-url', - help='url for zuul server', - default="https://zuul.openstack.org") - parser.add_argument('-g', '--gerrit-url', - help='url for gerrit server', - default="https://review.opendev.org") - return parser.parse_args() - - -def main(): - global ZUUL_UPSTREAM - global GERRIT_UPSTREAM - opts = parse_opts() - ZUUL_UPSTREAM = opts.zuul_url - GERRIT_UPSTREAM = opts.gerrit_url - server_address = ('', opts.port) - httpd = BaseHTTPServer.HTTPServer(server_address, GerritHandler) - - print "Test Server is running at http://localhost:%s" % opts.port - print "Ctrl-C to exit" - print - - while True: - httpd.handle_request() - -if __name__ == '__main__': - try: - main() - except KeyboardInterrupt: - print "\n" - print "Thanks for testing! Please come again." diff --git a/playbooks/roles/gerrit/README.rst b/playbooks/roles/gerrit/README.rst new file mode 100644 index 0000000000..984e3c5c95 --- /dev/null +++ b/playbooks/roles/gerrit/README.rst @@ -0,0 +1 @@ +Run Gerrit. diff --git a/playbooks/roles/gerrit/defaults/main.yaml b/playbooks/roles/gerrit/defaults/main.yaml new file mode 100644 index 0000000000..2136969cf7 --- /dev/null +++ b/playbooks/roles/gerrit/defaults/main.yaml @@ -0,0 +1,5 @@ +gerrit_id: 3000 +gerrit_user_name: gerrit2 +gerrit_home_dir: /home/gerrit2 +gerrit_site_dir: "{{ gerrit_home_dir }}/review_site" +gerrit_run_init: false diff --git a/playbooks/roles/gerrit/files/cla.html b/playbooks/roles/gerrit/files/cla.html new file mode 100644 index 0000000000..83f8688a7a --- /dev/null +++ b/playbooks/roles/gerrit/files/cla.html @@ -0,0 +1,259 @@ +<html><body><div> + +<h1> +OpenStack Project Individual Contributor License Agreement +</h1> + +<!-- +This is the current OpenStack Project Individual Contributor License Agreement +reformatted for HTML from the original "RevisedCLA.doc" with SHA1 sum +0467dd893d276cefde614e063a363b995d67e5ee provided by Jonathan Bryce, Executive +Director on behalf of The OpenStack Foundation on Monday, January 7, 2013. No +textual content was changed except to replace quote marks with their strict +ASCII equivalents, add the original LLC CLA text as a block quote, and restore +a previously inapplicable statement (sentence #2 of paragraph #2) adapted from +the Apache Software Foundation ICLA at his direction. +--> + +<p><em> +In order to clarify the intellectual property license granted with +Contributions from any person or entity, the OpenStack Project (the "Project") +must have a Contributor License Agreement ("Agreement") on file that has been +signed by each Contributor, indicating agreement to the license terms below. +This license is for your protection as a Contributor as well as the protection +of OpenStack Foundation as Project manager (the "Project Manager") and the +Project users; it does not change your rights to use your own Contributions for +any other purpose. +</em></p> + +<p><em> +You accept and agree to the following terms and conditions for Your present and +future Contributions submitted to the Project Manager. In return, the Project +Manager shall not use Your Contributions in a way that is contrary to the +public benefit or inconsistent with its nonprofit status and bylaws in effect +at the time of the Contribution. Except for the license granted herein to the +Project Manager and recipients of software distributed by the Project Manager, +You reserve all right, title, and interest in and to Your Contributions. +</em></p> + +<ol> + +<li><p><strong> +Definitions. +</strong> +"You" (or "Your") shall mean the copyright owner or legal entity authorized by +the copyright owner that is making this Agreement with the Project Manager. For +legal entities, the entity making a Contribution and all other entities that +control, are controlled by, or are under common control with that entity are +considered to be a single Contributor. For the purposes of this definition, +"control" means (i) the power, direct or indirect, to cause the direction or +management of such entity, whether by contract or otherwise, or (ii) ownership +of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial +ownership of such entity. "Contribution" shall mean any original work of +authorship, including any modifications or additions to an existing work, that +is intentionally submitted by You to the Project Manager for inclusion in, or +documentation of, any of the projects owned or managed by the Project Manager +(the "Work"). For the purposes of this definition, "submitted" means any form of +electronic, verbal, or written communication sent to the Project Manager or its +representatives, including but not limited to communication on electronic +mailing lists, source code control systems, and issue tracking systems that are +managed by, or on behalf of, the Project Manager for the purpose of discussing +and improving the Work, but excluding communication that is conspicuously marked +or otherwise designated in writing by You as "Not a Contribution." +</p></li> + +<li><p><strong> +Grant of Copyright License. +</strong> +Subject to the terms and conditions of this Agreement, You hereby grant to the +Project Manager and to recipients of software distributed by the Project +Manager a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare derivative works of, +publicly display, publicly perform, sublicense, and distribute Your +Contributions and such derivative works. +</p></li> + +<li><p><strong> +Grant of Patent License. +</strong> +Subject to the terms and conditions of this Agreement, You hereby grant to the +Project Manager and to recipients of software distributed by the Project +Manager a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by You that are +necessarily infringed by Your Contribution(s) alone or by combination of Your +Contribution(s) with the Work to which such Contribution(s) was submitted. If +any entity institutes patent litigation against You or any other entity +(including a cross-claim or counterclaim in a lawsuit) alleging that Your +Contribution, or the Work to which You have contributed, constitutes direct or +contributory patent infringement, then any patent licenses granted to that +entity under this Agreement for that Contribution or Work shall terminate as of +the date such litigation is filed. +</p></li> + +<li><p> +You represent that you are legally entitled to grant the above license. If your +employer(s) has rights to intellectual property that you create that includes +your Contributions, You represent that you have received permission to make +Contributions on behalf of that employer, that your employer has waived such +rights for your Contributions to the Project Manager, or that your employer has +executed a separate Corporate Contributor License Agreement with the Project +Manager. +</p></li> + +<li><p> +You represent that each of Your Contributions is Your original creation (see +Section 7 for submissions on behalf of others). You represent that Your +Contribution submissions include complete details of any third-party license or +other restriction (including, but not limited to, related patents and +trademarks) of which you are personally aware and which are associated with any +part of Your Contributions. +</p></li> + +<li><p> +You are not expected to provide support for Your Contributions, except to the +extent You desire to provide support. You may provide support for free, for a +fee, or not at all. Unless required by applicable law or agreed to in writing, +You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied, including, without +limitation, any warranties or conditions of TITLE, NONINFRINGEMENT, +MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. +</p></li> + +<li><p> +Should You wish to submit work that is not Your original creation, You may +submit it to the Project Manager separately from any Contribution, identifying +the complete details of its source and of any license or other restriction +(including, but not limited to, related patents, trademarks, and license +agreements) of which you are personally aware, and conspicuously marking the +work as "Submitted on behalf of a third-party: [named here]". +</p></li> + +<li><p> +You agree to notify the Project Manager of any facts or circumstances of which +you become aware that would make these representations inaccurate in any +respect. +</p></li> + +<li><p> +In addition, if you have provided a Contribution (as defined in the LLC +Contribution License Agreement below) to the Project under the Contribution +License Agreement to OpenStack, LLC ("LLC Contribution Agreement"), you agree +that OpenStack, LLC may assign the LLC Contribution Agreement along with all +its rights and obligations under the LLC Contribution License Agreement to the +Project Manager. +</p></li> + +</ol> + +<blockquote> +<p><em>In order to clarify the intellectual property license granted with +Contributions from any person or entity, the OpenStack Project (the "Project") +must have a Contributor License Agreement ("Agreement") on file that has been +signed by each Contributor, indicating agreement to the license terms below. +This license is for your protection as a Contributor as well as the protection +of OpenStack, LLC as Project manager (the "Project Manager") and the Project +users; it does not change your rights to use your own Contributions for any +other purpose. If you have not already done so, please complete and sign this +Individual License Agreement by following the instructions embedded below. +After you fill in the required information and apply your digital signature to +the Agreement, the signature service will generate an email to you. You must +confirm your digital signature as instructed in this email to complete the +signing process. The signature service will then send you a signed copy of this +Agreement for your records.</em></p> + +<p><em>You accept and agree to the following terms and conditions for Your +present and future Contributions submitted to the Project Manager. Except for +the license granted herein to the Project Manager and recipients of software +distributed by the Project Manager, You reserve all right, title, and interest +in and to Your Contributions.</em></p> + +<ol> + +<li><p><strong>Definitions</strong>"You" (or "Your") shall mean the copyright +owner or legal entity authorized by the copyright owner that is making this +Agreement with the Project Manager. For legal entities, the entity making a +Contribution and all other entities that control, are controlled by, or are +under common control with that entity are considered to be a single +Contributor. For the purposes of this definition, "control" means (i) the +power, direct or indirect, to cause the direction or management of such entity, +whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or +more of the outstanding shares, or (iii) beneficial ownership of such +entity. "Contribution" shall mean any original work of authorship, including +any modifications or additions to an existing work, that is intentionally +submitted by You to the Project Manager for inclusion in, or documentation of, +any of the projects owned or managed by the Project Manager (the "Work"). For +the purposes of this definition, "submitted" means any form of electronic, +verbal, or written communication sent to the Project Manager or its +representatives, including but not limited to communication on electronic +mailing lists, source code control systems, and issue tracking systems that are +managed by, or on behalf of, the Project Manager for the purpose of discussing +and improving the Work, but excluding communication that is conspicuously +marked or otherwise designated in writing by You as "Not a +Contribution."</p></li> + +<li><p><strong>Grant of Copyright License.</strong> Subject to the terms and +conditions of this Agreement, You hereby grant to the Project Manager and to +recipients of software distributed by the Project Manager a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright +license to reproduce, prepare derivative works of, publicly display, publicly +perform, sublicense, and distribute Your Contributions and such derivative +works.</p></li> + +<li><p><strong>Grant of Patent License.</strong> Subject to the terms and +conditions of this Agreement, You hereby grant to the Project Manager and to +recipients of software distributed by the Project Manager a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as +stated in this section) patent license to make, have made, use, offer to sell, +sell, import, and otherwise transfer the Work, where such license applies only +to those patent claims licensable by You that are necessarily infringed by Your +Contribution(s) alone or by combination of Your Contribution(s) with the Work +to which such Contribution(s) was submitted. If any entity institutes patent +litigation against You or any other entity (including a cross-claim or +counterclaim in a lawsuit) alleging that Your Contribution, or the Work to +which You have contributed, constitutes direct or contributory patent +infringement, then any patent licenses granted to that entity under this +Agreement for that Contribution or Work shall terminate as of the date such +litigation is filed.</p></li> + +<li><p>You represent that you are legally entitled to grant the above license. +If your employer(s) has rights to intellectual property that you create that +includes your Contributions, You represent that you have received permission to +make Contributions on behalf of that employer, that your employer has waived +such rights for your Contributions to the Project Manager, or that your +employer has executed a separate Corporate Contributor License Agreement with +the Project Manager.</p></li> + +<li><p>You represent that each of Your Contributions is Your original creation +(see Section 7 for submissions on behalf other others). You represent that Your +Contribution submissions include complete details of any third-party license or +other restriction (including, but not limited to, related patents and +trademarks) of which you are personally aware and which are associated with any +part of Your Contributions.</p></li> + +<li><p>You are not expected to provide support for Your Contributions, except +to the extent You desire to provide support. You may provide support for free, +for a fee, or not at all. Unless required by applicable law or agreed to in +writing, You provide Your Contributions on as "AS IS" BASIS, WITHOUT WARRANTIES +OR CONDITIONS OR ANY KIND, either express or implied, including, without +limitation, any warranties or conditions of TITLE, NONINFRINGEMENT, +MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.</p></li> + +<li><p>Should You wish to submit work that is not Your original creation, You +may submit it to the Project Manager separately from any Contribution, +identifying the complete details of its source and of any license or other +restriction (including, but not limited to, related patents, trademarks, and +license agreements) of which you are personally aware, and conspicuously +marking the work as "Submitted on behalf of a third-party: [named +here]".</p></li> + +<li><p>You agree to notify the Project Manager of any facts or circumstances of +which you become aware that would make these representations inaccurate in any +respect.</p></li> + +</ol> + +</blockquote> + +</div></body></html> diff --git a/playbooks/roles/gerrit/files/etc/GerritSite.css b/playbooks/roles/gerrit/files/etc/GerritSite.css new file mode 100644 index 0000000000..c1c9d47575 --- /dev/null +++ b/playbooks/roles/gerrit/files/etc/GerritSite.css @@ -0,0 +1,179 @@ +body {color: #000 !important;} +a,a:visited {color: #264D69 !important; text-decoration: none;} +a:hover {color: #000 !important; text-decoration: underline} + +a.gwt-InlineHyperlink {background: none !important} + +#openstack-logo img { height: 40px; } +#openstack-logo h1 { margin: 20px; } +#gerrit_header #openstack-logo h1 { margin: 20px 0 0 0; } + +#gerrit_header {display: block !important; position: relative; top: -60px; margin-bottom: -60px; width: 200px; padding-left: 17px} +#gerrit_header h1 {font-family: 'PT Sans', sans-serif; font-weight: normal; letter-spacing: -1px} + +#gerrit_topmenu {background: none; position:relative; top: 0px; left: 220px; margin-right: 220px} + +#gerrit_topmenu tbody tr td table {border: 0} + +#gerrit_topmenu tbody tr td table.gwt-TabBar {color: #353535; border-bottom: 1px solid #C5E2EA;} +#gerrit_topmenu .gwt-Button {padding: 3px 6px} +.gwt-TabBarItem-selected {color: #CF2F19 !important; border-bottom: 3px solid #CF2F19;} +.gwt-TabBarItem {color: #353535; border-right: 0 !important} +.gwt-TabBar .gwt-TabBarItem, .gwt-TabBar .gwt-TabBarRest, .gwt-TabPanelBottom {background: 0 !important;} + +#gerrit_topmenu .searchTextBox {width: 250px} + +#change_infoTable { + border-collapse: collapse; +} + +#change_infoTable th { + padding: 2px 4px 2px 6px; + background-color: #eef3f5; + font-style: italic; + text-align: left; +} + +#change_infoTable td { + padding: 2px 4px 2px 6px; + border-bottom: 1px solid #eef3f5; + border-right: 1px solid #eef3f5; +} + +#change_infoTable tr:last-child td { + border: none; +} + +.com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-cs2 { + padding-left: 10px; + padding-right: 10px; +} + +/* Section headers */ +.com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-cs2 + .com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-headerLine, +.com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-cs2 + .com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-sectionHeader { + margin-top: 10px !important; + margin-bottom: 10px !important; +} + +/* Commit message */ +.com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-cs2 + .com-google-gerrit-client-change-CommitBox_BinderImpl_GenCss_style-text::first-line { + font-weight: bold !important; +} + +/* Commit metadata */ +.com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-cs2 + .com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-commitColumn + .com-google-gerrit-client-change-CommitBox_BinderImpl_GenCss_style-header th { + padding: 2px 4px 2px 6px; + background-color: #eef3f5; + font-style: italic; + text-align: left; +} + +.com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-cs2 + .com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-commitColumn + .com-google-gerrit-client-change-CommitBox_BinderImpl_GenCss_style-header td { + border-bottom: 1px solid #eef3f5; + padding: 2px 4px 2px 6px; +} + +.com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-cs2 + .com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-commitColumn + .com-google-gerrit-client-change-CommitBox_BinderImpl_GenCss_style-header td:last-child { + border-right: 1px solid #eef3f5; +} + +/* increase the middle info column to fill empty space (for wide +monitors), but ensure there is a sufficient lower bound to kick in +horiz scroll bar. This will relieve the preasure on the hideci test +results. */ +.com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-infoColumn { + width: 100% !important; + min-width: 400px; +} + +/* Review history */ +.com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-cs2 + .com-google-gerrit-client-change-Message_BinderImpl_GenCss_style-name { + font-weight: bold !important; +} +.com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-cs2 + .com-google-gerrit-client-change-Message_BinderImpl_GenCss_style-messageBox { + width: inherit; + max-width: 1168px; +} + +.comment_test_name { + display: inline-block; + *display: inline; + *zoom: 1; + width: auto !important; + width: 25em; + min-width: 20em; + padding-bottom: 2pt; +} + +.comment_test_result { +} + +.result_SUCCESS { + color: #007f00; +} +.result_FAILURE, .result_POST_FAILURE, .result_TIMED_OUT, .result_RETRY_LIMIT, .result_DISK_FULL { + color: #cf2f19; +} +.result_UNSTABLE, .result_WARNING { + color: #e39f00; +} +.result_LOST { + color: #e39f00; +} +li.comment_test {list-style-type: none; } + +/* this is for support of 'Display Person Name In Review Category' */ +.cAPPROVAL { + max-width: 100px; + overflow: hidden; +} +/* fixes to make this like old gerrit */ +.changeTable td.dataCell { + height: 1em; +} + +/* don't make the non voting stand out more than the voting */ +table.infoTable td.notVotable, +.changeTable td.dataCell.labelNotApplicable { + background: inherit; +} + +.test_result_table { + border-collapse: collapse; +} + +.test_result_table tr { + border-left: 1px solid #eef3f5; + border-right: 1px solid #eef3f5; +} + +.test_result_table td.header { + background-color: #eef3f5; +} + +.test_result_table td { + padding: 2px 4px 2px 6px; + border: 1px solid #eef3f5; +} + +.addMemberTextBox { + width: 20em; +} + +/* css attribute selector to make -1s show up red in new screen */ +[title="Doesn't seem to work"], +[title="This patch needs further work before it can be merged"] { + color: red; +} diff --git a/playbooks/roles/gerrit/files/etc/GerritSiteHeader.html b/playbooks/roles/gerrit/files/etc/GerritSiteHeader.html new file mode 100644 index 0000000000..0e2f060fa8 --- /dev/null +++ b/playbooks/roles/gerrit/files/etc/GerritSiteHeader.html @@ -0,0 +1,6 @@ +<div id="openstack-logo"> + <script type="text/javascript" src="static/jquery.js" /> + <script type="text/javascript" src="static/jquery-visibility.js"></script> + <script type="text/javascript" src="static/hideci.js" /> + <a href="/"><h1><img src="static/title.svg" style="vertical-align:middle;" /></h1></a> +</div> diff --git a/playbooks/roles/gerrit/files/gerrit-podman/docker-compose.yaml b/playbooks/roles/gerrit/files/gerrit-podman/docker-compose.yaml new file mode 100644 index 0000000000..3ec71e443e --- /dev/null +++ b/playbooks/roles/gerrit/files/gerrit-podman/docker-compose.yaml @@ -0,0 +1,16 @@ +version: '3' + +services: + gerrit: + image: docker.io/opendevorg/gerrit:2.13 + network_mode: host + user: gerrit + volumes: + - /home/gerrit2/review_site/cache:/var/gerrit/cache + - /home/gerrit2/review_site/etc:/var/gerrit/etc + - /home/gerrit2/review_site/git:/var/gerrit/git + - /home/gerrit2/review_site/tmp:/var/gerrit/tmp + - /home/gerrit2/review_site/hooks:/var/gerrit/hooks + - /home/gerrit2/review_site/index:/var/gerrit/index + - /home/gerrit2/review_site/logs:/var/log/gerrit + - /home/gerrit2/review_site/static:/var/gerrit/static diff --git a/playbooks/roles/gerrit/files/hooks/change-abandoned b/playbooks/roles/gerrit/files/hooks/change-abandoned new file mode 100755 index 0000000000..5761951eca --- /dev/null +++ b/playbooks/roles/gerrit/files/hooks/change-abandoned @@ -0,0 +1,4 @@ +#!/bin/sh + +# Use timeout to kill any process running longer than 10 minutes. +timeout -k 2m 10m /usr/local/bin/update-bug change-abandoned "$@" diff --git a/playbooks/roles/gerrit/files/hooks/change-merged b/playbooks/roles/gerrit/files/hooks/change-merged new file mode 100755 index 0000000000..a35424f302 --- /dev/null +++ b/playbooks/roles/gerrit/files/hooks/change-merged @@ -0,0 +1,4 @@ +#!/bin/sh + +# Use timeout to kill any process running longer than 10 minutes. +timeout -k 2m 10m /usr/local/bin/update-bug change-merged "$@" diff --git a/playbooks/roles/gerrit/files/robots.txt b/playbooks/roles/gerrit/files/robots.txt new file mode 100644 index 0000000000..05cf74abae --- /dev/null +++ b/playbooks/roles/gerrit/files/robots.txt @@ -0,0 +1,11 @@ +# Directions for web crawlers. +# See http://www.robotstxt.org/wc/norobots.html. + +User-agent: HTTrack +User-agent: puf +User-agent: MSIECrawler +User-agent: Nutch +Disallow: / + +User-agent: msnbot +Crawl-delay: 1 diff --git a/playbooks/roles/gerrit/files/static/hideci.js b/playbooks/roles/gerrit/files/static/hideci.js new file mode 100644 index 0000000000..012b2c9512 --- /dev/null +++ b/playbooks/roles/gerrit/files/static/hideci.js @@ -0,0 +1,575 @@ +// Copyright (c) 2014 VMware, Inc. +// Copyright (c) 2014 Hewlett-Packard Development Company, L.P. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +// this regex matches the hash part of review pages +var hashRegex = /^\#\/c\/([\d]+)((\/\d+)([.][.](\d+))?)?\/?$/; +// this regex matches CI comments +var ciRegex = /^(.* CI|Jenkins|Zuul)$/; +// this regex matches "Patch set #" +var psRegex = /^(Uploaded patch set|Patch Set) (\d+)(:|\.)/; +// this regex matches merge failure messages +var mergeFailedRegex = /Merge Failed\./; +// this regex matches the name of CI systems we trust to report merge failures +var trustedCIRegex = /^(OpenStack CI|Jenkins|Zuul)$/; +// this regex matches the name+pipeline that we want at the top of the CI list +var firstPartyCI = /^(Jenkins|Zuul)/; +// this regex matches the pipeline markup +var pipelineNameRegex = /Build \w+ \(([-\w]+) pipeline\)/; +// The url to full status information on running jobs +var zuulStatusURL = 'https://zuul.openstack.org'; +// The json URL to check for running jobs +var zuulStatusJSON = 'https://zuul.openstack.org/status/change/'; + +// This is a variable to determine if we're in debugging mode, which +// lets you globally set it to see what's going on in the flow. +var hideci_debug = false; +// This is a variable to enable zuul integration, we default it off so +// that it creates no additional load, and that it's easy to turn off +// the feature. +var zuul_inline = false; + +/** + dbg(...) - prints a list of items out to the javascript + console.log. This allows us to leave tracing in this file which is a + no-op by default, but can be triggered if you enter a javascript + console and set hideci_debug = true. +*/ +function dbg () { + if (hideci_debug == true) { + for (var i = 0; i < arguments.length; i++) { + console.log(arguments[i]); + } + } +} + + +function format_time(ms, words) { + if (ms == null) { + return "unknown"; + } + var seconds = (+ms)/1000; + var minutes = Math.floor(seconds/60); + var hours = Math.floor(minutes/60); + seconds = Math.floor(seconds % 60); + minutes = Math.floor(minutes % 60); + r = ''; + if (words) { + if (hours) { + r += hours; + r += ' hr '; + } + r += minutes + ' min'; + } else { + if (hours < 10) r += '0'; + r += hours + ':'; + if (minutes < 10) r += '0'; + r += minutes + ':'; + if (seconds < 10) r += '0'; + r += seconds; + } + return r; +} + +var ci_parse_psnum = function($panel) { + var match = psRegex.exec($panel.html()); + if (match !== null) { + return parseInt(match[2]); + } + return 0; +}; + +var ci_parse_is_merge_conflict = function($panel) { + return (mergeFailedRegex.exec($panel.html()) !== null); +}; + +var ci_find_pipeline = function($panel) { + var match = pipelineNameRegex.exec($panel.html()); + if (match !== null) { + return match[1]; + } else { + return null; + } +}; + +var ci_parse_results = function($panel) { + var result_list = []; + var test_results = $panel.find("li.comment_test"); + var pipeline = null; + if (test_results !== null) { + test_results.each(function(i, li) { + var result = {}; + if ($(li).find("a").length > 0) { + result["name"] = $(li).find("span.comment_test_name").find("a")[0].innerHTML; + result["link"] = $(li).find("span.comment_test_name").find("a")[0]; + } + else { + result["name"] = $(li).find("span.comment_test_name")[0].innerHTML; + } + result["result"] = $(li).find("span.comment_test_result")[0]; + result_list.push(result); + }); + } + return result_list; +}; + +/*** + * function ci_group_by_ci_pipeline - create a group by structure for + * iterating on CI's pipelines + * + * This function takes the full list of comments, the current patch + * number, and builds an array of (ci_name_pipelinename, comments array) + * tuples. That makes it very easy to process during the display + * phase to ensure we only display the latest result for every CI + * pipeline. + * + * Comments that do not have a parsable pipeline (3rd party ci + * systems) get collapsed by name, and we specify 'check' for their + * pipeline. + * + **/ + +var ci_group_by_ci_pipeline = function(current, comments) { + var ci_pipelines = []; + var ci_pipeline_comments = []; + for (var i = 0; i < comments.length; i++) { + var comment = comments[i]; + if ((comment.psnum != current) || !comment.is_ci || (comment.results.length == 0)) { + continue; + } + var name_pipeline = comment.name; + if (comment.pipeline !== null) { + name_pipeline += ' ' + comment.pipeline; + } + + var index = ci_pipelines.indexOf(name_pipeline); + if (index == -1) { + // not found, so create new entries + ci_pipelines.push(name_pipeline); + ci_pipeline_comments.push([comment]); + } else { + ci_pipeline_comments[index].push(comment); + } + } + + function sort_by_name(a,b) { + if (a[0] < b[0]) + return -1; + else if (a[0] > b[0]) + return 1; + else + return 0; + } + + var results = []; + var notfirstparty = []; + // we want to separate out first party CI results to always be the + // top of the list, and third party CI to come after, so that + // hunting for first party CI isn't tough. + for (i = 0; i < ci_pipelines.length; i++) { + if (firstPartyCI.test(ci_pipelines[i])) { + results.push([ci_pipelines[i], ci_pipeline_comments[i]]); + } else { + notfirstparty.push([ci_pipelines[i], ci_pipeline_comments[i]]); + } + } + + notfirstparty.sort(sort_by_name); + + for (i = 0; i < notfirstparty.length; i++) { + results.push(notfirstparty[i]); + } + return results; +}; + +var ci_parse_comments = function() { + var comments = []; + $("p").each(function() { + var match = psRegex.exec($(this).html()); + if (match !== null) { + var psnum = parseInt(match[2]); + var top = $(this).parent().parent().parent(); + // old change screen + var name = top.attr("name"); + if (!name) { + // new change screen + name = $(this).parent().parent().parent().children().children()[0].innerHTML; + top = $(this).parent().parent().parent().parent(); + } + var comment = {}; + comment.name = name; + + var date_cell = top.find(".commentPanelDateCell"); + if (date_cell.attr("title")) { + // old change screen + comment.date = date_cell.attr("title"); + } else { + // new change screen + comment.date = $(this).parent().parent().parent().children().children()[2].innerHTML + } + var comment_panel = $(this).parent(); + comment.psnum = psnum; + comment.merge_conflict = ci_parse_is_merge_conflict(comment_panel); + comment.pipeline = ci_find_pipeline(comment_panel); + comment.results = ci_parse_results(comment_panel); + comment.is_ci = (ciRegex.exec(comment.name) !== null); + comment.is_trusted_ci = (trustedCIRegex.exec(comment.name) !== null); + comment.ref = top; + dbg("Found comment", comment); + comments.push(comment); + } + }); + return comments; +}; + +var ci_latest_patchset = function(comments) { + var psnum = 0; + for (var i = 0; i < comments.length; i++) { + psnum = Math.max(psnum, comments[i].psnum); + } + return psnum; +}; + +var ci_is_merge_conflict = function(comments) { + var latest = ci_latest_patchset(comments); + var conflict = false; + for (var i = 0; i < comments.length; i++) { + var comment = comments[i]; + // only if we are actually talking about the latest patch set + if (comment.psnum == latest) { + if (comment.is_trusted_ci) { + conflict = comment.merge_conflict; + } + } + } + return conflict; +}; + +var ci_prepare_results_table = function() { + // Create a table and insert it after the approval table + var table = $("table.test_result_table")[0]; + if (!table) { + table = document.createElement("table"); + $(table).addClass("test_result_table"); + $(table).addClass("infoTable").css({"margin-top":"1em", "margin-bottom":"1em"}); + + var approval_table = $("div.approvalTable"); + if (approval_table.length) { + var outer_table = document.createElement("table"); + $(outer_table).insertBefore(approval_table); + var outer_table_row = document.createElement("tr"); + $(outer_table).append(outer_table_row); + var td = document.createElement("td"); + $(outer_table_row).append(td); + $(td).css({"vertical-align":"top"}); + $(td).append(approval_table); + td = document.createElement("td"); + $(outer_table_row).append(td); + $(td).css({"vertical-align":"top"}); + $(td).append(table); + } else { + var big_table_row = $("div.screen>div>div>table>tbody>tr"); + var td = $(big_table_row).children()[1]; + $(td).append(table); + } + } else { + $(table).empty(); + } + return table; +}; + +var ci_display_results = function(comments) { + var table = ci_prepare_results_table(); + if (ci_is_merge_conflict(comments)) { + var mc_header = $("<tr>").append($('<td class="merge_conflict" colpsan="2">Patch in Merge Conflict</td>')); + mc_header.css('width', '400'); + mc_header.css('font-weight', 'bold'); + mc_header.css('color', 'red'); + mc_header.css('padding-left', '2em'); + $(table).append(mc_header); + + return; + } + var current = ci_latest_patchset(comments); + var ci_pipelines = ci_group_by_ci_pipeline(current, comments); + for (var i = 0; i < ci_pipelines.length; i++) { + var ci_pipeline_name = ci_pipelines[i][0]; + var ci_pipeline_comments = ci_pipelines[i][1]; + // the most recent comment on a pipeline + var last = ci_pipeline_comments.length - 1; + var comment = ci_pipeline_comments[last]; + var rechecks = ""; + if (last > 0) { + rechecks = " (" + last + " rechecks)"; + } + + var header = $("<tr>").append($('<td class="header">' + ci_pipeline_name + rechecks + '</td>')); + header.append('<td class="header ci_date">' + comment.date + '</td>'); + $(table).append(header); + for (var j = 0; j < comment.results.length; j++) { + var result = comment.results[j]; + var tr = $("<tr>"); + if ("link" in result) { + tr.append($("<td>").append($(result["link"]).clone())); + } + else { + tr.append($("<td>").text(result["name"])); + } + tr.append($("<td>").append($(result["result"]).clone())); + $(table).append(tr); + } + } +}; + +var set_cookie = function (name, value) { + document.cookie = name + "=" + value + "; path=/"; +}; + +var read_cookie = function (name) { + var nameEQ = name + "="; + var ca = document.cookie.split(';'); + for (var i = 0; i < ca.length; i++) { + var c = ca[i]; + while (c.charAt(0) == ' ') { + c = c.substring(1, c.length); + } + if (c.indexOf(nameEQ) == 0) { + return c.substring(nameEQ.length, c.length); + } + } + return null; +}; + +var ci_toggle_visibility = function(comments, showOrHide) { + if (!comments) { + comments = ci_parse_comments(); + } + $.each(comments, function(i, comment) { + if (comment.is_ci && !comment.is_trusted_ci) { + $(comment.ref).toggle(showOrHide); + } + }); +}; + +var ci_hide_ci_comments = function(comments) { + if (!comments) { + comments = ci_parse_comments(); + } + $.each(comments, function(i, comment) { + if (comment.is_ci && !comment.is_trusted_ci) { + $(comment.ref).hide(); + } + }); +}; + +var ci_page_loaded = function() { + if (hashRegex.test(window.location.hash)) { + dbg("Searching for ci results on " + window.location.hash); + $("#toggleci").show(); + var comments = ci_parse_comments(); + ci_display_results(comments); + var showOrHide = 'true' == read_cookie('show-ci-comments'); + if (!showOrHide) { + ci_hide_ci_comments(comments); + } + if (zuul_inline === true) { + ci_zuul_for_change(comments); + } + } else { + $("#toggleci").hide(); + } +}; + +var ci_current_change = function() { + var change = hashRegex.exec(window.location.hash); + if (change.length > 1) { + return change[1]; + } + return null; +}; + +// recursively find the zuul status change, will be much more +// efficient once zuul supports since json status. +var ci_find_zuul_status = function (data, change_psnum) { + var objects = []; + for (var i in data) { + if (!data.hasOwnProperty(i)) continue; + if (typeof data[i] == 'object') { + objects = objects.concat(ci_find_zuul_status(data[i], + change_psnum)); + } else if (i == 'id' && data.id == change_psnum) { + objects.push(data); + } + } + return objects; +}; + +var ci_zuul_all_status = function(jobs) { + var status = "passing"; + for (var i = 0; i < jobs.length; i++) { + if (jobs[i].result && jobs[i].result != "SUCCESS") { + status = "failing"; + break; + } + } + return status; +}; + +var ci_zuul_display_status = function(status) { + var zuul_table = $("table.zuul_result_table")[0]; + if (!zuul_table) { + var test_results = $("table.test_result_table")[0]; + zuul_table = document.createElement("table"); + $(zuul_table).addClass("zuul_result_table"); + $(zuul_table).addClass("infoTable").css({"margin-bottom":"1em"}); + if (test_results) { + $(test_results).prepend(zuul_table); + } + } + $(zuul_table).empty(); + $(zuul_table).show(); + $(zuul_table).append("<tr><td class='header'>Change currently being tested (<a href='" + zuulStatusURL + "'>full status</a>)</td></tr>"); + for (var i = 0; i < status.length; i++) { + var item = status[i]; + var pipeline = item.jobs[0].pipeline; + var passing = (item.failing_reasons && item.failing_reasons.length > 0) ? "failing" : "passing"; + var timeleft = item.remaining_time; + var row = "<tr><td>"; + if (pipeline != null) { + row += pipeline + " pipeline: " + passing; + row += " (" + format_time(timeleft, false) + " left)"; + } else { + row += "in between pipelines, status should update shortly"; + } + row += "</td></tr>"; + + $(zuul_table).append(row); + } +}; + +var ci_zuul_clear_status = function () { + var zuul_table = $("table.zuul_result_table")[0]; + if (zuul_table) { + $(zuul_table).hide(); + } +}; + +var ci_zuul_process_changes = function(data, change_psnum) { + var zuul_status = ci_find_zuul_status(data, change_psnum); + if (zuul_status.length) { + ci_zuul_display_status(zuul_status); + } else { + ci_zuul_clear_status(); + } +}; + +var ci_zuul_for_change = function(comments) { + if (!comments) { + comments = ci_parse_comments(); + } + var change = ci_current_change(); + var psnum = ci_latest_patchset(comments); + var change_psnum = change + "," + psnum; + + // do the loop recursively in ajax + (function poll() { + $.ajax({ + url: zuulStatusJSON + change_psnum, + type: "GET", + success: function(data) { + dbg("Found zuul data for " + change_psnum, data); + ci_zuul_process_changes(data, change_psnum); + }, + dataType: "json", + complete: setTimeout(function() { + // once we are done with this cycle in the loop we + // schedule ourselves again in the future with + // setTimeout. However, by the time the function + // actually gets called, other things might have + // happened, and we may want to just dump the data + // instead. + // + // the UI might have gone hidden (user was bored, + // switched to another tab / window). + // + // the user may have navigated to another review url, + // so the data returned is not relevant. + // + // both cases are recoverable when the user navigates + // around, because a new "thread" gets started on + // ci_page_load. + // + // BUG(sdague): there is the possibility that the user + // navigates away from a page and back fast enough + // that the first "thread" is not dead, and a second + // one is started. greghaynes totally said he'd come + // up with a way to fix that. + if (window.zuul_enable_status_updates == false) { + return; + } + var current = ci_current_change(); + if (current && change_psnum.indexOf(current) != 0) { + // window url is dead, so don't schedule any more future + // updates for this url. + return; + } + poll(); + }, 15000), + timeout: 5000 + }); + })(); +}; + + +window.onload = function() { + var input = document.createElement("input"); + input.id = "toggleci"; + input.type = "button"; + input.className = "gwt-Button"; + input.value = "Toggle Extra CI"; + input.onclick = function () { + // Flip the cookie + var showOrHide = 'true' == read_cookie('show-ci-comments'); + set_cookie('show-ci-comments', showOrHide ? 'false' : 'true'); + // Hide or Show existing comments based on cookie + ci_toggle_visibility(null, !showOrHide); + }; + document.body.appendChild(input); + + MutationObserver = window.MutationObserver || window.WebKitMutationObserver; + var observer = new MutationObserver(function(mutations, observer) { + var span = $("span.rpcStatus"); + $.each(mutations, function(i, mutation) { + if (mutation.target === span[0] && + mutation.attributeName === "style" && + (!(span.is(":visible")))) { + ci_page_loaded(); + } + }); + }); + observer.observe(document, { + subtree: true, + attributes: true + }); + + $(document).on({ + 'show.visibility': function() { + window.zuul_enable_status_updates = true; + ci_page_loaded(); + }, + 'hide.visibility': function() { + window.zuul_enable_status_updates = false; + } + }); +}; diff --git a/playbooks/roles/gerrit/files/static/system-cla.html b/playbooks/roles/gerrit/files/static/system-cla.html new file mode 100644 index 0000000000..e970a56a77 --- /dev/null +++ b/playbooks/roles/gerrit/files/static/system-cla.html @@ -0,0 +1,14 @@ +<html><body><div> + +<h1> +Gerrit System Role Accounts Proxy CLA +</h1> + +<p> +This is not a real CLA and cannot be signed. See <a +href="https://docs.openstack.org/infra/manual/developers.html#account-setup">the +account setup instructions</a> for more information on OpenStack Contributor +License Agreements. +</p> + +</div></body></html> diff --git a/playbooks/roles/gerrit/files/static/usg-cla.html b/playbooks/roles/gerrit/files/static/usg-cla.html new file mode 100644 index 0000000000..832fe152c9 --- /dev/null +++ b/playbooks/roles/gerrit/files/static/usg-cla.html @@ -0,0 +1,16 @@ +<html><body><div> + +<h1> +OpenStack Project U.S. Government Contributor License Agreement +</h1> + +<p> +This agreement is not managed through Gerrit. If you need to sign the U.S. +Government Contributor License Agreement, please contact the OpenStack +Foundation to initiate the process. See <a +href="https://docs.openstack.org/infra/manual/developers.html#account-setup">the +account setup instructions</a> for more information on OpenStack Contributor +License Agreements. +</p> + +</div></body></html> diff --git a/playbooks/roles/gerrit/tasks/main.yaml b/playbooks/roles/gerrit/tasks/main.yaml new file mode 100644 index 0000000000..b8614d2f00 --- /dev/null +++ b/playbooks/roles/gerrit/tasks/main.yaml @@ -0,0 +1,170 @@ +# TODO(mordred) We should do *something* where this could use a zuul cloned +# copy of project-config instead. This is needed not just for things like +# manage-projects (which could be run completely differently and non-locally) +# but also for things like notify-impact, which is currently run by a gerrit +# hook inside of the container via jeepyb. +- name: Clone project-config repo + git: + repo: https://opendev.org/openstack/project-config + dest: /opt/project-config + force: yes + +- name: Synchronize podman-compose directory + synchronize: + src: gerrit-podman/ + dest: /etc/gerrit-podman/ + +- name: Create Gerrit Group + group: + name: "{{ gerrit_user_name }}" + gid: "{{ gerrit_id }}" + system: yes + +- name: Create Gerrit User + user: + name: "{{ gerrit_user_name }}" + uid: "{{ gerrit_id }}" + comment: Gerit User + shell: /bin/bash + home: "{{ gerrit_home_dir }}" + group: "{{ gerrit_user_name }}" + create_home: yes + system: yes + +- name: Ensure review_site directory exists + file: + state: directory + path: "{{ gerrit_site_dir }}" + owner: "{{ gerrit_user_name }}" + group: "{{ gerrit_user_name }}" + mode: 0755 + +- name: Ensure Gerrit volume directories exists + file: + state: directory + path: "{{ gerrit_site_dir }}/{{ item }}" + owner: "{{ gerrit_user_name }}" + group: "{{ gerrit_user_name }}" + mode: 0755 + loop: + - etc + - git + - index + - cache + - static + - hooks + - tmp + - logs + +- name: Write Gerrit config file + template: + src: gerrit.config + dest: "{{ gerrit_site_dir }}/etc/gerrit.config" + owner: "{{ gerrit_user_name }}" + group: "{{ gerrit_user_name }}" + mode: 0644 + +- name: Write Gerrit SSH private key + copy: + content: "{{ gerrit_ssh_rsa_key_contents }}" + dest: "{{ gerrit_site_dir }}/etc/ssh_host_rsa_key" + owner: "{{ gerrit_user_name }}" + group: "{{ gerrit_user_name }}" + mode: 0600 + +- name: Write Gerrit SSH public key + copy: + content: "{{ gerrit_ssh_rsa_pubkey_contents }}" + dest: "{{ gerrit_site_dir }}/etc/ssh_host_rsa_key.pub" + owner: "{{ gerrit_user_name }}" + group: "{{ gerrit_user_name }}" + mode: 0644 + +- name: Write Welcome SSH private key + copy: + content: "{{ welcome_message_gerrit_ssh_private_key }}" + dest: "{{ gerrit_site_dir }}/etc/ssh_welcome_rsa_key" + owner: "{{ gerrit_user_name }}" + group: "{{ gerrit_user_name }}" + mode: 0600 + when: welcome_message_gerrit_ssh_private_key is defined + +- name: Write Welcome SSH public key + copy: + content: "{{ welcome_message_gerrit_ssh_public_key }}" + dest: "{{ gerrit_site_dir }}/etc/ssh_welcome_rsa_key.pub" + owner: "{{ gerrit_user_name }}" + group: "{{ gerrit_user_name }}" + mode: 0644 + when: welcome_message_gerrit_ssh_public_key is defined + +- name: Copy static hooks + copy: + src: "hooks/{{ item }}" + dest: "{{ gerrit_site_dir }}/hooks/{{ item }}" + owner: "{{ gerrit_user_name }}" + group: "{{ gerrit_user_name }}" + mode: 0555 + loop: + - change-merged + - change-abandoned + +- name: Copy notify-impact yaml file + copy: + src: "/opt/project-config/gerrit/notify_impact.yaml" + dest: "{{ gerrit_site_dir }}/hooks/notify_impact.yaml" + remote_src: yes + owner: "{{ gerrit_user_name }}" + group: "{{ gerrit_user_name }}" + mode: 0444 + +- name: Install patchset-created hook + template: + src: patchset-created.j2 + dest: "{{ gerrit_site_dir }}/hooks/patchset-created" + owner: "{{ gerrit_user_name }}" + group: "{{ gerrit_user_name }}" + mode: 0555 + +# TODO(mordred) These things should really go into the image instead. +- name: Copy static and etc + copy: + src: "{{ item }}" + dest: "{{ gerrit_site_dir }}/{{ item }}" + owner: "{{ gerrit_user_name }}" + group: "{{ gerrit_user_name }}" + mode: preserve + loop: + - static + - etc + +- name: Install podman-compose + pip: + name: podman-compose + state: latest + # NOTE(mordred) Cannot use full path to pip3 here because it is + # different on zuul test nodes and in production. This is, of + # course, not stellar. + executable: pip3 + +# TODO(mordred) Make this suck less, like if we could do an init container +# or something just generally less gross. +- name: Run gerrit init + when: gerrit_run_init | bool + command: > + podman run -it --rm --net=host -u gerrit + -v /home/gerrit2/review_site/cache:/var/gerrit/cache + -v /home/gerrit2/review_site/etc:/var/gerrit/etc + -v /home/gerrit2/review_site/git:/var/gerrit/git + -v /home/gerrit2/review_site/tmp:/var/gerrit/tmp + -v /home/gerrit2/review_site/hooks:/var/gerrit/hooks + -v /home/gerrit2/review_site/index:/var/gerrit/index + -v /home/gerrit2/review_site/logs:/var/log/gerrit + -v /home/gerrit2/review_site/static:/var/gerrit/static + docker.io/opendevorg/gerrit:2.13 + /usr/local/openjdk-8/bin/java -jar /var/gerrit/bin/gerrit.war init -d /var/gerrit -b --no-auto-start --install-all-plugins + +- name: Run podman-compose up + shell: + cmd: podman-compose up -d + chdir: /etc/gerrit-podman/ diff --git a/playbooks/roles/gerrit/templates/gerrit.config b/playbooks/roles/gerrit/templates/gerrit.config new file mode 100644 index 0000000000..5f6c82f2d7 --- /dev/null +++ b/playbooks/roles/gerrit/templates/gerrit.config @@ -0,0 +1,180 @@ +# This file is managed by ansible. +# https://opendev.org/opendev/system-config + +[gerrit] + basePath = git + canonicalWebUrl = https://review.opendev.org/ + changeScreen = OLD_UI + reportBugText = Get Help + reportBugUrl = https://docs.openstack.org/infra/system-config/project.html#contributing + gitHttpUrl = https://review.opendev.org/ +{{ gerrit_database_config_section }} +[auth] + contributorAgreements = true + type = OPENID_SSO + cookieSecure = true + enableRunAs = true + openIdSsoUrl = https://login.ubuntu.com/+openid + +[sendemail] + smtpServer = localhost + from = MIXED + includeDiff = false +[container] + user = gerrit2 + startupTimeout = 300 + heapLimit = 48g +[gc] +[core] + packedGitOpenFiles = 4096 + packedGitLimit = 400m + packedGitWindowSize = 16k +[sshd] + listenAddress = *:29418 + threads = 100 + maxConnectionsPerUser = 96 +[httpd] + listenUrl = proxy-https://*:8081/ + minThreads = 20 + maxThreads = 100 + maxQueued = 200 +[cache] + directory = cache +[cache "web_sessions"] + maxAge = 7days +[cache "accounts"] + memoryLimit = 32768 +[cache "accounts_byemail"] + memoryLimit = 32768 +[cache "accounts_byname"] + memoryLimit = 32768 +[cache "groups_byuuid"] + memoryLimit = 32768 +[user] + email = review@openstack.org +[change] + allowDrafts = false +[receive] + maxObjectSizeLimit = 100 m +[commentlink "bugheader"] + match = "([Cc]loses|[Pp]artial|[Rr]elated)-[Bb]ug:\\s*#?(\\d+)" + link = "https://launchpad.net/bugs/$2" + html = "" +[commentlink "bug"] + match = "\\b[Bb]ug:? #?(\\d+)" + link = "https://launchpad.net/bugs/$1" + html = "" +[commentlink "story"] + match = "\\b[Ss]tory:? #?(\\d+)" + link = "https://storyboard.openstack.org/#!/story/$1" + html = "" +[commentlink "task"] + match = "\\b[Tt]ask:? #?(\\d+)" + link = "https://storyboard.openstack.org/#!/task/$1" + html = "" +[commentlink "its-storyboard"] + match = "\\b[Tt]ask:? #?(\\d+)" + link = "task: $1" + html = "" +[commentlink "blueprint"] + match = "(\\b[Bb]lue[Pp]rint\\b|\\b[Bb][Pp]\\b)[ \\t#:]*([A-Za-z0-9\\-]+)" + link = "https://blueprints.launchpad.net/openstack/?searchtext=$2" + html = "" +[commentlink "testresult"] + match = "<li>([^ ]+) <a href=\"[^\"]+\" target=\"_blank\" rel=\"nofollow\">([^<]+)</a> : ([^ ]+)([^<]*)</li>" + link = "" + html = "<li class=\"comment_test\"><span class=\"comment_test_name\"><a href=\"$2\" rel=\"nofollow\">$1</a></span> <span class=\"comment_test_result\"><span class=\"result_$3\">$3</span>$4</span></li>" +[commentlink "testresultnoop"] + match = "<li>noop noop : SUCCESS([^<]*)</li>" + link = "" + html = "<li class=\"comment_test\"><span class=\"comment_test_name\">noop</span> <span class=\"comment_test_result\"><span class=\"result_SUCCESS\">SUCCESS</span>$1</span></li>" +[commentlink "launchpadbug"] + match = "<a href=\"(https://bugs\\.launchpad\\.net/[a-zA-Z0-9\\-]+/\\+bug/(\\d+))[^\"]*\">[^<]+</a>" + link = "" + html = "<a href=\"$1\">$1</a>" +[commentlink "changeid"] + match = "(I[0-9a-f]{8,40})" + link = "/#/q/$1" + html = "" +[commentlink "gitsha"] + match = "(<p>|[\\s(])([0-9a-f]{40})(</p>|[\\s.,;:)])" + link = "" + html = "$1<a href=\"/#/q/$2\">$2</a>$3" +[its-storyboard] + url = https://storyboard.openstack.org +[trackingid "launchpad-bug"] + match = "\\#?(\\d+)" + footer = "closes-bug:" + footer = "partial-bug:" + footer = "related-bug:" + system = "Launchpad" +[trackingid "storyboard-story"] + match = "\\#?(\\d+)" + footer = "story:" + system = "Storyboard" +[trackingid "storyboard-task"] + match = "\\#?(\\d+)" + footer = "task:" + system = "Storyboard" +[theme] + backgroundColor = ffffff + topMenuColor = ffffff + textColor = 264d69 + trimColor = eef3f5 + selectionColor = d1e6ea + changeTableOutdatedColor = f5cccc + tableOddRowColor = ffffff + tableEvenRowColor = f5f5ff +[melody] + monitoring = true + session = true +[plugin "javamelody"] + allowTopMenu = false +# Gerrit upstream hardcodes a .git extension for cgit. +# The cgit settings below are the same just without the +# .git extension. +[gitweb] + type = gitweb + cgi = /usr/share/gitweb/gitweb.cgi + revision = "?p=${project}.git;a=commitdiff;h=${commit}" +[index] + type = LUCENE + threads = 4 +[download] + command = checkout + command = cherry_pick + command = pull + command = format_patch + scheme = ssh + scheme = anon_http + scheme = anon_git + archive = tar + archive = tbz2 + archive = tgz + archive = txz +[commitmessage] + maxLineLength = 72 +[groups] + newGroupsVisibleToAll = true +[mimetype "image/*"] + safe = true +[mimetype "text/x-yaml"] + safe = true +[mimetype "text/xml"] + safe = true +[mimetype "application/xml"] + safe = true +[mimetype "text/x-rst"] + safe = true +[mimetype "text/plain"] + safe = true +[mimetype "text/x-puppet"] + safe = true +[mimetype "text/x-ini"] + safe = true +[mimetype "text/x-properties"] + safe = true +[mimetype "text/x-markdown"] + safe = true +[mimetype "text/css"] + safe = true diff --git a/playbooks/roles/gerrit/templates/patchset-created.j2 b/playbooks/roles/gerrit/templates/patchset-created.j2 new file mode 100755 index 0000000000..59147b0810 --- /dev/null +++ b/playbooks/roles/gerrit/templates/patchset-created.j2 @@ -0,0 +1,11 @@ +#!/bin/sh + +# Use timeout to kill any process running longer than 10 minutes. +timeout -k 2m 10m /usr/local/bin/update-blueprint patchset-created "$@" +timeout -k 2m 10m /usr/local/bin/update-bug patchset-created "$@" +timeout -k 2m 10m /usr/local/bin/notify-impact patchset-created "$@" --impact SecurityImpact --dest-address 'openstack-security@lists.openstack.org' +{% if welcome_message_gerrit_ssh_private_key is defined %} +timeout -k 2m 10m /usr/local/bin/welcome-message patchset-created \ + --verbose --ssh-user=welcome-message \ + --ssh-key=/var/gerrit/etc/ssh_welcome_rsa_key "$@" +{% endif %} diff --git a/playbooks/roles/install-podman/README.rst b/playbooks/roles/install-podman/README.rst new file mode 100644 index 0000000000..7afdaaa052 --- /dev/null +++ b/playbooks/roles/install-podman/README.rst @@ -0,0 +1 @@ +An ansible role to install podman in the OpenDev production environment diff --git a/playbooks/roles/install-podman/defaults/main.yaml b/playbooks/roles/install-podman/defaults/main.yaml new file mode 100644 index 0000000000..b2555554ac --- /dev/null +++ b/playbooks/roles/install-podman/defaults/main.yaml @@ -0,0 +1,29 @@ +projectatomic_gpg_key: | + -----BEGIN PGP PUBLIC KEY BLOCK----- + + xsFNBFlRJjABEADuE3ZLY/2W++bPsxtcaoi7VaNnkvsXuVYbbHalEh/YwKFVsDTo + PQpuw1UlPpmVTwT3ufWfv2v42eZiiWMZaKG9/aWF/TeIdH5+3anfVi+X+tuIW9sv + GKTHZdtDqd7fIhtY6AuNQ/D629TJxLvafZ5MoGeyxjsebt5dOvOrl0SHpwR75uPP + aCXTWrokhH7W2BbJQUB+47k62BMd03EKe8stz9FzUxptROFJJ2bITijJlDXNfSbV + bwCiyREIkzXS6ZdWliJAqencOIZ4UbUax+5BT8SRbSLtr/c4YxvARilpSVCkxo8/ + EkPHBGygmgfw0kRPSGtLL7IqfWip9mFObji2geoU3A8gV/i3s9Ccc9GPKApX8r7b + QFs1tIlgUJKPqVwB2FAh+Xrqlsy/+8r95jL2gfRptSw7u8OP4AySj5WVm7cCEQ69 + aLyemCsf+v72bFOUXuYQ22Kr3yqz2O/1IsG/0Usr4riTdG65Aq6gnq4KRHMNgXu8 + 7fC9omoy3sKHvzeAJsw/eC9chYNwO8pv8KRIvpDSGL5L7Ems8mq2C5xMyzSVegTr + AvXu7nJoZWVBFRluh42bZa9QesX9MzzfOQ+G3085aW8BE++lhtX5QOkfRd74E49H + 1I2piAq/aE8P9jUHr60Po1C1Tw9iXeEaULLKut8eTMLkQ/02DXhBfq0I5QARAQAB + zSBMYXVuY2hwYWQgUFBBIGZvciBQcm9qZWN0IEF0b21pY8LBeAQTAQIAIgUCWVEm + MAIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQi+zxY3rYx50HLw/5Ad6k + EHf2uT4owvzu393S/bUR6VVwCWYMbg14XgphxnoOfrHZWUjbrETTURyd1UexoHt7 + ZDtMCVmzeY0jpvMb1W3WDebFVo+wR4CI15sPjyycsOxWTviD743wxaPCL1s009co + CzWg5AgP88B0D353Y39meC07BBgOJgIfk1OkFdeRjqHfAtucT99NrCuKr/bbBwDn + 0E+wWaJoIbQvBzsPIFzMWWQ6RcnrZtyQv35epo+VBmW3VEIkorv1VoStF0RjvJM+ + cMW/ogZsIEZk0IUREOtrtTKUXVrMw1hZ9IGYZRpbJ2g670UGuNjW/vo3rRCRSDaF + 6Txp5Pn6ZLTgQWsWMw/6M6ooFIEpz3rhYmQSJLNmUN6SgKeWGVmOrQlg4f7YM75o + UEw56GKQWl9FAthO0qH0qF1OMfUKp/Tv2OSV/FNZsokf6alWXOB6Bzj6gYmmGXIv + MfFW5fZ1cuu5/0ULDckxWhVQ1ywLHREEoBQ6oKYONwUjSdWcM+VsKCEFeCqsNwak + qweP8C0fooycfiEZuncc/9ZujgkQ2p7xXTlv3t2SPF9h43xHs3515VS/OTJPGW59 + 98AqllpfqGxggYs5cwi2LO3xwvHyPoTqj3hcl1dRMspZINRsIo4VC8bSrCOqbjDc + CD2WFOo2c4mwTDmJpz0PLK87ev/WZ8K0OEflTfc= + =DzDk + -----END PGP PUBLIC KEY BLOCK----- diff --git a/playbooks/roles/install-podman/tasks/main.yaml b/playbooks/roles/install-podman/tasks/main.yaml new file mode 100644 index 0000000000..8318382b4a --- /dev/null +++ b/playbooks/roles/install-podman/tasks/main.yaml @@ -0,0 +1,20 @@ +- name: Add PPA GPG key + become: yes + apt_key: + data: "{{ projectatomic_gpg_key }}" + +- name: Add projectatomic apt repo + become: yes + template: + dest: /etc/apt/sources.list.d/projectatomic.list + group: root + mode: 0644 + owner: root + src: sources.list.j2 + +- name: Install podman + become: yes + apt: + name: podman + state: present + update_cache: yes diff --git a/playbooks/roles/install-podman/templates/sources.list.j2 b/playbooks/roles/install-podman/templates/sources.list.j2 new file mode 100644 index 0000000000..cc249acda6 --- /dev/null +++ b/playbooks/roles/install-podman/templates/sources.list.j2 @@ -0,0 +1 @@ +deb http://ppa.launchpad.net/projectatomic/ppa/ubuntu {{ ansible_lsb.codename }} main diff --git a/playbooks/service-review-dev.yaml b/playbooks/service-review-dev.yaml new file mode 100644 index 0000000000..eb274834a8 --- /dev/null +++ b/playbooks/service-review-dev.yaml @@ -0,0 +1,9 @@ +- hosts: "review-dev01.openstack.org:!disabled" + name: "Configure gerrit on review-dev01.openstack.org" + roles: + - pip3 + - install-podman + - role: gerrit + gerrit_ssh_rsa_key_contents: "{{ gerrit_dev_ssh_rsa_key_contents }}" + gerrit_ssh_rsa_pubkey_contents: "{{ gerrit_dev_ssh_rsa_pubkey_contents }}" + gerrit_database_config_section: "{{ gerrit_dev_database_config_section }}" diff --git a/playbooks/zuul/run-base-post.yaml b/playbooks/zuul/run-base-post.yaml index 24f8b464df..57380ac970 100644 --- a/playbooks/zuul/run-base-post.yaml +++ b/playbooks/zuul/run-base-post.yaml @@ -16,19 +16,32 @@ - hosts: all tasks: - - name: List containers - command: "docker ps -a --format '{{ '{{ .Names }}' }}'" - register: docker_containers - ignore_errors: true - become: true - - name: Create container log dir file: path: "/var/log/docker" state: directory become: true - - name: Save container logs + - name: List podman containers + command: "podman ps -a --format '{{ '{{ .Names }}' }}'" + register: podman_containers + ignore_errors: true + become: true + + - name: Save podman container logs + loop: "{{ podman_containers.stdout_lines | default([]) }}" + shell: "podman logs {{ item }} &> /var/log/docker/{{ item }}.txt" + args: + executable: /bin/bash + become: true + + - name: List docker containers + command: "docker ps -a --format '{{ '{{ .Names }}' }}'" + register: docker_containers + ignore_errors: true + become: true + + - name: Save docker container logs loop: "{{ docker_containers.stdout_lines | default([]) }}" shell: "docker logs {{ item }} &> /var/log/docker/{{ item }}.txt" args: diff --git a/playbooks/zuul/run-base.yaml b/playbooks/zuul/run-base.yaml index fe42556df8..54158067a9 100644 --- a/playbooks/zuul/run-base.yaml +++ b/playbooks/zuul/run-base.yaml @@ -80,6 +80,8 @@ - group_vars/gitea-lb.yaml - group_vars/letsencrypt.yaml - group_vars/registry.yaml + - group_vars/review.yaml + - group_vars/review-dev.yaml - group_vars/control-plane-clouds.yaml - group_vars/mirror_opendev.yaml - host_vars/bridge.openstack.org.yaml diff --git a/playbooks/zuul/templates/group_vars/review-dev.yaml.j2 b/playbooks/zuul/templates/group_vars/review-dev.yaml.j2 new file mode 100644 index 0000000000..4b9a212adf --- /dev/null +++ b/playbooks/zuul/templates/group_vars/review-dev.yaml.j2 @@ -0,0 +1,34 @@ +gerrit_dev_ssh_rsa_key_contents: | + -----BEGIN RSA PRIVATE KEY----- + MIIEpQIBAAKCAQEAvqQkJUwEGJgqzmOmj2728ikA3Dgl4mzzRiI5zzzLhCLQktL7 + UZ6hAc+851mUuQ66vciqUToerhRdNWqNlZzY8On/jXUTVdfUVlXupmDfqmtlax9n + Gi8Aayj4h9F3P3iuNQ+eXWVOyFsCmAMPzaYgWgXx2rxcIqSPq5hG+vDB9oXIpg3a + /244vtIZId1/uNnZDb5jHbZLglupynQBIZ12h2XOUiUfxL84EQnwfL2zC9d6eOjv + cYaCYJ+2VrzG972keY8SJEMLLVEd+q2hFYbbQQxLlmrFpx2G6zNc3d6KLnW0xEH+ + b1yEmShcoB8iRRam+IkO+ovoQ5W9FUCmQnWqJQIDAQABAoIBAQCABKeFKDPD9EMi + j0ZlIUXRPfmm6EmAcFs46Hjbkl60H9DiF63OlHBYUBDxZnV5g8ug8CR3IUlC6sfg + u+nR4x7HQMtsSYcvaRzc0R3OOlVYEoBrXA4XRiLI0x15zw593+NUHGXjH8m0v3DR + dZTiK0GkUkOj+EMCvHEB8OMRViVaDjel+TXI6lM2UuexpYLag/u+GotDUQ8sjq4v + kT2FWzrZAGHih98oZ7AflinasGjMBr21lCRq/u3w0ieU4ZPmxpLxz9EUbWS06kQe + W2pafIhDq+4mVtDuhmb87yMMpda+TCBcCRCzA3MGDMGVzQgQvPe49R4EPRWzBWXU + vso8JSzBAoGBAPrDobXukDJ0j2zD3Cw7xCSJy3foU4sdQF5yxeIWox1gfsgkAhn2 + zxmuewdfdh0hZAnZWZ41sJzFrEhrvTV/wFIfIZ2qlMf3q3ZdG8c0CQ6E3blsAF8g + jExgck8mV2kvZItowS8JCdWvNw1zpwNJ8Ae+mMUSMBKbs5hzO8X0V1FxAoGBAMKf + JNjqN/LegvlnfFXMPM+vo39MX2RsukwmTZT6msMi3rNgN3oekXSpOK1Mkftrd/wL + B5Vp9Nl3d3kFu3bTKA+N8bjtokXfN+fF9zPFeLwOfEOEtQlnvzb/XF4LhSGiq7Kg + OP6/4udaa9cr9yLE7jTDoLTiyRP796k4ADGRo8n1AoGBAPad0XsAbPYCJk/ca7tg + 5+zbS6zYYtlM4lJA5BYPF0o77VPd/ecVEOZ772j33EyX2y/If1eWC+SSj3YF52Yn + Brh8/211Jq9nB0z4EuqdZU7PItRJwC/N7czriWAIIC1FO8fTNTKR3Ac4M5daJ2WX + oKWtL8eYtIiIcl867Q0o2XsxAoGAHtJrWHsHb0wz++GavE/DFbUgNInY1aOugV7T + jJN/rQW5tTi4sHtk18/w7OkieWnUr7LjeZM1NreH0T/KJ5BbWNNHA92GhIBMb0VX + 1/gfHdFBdsPuk9W9X61jaHV0mRYVEQ302Mt02OTmDUamNfhwLSUKL3t3EtYlq8P1 + q+P/x30CgYEAiLaGdCtlPy5e35ULD/Ep73kOB1uRVtF4JlVpqZ4CygVoCguSZ3Sd + pHMmNylg7j2NyL/9aLKs1NzdGBxpxVa5A4vgcr1DjoS1cuRVEiQoSkI6D6DCmENA + Pb95AevPUxqqAKNZYsj4yDsXnmbFSHARijPWcpfkCDJmVhMFPObr4OE= + -----END RSA PRIVATE KEY----- +gerrit_dev_ssh_rsa_pubkey_contents: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+pCQlTAQYmCrOY6aPbvbyKQDcOCXibPNGIjnPPMuEItCS0vtRnqEBz7znWZS5Drq9yKpROh6uFF01ao2VnNjw6f+NdRNV19RWVe6mYN+qa2VrH2caLwBrKPiH0Xc/eK41D55dZU7IWwKYAw/NpiBaBfHavFwipI+rmEb68MH2hcimDdr/bji+0hkh3X+42dkNvmMdtkuCW6nKdAEhnXaHZc5SJR/EvzgRCfB8vbML13p46O9xhoJgn7ZWvMb3vaR5jxIkQwstUR36raEVhttBDEuWasWnHYbrM1zd3ooudbTEQf5vXISZKFygHyJFFqb4iQ76i+hDlb0VQKZCdaol gerrit-code-review@829f141b0fa5 +gerrit_dev_database_config_section: | + [database] + type = h2 + database = tmp/ReviewDB +gerrit_run_init: true diff --git a/playbooks/zuul/templates/group_vars/review.yaml.j2 b/playbooks/zuul/templates/group_vars/review.yaml.j2 new file mode 100644 index 0000000000..0d742b678f --- /dev/null +++ b/playbooks/zuul/templates/group_vars/review.yaml.j2 @@ -0,0 +1,29 @@ +gerrit_ssh_rsa_key_contents: | + -----BEGIN RSA PRIVATE KEY----- + MIIEpQIBAAKCAQEAvqQkJUwEGJgqzmOmj2728ikA3Dgl4mzzRiI5zzzLhCLQktL7 + UZ6hAc+851mUuQ66vciqUToerhRdNWqNlZzY8On/jXUTVdfUVlXupmDfqmtlax9n + Gi8Aayj4h9F3P3iuNQ+eXWVOyFsCmAMPzaYgWgXx2rxcIqSPq5hG+vDB9oXIpg3a + /244vtIZId1/uNnZDb5jHbZLglupynQBIZ12h2XOUiUfxL84EQnwfL2zC9d6eOjv + cYaCYJ+2VrzG972keY8SJEMLLVEd+q2hFYbbQQxLlmrFpx2G6zNc3d6KLnW0xEH+ + b1yEmShcoB8iRRam+IkO+ovoQ5W9FUCmQnWqJQIDAQABAoIBAQCABKeFKDPD9EMi + j0ZlIUXRPfmm6EmAcFs46Hjbkl60H9DiF63OlHBYUBDxZnV5g8ug8CR3IUlC6sfg + u+nR4x7HQMtsSYcvaRzc0R3OOlVYEoBrXA4XRiLI0x15zw593+NUHGXjH8m0v3DR + dZTiK0GkUkOj+EMCvHEB8OMRViVaDjel+TXI6lM2UuexpYLag/u+GotDUQ8sjq4v + kT2FWzrZAGHih98oZ7AflinasGjMBr21lCRq/u3w0ieU4ZPmxpLxz9EUbWS06kQe + W2pafIhDq+4mVtDuhmb87yMMpda+TCBcCRCzA3MGDMGVzQgQvPe49R4EPRWzBWXU + vso8JSzBAoGBAPrDobXukDJ0j2zD3Cw7xCSJy3foU4sdQF5yxeIWox1gfsgkAhn2 + zxmuewdfdh0hZAnZWZ41sJzFrEhrvTV/wFIfIZ2qlMf3q3ZdG8c0CQ6E3blsAF8g + jExgck8mV2kvZItowS8JCdWvNw1zpwNJ8Ae+mMUSMBKbs5hzO8X0V1FxAoGBAMKf + JNjqN/LegvlnfFXMPM+vo39MX2RsukwmTZT6msMi3rNgN3oekXSpOK1Mkftrd/wL + B5Vp9Nl3d3kFu3bTKA+N8bjtokXfN+fF9zPFeLwOfEOEtQlnvzb/XF4LhSGiq7Kg + OP6/4udaa9cr9yLE7jTDoLTiyRP796k4ADGRo8n1AoGBAPad0XsAbPYCJk/ca7tg + 5+zbS6zYYtlM4lJA5BYPF0o77VPd/ecVEOZ772j33EyX2y/If1eWC+SSj3YF52Yn + Brh8/211Jq9nB0z4EuqdZU7PItRJwC/N7czriWAIIC1FO8fTNTKR3Ac4M5daJ2WX + oKWtL8eYtIiIcl867Q0o2XsxAoGAHtJrWHsHb0wz++GavE/DFbUgNInY1aOugV7T + jJN/rQW5tTi4sHtk18/w7OkieWnUr7LjeZM1NreH0T/KJ5BbWNNHA92GhIBMb0VX + 1/gfHdFBdsPuk9W9X61jaHV0mRYVEQ302Mt02OTmDUamNfhwLSUKL3t3EtYlq8P1 + q+P/x30CgYEAiLaGdCtlPy5e35ULD/Ep73kOB1uRVtF4JlVpqZ4CygVoCguSZ3Sd + pHMmNylg7j2NyL/9aLKs1NzdGBxpxVa5A4vgcr1DjoS1cuRVEiQoSkI6D6DCmENA + Pb95AevPUxqqAKNZYsj4yDsXnmbFSHARijPWcpfkCDJmVhMFPObr4OE= + -----END RSA PRIVATE KEY----- +gerrit_ssh_rsa_pubkey_contents: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+pCQlTAQYmCrOY6aPbvbyKQDcOCXibPNGIjnPPMuEItCS0vtRnqEBz7znWZS5Drq9yKpROh6uFF01ao2VnNjw6f+NdRNV19RWVe6mYN+qa2VrH2caLwBrKPiH0Xc/eK41D55dZU7IWwKYAw/NpiBaBfHavFwipI+rmEb68MH2hcimDdr/bji+0hkh3X+42dkNvmMdtkuCW6nKdAEhnXaHZc5SJR/EvzgRCfB8vbML13p46O9xhoJgn7ZWvMb3vaR5jxIkQwstUR36raEVhttBDEuWasWnHYbrM1zd3ooudbTEQf5vXISZKFygHyJFFqb4iQ76i+hDlb0VQKZCdaol gerrit-code-review@829f141b0fa5 diff --git a/testinfra/test_gerrit.py b/testinfra/test_gerrit.py new file mode 100644 index 0000000000..7fb3d1a1cf --- /dev/null +++ b/testinfra/test_gerrit.py @@ -0,0 +1,21 @@ +# Copyright 2018 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +testinfra_hosts = ['review-dev01.openstack.org'] + + +def test_gerrit_listening(host): + gerrit_web = host.socket("tcp://:::8081") + assert gerrit_web.is_listening