Skip to content

Commit 651badb

Browse files
Merge remote-tracking branch 'origin/master' into feature/SK-1336
2 parents 23cdf7e + 5b258fa commit 651badb

32 files changed

+784
-905
lines changed

.ci/tests/studio/studio.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ fi
3232
fedn studio login -u $STUDIO_USER -P $STUDIO_PASSWORD -H $STUDIO_HOST
3333
TAG=sha-$(git rev-parse HEAD | cut -c1-7)
3434
PROJECT_NAME=citest_$TAG
35-
fedn project create -n $PROJECT_NAME -H $STUDIO_HOST --branch main --repository ghcr.io/scaleoutsystems/fedn --image fedn:$TAG --no-interactive
35+
fedn project create -n $PROJECT_NAME -H $STUDIO_HOST --branch $STUDIO_BRANCH --repository ghcr.io/scaleoutsystems/fedn --image fedn:$TAG --no-interactive
3636
for i in {1..10}; do echo "Attempt $i of 10"; if ! fedn project list -H $STUDIO_HOST | awk -F'|' -v project="$PROJECT_NAME" '$1 ~ project {gsub(/^[ \t]+|[ \t]+$/, "", $4); if ($4 == "active") {exit 1} else {exit 0}}'; then echo "Status is active, exiting"; break; else echo "Status is not active, sleeping..."; sleep 5; fi; done
3737
FEDN_PROJECT=$(fedn project list -H $STUDIO_HOST | awk -F'|' -v project="$PROJECT_NAME" '$1 ~ project {gsub(/^[ \t]+|[ \t]+$/, "", $2); print $2}')
3838
fedn project set-context -id $FEDN_PROJECT -H $STUDIO_HOST

.github/dependabot.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ updates:
1212
reviewers:
1313
- "Wrede"
1414
- "stefanhellander"
15+
- "niklastheman"
1516
# To ignore a dependency, uncomment the next two lines and replace "example-package" with the name of the dependency
1617
#ignore:
1718
# - dependency-name: "example-package"
18-
# versions: ["< 1.0.0"]
19+
# versions: ["< 1.0.0"]

.github/workflows/integration-test-studio.yaml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ on:
4141
description: 'Array Size Factor, used in load-test, 1 = 144MB'
4242
required: false
4343
default: '1'
44-
FEDN_CLIENT_TIMEOUT:
45-
description: 'Client Connection Timeout (OBS - not related to round timeout)'
44+
STUDIO_BRANCH:
45+
description: 'Branch to test fedn chart'
4646
required: false
47-
default: '420'
47+
default: 'main'
4848

4949
jobs:
5050
integration-test:
@@ -84,8 +84,9 @@ jobs:
8484
echo "FEDN_NR_EXPECTED_AGG=${{ github.event.inputs.FEDN_NR_EXPECTED_AGG || '2' }}" >> .ci/tests/studio/.env
8585
echo "FEDN_SESSION_TIMEOUT=${{ github.event.inputs.FEDN_SESSION_TIMEOUT || '420' }}" >> .ci/tests/studio/.env
8686
echo "FEDN_ARRAY_SIZE_FACTOR=${{ github.event.inputs.FEDN_ARRAY_SIZE_FACTOR || '1' }}" >> .ci/tests/studio/.env
87-
echo "FEDN_CLIENT_TIMEOUT=${{ github.event.inputs.FEDN_CLIENT_TIMEOUT || '420' }}" >> .ci/tests/studio/.env
87+
echo "FEDN_CLIENT_TIMEOUT=420" >> .ci/tests/studio/.env
8888
echo "FEDN_PACKAGE_EXTRACT_DIR=client" >> .ci/tests/studio/.env
89+
echo "STUDIO_BRANCH=${{ github.event.inputs.STUDIO_BRANCH || 'main' }}" >> .ci/tests/studio/.env
8990
9091
- name: Run integration tests
9192
env:

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
author = "Scaleout Systems AB"
1212

1313
# The full version, including alpha/beta/rc tags
14-
release = "0.28.1"
14+
release = "0.30.0"
1515

