Fix infra samples from local verification
This commit is contained in:
parent
397aed251f
commit
f191a276a8
13 changed files with 95 additions and 10 deletions
|
|
@ -8,7 +8,7 @@ Image=docker.io/library/postgres:18
|
|||
ContainerName=dew_keycloak-postgresql
|
||||
Network=dew_keycloak.network
|
||||
NetworkAlias=postgres
|
||||
Volume=dew_keycloak-postgresql.volume:/var/lib/postgresql/data
|
||||
Volume=dew_keycloak-postgresql.volume:/var/lib/postgresql
|
||||
Environment=POSTGRES_DB=keycloak
|
||||
Environment=POSTGRES_USER=keycloak
|
||||
Environment=POSTGRES_PASSWORD=keycloak_dev_password
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
FROM docker.io/library/alpine:3.23
|
||||
FROM docker.io/library/nginx:alpine
|
||||
|
||||
RUN mkdir -p /srv/www \
|
||||
&& printf '{"service":"local-api-build","status":"ok"}\n' > /srv/www/index.html
|
||||
RUN printf '{"service":"local-api-build","status":"ok"}\n' \
|
||||
> /usr/share/nginx/html/index.html
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD ["busybox", "httpd", "-f", "-p", "8080", "-h", "/srv/www"]
|
||||
EXPOSE 80
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ File=Containerfile
|
|||
SetWorkingDirectory=unit
|
||||
|
||||
[Service]
|
||||
RemainAfterExit=yes
|
||||
TimeoutStartSec=900
|
||||
|
||||
[Install]
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ After=dew_local-api-build.build
|
|||
[Container]
|
||||
Image=dew_local-api-build.build
|
||||
ContainerName=dew_local-api-build
|
||||
PublishPort=127.0.0.1:8090:8080
|
||||
PublishPort=127.0.0.1:8090:80
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ quadlets:
|
|||
unit: dew_local-api-build.service
|
||||
container_name: dew_local-api-build
|
||||
|
||||
files:
|
||||
- Containerfile
|
||||
|
||||
schemas:
|
||||
configure: schemas/configure.schema.json
|
||||
init: schemas/init.schema.json
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ Environment=POSTGRES_DB=dew
|
|||
Environment=POSTGRES_USER=dew
|
||||
Environment=POSTGRES_PASSWORD=dew_dev_password
|
||||
PublishPort=127.0.0.1:5432:5432
|
||||
Volume=dew_postgresql-18_data:/var/lib/postgresql/data:Z
|
||||
Volume=dew_postgresql-18_data:/var/lib/postgresql:Z
|
||||
HealthCmd=pg_isready -U dew -d dew
|
||||
HealthInterval=10s
|
||||
HealthTimeout=5s
|
||||
|
|
|
|||
8
.project/kanban/done/DEW-0036.md
Normal file
8
.project/kanban/done/DEW-0036.md
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
id: DEW-0036
|
||||
title: Verify infra samples locally
|
||||
type: task
|
||||
created: 2026-05-05T04:28:49.175443Z
|
||||
---
|
||||
|
||||
Bring up the new sample infrastructure services with dew infra, verify they start and respond as expected, then stop them without deleting retained data volumes.
|
||||
|
|
@ -51,6 +51,9 @@ The `quadlets` list can contain any supported Podman Quadlet source type:
|
|||
from the Quadlet filename. Declare `unit` when the Quadlet file uses a
|
||||
`ServiceName=` override.
|
||||
|
||||
Use `files` for non-Quadlet assets that must be installed beside the Quadlet
|
||||
files, such as a `Containerfile` used by a `.build` unit.
|
||||
|
||||
The package-level schema for this file is
|
||||
`packages/infra/schemas/service-manifest.schema.json`.
|
||||
|
||||
|
|
|
|||
|
|
@ -167,6 +167,9 @@ class InfraValidator {
|
|||
issues,
|
||||
);
|
||||
}
|
||||
for (final path in manifest.filePaths) {
|
||||
await _requireFile(manifest, path, issues);
|
||||
}
|
||||
await _validateJsonSchema(
|
||||
manifest,
|
||||
label: 'configure schema',
|
||||
|
|
|
|||
|
|
@ -222,6 +222,12 @@ class PodmanQuadletRuntime implements ContainerRuntime {
|
|||
await fs.link(target).exists() || await fs.file(target).exists();
|
||||
if (!exists) return false;
|
||||
}
|
||||
for (final file in manifest.files) {
|
||||
final target = _targetFilePath(file, scope);
|
||||
final exists =
|
||||
await fs.link(target).exists() || await fs.file(target).exists();
|
||||
if (!exists) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -268,6 +274,14 @@ class PodmanQuadletRuntime implements ContainerRuntime {
|
|||
}
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < manifest.files.length; i++) {
|
||||
await _link(
|
||||
actions,
|
||||
dryRun,
|
||||
manifest.filePaths[i],
|
||||
_targetFilePath(manifest.files[i], scope),
|
||||
);
|
||||
}
|
||||
|
||||
return InfraRuntimeResult(actions: actions);
|
||||
}
|
||||
|
|
@ -291,6 +305,9 @@ class PodmanQuadletRuntime implements ContainerRuntime {
|
|||
);
|
||||
}
|
||||
}
|
||||
for (final file in manifest.files) {
|
||||
await _deletePath(actions, dryRun, _targetFilePath(file, scope));
|
||||
}
|
||||
return InfraRuntimeResult(actions: actions);
|
||||
}
|
||||
|
||||
|
|
@ -409,6 +426,9 @@ class PodmanQuadletRuntime implements ContainerRuntime {
|
|||
p.basename(quadlet.file),
|
||||
);
|
||||
|
||||
String _targetFilePath(String file, InfraScope scope) =>
|
||||
p.join(quadletSearchPath(scope, environment: environment), file);
|
||||
|
||||
Future<void> _link(
|
||||
List<String> actions,
|
||||
bool dryRun,
|
||||
|
|
@ -416,6 +436,7 @@ class PodmanQuadletRuntime implements ContainerRuntime {
|
|||
String target,
|
||||
) async {
|
||||
await _action(actions, dryRun, 'link $source -> $target', () async {
|
||||
await fs.directory(p.dirname(target)).create(recursive: true);
|
||||
await _deleteIfExists(target);
|
||||
await fs.link(target).create(source, recursive: true);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -153,6 +153,7 @@ class InfraServiceManifest {
|
|||
required this.serviceDir,
|
||||
required this.manifestPath,
|
||||
required this.quadlets,
|
||||
this.files = const [],
|
||||
this.configureSchema,
|
||||
this.initSchema,
|
||||
});
|
||||
|
|
@ -175,6 +176,9 @@ class InfraServiceManifest {
|
|||
/// Quadlet files deployed for this service.
|
||||
final List<InfraQuadletManifest> quadlets;
|
||||
|
||||
/// Additional files installed beside Quadlets for build contexts or assets.
|
||||
final List<String> files;
|
||||
|
||||
/// Optional relative path to the configure JSON Schema.
|
||||
final String? configureSchema;
|
||||
|
||||
|
|
@ -198,6 +202,9 @@ class InfraServiceManifest {
|
|||
/// Active init payload path.
|
||||
String get activeInitPath => p.join(configDir, 'init.json');
|
||||
|
||||
/// Absolute paths to additional installed files.
|
||||
List<String> get filePaths => files.map(_resolve).toList();
|
||||
|
||||
/// Units generated by the declared Quadlet files.
|
||||
List<String> get units =>
|
||||
quadlets.map((quadlet) => quadlet.serviceUnit).toList();
|
||||
|
|
@ -231,6 +238,7 @@ class InfraServiceManifest {
|
|||
serviceDir: serviceDir,
|
||||
manifestPath: manifestPath,
|
||||
quadlets: quadlets,
|
||||
files: _optionalStringList(map, 'files'),
|
||||
configureSchema: schemas == null
|
||||
? null
|
||||
: _optionalString(schemas, 'configure'),
|
||||
|
|
@ -246,6 +254,7 @@ class InfraServiceManifest {
|
|||
'manifest': manifestPath,
|
||||
'units': units,
|
||||
'quadlets': quadlets.map((quadlet) => quadlet.toJson()).toList(),
|
||||
'files': filePaths,
|
||||
'configure_schema': configureSchemaPath,
|
||||
'init_schema': initSchemaPath,
|
||||
'active_config': activeConfigurePath,
|
||||
|
|
@ -311,6 +320,20 @@ List<dynamic> _requiredList(Map<String, dynamic> map, String key) {
|
|||
throw FormatException('manifest.yaml is missing list "$key".');
|
||||
}
|
||||
|
||||
List<String> _optionalStringList(Map<String, dynamic> map, String key) {
|
||||
final value = map[key];
|
||||
if (value == null) return const [];
|
||||
if (value is! List) {
|
||||
throw FormatException('manifest.yaml field "$key" must be a list.');
|
||||
}
|
||||
return value.map((item) {
|
||||
if (item is String && item.isNotEmpty) return item;
|
||||
throw FormatException(
|
||||
'manifest.yaml field "$key" must contain non-empty strings.',
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
String _requiredString(Map<String, dynamic> map, String key) {
|
||||
final value = _optionalString(map, key);
|
||||
if (value == null || value.isEmpty) {
|
||||
|
|
|
|||
|
|
@ -61,6 +61,15 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"type": "array",
|
||||
"description": "Additional files installed beside Quadlets, such as Containerfiles for build contexts.",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"pattern": "^[^/].*$"
|
||||
}
|
||||
},
|
||||
"schemas": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ void main() {
|
|||
'install dry-run reports symlink actions without writing files',
|
||||
() async {
|
||||
final fs = MemoryFileSystem.test();
|
||||
_writeService(fs, includeNetwork: true);
|
||||
_writeService(fs, includeNetwork: true, includeFile: true);
|
||||
final manifest = await InfraRepository(
|
||||
infraDir: '/project/.project/infrastructure',
|
||||
fs: fs,
|
||||
|
|
@ -133,6 +133,7 @@ void main() {
|
|||
|
||||
expect(result.actions.join('\n'), contains('app_postgres.container'));
|
||||
expect(result.actions.join('\n'), contains('app_postgres.network'));
|
||||
expect(result.actions.join('\n'), contains('Containerfile'));
|
||||
expect(
|
||||
await fs
|
||||
.link(
|
||||
|
|
@ -174,6 +175,7 @@ void _writeService(
|
|||
String serviceId = 'postgres',
|
||||
String unit = 'app_postgres.service',
|
||||
bool includeNetwork = false,
|
||||
bool includeFile = false,
|
||||
}) {
|
||||
final serviceDir = fs.directory(
|
||||
'/project/.project/infrastructure/services/postgres',
|
||||
|
|
@ -188,6 +190,11 @@ void _writeService(
|
|||
.file('${serviceDir.path}/app_postgres.network')
|
||||
.writeAsStringSync('[Network]\nNetworkName=app_postgres\n');
|
||||
}
|
||||
if (includeFile) {
|
||||
fs
|
||||
.file('${serviceDir.path}/Containerfile')
|
||||
.writeAsStringSync('FROM scratch\n');
|
||||
}
|
||||
fs
|
||||
.file('${serviceDir.path}/configure.schema.json')
|
||||
.writeAsStringSync('{"type":"object"}');
|
||||
|
|
@ -197,6 +204,13 @@ void _writeService(
|
|||
final networkQuadlet = includeNetwork
|
||||
? '''
|
||||
- file: app_postgres.network
|
||||
'''
|
||||
: '';
|
||||
final files = includeFile
|
||||
? '''
|
||||
files:
|
||||
- Containerfile
|
||||
|
||||
'''
|
||||
: '';
|
||||
fs.file('${serviceDir.path}/manifest.yaml').writeAsStringSync('''
|
||||
|
|
@ -214,6 +228,7 @@ quadlets:
|
|||
profiles_dir: app_postgres.profiles.d
|
||||
$networkQuadlet
|
||||
|
||||
$files
|
||||
schemas:
|
||||
configure: configure.schema.json
|
||||
init: init.schema.json
|
||||
|
|
@ -234,6 +249,7 @@ Map<String, Object?> _manifestObject() => {
|
|||
},
|
||||
{'file': 'app_postgres.network'},
|
||||
],
|
||||
'files': ['Containerfile'],
|
||||
'schemas': {'configure': 'configure.schema.json', 'init': 'init.schema.json'},
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue