add myoffice scripts

This commit is contained in:
aleksandr.vodyanov
2024-04-09 10:19:48 +03:00
parent 6596117571
commit 9f2c40e688
28 changed files with 1310 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
FROM python:3.10-alpine
WORKDIR /srv/hyperus_apps/pgs_sync
COPY group_sync_pgs.py ./
RUN python3 -m venv venv && \
source venv/bin/activate && \
pip install \
python-freeipa==1.0.6 \
requests
CMD ["/bin/sh", "-c", "source venv/bin/activate; python ./group_sync_pgs.py"]

View File

@@ -0,0 +1,30 @@
# PGS_GROUP_SYNC
- Скрипт синхронизирует группы в PGS из IPA
- Актуализирует состав групп пользователей
## Переменные окружения
| Название | Значение по умолчанию | Описание |
| --------------------- | ------------------------------------- | ---------------------------------------------- |
| IPA_ADDRESS | "ipa01.hyperus.team" | Адрес сервера IPA |
| IPA_GROUP_ATTR | "description" | Атрибут используемый в качестве имени группы |
| IPA_USERNAME | "automated.carbon" | Учетная запись подключения к IPA |
| IPA_PASSWORD | | Пароль учетной записи подключения к IPA |
| PGS_ADMINAPI_URL | "https://admin.hyperus.team/adminapi" | Адрес AdminAPI PGS |
| PGS_ADMINAPI_PASSWORD | | Пароль учетной записи с правами администратора |
| PGS_ADMINAPI_TENANT | "default" | Тенант к которому принадлежит домен |
| PGS_ADMINAPI_USERNAME | "admin@hyperus.team" | Учетная запись с правами администратора |
## Установка
1. Собрать образ и запустить контейнер.
После аргумента `-e` указать переменные окружения и их значения
```bash
docker build . --tag pgs_group_sync:0.0.1
docker run -d -e IPA_PASSWORD="securepassword" -e PGS_ADMINAPI_PASSWORD="securepassword" --name pgs_group_sync pgs_group_sync:0.0.1
```
2. Добавить в cron задачу по запуску контейнера с необходимым интервалом.
```
*/5 * * * * docker start pgs_group_sync 2>%1 1>/dev/null
```

View File

@@ -0,0 +1,29 @@
apiVersion: "batch/v1"
kind: "CronJob"
metadata:
name: "groupsync-cronjob"
spec:
concurrencyPolicy: "Forbid"
failedJobsHistoryLimit: 1
jobTemplate:
spec:
backoffLimit: 0
template:
spec:
containers:
- name: "group_sync_pgs"
image: "nexus.hyperus.team/groupsync:latest"
imagePullPolicy: "IfNotPresent"
env:
- name: "PGS_ADMINAPI_PASSWORD"
valueFrom:
secretKeyRef:
name: "infrastructure/pgs"
key: "ADMIN_PASSWORD"
- name: "IPA_PASSWORD"
valueFrom:
secretKeyRef:
name: "infrastructure/service_accounts/carbon"
key: "password"
restartPolicy: "Never"
schedule: "*/5 * * * *"

View File

