Skip to content

Commit

Permalink
Create team from group.
Browse files Browse the repository at this point in the history
  • Loading branch information
julialawrence committed Nov 13, 2023
1 parent 2eeccd5 commit 27746c1
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 15 deletions.
37 changes: 28 additions & 9 deletions app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
import json
from models import init_app, db, DataSource, UserDataSourcePermission, User
from forms import DataSourceForm
from azure_active_directory import create_aad_group, add_users_to_aad_group
from azure_active_directory import (
create_aad_group,
add_users_to_aad_group,
create_team_from_group,
)
from cluster_manager import launch_vscode_for_user, sanitize_username
from requests.exceptions import RequestException
from gevent.pywsgi import WSGIServer
Expand All @@ -36,7 +40,7 @@

app.config["SECRET_KEY"] = secrets["session_secret"]
app.config["SESSION_TYPE"] = "filesystem"
app.config['LOGGING_LEVEL'] = 10
app.config["LOGGING_LEVEL"] = 10

# Initialize database
init_app(app)
Expand Down Expand Up @@ -197,6 +201,25 @@ def create_data_source():
flash(
"Data source and associated AAD group created successfully!", "success"
)

team_creation_response = create_team_from_group(
group_id=aad_group_id,
access_token=session.get("token").get("access_token"),
)
if team_creation_response:
team_info = team_creation_response.json()
team_id = team_info.get("id")
if team_id:
data_source.team_id = team_id
db.session.commit()
flash(
"Team created and associated with data source successfully!",
"success",
)
else:
flash("Failed to extract team ID from the response.", "error")
else: # If there was an error
flash("Failed to create the team.", "error")
else:
flash("Failed to create AAD group.", "error")

Expand Down Expand Up @@ -438,13 +461,11 @@ def start_vscode(id):
# Redirect to a waiting page or directly embed the VS Code interface if it's ready
# The implementation of this part can vary based on how you handle the VS Code UI embedding
# return render_template("vscode.html")
vscode_url = url_for('vscode_proxy')
vscode_url = url_for("vscode_proxy")
return redirect(vscode_url)


