Page Menu
Home
DevCentral
Search
Configure Global Search
Log In
Files
F3768237
D2854.id7278.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
22 KB
Referenced Files
None
Subscribers
None
D2854.id7278.diff
View Options
diff --git a/UIDs b/UIDs
--- a/UIDs
+++ b/UIDs
@@ -7,4 +7,4 @@
3004 mediawiki
9001 salt
9002 deploy
-8900 zr
+8900 zr LEGACY
diff --git a/_modules/zr.py b/_modules/zr.py
deleted file mode 100644
--- a/_modules/zr.py
+++ /dev/null
@@ -1,166 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# -------------------------------------------------------------
-# Salt — Zemke-Rhyne module
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-# Project: Nasqueron
-# Created: 2018-09-11
-# Description: Fetch Zemke-Rhyne credentials
-# License: BSD-2-Clause
-# -------------------------------------------------------------
-
-
-import os
-
-from salt.utils.path import which as path_which
-
-
-def __virtual__():
- """
- Only load if zr exists on the system
- """
- return (
- path_which("zr") is not None,
- "The Zemke-Rhyne execution module cannot be loaded: zr not installed.",
- )
-
-
-def _are_credentials_hidden():
- return "CONFIG_PUBLISHER" in os.environ or "state.show_sls" in os.environ.get(
- "SUDO_COMMAND", ""
- )
-
-
-def _build_pillar_key(expression):
- return "zr_credentials:" + expression.replace(".", ":")
-
-
-def _get_credential_id_from_pillar_key(expression):
- """Gets credentials id from a dot pillar path, e.g. nasqueron.foo.bar"""
- key = _build_pillar_key(expression)
- return __salt__["pillar.get"](key)
-
-
-def get_credential_id(expression):
- try:
- # Case I - expression is an integer
- number = int(expression)
-
- if number < 1:
- raise ValueError(expression, "A strictly positive integer was expected.")
-
- return number
- except ValueError:
- # Case II - expression is a pillar key
- credential_id = _get_credential_id_from_pillar_key(expression)
-
- if credential_id is None or credential_id == "":
- raise ValueError(expression, "Pillar key not found")
-
- return credential_id
-
-
-def get_password(credential_expression):
- """
- A function to fetch credential through Zemke-Rhyne
-
-
- CLI Example:
-
- salt equatower zr.get_password 124
-
- :param credential_expression: The credential number (K...) in Phabricator
- or a key in zr_credentials pillar entry
- :return: The secret value
- """
- if _are_credentials_hidden():
- return "credential for " + credential_expression
-
- credential_id = get_credential_id(credential_expression)
-
- zr_command = "zr getcredentials {0}".format(credential_id)
- return __salt__["cmd.shell"](zr_command)
-
-
-def get_username(credential_expression):
- """
- A function to fetch the username associated to a credential
- through Zemke-Rhyne
-
- CLI Example:
-
- salt equatower zr.get_username 124
-
- :param credential_expression: The credential number (K...) in Phabricator
- or a key in zr_credentials pillar entry
-
- :return: The username
- """
- credential_id = get_credential_id(credential_expression)
-
- zr_command = "zr getcredentials {0} username".format(credential_id)
- return __salt__["cmd.shell"](zr_command)
-
-
-def get_token(credential_expression):
- """
- A function to fetch credential through Zemke-Rhyne
-
-
- CLI Example:
-
- salt equatower zr.get_token 126
-
- :param credential_expression: The credential number (K...) in Phabricator
- or a key in zr_credentials pillar entry
- :return: The secret value
- """
- if _are_credentials_hidden():
- return "credential for " + credential_expression
-
- credential_id = get_credential_id(credential_expression)
-
- zr_command = "zr getcredentials {0} token".format(credential_id)
- return __salt__["cmd.shell"](zr_command)
-
-
-def generate_random(secret_len):
- """
- A function to generate a random credential
- """
- if _are_credentials_hidden():
- return "random credential"
-
- return __salt__["random.get_str"](secret_len)
-
-
-def get_sentry_dsn(args):
- sentry_server = _get_sentry_server(args["realm"])
-
- if _are_credentials_hidden():
- return (
- "https://[…]@"
- + sentry_server
- + "/"
- + str(args["project_id"])
- + " with credential for "
- + args["credential"]
- )
-
- return (
- "https://"
- + ":".join(
- [
- get_username(args["credential"]),
- get_password(args["credential"]),
- ]
- )
- + "@"
- + sentry_server
- + "/"
- + str(args["project_id"])
- )
-
-
-def _get_sentry_server(realm):
- return __pillar__["sentry_realms"][realm]["host"]
diff --git a/pillar/credentials/zr.sls b/pillar/credentials/zr.sls
deleted file mode 100644
--- a/pillar/credentials/zr.sls
+++ /dev/null
@@ -1,122 +0,0 @@
-# -------------------------------------------------------------
-# Salt configuration for Nasqueron servers
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-# Project: Nasqueron
-# Created: 2018-09-12
-# License: Trivial work, not eligible to copyright
-# -------------------------------------------------------------
-
-# -------------------------------------------------------------
-# Zemke-Rhyne credentials
-#
-# Map K<id> on DevCentral with hierarchical keys
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-zr_credentials:
-
- #
- # Credentials used by Nasqueron services
- #
-
- nasqueron:
-
- # login.nasqueron.org
- auth-grove:
- mysql: 67
-
- # status.nasqueron.org
- cachet:
- mysql: 47
- app_key: 126
-
- # pad.nasqueron.org
- etherpad:
- # This API key is used by Wolfplex API to access to the pad lists
- api: 125
-
- # notifications.nasqueron.org
- notifications:
- broker: 56
- mailgun: 82
- sentry: 141
-
- # OpenSearch clusters
- opensearch:
- infra-logs:
- internal_users:
- admin: 163
- dashboards: 164
-
- # photos.nasqueron.org
- pixelfed:
- mysql: 142
- app_key: 143
- mailgun: 145
-
- # sentry.nasqueron.org
- sentry:
- postgresql: 139
- app_key: 140
-
- #
- # Credentials used by Nasqueron members private services
- #
-
- dereckson:
-
- # River Sector
- phabricator:
- mysql: 133
-
- #
- # Credentials used by Espace Win services
- #
-
- espacewin:
-
- # bugzilla.espace-win.org
- bugzilla:
- mysql: 131
-
- #
- # Credentials used by Wolfplex services
- #
-
- wolfplex:
-
- # phabricator.wolfplex.be
- phabricator:
- mysql: 135
- mailgun: 138
-
- #
- # Credentials used by Zed services
- #
-
- zed:
-
- # code.zed.dereckson.be
- phabricator:
- mysql: 134
- sendgrid: 45
-
-# -------------------------------------------------------------
-# Zemke-Rhyne clients
-#
-# This section should list all the Docker engines server
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-zr_clients:
- - key: 2
- allowedConnectionFrom:
- - 172.27.26.49
- - dwellers.nasqueron.drake
- - dwellers.nasqueron.org
- restrictCommand:
- comment: Zemke-Rhyne
-
- - key: 162
- allowedConnectionFrom:
- - cloudhugger.nasqueron.org
- restrictCommand:
- comment: Zemke-Rhyne
diff --git a/pillar/top.sls b/pillar/top.sls
--- a/pillar/top.sls
+++ b/pillar/top.sls
@@ -18,7 +18,6 @@
- webserver.sites
cloudhugger:
- - credentials.zr
- opensearch.software
- opensearch.clusters
@@ -36,7 +35,6 @@
- dbserver.cluster-A
dwellers:
- - credentials.zr
- paas.docker
- saas.jenkins
- saas.sentry
@@ -46,7 +44,6 @@
ysul:
- devserver.repos
- - credentials.zr
- saas.mediawiki
- viperserv.bots
- viperserv.fantoir
diff --git a/roles/opensearch/opensearch/wrapper.sls b/roles/opensearch/opensearch/wrapper.sls
--- a/roles/opensearch/opensearch/wrapper.sls
+++ b/roles/opensearch/opensearch/wrapper.sls
@@ -29,5 +29,5 @@
- template: jinja
- show_changes: False
- context:
- username: {{ salt['zr.get_username'](config['users']['admin']) }}
- password: {{ salt['zr.get_password'](config['users']['admin']) }}
+ username: {{ salt['credential.get_username'](config['users']['admin']) }}
+ password: {{ salt['credential.get_password'](config['users']['admin']) }}
diff --git a/roles/paas-docker/containers/phabricator.sls b/roles/paas-docker/containers/phabricator.sls
--- a/roles/paas-docker/containers/phabricator.sls
+++ b/roles/paas-docker/containers/phabricator.sls
@@ -38,11 +38,9 @@
#
# /!\ DEVCENTRAL DEPLOYMENT ISSUE /!\
#
-# We've currently a chicken or egg problem here: the zr
-# credentials source is the Nasqueron Phabricator instance,
-# DevCentral. As such, we can't provision it through this block.
-#
-# This is blocked by secrets migration to Vault.
+# The DevCentral container is currently not managed
+# by a reproducible Dockerfile. As such, this container
+# is deployed manually from the registry. See T1547.
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{% if create_container %}
diff --git a/roles/paas-docker/init.sls b/roles/paas-docker/init.sls
--- a/roles/paas-docker/init.sls
+++ b/roles/paas-docker/init.sls
@@ -12,10 +12,7 @@
- .kernel
- .salt
- .docker
- - .zemke-rhyne
-{% if salt['file.file_exists'](dirs['bin'] + '/zr') %}
- .containers
-{% endif %}
- .systemd-unit
- .wwwroot-502
- .wwwroot-content
diff --git a/roles/paas-docker/zemke-rhyne/directory.sls b/roles/paas-docker/zemke-rhyne/directory.sls
deleted file mode 100644
--- a/roles/paas-docker/zemke-rhyne/directory.sls
+++ /dev/null
@@ -1,13 +0,0 @@
-# -------------------------------------------------------------
-# Salt — Provision Docker engine
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-# Project: Nasqueron
-# Created: 2018-09-08
-# License: Trivial work, not eligible to copyright
-# -------------------------------------------------------------
-
-{% from "map.jinja" import dirs with context %}
-
-{{ dirs.etc }}/zr:
- file.directory:
- - mode: 700
diff --git a/roles/paas-docker/zemke-rhyne/files/zr.sh b/roles/paas-docker/zemke-rhyne/files/zr.sh
deleted file mode 100755
--- a/roles/paas-docker/zemke-rhyne/files/zr.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/sh
-
-# -------------------------------------------------------------
-# PaaS Docker
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-# Project: Nasqueron
-# Created: 2018-09-08
-# License: Trivial work, not eligible to copyright
-# Source file: roles/paas-docker/zemke-rhyne/files/zr.sh
-# -------------------------------------------------------------
-#
-# <auto-generated>
-# This file is managed by our rOPS SaltStack repository.
-#
-# Changes to this file may cause incorrect behavior
-# and will be lost if the state is redeployed.
-# </auto-generated>
-
-ZR_SERVER="${ZR_SERVER:-ysul.nasqueron.org}"
-
-if [ "$#" -eq 0 ]; then
- echo "Usage: $0 <command name> [options...]" 1>&2;
- exit 1
-fi
-
-ssh -4 -i /etc/zr/id_zr "zr@$ZR_SERVER" "$@"
diff --git a/roles/paas-docker/zemke-rhyne/init.sls b/roles/paas-docker/zemke-rhyne/init.sls
deleted file mode 100644
--- a/roles/paas-docker/zemke-rhyne/init.sls
+++ /dev/null
@@ -1,40 +0,0 @@
-# -------------------------------------------------------------
-# Salt — Provision Docker engine
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-# Project: Nasqueron
-# Created: 2018-09-08
-# License: Trivial work, not eligible to copyright
-#
-# ___ ___ ___ ___ ___
-# / /\ / /\ /__/\ /__/| / /\
-# / /::| / /:/_ | |::\ | |:| / /:/_
-# / /:/:| / /:/ /\ | |:|:\ | |:| / /:/ /\
-# / /:/|:|__ / /:/ /:/_ __|__|:|\:\ __| |:| / /:/ /:/_
-# /__/:/ |:| /\ /__/:/ /:/ /\ /__/::::| \:\ /__/\_|:|____ /__/:/ /:/ /\
-# \__\/ |:|/:/ \ \:\/:/ /:/ \ \:\~~\__\/ \ \:\/:::::/ \ \:\/:/ /:/
-# | |:/:/ \ \::/ /:/ \ \:\ \ \::/~~~~ \ \::/ /:/
-# | |::/ \ \:\/:/ \ \:\ \ \:\ \ \:\/:/
-# | |:/ \ \::/ \ \:\ \ \:\ \ \::/
-# |__|/ ___ \__\/ ___ \__\/ \__\/ ___ \__\/ ___
-# / /\ /__/\ ___ /__/\ / /\
-# / /::\ \ \:\ /__/| \ \:\ / /:/_
-# / /:/\:\ \__\:\ | |:| \ \:\ / /:/ /\
-# / /:/~/:/ ___ / /::\ | |:| _____\__\:\ / /:/ /:/_
-# /__/:/ /:/___ /__/\ /:/\:\ __|__|:| /__/::::::::\ /__/:/ /:/ /\
-# \ \:\/:::::/ \ \:\/:/__\/ /__/::::\ \ \:\~~\~~\/ \ \:\/:/ /:/
-# \ \::/~~~~ \ \::/ ~\~~\:\ \ \:\ ~~~ \ \::/ /:/
-# \ \:\ \ \:\ \ \:\ \ \:\ \ \:\/:/
-# \ \:\ \ \:\ \__\/ \ \:\ \ \::/
-# \__\/ \__\/ \__\/ \__\/
-#
-# Support tools for a Docker <--> Phabricator bridge.
-#
-# Use the Zemke-Rhyne account to build Docker containers for
-# Nasqueron applications, fetching information from DevCentral.
-#
-# -------------------------------------------------------------
-
-include:
- - .directory
- - .key
- - .utilities
diff --git a/roles/paas-docker/zemke-rhyne/key.sls b/roles/paas-docker/zemke-rhyne/key.sls
deleted file mode 100644
--- a/roles/paas-docker/zemke-rhyne/key.sls
+++ /dev/null
@@ -1,16 +0,0 @@
-# -------------------------------------------------------------
-# Salt — Provision Docker engine
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-# Project: Nasqueron
-# Created: 2018-09-08
-# License: Trivial work, not eligible to copyright
-# -------------------------------------------------------------
-
-{% from "map.jinja" import dirs with context %}
-
-{% set key = dirs['etc'] + "/zr/id_zr" %}
-
-zr_key:
- cmd.run:
- - name: ssh-keygen -N '' -t ed25519 -f {{ key }}
- - creates: {{ key }}
diff --git a/roles/paas-docker/zemke-rhyne/utilities.sls b/roles/paas-docker/zemke-rhyne/utilities.sls
deleted file mode 100644
--- a/roles/paas-docker/zemke-rhyne/utilities.sls
+++ /dev/null
@@ -1,14 +0,0 @@
-# -------------------------------------------------------------
-# Salt — Provision Docker engine
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-# Project: Nasqueron
-# Created: 2018-09-08
-# License: Trivial work, not eligible to copyright
-# -------------------------------------------------------------
-
-{% from "map.jinja" import dirs with context %}
-
-{{ dirs.bin }}/zr:
- file.managed:
- - source: salt://roles/paas-docker/zemke-rhyne/files/zr.sh
- - mode: 755
diff --git a/roles/salt-primary/zemke-rhyne/account.sls b/roles/salt-primary/zemke-rhyne/account.sls
deleted file mode 100644
--- a/roles/salt-primary/zemke-rhyne/account.sls
+++ /dev/null
@@ -1,25 +0,0 @@
-# -------------------------------------------------------------
-# Salt — Provision Docker engine
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-# Project: Nasqueron
-# Created: 2017-04-28
-# License: Trivial work, not eligible to copyright
-# -------------------------------------------------------------
-
-{% from "map.jinja" import dirs with context %}
-{% set zr_home = "/home/zr" %}
-
-# -------------------------------------------------------------
-# Account
-#
-# This account is used by Jenkins jobs to deploy artifacts
-# after a build.
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-zr_account:
- user.present:
- - name: zr
- - fullname: Zemke-Rhyne
- - uid: 8900
- - gid: 9002
- - home: {{ zr_home }}
diff --git a/roles/salt-primary/zemke-rhyne/data.sls b/roles/salt-primary/zemke-rhyne/data.sls
deleted file mode 100644
--- a/roles/salt-primary/zemke-rhyne/data.sls
+++ /dev/null
@@ -1,29 +0,0 @@
-# -------------------------------------------------------------
-# Salt — Provision Docker engine
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-# Project: Nasqueron
-# Created: 2018-09-08
-# License: Trivial work, not eligible to copyright
-# -------------------------------------------------------------
-
-{% set zr_home = "/home/zr" %}
-
-# If we pass the JSON as contents, it will be converted into Python,
-# so we've a template to call directly the method.
-
-{{ zr_home }}/data/servers.json:
- file.managed:
- - source: salt://roles/salt-primary/zemke-rhyne/files/servers.json.jinja
- - template: jinja
- - user: zr
-
-zr_authorized_keys:
- cmd.run:
- - runas: zr
- - cwd: {{ zr_home }}
- - name: make clean all
- - onchanges:
- - file: {{ zr_home }}/data/servers.json
- - require:
- - user: zr_account
- - file: {{ zr_home }}/Makefile
diff --git a/roles/salt-primary/zemke-rhyne/files/dot.arcrc.json b/roles/salt-primary/zemke-rhyne/files/dot.arcrc.json
deleted file mode 100644
--- a/roles/salt-primary/zemke-rhyne/files/dot.arcrc.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "config": {
- "default": "https://devcentral.nasqueron.org/"
- }
-}
diff --git a/roles/salt-primary/zemke-rhyne/files/servers.json.jinja b/roles/salt-primary/zemke-rhyne/files/servers.json.jinja
deleted file mode 100644
--- a/roles/salt-primary/zemke-rhyne/files/servers.json.jinja
+++ /dev/null
@@ -1 +0,0 @@
-{{ salt['convert.to_json_from_pillar_key']('zr_clients') }}
diff --git a/roles/salt-primary/zemke-rhyne/init.sls b/roles/salt-primary/zemke-rhyne/init.sls
deleted file mode 100644
--- a/roles/salt-primary/zemke-rhyne/init.sls
+++ /dev/null
@@ -1,40 +0,0 @@
-# -------------------------------------------------------------
-# Salt — Provision Docker engine
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-# Project: Nasqueron
-# Created: 2017-04-28
-# License: Trivial work, not eligible to copyright
-# -------------------------------------------------------------
-
-# -------------------------------------------------------------
-# But first, we interrupt your configuration for some ASCII art.
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-#
-#
-# ___ ___ ___ ___ ___
-# / /\ / /\ /__/\ /__/| / /\
-# / /::| / /:/_ | |::\ | |:| / /:/_
-# / /:/:| / /:/ /\ | |:|:\ | |:| / /:/ /\
-# / /:/|:|__ / /:/ /:/_ __|__|:|\:\ __| |:| / /:/ /:/_
-# /__/:/ |:| /\ /__/:/ /:/ /\ /__/::::| \:\ /__/\_|:|____ /__/:/ /:/ /\
-# \__\/ |:|/:/ \ \:\/:/ /:/ \ \:\~~\__\/ \ \:\/:::::/ \ \:\/:/ /:/
-# | |:/:/ \ \::/ /:/ \ \:\ \ \::/~~~~ \ \::/ /:/
-# | |::/ \ \:\/:/ \ \:\ \ \:\ \ \:\/:/
-# | |:/ \ \::/ \ \:\ \ \:\ \ \::/
-# |__|/ ___ \__\/ ___ \__\/ \__\/ ___ \__\/ ___
-# / /\ /__/\ ___ /__/\ / /\
-# / /::\ \ \:\ /__/| \ \:\ / /:/_
-# / /:/\:\ \__\:\ | |:| \ \:\ / /:/ /\
-# / /:/~/:/ ___ / /::\ | |:| _____\__\:\ / /:/ /:/_
-# /__/:/ /:/___ /__/\ /:/\:\ __|__|:| /__/::::::::\ /__/:/ /:/ /\
-# \ \:\/:::::/ \ \:\/:/__\/ /__/::::\ \ \:\~~\~~\/ \ \:\/:/ /:/
-# \ \::/~~~~ \ \::/ ~\~~\:\ \ \:\ ~~~ \ \::/ /:/
-# \ \:\ \ \:\ \ \:\ \ \:\ \ \:\/:/
-# \ \:\ \ \:\ \__\/ \ \:\ \ \::/
-# \__\/ \__\/ \__\/ \__\/
-#
-
-include:
- - .account
- - .software
- - .data
diff --git a/roles/salt-primary/zemke-rhyne/software.sls b/roles/salt-primary/zemke-rhyne/software.sls
deleted file mode 100644
--- a/roles/salt-primary/zemke-rhyne/software.sls
+++ /dev/null
@@ -1,69 +0,0 @@
-# -------------------------------------------------------------
-# Salt — Provision Docker engine
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-# Project: Nasqueron
-# Created: 2017-04-28
-# License: Trivial work, not eligible to copyright
-# -------------------------------------------------------------
-
-{% from "map.jinja" import dirs with context %}
-{% set zr_home = "/home/zr" %}
-
-# -------------------------------------------------------------
-# Required dependencies
-#
-# :: jq
-# :: arc
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-zr_required_sofware:
- pkg.installed:
- - pkgs:
- - jq
-
- # Devserver role provides their own Git clone of Arcanist
- # For other servers, we need the package.
- {% if not salt['node.has_role']('devserver') %}
- - arcanist
- {% endif %}
-
-# -------------------------------------------------------------
-# Deploy files and directory
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-{% for dir in ['data', 'lib'] %}
-{{ zr_home }}/{{ dir }}:
- file.recurse:
- - source: salt://software/zemke-rhyne/{{ dir }}
- - include_empty: True
- - clean: False
- - dir_mode: 755
- - file_mode: 644
- - user: 8900
- - group: 9002
-{% endfor %}
-
-{{ zr_home }}/bin:
- file.recurse:
- - source: salt://software/zemke-rhyne/bin
- - dir_mode: 755
- - file_mode: 755
- - user: 8900
- - group: 9002
-
-{% for file in ['README', 'Makefile', '.arcconfig', '.arclint'] %}
-{{ zr_home }}/{{ file }}:
- file.managed:
- - source: salt://software/zemke-rhyne/{{ file }}
- - mode: 644
- - user: 8900
- - group: 9002
-{% endfor %}
-
-{{ zr_home }}/.arcrc:
- file.managed:
- - source: salt://roles/webserver-legacy/zr/files/dot.arcrc.json
- - replace: False
- - mode: 600
- - user: 8900
- - group: 9002
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Nov 24, 07:13 (11 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2259690
Default Alt Text
D2854.id7278.diff (22 KB)
Attached To
Mode
D2854: Decommission Zemke-Rhyne
Attached
Detach File
Event Timeline
Log In to Comment