pyceo/docs/openapi.yaml

1034 lines
35 KiB
YAML

openapi: 3.0.0
info:
title: ceod - OpenAPI 3.0
description: |
This is an OpenAPI specification of ceod, the CSC Electronic Office daemon.
Visit the [git repository](https://git.csclub.uwaterloo.ca/public/pyceo) for
more details.
## Streaming Responses
Many endpoints return a "streaming response", which consists of a series of JSON
objects, one per line (the mimetype is text/plain). For example:
```
{"status": "in progress", "operation": "replace_login_shell"}
{"status": "in progress", "operation": "replace_forwarding_addresses"}
{"status": "completed", "result": "OK"}
```
Whenever an operation is completed, a corresponding JSON object will be streamed
from the server to the client. This allows the client to track the server's progress
in real time.
contact:
email: syscom@csclub.uwaterloo.ca
version: 1.0.0
servers:
- url: https://phosphoric-acid.csclub.uwaterloo.ca:9987/api
tags:
- name: members
description: Operations on members and club reps
- name: groups
description: Operations on groups and clubs
- name: mailman
description: Operations on mailing list subscriptions
- name: uwldap
description: Operations related to the UW LDAP directory
- name: database
description: Operations related to databases
- name: cloud
description: Operations related to the CSC Cloud
security:
- GSSAPIAuth: []
paths:
/members:
post:
tags: ['members']
summary: Create a new user
description: >-
Creates a new member or club rep. If `terms` is specified, a member is created;
if `non_member_terms` is specified, a club rep is created.
requestBody:
content:
application/json:
schema:
type: object
properties:
uid:
$ref: "#/components/schemas/UID"
cn:
$ref: "#/components/schemas/UserCN"
sn:
$ref: "#/components/schemas/UserSN"
given_name:
$ref: "#/components/schemas/UserGivenName"
program:
$ref: "#/components/schemas/Program"
terms:
$ref: "#/components/schemas/Terms"
non_member_terms:
$ref: "#/components/schemas/NonMemberTerms"
forwarding_addresses:
$ref: "#/components/schemas/ForwardingAddresses"
responses:
"200":
description: Success
content:
text/plain:
schema:
type: string
description: Streaming response
example: |
{"status": "in progress", "operation": "add_user_to_ldap"}
{"status": "in progress", "operation": "add_group_to_ldap"}
{"status": "in progress", "operation": "add_user_to_kerberos"}
{"status": "in progress", "operation": "create_home_dir"}
{"status": "in progress", "operation": "send_welcome_message"}
{"status": "in progress", "operation": "subscribe_to_mailing_list"}
{"status": "in progress", "operation": "announce_new_user"}
{"status": "completed", "result": {"cn": "Calum Dalek", "given_name": "Calum", "sn": "Dalek", "uid": "ctdalek", "uid_number": 20001, "gid_number": 20001, "login_shell": "/bin/bash", "home_directory": "/users/ctdalek", "is_club": false, "program": "MAT/Mathematics Computer Science", "terms": ["f2021"], "forwarding_addresses": ["ctdalek@uwaterloo.ca"], "password": "Wlw1wOTofERTEBlXWzR6/MZL"}}
/members/{username}:
get:
tags: ['members']
summary: Get information about a user
description: >-
Returns information about a member or club rep. The `forwarding_addresses` field
will only be present if the client is an authenticated syscom member.
parameters:
- name: username
in: path
description: username of the user to return
required: true
schema:
type: string
responses:
"200":
description: Success
content:
application/json:
schema:
$ref: "#/components/schemas/User"
"404":
$ref: "#/components/responses/UserNotFoundErrorResponse"
patch:
tags: ['members']
summary: Modify a user
description: Replace the login shell and/or forwarding addresses of a user
parameters:
- name: username
in: path
description: username of the user to modify
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
properties:
login_shell:
$ref: "#/components/schemas/LoginShell"
forwarding_addresses:
$ref: "#/components/schemas/ForwardingAddresses"
responses:
"200":
description: Success
content:
text/plain:
schema:
type: string
description: Streaming response
example: |
{"status": "in progress", "operation": "replace_login_shell"}
{"status": "in progress", "operation": "replace_forwarding_addresses"}
{"status": "completed", "result": "OK"}
"404":
$ref: "#/components/responses/UserNotFoundErrorResponse"
/members/{username}/renew:
post:
tags: ['members']
summary: Renew a user
description: Add member **or** non-member terms to a user
parameters:
- name: username
in: path
description: username of the user to renew
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
oneOf:
- type: object
properties:
terms:
type: array
description: Terms for which this user will be a member
items:
$ref: "#/components/schemas/Term"
- type: object
properties:
non_member_terms:
type: array
description: Terms for which this user will be a club rep
items:
$ref: "#/components/schemas/Term"
example: {"terms": ["f2021"]}
responses:
"200":
description: Success
content:
application/json:
schema:
oneOf:
- type: object
properties:
terms_added:
type: array
description: Member terms which were added to this user
items:
$ref: "#/components/schemas/Term"
- type: object
properties:
non_member_terms_added:
type: array
description: Non-member terms which were added to this user
items:
$ref: "#/components/schemas/Term"
example: {"terms_added": ["f2021"]}
"404":
$ref: "#/components/responses/UserNotFoundErrorResponse"
/members/{username}/pwreset:
post:
tags: ['members']
summary: Reset a user's password
description: >-
Sets a user's password to a randomly generated string, and returns it. The user will be
prompted to set a new password on their next login.
parameters:
- name: username
in: path
description: username of the user whose password will be reset
required: true
schema:
type: string
responses:
"200":
description: Success
content:
application/json:
schema:
type: object
properties:
password:
type: string
description: The user's new password
example: "EPGbJwLl1pmiWz8Wvu/MSs+v"
"404":
$ref: "#/components/responses/UserNotFoundErrorResponse"
/groups:
post:
tags: ['groups']
summary: Create a new group
description: >-
Creates a new Unix group for a club. A new Unix user account with the same name will also be created.
A sudo role will be created allowing members of the group to become this user.
requestBody:
content:
application/json:
schema:
type: object
properties:
cn:
$ref: "#/components/schemas/GroupCN"
description:
$ref: "#/components/schemas/GroupDescription"
responses:
"200":
description: Success
content:
text/plain:
schema:
type: string
description: Streaming response
example: |
{"status": "in progress", "operation": "add_user_to_ldap"}
{"status": "in progress", "operation": "add_group_to_ldap"}
{"status": "in progress", "operation": "add_sudo_role"}
{"status": "in progress", "operation": "create_home_dir"}
{"status": "completed", "result": {"cn": "uwclub1", "gid_number": 30001, "description": "Club One", "members": []}}
/groups/{group_name}:
get:
tags: ['groups']
summary: Get information about a group
description: Returns information about a group
security: []
parameters:
- name: group_name
in: path
description: name of the group to return
required: true
schema:
type: string
responses:
"200":
description: Success
content:
application/json:
schema:
type: object
properties:
cn:
$ref: "#/components/schemas/GroupCN"
description:
$ref: "#/components/schemas/GroupDescription"
gid_number:
$ref: "#/components/schemas/GIDNumber"
members:
type: array
description: Members of the group
items:
$ref: "#/components/schemas/UID"
"404":
$ref: "#/components/responses/GroupNotFoundErrorResponse"
/groups/{group_name}/members/{username}:
post:
tags: ['groups']
summary: Add a member to a group
description: >-
Adds a member to a group. The member will also be added to any auxiliary groups
specified in ceod.conf. The member may also be added to auxiliary mailing lists.
parameters:
- name: group_name
in: path
description: name of the group to which the member will be added
required: true
schema:
type: string
- name: username
in: path
description: username of the member who will be added to the group
required: true
schema:
type: string
- name: subscribe_to_lists
in: query
description: whether the member should be subscribed to auxiliary mailing lists
schema:
type: boolean
default: true
responses:
"200":
description: Success
content:
text/plain:
schema:
type: string
example: |
{"status": "in progress", "operation": "add_user_to_group"}
{"status": "in progress", "operation": "add_user_to_auxiliary_groups"}
{"status": "in progress", "operation": "subscribe_user_to_auxiliary_mailing_lists"}
{"status": "completed", "result": {"added_to_groups": ["group2","group3"], "subscribed_to_lists": ["list1","list2"]}}
"404":
$ref: "#/components/responses/GroupNotFoundErrorResponse"
delete:
tags: ['groups']
summary: Remove a member from a group
description: >-
Removes a member from a group. The member will also be removed from any auxiliary groups
specified in ceod.conf. The member may also be removed from auxiliary mailing lists.
parameters:
- name: group_name
in: path
description: name of the group from which the member will be removed
required: true
schema:
type: string
- name: username
in: path
description: username of the member who will be removed from the group
required: true
schema:
type: string
- name: unsubscribe_from_lists
in: query
description: whether the member should be unsubscribed from auxiliary mailing lists
schema:
type: boolean
default: true
responses:
"200":
description: Success
content:
text/plain:
schema:
type: string
example: |
{"status": "in progress", "operation": "remove_user_from_group"}
{"status": "in progress", "operation": "remove_user_from_auxiliary_groups"}
{"status": "in progress", "operation": "unsubscribe_user_from_auxiliary_mailing_lists"}
{"status": "completed", "result": {"removed_from_groups": ["group2","group3"], "unsubscribed_from_lists": ["list1","list2"]}}
"404":
$ref: "#/components/responses/GroupNotFoundErrorResponse"
/positions:
get:
tags: ['positions']
summary: Show current positions
description: >-
Shows the list of positions and members holding them.
responses:
"200":
description: Success
content:
application/json:
schema:
type: object
additionalProperties:
type: string
example:
president: user0
vice-president: user1
sysadmin: user2
treasurer:
post:
tags: ['positions']
summary: Update positions
description: >-
Update members for each positions. Members not specified in the parameters will be removed
from the position and unsubscribed from the exec's mailing list. New position holders will
be subscribed to the mailing list.
requestBody:
description: New position holders
required: true
content:
application/json:
schema:
type: object
additionalProperties:
type: string
example:
president: user0
vice-president: user1
sysadmin: user2
treasurer:
responses:
"200":
description: Success
content:
text/plain:
schema:
type: string
description: Streaming response
example: |
{"status": "in progress", "operation": "update_positions_ldap"}
{"status": "in progress", "operation": "update_exec_group_ldap"}
{"status": "in progress", "operation": "subscribe_to_mailing_list"}
{"status": "completed", "result": "OK"}
"400":
description: Failed
content:
application/json:
schema:
type: object
properties:
error:
type: string
/mailman/{mailing_list}/{username}:
post:
tags: ['mailman']
servers:
- url: "https://mail.csclub.uwaterloo.ca:9987/api"
summary: subscribe a user to a mailing list
description: Subscribes a user to a mailing list.
parameters:
- name: mailing_list
in: path
description: >-
The name of the list to which the user will be subscribed. If there is no '@' symbol,
then '@csclub.uwaterloo.ca' will be appended to the list name.
required: true
schema:
type: string
- name: username
in: path
required: true
description: >-
The user who will be subscribed to the list. If there is no '@' symbol, then '@csclub.uwaterloo.ca'
will be appended to he username; otherwise, the given email address will be subscribed.
schema:
type: string
responses:
"200":
description: Success
content:
application/json:
schema:
type: object
properties:
result:
type: string
example: OK
"404":
$ref: "#/components/responses/NoSuchListErrorResponse"
"409":
$ref: "#/components/responses/UserAlreadySubscribedErrorResponse"
delete:
tags: ['mailman']
servers:
- url: "https://mail.csclub.uwaterloo.ca:9987/api"
summary: unsubscribe a user from a mailing list
description: Unsubscribes a user from a mailing list.
parameters:
- name: mailing_list
in: path
description: >-
The name of the list from which the user will be unsubscribed. If there is no '@' symbol,
then '@csclub.uwaterloo.ca' will be appended to the list name.
required: true
schema:
type: string
- name: username
in: path
required: true
description: >-
The user who will be unsubscribed from the list. If there is no '@' symbol, then '@csclub.uwaterloo.ca'
will be appended to he username; otherwise, the given email address will be unsubscribed.
schema:
type: string
responses:
"200":
description: Success
content:
application/json:
schema:
type: object
properties:
result:
type: string
example: OK
"404":
$ref: "#/components/responses/UserAlreadySubscribedOrNoSuchListErrorResponse"
/uwldap/{username}:
get:
tags: ['uwldap']
security: []
summary: get UWLDAP information for a user
description: Returns information about a user from the UW LDAP directory.
parameters:
- name: username
in: path
description: username of the user to return
required: true
schema:
type: string
responses:
"200":
description: Success
content:
application/json:
schema:
$ref: "#/components/schemas/UWLDAPUser"
"404":
$ref: "#/components/responses/UserNotFoundErrorResponse"
/uwldap/updateprograms:
post:
tags: ['uwldap']
summary: update CSC programs from UWLDAP
description: |
Sync the 'program' attribute in the CSC LDAP with the UW LDAP.
The JSON request body may be omitted.
parameters:
- name: dry_run
in: query
description: >-
Whether to perform a dry run or not. If true, a list of members who *would* have been
changed is returned.
schema:
type: boolean
default: false
requestBody:
content:
application/json:
schema:
type: object
properties:
members:
type: array
description: If non-empty, only these members will be synced with UWLDAP
default: []
items:
$ref: "#/components/schemas/UID"
responses:
"200":
description: Success
content:
application/json:
schema:
type: array
description: >-
A list of members whose programs were (or who would have been) changed.
Each item of the list is a 3-tuple of the form (username, old_program, new_program).
items:
type: array
items:
type: string
example: [['ctdalek', 'old_program', 'new_program']]
/db/mysql/{username}:
post:
tags: ['database']
servers:
- url: https://caffeine.csclub.uwaterloo.ca:9987/api
summary: Create a MySQL database
description: Create a MySQL database for the user
parameters:
- name: username
in: path
description: name of the user to create MySQL database for
required: true
schema:
type: string
responses:
"200":
description: Success
content:
application/json:
schema:
type: object
properties:
password:
type: string
description: The password to the database
example: {"password": "7fUi5rQr/lcpeEj4M86ZBbwM"}
"400":
$ref: "#/components/responses/InvalidUsernameErrorResponse"
"404":
$ref: "#/components/responses/UserNotFoundErrorResponse"
"409":
$ref: "#/components/responses/DBAlreadyCreatedErrorResponse"
"500":
$ref: "#/components/responses/DBConnectionOrPermissionErrorResponse"
/db/mysql/{username}/pwreset:
post:
tags: ['database']
servers:
- url: https://caffeine.csclub.uwaterloo.ca:9987/api
summary: Reset MySQL database password
description: Reset the password for a user's MySQL database
parameters:
- name: username
in: path
description: name of the user to reset the MySQL database password for
required: true
schema:
type: string
responses:
"200":
description: Success
content:
application/json:
schema:
type: object
properties:
password:
type: string
description: The new password to the database
example: {"password": "kM90d3G/eofIUxr9O3CQHTlP"}
"400":
$ref: "#/components/responses/InvalidUsernameErrorResponse"
"404":
$ref: "#/components/responses/UserNotFoundErrorResponse"
"500":
$ref: "#/components/responses/DBConnectionOrPermissionErrorResponse"
/db/postgresql/{username}:
post:
tags: ['database']
servers:
- url: https://caffeine.csclub.uwaterloo.ca:9987/api
summary: Create a PostgreSQL database
description: Create a PostgreSQL database for the user
parameters:
- name: username
in: path
description: name of the user to create PostgreSQL database for
required: true
schema:
type: string
responses:
"200":
description: Success
content:
application/json:
schema:
type: object
properties:
password:
type: string
description: The password to the database
example: {"password": "iHxd62DC7Qt1HyYRj18P6ujS"}
"400":
$ref: "#/components/responses/InvalidUsernameErrorResponse"
"404":
$ref: "#/components/responses/UserNotFoundErrorResponse"
"409":
$ref: "#/components/responses/DBAlreadyCreatedErrorResponse"
"500":
$ref: "#/components/responses/DBConnectionOrPermissionErrorResponse"
/db/postgresql/{username}/pwreset:
post:
tags: ['database']
servers:
- url: https://caffeine.csclub.uwaterloo.ca:9987/api
summary: Reset PostgreSQL database password
description: Reset the password for a user's PostgreSQL database
parameters:
- name: username
in: path
description: name of the user to reset the PostgreSQL database password for
required: true
schema:
type: string
responses:
"200":
description: Success
content:
application/json:
schema:
type: object
properties:
password:
type: string
description: The new password to the database
example: {"password": "CdPHT49iYAWzzKuhKTt2dNeu"}
"400":
$ref: "#/components/responses/InvalidUsernameErrorResponse"
"404":
$ref: "#/components/responses/UserNotFoundErrorResponse"
"500":
$ref: "#/components/responses/DBConnectionOrPermissionErrorResponse"
/cloud/accounts/create:
post:
tags: ['cloud']
servers:
- url: https://biloba.csclub.uwaterloo.ca:9987/api
summary: Activate a cloud account
description: Activate a cloud account for the calling user
responses:
"200":
"$ref": "#/components/responses/SimpleSuccessResponse"
"403":
"$ref": "#/components/responses/InvalidMembershipErrorResponse"
/cloud/accounts/purge:
post:
tags: ['cloud']
servers:
- url: https://biloba.csclub.uwaterloo.ca:9987/api
summary: Purge expired accounts
description: |
Delete the cloud accounts of expired members.
There is a one-month grace period after the expiration.
After one month, expired members will be sent an email warning them
that their account will be deleted.
One week after that, if an expired member has still not renewed their
membership, their account will be deleted.
responses:
"200":
description: Success
content:
application/json:
schema:
type: object
properties:
accounts_to_be_deleted:
type: array
description: usernames of accounts which will be deleted
items:
type: string
accounts_deleted:
type: array
description: usernames of accounts which were deleted
items:
type: string
/cloud/vhosts/{domain}:
put:
tags: ['cloud']
servers:
- url: https://biloba.csclub.uwaterloo.ca:9987/api
summary: Create a vhost
description: Add a new virtual host configuration.
parameters:
- name: domain
in: path
description: domain name of the virtual host
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
properties:
ip_address:
type: string
description: IP address of the virtual host
example: {"ip_address": "172.19.134.11"}
responses:
"200":
"$ref": "#/components/responses/SimpleSuccessResponse"
"403":
"$ref": "#/components/responses/InvalidMembershipErrorResponse"
delete:
tags: ['cloud']
servers:
- url: https://biloba.csclub.uwaterloo.ca:9987/api
summary: Delete a vhost
description: Delete a virtual host configuration.
parameters:
- name: domain
in: path
description: domain name of the virtual host
required: true
schema:
type: string
responses:
"200":
"$ref": "#/components/responses/SimpleSuccessResponse"
/cloud/vhosts:
get:
tags: ['cloud']
servers:
- url: https://biloba.csclub.uwaterloo.ca:9987/api
summary: List all vhosts
description: List all virtual host configurations for the calling user.
responses:
"200":
description: Success
content:
application/json:
schema:
type: object
properties:
vhosts:
type: array
description: virtual hosts
items:
type: object
properties:
domain:
type: string
description: domain name of the virtual host
ip_address:
type: string
description: IP address of the virtual host
example: {"vhosts": [{"domain": "ctdalek.m.csclub.cloud", "ip_address": "172.19.134.11"}]}
/cloud/k8s/account/create:
post:
tags: ['cloud']
servers:
- url: https://biloba.csclub.uwaterloo.ca:9987/api
summary: Activate a Kubernetes account
description: |
Create a Kubernetes namespace for the calling user. A new kubeconfig file will be returned.
If the namespace already exists, the certificate inside the kubeconfig will be renewed.
responses:
"200":
description: Success
content:
application/json:
schema:
type: object
properties:
status:
type: string
description: '"OK"'
example: OK
kubeconfig:
type: string
description: the contents of a new kubeconfig file
components:
securitySchemes:
GSSAPIAuth:
type: http
scheme: negotiate
description: |
ceod uses SPNEGO-based authentication over HTTP, as specified in [RFC 4559](https://datatracker.ietf.org/doc/html/rfc4559).
It is basically a base64-encoded Kerberos ticket wrapped in a HTTP header. For endpoints which make modifications
to LDAP, the Delegate flag must also be set.
For example, with cURL:
```sh
kinit
curl --negotiate -u : --service-name ceod --delegation always -X POST -d '{"terms":["w2022"]}' https://phosphoric-acid.csclub.uwaterloo.ca/api/members/ctdalek/renew
```
schemas:
UserCN:
type: string
description: Full name
example: Calum Dalek
UserSN:
type: string
description: Last name
example: Dalek
UserGivenName:
type: string
description: First name
example: Calum
UID:
type: string
description: Username
example: ctdalek
Program:
type: string
description: Academic program
example: MAT/Mathematics Computer Science
Terms:
type: array
description: Terms for which this user was a member
items:
$ref: "#/components/schemas/Term"
NonMemberTerms:
type: array
description: Terms for which this user was a club rep
items:
$ref: "#/components/schemas/Term"
LoginShell:
type: string
description: Login shell
example: /bin/bash
UIDNumber:
type: integer
description: UID number
example: 20001
GIDNumber:
type: integer
description: GID number
example: 20001
User:
type: object
properties:
cn:
$ref: "#/components/schemas/UserCN"
sn:
$ref: "#/components/schemas/UserSN"
given_name:
$ref: "#/components/schemas/UserGivenName"
uid:
$ref: "#/components/schemas/UID"
uid_number:
$ref: "#/components/schemas/UIDNumber"
gid_number:
$ref: "#/components/schemas/GIDNumber"
home_directory:
type: string
description: Home directory
example: /users/ctdalek
is_club:
type: boolean
description: Whether this user is a club account or not
example: false
login_shell:
$ref: "#/components/schemas/LoginShell"
program:
$ref: "#/components/schemas/Program"
positions:
type: array
description: Positions held by this member
items:
type: string
example: president
terms:
$ref: "#/components/schemas/Terms"
non_member_terms:
$ref: "#/components/schemas/NonMemberTerms"
forwarding_addresses:
$ref: "#/components/schemas/ForwardingAddresses"
UWLDAPUser:
type: object
properties:
uid:
$ref: "#/components/schemas/UID"
cn:
$ref: "#/components/schemas/UserCN"
given_name:
type: string
description: Given name
example: Calum
sn:
type: string
description: Surname
example: Dalek
mail_local_addresses:
type: array
description: UW email addresses for this user
items:
type: string
format: email
example: ctdalek@uwaterloo.ca
ForwardingAddresses:
type: array
description: Forwarding addresses in ~/.forward
items:
type: string
format: email
example: ctdalek@uwaterloo.ca
Term:
type: string
description: Academic term
example: f2021
GroupCN:
type: string
description: the name of the group
example: uwclub1
GroupDescription:
type: string
description: a description of the group
example: Club One
responses:
ErrorResponse: &ErrorResponse
content:
application/json:
schema:
type: object
properties:
error:
type: string
description: Error message
UserNotFoundErrorResponse:
<<: *ErrorResponse
description: User not found
GroupNotFoundErrorResponse:
<<: *ErrorResponse
description: Group not found
UserAlreadySubscribedErrorResponse:
<<: *ErrorResponse
description: User is already subscribed
NoSuchListErrorResponse:
<<: *ErrorResponse
description: Mailing list does not exist
UserAlreadySubscribedOrNoSuchListErrorResponse:
<<: *ErrorResponse
description: User is already subscribed or mailing list does not exist
DBAlreadyCreatedErrorResponse:
<<: *ErrorResponse
description: User already has a database
InvalidUsernameErrorResponse:
<<: *ErrorResponse
description: Username contains invalid characters
DBConnectionOrPermissionErrorResponse:
<<: *ErrorResponse
description: Unable to connect to database or action failed due to permissions
InvalidMembershipErrorResponse:
<<: *ErrorResponse
description: Membership is invalid or expired
SimpleSuccessResponse:
description: Success
content:
application/json:
schema:
type: object
properties:
status:
type: string
description: '"OK"'
example: {"status": "OK"}