diff --git a/api_docs.yml b/api_docs.yml index 89c48ab0..2bb2b96d 100644 --- a/api_docs.yml +++ b/api_docs.yml @@ -3739,6 +3739,34 @@ paths: 500: description: "Internal Server Error" + "/apps/{app_id}/restart": + post: + description: "restarts app by pulling the latest image" + tags: + - apps + consumes: + - application/json + parameters: + - in: header + name: Authorization + required: true + description: "Bearer [token]" + type: string + - in: path + name: app_id + required: true + type: string + + responses: + 201: + description: "Success" + 404: + description: "App not found" + 400: + description: "Bad request" + 500: + description: "Internal Server Error" + "/apps/{app_id}/{user_id}/docker/{tag}/webhook": post: description: "redeploys apps by getting webhook notifiations from docker" diff --git a/app/controllers/app.py b/app/controllers/app.py index f2222263..6024d8cf 100644 --- a/app/controllers/app.py +++ b/app/controllers/app.py @@ -1217,6 +1217,72 @@ def get(self, app_id): return dict(status='fail', message=str(exc)), 500 +class AppRestartView(Resource): + @jwt_required + def post(self, app_id): + """ + restart app, to pull the latest images + """ + try: + current_user_id = get_jwt_identity() + current_user_roles = get_jwt_claims()['roles'] + app = App.get_by_id(app_id) + + if not app: + return dict(status='fail', message=f'App {app_id} not found'), 404 + + project = app.project + + if not is_owner_or_admin(project, current_user_id, current_user_roles): + if not is_authorised_project_user(project, current_user_id, 'admin'): + return dict(status='fail', message='Unauthorised'), 403 + + cluster = project.cluster + namespace = project.alias + if not cluster or not namespace: + return dict(status='fail', message='Internal server error'), 500 + + kube_host = cluster.host + kube_token = cluster.token + kube_client = create_kube_clients(kube_host, kube_token) + + dep_name = f'{app.alias}-deployment' + + # Create restart annotation + now = datetime.datetime.utcnow().isoformat() + + patch_body = { + "spec": { + "template": { + "metadata": { + "annotations": { + "kubectl.kubernetes.io/restartedAt": now + } + } + } + } + } + # Patch the deployment + kube_client.appsv1_api.patch_namespaced_deployment( + name=dep_name, + namespace=namespace, + body=patch_body, + _preload_content=False + ) + + log_activity('App', status='Success', + operation='Restart', + description='App restarted successfully', + a_project=project, + a_cluster_id=project.cluster_id, + a_app=app) + return dict(status='success', message='App restarted successfully'), 200 + except client.rest.ApiException as exc: + return dict(status='fail', message=exc.reason), check_kube_error_code(exc.status) + except Exception as exc: + return dict(status='fail', message=str(exc)), 500 + + class AppRevertView(Resource): @jwt_required def patch(self, app_id): diff --git a/app/routes/__init__.py b/app/routes/__init__.py index b05fcdb0..a8cdb852 100644 --- a/app/routes/__init__.py +++ b/app/routes/__init__.py @@ -15,8 +15,8 @@ BillingInvoiceView, BillingInvoiceNotificationView, SystemSummaryView, CreditDetailView, ProjectUsersView, ProjectUsersTransferView, AppReviseView, ProjectUsersHandleInviteView, ClusterProjectsView, ProjectDisableView, ProjectEnableView, AppRedeployView, AppDisableView, AppEnableView, TagsView, TagsDetailView, TagFollowingView, GenericSearchView, MLProjectAppsView, ProjectMigrationView, - UserDisableView, UserEnableView, AppDockerWebhookListenerView, UserFollowersView, UserFollowView, ProjectFollowingView, ActivityFeedView, SendInactiveUserMailReminder,GoogleOAuthView,TagProjectsView) -from app.controllers.app import AppRevisionsView + UserDisableView, UserEnableView, AppDockerWebhookListenerView, UserFollowersView, UserFollowView, ProjectFollowingView, ActivityFeedView, SendInactiveUserMailReminder, GoogleOAuthView, TagProjectsView) +from app.controllers.app import AppRestartView, AppRevisionsView from app.controllers.app_domain import AppDomainView, AppDomainDetailView from app.controllers.billing_invoice import BillingInvoiceDetailView from app.controllers.receipts import BillingReceiptsDetailView, BillingReceiptsView @@ -172,6 +172,7 @@ api.add_resource(AppDetailView, '/apps/') api.add_resource(AppRevertView, '/apps//revert_url') api.add_resource(AppRevisionsView, '/apps//revisions') +api.add_resource(AppRestartView, '/apps//restart') api.add_resource( AppReviseView, '/apps//revise/') api.add_resource( @@ -189,7 +190,8 @@ # App Domain routes api.add_resource(AppDomainView, '/apps//domains') -api.add_resource(AppDomainDetailView, '/apps//domains/') +api.add_resource(AppDomainDetailView, + '/apps//domains/') # Registry routes @@ -211,4 +213,4 @@ api.add_resource(SendInactiveUserMailReminder, '/users/inactive_user_reminder', endpoint='inactive_user_reminder') -api.add_resource(SocialView, '/socials', endpoint='socials') \ No newline at end of file +api.add_resource(SocialView, '/socials', endpoint='socials')