@app.route(
"/vscode_proxy", methods=["GET", "POST", "PUT", "DELETE", "PATCH"]
)
@app.route("/vscode_proxy", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
def vscode_proxy():
"""
This route acts as a proxy for the VS Code server, forwarding requests and responses.
Expand All @@ -464,9 +485,7 @@ def vscode_proxy():
app.logger.info(f"Service name: {service_name}")

# Construct the URL of the VS Code server for this user.
vscode_url = (
f"http://vscode-service-dbe0354c6b5f4bdc8a356af8d4ec68ed.dataaccessmanager.svc.cluster.local/"
)
vscode_url = f"http://vscode-service-dbe0354c6b5f4bdc8a356af8d4ec68ed.dataaccessmanager.svc.cluster.local/"
app.logger.info(f"VSCode URL: {vscode_url}")

# Check if it's a WebSocket request
Expand Down
39 changes: 37 additions & 2 deletions app/azure_active_directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ def create_aad_group(group_name, description, user_id, access_token, dry_run=Fal
"Content-Type": "application/json",
}

# The payload for the request
# The payload for the request, setting 'visibility' to 'Private' to make a private group
group_data = {
"displayName": group_name,
"description": description,
"mailEnabled": False,
"mailNickname": group_name.replace(" ", "").lower(),
"securityEnabled": True,
"securityEnabled": False, # Unified groups are not security groups
"visibility": "Private", # Setting the group as a private group
}

# If dry_run is enabled, we skip the actual creation process
Expand Down Expand Up @@ -64,6 +65,40 @@ def create_aad_group(group_name, description, user_id, access_token, dry_run=Fal
return None


def create_team_from_group(group_id, access_token):
url = f"https://graph.microsoft.com/v1.0/groups/{group_id}/team"

headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json",
}

team_data = {
"memberSettings": {"allowCreateUpdateChannels": True},
"messagingSettings": {
"allowUserEditMessages": True,
"allowUserDeleteMessages": True,
},
"funSettings": {"allowGiphy": True, "giphyContentRating": "Moderate"},
}

try:
response = requests.put(
url, headers=headers, json=team_data
) # Using PUT as per Graph API documentation for creating team from group
response.raise_for_status()
# If the request was successful, get the JSON response
return response.json()
except requests.exceptions.HTTPError as err:
print(f"An HTTP error occurred: {err}")
flash("An error occurred while creating the team.", "error")
return None
except Exception as e:
print(f"An unexpected error occurred: {e}")
flash("An unexpected error occurred while creating the team.", "error")
return None


def add_user_as_group_admin(group_id, user_id, access_token):
# Microsoft Graph API endpoint to add a member to the group
url = f"https://graph.microsoft.com/v1.0/groups/{group_id}/members/$ref"
Expand Down
17 changes: 13 additions & 4 deletions app/cluster_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ def create_service_account(user_id):
else:
print(f"Failed to check service account {name}: {e}", flush=True)


def deploy_vscode_server(user_id):
namespace = "dataaccessmanager"
sanitized_user_id = sanitize_username(user_id)
Expand All @@ -77,12 +78,15 @@ def deploy_vscode_server(user_id):
],
)
metadata = client.V1ObjectMeta(name=name, labels={"app": name})
pod = client.V1Pod(api_version="v1", kind="Pod", metadata=metadata, spec=pod_spec)
pod = client.V1Pod(
api_version="v1", kind="Pod", metadata=metadata, spec=pod_spec
)
api_instance.create_namespaced_pod(namespace, pod)
print(f"Deployed pod {name}.", flush=True)
else:
print(f"Failed to check pod {name}: {e}", flush=True)


def create_service_for_vscode(user_id):
namespace = "dataaccessmanager"
sanitized_user_id = sanitize_username(user_id)
Expand Down Expand Up @@ -111,6 +115,7 @@ def create_service_for_vscode(user_id):
else:
print(f"Failed to check service {name}: {e}", flush=True)


def wait_for_pod_ready(namespace, pod_name):
# Create a watch object for Pod events
w = watch.Watch()
Expand All @@ -126,6 +131,7 @@ def wait_for_pod_ready(namespace, pod_name):

return False # Default case, though your logic might differ based on how you want to handle timeouts


def wait_for_service_ready(service_url, timeout=300):
"""
Wait for the service to become ready by sending requests to the service URL.
Expand All @@ -138,16 +144,17 @@ def wait_for_service_ready(service_url, timeout=300):
try:
response = requests.get(service_url, timeout=5)
if response.status_code == 200:
print("VSCODE Service is ready",flush=True)
print("VSCODE Service is ready", flush=True)
# Service is ready
return True
except requests.RequestException as e:
print(f"Request failed: {e}")
# Wait for a while before retrying
time.sleep(5)
print("VSCODE Service is NOT ready",flush=True)
print("VSCODE Service is NOT ready", flush=True)
return False # Timeout reached


def launch_vscode_for_user(user_id):
# Step 1: Create a service account for the user
create_service_account(user_id)
Expand All @@ -164,7 +171,9 @@ def launch_vscode_for_user(user_id):
namespace = "dataaccessmanager"

# if wait_for_pod_ready(namespace, pod_name):
if wait_for_service_ready(service_url="http://vscode-service-dbe0354c6b5f4bdc8a356af8d4ec68ed.dataaccessmanager.svc.cluster.local/"):
if wait_for_service_ready(
service_url="http://vscode-service-dbe0354c6b5f4bdc8a356af8d4ec68ed.dataaccessmanager.svc.cluster.local/"
):
print("VS Code server is ready for use.")
else:
print("There was a problem starting the VS Code server.")
Expand Down
1 change: 1 addition & 0 deletions app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class DataSource(db.Model):
)
created_by = db.Column(db.String(255), db.ForeignKey("users.id"))
aad_group_id = db.Column(db.String(255), unique=True)
teams_id = db.Column(db.String(255), unique=True)

# Relationships
permissions = db.relationship(
Expand Down

0 comments on commit 27746c1

Please sign in to comment.