Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Self-service building (backend pieces) #39

Merged
merged 14 commits into from
Jan 29, 2024
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,21 @@ $ source spack/share/spack/setup-env.sh
```

To start the service, you will also need to configure a git repository to store
artifacts.
artifacts, and configure details of an LDAP server to query group information:

```yaml
artifacts:
repo: # see "integration tests" below

ldap:
server: "ldaps://ldap.example"
base: "ou=group,dc=example,dc=ac,dc=uk"
filter: "memberuid={user}"
group:
attr: "cn"
pattern: ".*"

```

### Stable release

Expand Down
91 changes: 89 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ types-setuptools = "^67.7.0.1"
types-PyYAML = "^6.0.12.9"
types-requests = "^2.30.0.0"
virtualenv = "^20.20.0"
watchfiles = "^0.21.0"

[tool.poetry.group.doc]
optional = true
Expand Down
6 changes: 5 additions & 1 deletion softpack_core/config/conf/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ server:
- http://localhost:3000
- http://localhost:5173

builder:
host: 0.0.0.0
port: 8001

artifacts:
repo:
url: https://github.com/mjkw31/softpack-artifacts
Expand All @@ -35,4 +39,4 @@ spack:
# filter:
# group:
# attr:
# pattern:
# pattern:
7 changes: 7 additions & 0 deletions softpack_core/config/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ class HeaderConfig(BaseModel):
port: int


class BuilderConfig(BaseModel):
"""Builder config model."""

host: str
port: int


class VaultConfig(BaseModel):
"""HashiCorp vault config."""

Expand Down
2 changes: 2 additions & 0 deletions softpack_core/config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from .models import (
ArtifactsConfig,
BuilderConfig,
LDAPConfig,
ServerConfig,
SpackConfig,
Expand All @@ -32,6 +33,7 @@ class Settings(BaseSettings):
ldap: Optional[LDAPConfig]
artifacts: ArtifactsConfig
spack: SpackConfig
builder: BuilderConfig

class Config:
"""Configuration loader."""
Expand Down
6 changes: 4 additions & 2 deletions softpack_core/graphql.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@
from .app import app
from .schemas.base import BaseSchema
from .schemas.environment import EnvironmentSchema
from .schemas.groups import GroupsSchema
from .schemas.package_collection import PackageCollectionSchema


class GraphQL(API):
"""GraphQL API."""

prefix = "/graphql"
schemas = [EnvironmentSchema, PackageCollectionSchema]
schemas = [EnvironmentSchema, PackageCollectionSchema, GroupsSchema]
commands = Typer(help="GraphQL commands.")

@staticmethod
Expand Down Expand Up @@ -126,4 +127,5 @@ def __init__(self, schema: strawberry.Schema, prefix: str) -> None:
"""
super().__init__(schema=schema, path=prefix)

router = Router(schema=Schema(schemas), prefix=prefix)
schema = Schema(schemas)
router = Router(schema=schema, prefix=prefix)
60 changes: 45 additions & 15 deletions softpack_core/schemas/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
import io
from dataclasses import dataclass
from pathlib import Path
from traceback import format_exception_only
from typing import Iterable, List, Optional, Tuple, Union, cast

import httpx
import starlette.datastructures
import strawberry
from fastapi import UploadFile
from strawberry.file_uploads import Upload
import yaml

from softpack_core.app import app
from softpack_core.artifacts import Artifacts, Package, State
from softpack_core.module import GenerateEnvReadme, ToSoftpackYML
from softpack_core.schemas.base import BaseSchema
Expand Down Expand Up @@ -80,13 +83,19 @@ class EnvironmentAlreadyExistsError(Error):
name: str


@strawberry.type
class BuilderError(Error):
"""Unable to connect to builder."""


# Unions
CreateResponse = strawberry.union(
"CreateResponse",
[
CreateEnvironmentSuccess,
InvalidInputError,
EnvironmentAlreadyExistsError,
BuilderError,
],
)

Expand Down Expand Up @@ -252,19 +261,31 @@ def create(cls, env: EnvironmentInput) -> CreateResponse: # type: ignore

env.name = name

# TODO: remove hard-coding of URL.
# Send build request
httpx.post(
"http://0.0.0.0:7080/environments/build",
json={
"name": f"{env.path}/{env.name}",
"version": str(version),
"model": {
"description": env.description,
"packages": [f"{pkg.name}" for pkg in env.packages],
try:
r = httpx.post(
f"http://{app.settings.builder.host}:{app.settings.builder.port}/environments/build",
json={
"name": f"{env.path}/{env.name}",
"version": str(version),
"model": {
"description": env.description,
"packages": [
{
"name": pkg.name,
"version": pkg.version,
}
for pkg in env.packages
],
},
},
},
)
)
r.raise_for_status()
except Exception as e:
return BuilderError(
message="Connection to builder failed: "
+ "".join(format_exception_only(e))
)

return CreateEnvironmentSuccess(
message="Successfully scheduled environment creation"
Expand Down Expand Up @@ -310,14 +331,23 @@ def create_new_env(
# Create folder with place-holder file
new_folder_path = Path(env.path, env.name)
try:
tree_oid = cls.artifacts.create_file(
new_folder_path, env_type, "", True
softpack_definition = dict(
description = env.description,
packages = [pkg.name + ("@" + pkg.version if pkg.version else "") for pkg in env.packages]
)
ymlData = yaml.dump(softpack_definition)

tree_oid = cls.artifacts.create_files(
new_folder_path, [
(env_type, ""), # e.g. .built_by_softpack
(cls.artifacts.environments_file, ymlData) # softpack.yml
], True
)
cls.artifacts.commit_and_push(
tree_oid, "create environment folder"
)
except RuntimeError as e:
return InvalidInputError(message=str(e))
return InvalidInputError(message="".join(format_exception_only(e)))

return CreateEnvironmentSuccess(
message="Successfully created environment in artifacts repo"
Expand Down Expand Up @@ -535,7 +565,7 @@ async def write_artifacts(
)

except Exception as e:
return InvalidInputError(message=str(e))
return InvalidInputError(message="".join(format_exception_only(e)))

@classmethod
async def update_from_module(
Expand Down
Loading
Loading