@@ -0,0 +1,147 @@
import os
import requests
import python_freeipa as freeipa
import warnings
warnings.filterwarnings("ignore")
class GroupSyncPGS:
"""
Реализует:
- Получение списка групп с участниками из FreeIPA
- Получение списка групп с участниками из PGS
- Получение списка пользователей из PGS
- Сравнение групп и членства участников
- Добавление групп и участников в PGS
- Удаление групп и участников в PGS
"""
def __init__(self):
self.ipa_address = os.environ.get("IPA_ADDRESS", "ipa01.hyperus.team")
self.ipa_group_attr = os.environ.get("IPA_GROUP_ATTR", "description")
self.ipa_password = os.environ.get("IPA_PASSWORD")
self.ipa_username = os.environ.get("IPA_USERNAME", "automated.carbon")
self.pgs_adminapi_address = os.environ.get("PGS_ADMINAPI_URL", "https://admin.hyperus.team/adminapi")
self.pgs_adminapi_password = os.environ.get("PGS_ADMINAPI_PASSWORD")
self.pgs_adminapi_tenant = os.environ.get("PGS_ADMINAPI_TENANT", "default")
self.pgs_adminapi_username = os.environ.get("PGS_ADMINAPI_USERNAME", "admin@hyperus.team")
def pgs_auth(self) -> None:
pgs_credentials = {"username": self.pgs_adminapi_username, "password": self.pgs_adminapi_password}
result = requests.post(url=f"{self.pgs_adminapi_address}/auth", data=pgs_credentials, verify=False)
if result.status_code == 200:
self.pgs_adminapi_token = result.json()["token"]
else:
raise ConnectionRefusedError("Authentication failed")
self.__pgs_adminapi_header = {"Authorization": self.pgs_adminapi_token}
def get_ipa_groups(self) -> dict:
ipa_groups_formated = {}
ipa_client = freeipa.ClientMeta(host=self.ipa_address, verify_ssl=False)
ipa_client.login(self.ipa_username, self.ipa_password)
ipa_groups_find = ipa_client.group_find()
ipa_client.logout()
ipa_groups_find = list(filter( lambda ipa_group: "member_user" in ipa_group.keys(), ipa_groups_find["result"] ))
for ipa_group in ipa_groups_find:
ipa_group_name = "".join(ipa_group[self.ipa_group_attr])
ipa_groups_formated[ipa_group_name] = ["{}@hyperus.team".format(user) for user in ipa_group["member_user"]]
return ipa_groups_formated
def get_pgs_groups(self) -> dict:
pgs_groups_formated = {}
response = requests.get(url=f"{self.pgs_adminapi_address}/tenants/{self.pgs_adminapi_tenant}/groups", headers=self.__pgs_adminapi_header, verify=False)
if response.status_code == 200:
pgs_groups_finded = response.json()["groups"]
else:
raise Exception("PGS API: can't get groups list")
for pgs_group in pgs_groups_finded:
pgs_groups_formated[pgs_group["name"]] = {}
pgs_groups_formated[pgs_group["name"]]["id"] = pgs_group["id"]
pgs_groups_formated[pgs_group["name"]]["members"] = ["{}".format(user["username"]) for user in pgs_group["users"]]
return pgs_groups_formated
def get_pgs_users(self) -> dict:
pgs_users_formated = {}
response = requests.get(url=f"{self.pgs_adminapi_address}/tenants/{self.pgs_adminapi_tenant}/users", headers=self.__pgs_adminapi_header, verify=False)
if response.status_code == 200:
pgs_users_finded = response.json()["users"]
else:
raise Exception("PGS API: can't get users list")
for pgs_user in pgs_users_finded:
pgs_users_formated[pgs_user["username"]] = pgs_user["id"]
return pgs_users_formated
def compare_groups(self, source={}, destination={}, pgs_users={}) -> None:
if not source:
source = self.get_ipa_groups()
if not destination:
destination = self.get_pgs_groups()
if not pgs_users:
pgs_users = self.get_pgs_users()
to_create_groups = list(filter(lambda group: group not in destination, source))
to_delete_groups = list(filter(lambda group: group not in source, destination))
for group in to_create_groups:
group_members = [pgs_users[username] for username in source[group]]
self.create_pgs_group(group, group_members)
for group in to_delete_groups:
self.delete_pgs_group(destination[group]["id"])
def compare_members(self, source={}, destination={}, pgs_users={}) -> None:
if not source:
source = self.get_ipa_groups()
if not destination:
destination = self.get_pgs_groups()
if not pgs_users:
pgs_users = self.get_pgs_users()
for group in source:
to_create_membership = list(filter( lambda member: member not in destination[group]["members"], source[group] ))
to_remove_membership = list(filter( lambda member: member not in source[group], destination[group]["members"] ))
if len(to_create_membership) > 0:
group_members = [pgs_users[username] for username in to_create_membership]
response = self.set_pgs_group_members("POST", destination[group]["id"], group_members)
if response.status_code == 200:
print("Users has been added to group <{}>".format(group))
else:
raise Exception("Error during adding members to group <{}>".format(group))
if len(to_remove_membership) > 0:
group_members = [pgs_users[username] for username in to_remove_membership]
response = self.set_pgs_group_members("DELETE", destination[group]["id"], group_members)
if response.status_code == 200:
print("Users has been removed from group <{}>".format(group))
else:
raise Exception("Error during removing members from group <{}>".format(group))
def create_pgs_group(self, pgs_group_name, pgs_users={}):
pgs_group_data = {"name": pgs_group_name, "users": pgs_users}
response = requests.post(url=f"{self.pgs_adminapi_address}/tenants/{self.pgs_adminapi_tenant}/groups", headers=self.__pgs_adminapi_header, data=pgs_group_data, verify=False)
if response.status_code == 200:
print("Group <{}> was created".format(pgs_group_name))
else:
raise Exception("Error during creation group <{}>".format(pgs_group_name))
return response
def delete_pgs_group(self, pgs_group_name):
response = requests.delete(url=f"{self.pgs_adminapi_address}/tenants/{self.pgs_adminapi_tenant}/groups/{pgs_group_name}", headers=self.__pgs_adminapi_header, verify=False)
if response.status_code == 200:
print("Group <{}> was deleted".format(pgs_group_name))
else:
raise Exception("Error during removing group <{}>".format(pgs_group_name))
return response
def set_pgs_group_members(self, method, pgs_group_id, pgs_users={}):
pgs_data = {"users": pgs_users}
response = requests.request(method, f"{self.pgs_adminapi_address}/tenants/{self.pgs_adminapi_tenant}/groups/{pgs_group_id}/users", headers=self.__pgs_adminapi_header, data=pgs_data, verify=False)
return response
if __name__ == "__main__":
sync_manager = GroupSyncPGS()
sync_manager.pgs_auth()
pgs_users = sync_manager.get_pgs_users()
ipa_groups = sync_manager.get_ipa_groups()
pgs_groups = sync_manager.get_pgs_groups()
sync_manager.compare_groups(ipa_groups, pgs_groups, pgs_users)
sync_manager.compare_members(ipa_groups, pgs_users=pgs_users)