1616
# Add any Sphinx extension module names here, as strings
1717
extensions = [

examples/api-tutorials/Local_Compute_Example.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
},
2727
{
2828
"cell_type": "code",
29-
"execution_count": 7,
29+
"execution_count": null,
3030
"id": "c4d3134e-f22c-40af-989d-439c9867acc0",
3131
"metadata": {},
3232
"outputs": [],

examples/async-clients/run_clients.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818
from io import BytesIO
1919
from multiprocessing import Process
2020

21+
import click
2122
import numpy as np
2223
from init_seed import compile_model, make_data
2324
from sklearn.metrics import accuracy_score
24-
import click
2525

2626
from config import settings
2727
from fedn import FednClient
@@ -168,7 +168,9 @@ def run_client(name="client", client_id=None, no_discovery=False, intermittent=F
168168
else:
169169
fl_client.run()
170170

171+
171172
if __name__ == "__main__":
173+
172174
@click.command()
173175
@click.option("--name", "-n", default="client", help="Base name for clients (will be appended with number)")
174176
@click.option("--no-discovery", is_flag=True, help="Connect to combiner without discovery service")

examples/mnist-pytorch/client/validate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
import sys
33

44
import torch
5+
from data import load_data
56
from model import load_parameters
67

7-
from data import load_data
88
from fedn.utils.helpers.helpers import save_metrics
99

1010
dir_path = os.path.dirname(os.path.realpath(__file__))

fedn/cli/client_cmd.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ def client_start_v2_cmd(
269269
if token and token != "":
270270
config["token"] = token
271271
if config["token"]:
272-
click.echo(f"Input param token: {token} overrides value from file")
272+
click.echo("Input param token overrides value from file")
273273

274274
if name and name != "":
275275
config["name"] = name

fedn/cli/project_cmd.py

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ def delete_project(ctx, id: str = None, protocol: str = None, host: str = None,
4949

5050

5151
@click.option("-n", "--name", required=False, default=None, help="Name of new project.")
52+
@click.option("-n", "--nr-of-combiners", required=False, default=1, help="Number of combiners for the project (admin feature).")
5253
@click.option("-p", "--protocol", required=False, default=STUDIO_DEFAULTS["protocol"], help="Communication protocol of studio (api)")
5354
@click.option("-H", "--host", required=False, default=STUDIO_DEFAULTS["host"], help="Hostname of studio (api)")
5455
@click.option("--branch", required=False, default=None, help="Studio branch (default main). Requires admin in Studio")
@@ -61,6 +62,7 @@ def delete_project(ctx, id: str = None, protocol: str = None, host: str = None,
6162
def create_project(
6263
ctx,
6364
name: str = None,
65+
nr_of_combiners: int = 1,
6466
protocol: str = None,
6567
host: str = None,
6668
no_interactive: bool = False,
@@ -90,7 +92,11 @@ def create_project(
9092
else:
9193
# Call the authentication API
9294
try:
93-
response = requests.post(url, data={"name": name, "studio_branch": branch, "fedn_image": image, "fedn_repo": repository}, headers=headers)
95+
response = requests.post(
96+
url,
97+
data={"name": name, "nr_of_combiners": nr_of_combiners, "studio_branch": branch, "fedn_image": image, "fedn_repo": repository},
98+
headers=headers,
99+
)
94100
response_message = response.json().get("message")
95101
if response.status_code == 201:
96102
click.secho(f"Project with name '{name}' created.", fg="green")
@@ -260,3 +266,54 @@ def no_project_exists(response) -> bool:
260266
elif response_json.get("error"):
261267
return True
262268
return False
269+
270+
271+
@click.option("-id", "--id", required=True, help="Slug of the project to add the combiner to.")
272+
@click.option("-nr_of_combiners", "--nr_of_combiners", required=True, help="Total number of combiners to deploy.")
273+
@click.option("--branch", required=False, default=None, help="Studio branch (optional)")
274+
@click.option("--image", required=False, default=None, help="FEDn image (optional)")
275+
@click.option("--repository", required=False, default=None, help="FEDn repo URL (optional)")
276+
@click.option("-p", "--protocol", required=False, default=STUDIO_DEFAULTS["protocol"], help="Protocol to use for Studio API")
277+
@click.option("-H", "--host", required=False, default=STUDIO_DEFAULTS["host"], help="Host to use for Studio API")
278+
@project_cmd.command("add-combiner")
279+
@click.pass_context
280+
def add_combiner_to_project(
281+
ctx,
282+
id: str,
283+
nr_of_combiners: str,
284+
branch: str = None,
285+
image: str = None,
286+
repository: str = None,
287+
protocol: str = None,
288+
host: str = None,
289+
):
290+
"""Add a Combiner (and optional Server Functions) to an existing project."""
291+
studio_api = True
292+
headers = {"Content-Type": "application/json"}
293+
294+
_token = get_token(None, True)
295+
if _token:
296+
headers["Authorization"] = _token
297+
298+
url = get_api_url(protocol=protocol, host=host, port=None, endpoint="projects/add_combiner", usr_api=studio_api)
299+
300+
payload = {
301+
"project_slug": id,
302+
"nr_of_combiners": nr_of_combiners,
303+
}
304+
if branch:
305+
payload["studio_branch"] = branch
306+
if image:
307+
payload["fedn_image"] = image
308+
if repository:
309+
payload["fedn_repo"] = repository
310+
311+
try:
312+
response = requests.post(url, json=payload, headers=headers)
313+
if response.status_code in [200, 201, 202]:
314+
click.secho(f"Combiner deployment initiated for project '{id}'.", fg="green")
315+
else:
316+
click.secho(f"Failed to initiate combiner deployment: {response.status_code}", fg="red")
317+
print_response(response, "error", True)
318+
except requests.exceptions.RequestException as e:
319+
click.secho(f"Request failed: {e}", fg="red")

fedn/cli/shared.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ def get_project_url(protocol: str, host: str, port: str, endpoint: str) -> str:
7171

7272

7373
def get_token(token: str, usr_token: bool) -> str:
74-
_token = token or os.environ.get("FEDN_AUTH_TOKEN", None)
74+
_token = None
75+
if token and isinstance(token, str) and len(token) > 0:
76+
_token = token
7577

7678
if _token is None:
7779
context_path = os.path.join(HOME_DIR, ".fedn")
@@ -82,8 +84,12 @@ def get_token(token: str, usr_token: bool) -> str:
8284
else:
8385
_token = context_data.get("Active project tokens").get("access")
8486
except Exception as e:
87+
_token = None
8588
click.secho(f"Encountered error {e}. Make sure you are logged in and have activated a project.", fg="red")
8689

90+
if _token is None:
91+
_token = token or os.environ.get("FEDN_AUTH_TOKEN", None)
92+
8793
scheme = os.environ.get("FEDN_AUTH_SCHEME", "Bearer")
8894

8995
return f"{scheme} {_token}"

0 commit comments

Comments
 (0)