deploy(devicemgmt): enable web runtime

This commit is contained in:
Andrew Stoltz
2026-06-11 14:21:51 -05:00
parent 2707f1ae1e
commit 3798b7c00e
4 changed files with 230 additions and 46 deletions

View File

@@ -11,7 +11,7 @@ metadata:
flowercore.io/created-by: bluejay-infra flowercore.io/created-by: bluejay-infra
rules: rules:
- apiGroups: - apiGroups:
- devices.flowercore.io - flowercore.io
resources: resources:
- '*' - '*'
verbs: verbs:
@@ -23,7 +23,7 @@ rules:
- patch - patch
- delete - delete
- apiGroups: - apiGroups:
- devices.flowercore.io - flowercore.io
resources: resources:
- devices/status - devices/status
- devices/finalizers - devices/finalizers
@@ -33,6 +33,8 @@ rules:
- devicepolicies/finalizers - devicepolicies/finalizers
- remotecommands/status - remotecommands/status
- remotecommands/finalizers - remotecommands/finalizers
- desiredstatedocuments/status
- desiredstatedocuments/finalizers
verbs: verbs:
- get - get
- update - update

View File

@@ -0,0 +1,186 @@
# FlowerCore.DeviceManagement CRDs.
#
# These CRDs match the current operator annotations:
# [KubernetesEntity(Group = "flowercore.io", ApiVersion = "v1alpha1", ...)]
# Keep the schemas intentionally permissive until the DeviceManagement operator
# grows enforced CRD validation.
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: devices.flowercore.io
labels:
app.kubernetes.io/name: fc-devicemgmt-operator
app.kubernetes.io/component: operator
app.kubernetes.io/part-of: flowercore
app.kubernetes.io/managed-by: argocd
flowercore.io/tenant-id: system
flowercore.io/created-by: bluejay-infra
spec:
group: flowercore.io
scope: Namespaced
names:
plural: devices
singular: device
kind: Device
listKind: DeviceList
versions:
- name: v1alpha1
served: true
storage: true
subresources:
status: {}
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
x-kubernetes-preserve-unknown-fields: true
status:
type: object
x-kubernetes-preserve-unknown-fields: true
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: devicegroups.flowercore.io
labels:
app.kubernetes.io/name: fc-devicemgmt-operator
app.kubernetes.io/component: operator
app.kubernetes.io/part-of: flowercore
app.kubernetes.io/managed-by: argocd
flowercore.io/tenant-id: system
flowercore.io/created-by: bluejay-infra
spec:
group: flowercore.io
scope: Namespaced
names:
plural: devicegroups
singular: devicegroup
kind: DeviceGroup
listKind: DeviceGroupList
versions:
- name: v1alpha1
served: true
storage: true
subresources:
status: {}
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
x-kubernetes-preserve-unknown-fields: true
status:
type: object
x-kubernetes-preserve-unknown-fields: true
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: devicepolicies.flowercore.io
labels:
app.kubernetes.io/name: fc-devicemgmt-operator
app.kubernetes.io/component: operator
app.kubernetes.io/part-of: flowercore
app.kubernetes.io/managed-by: argocd
flowercore.io/tenant-id: system
flowercore.io/created-by: bluejay-infra
spec:
group: flowercore.io
scope: Namespaced
names:
plural: devicepolicies
singular: devicepolicy
kind: DevicePolicy
listKind: DevicePolicyList
versions:
- name: v1alpha1
served: true
storage: true
subresources:
status: {}
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
x-kubernetes-preserve-unknown-fields: true
status:
type: object
x-kubernetes-preserve-unknown-fields: true
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: remotecommands.flowercore.io
labels:
app.kubernetes.io/name: fc-devicemgmt-operator
app.kubernetes.io/component: operator
app.kubernetes.io/part-of: flowercore
app.kubernetes.io/managed-by: argocd
flowercore.io/tenant-id: system
flowercore.io/created-by: bluejay-infra
spec:
group: flowercore.io
scope: Namespaced
names:
plural: remotecommands
singular: remotecommand
kind: RemoteCommand
listKind: RemoteCommandList
versions:
- name: v1alpha1
served: true
storage: true
subresources:
status: {}
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
x-kubernetes-preserve-unknown-fields: true
status:
type: object
x-kubernetes-preserve-unknown-fields: true
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: desiredstatedocuments.flowercore.io
labels:
app.kubernetes.io/name: fc-devicemgmt-operator
app.kubernetes.io/component: operator
app.kubernetes.io/part-of: flowercore
app.kubernetes.io/managed-by: argocd
flowercore.io/tenant-id: system
flowercore.io/created-by: bluejay-infra
spec:
group: flowercore.io
scope: Namespaced
names:
plural: desiredstatedocuments
singular: desiredstatedocument
kind: DesiredStateDocument
listKind: DesiredStateDocumentList
versions:
- name: v1alpha1
served: true
storage: true
subresources:
status: {}
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
x-kubernetes-preserve-unknown-fields: true
status:
type: object
x-kubernetes-preserve-unknown-fields: true

View File

@@ -5,27 +5,33 @@
# exist yet; import localhost/fc-devicemgmt-web:<tag> to all schedulable RKE2 # exist yet; import localhost/fc-devicemgmt-web:<tag> to all schedulable RKE2
# nodes before letting ArgoCD sync a live rollout. # nodes before letting ArgoCD sync a live rollout.
# #
# SCALED TO 0 — 2026-05-19 morning-routine cleanup. # LIVE — 2026-06-11 DeviceManagement product-host enablement.
# The Web pod cannot start until TWO upstream gaps close: # The current DeviceManagement Web source is SQLite-backed in Program.cs, so
# 1. MySQL DB instance `flowercore_devicemgmt` (user `fc_devicemgmt`) is # Phase 1 production uses a Longhorn RWO PVC at /data/devicemgmt.db. The
# provisioned via fc-mysql Manager. The cluster currently has ZERO # 1Password runtime item stays mounted through env for future MySQL/API-key
# MySqlInstanceCrds and no `mysql.fc-mysql.svc:3306` Service, so the # cutover, but MySQL is not required for this first product-host rollout.
# deployment-web container env `FlowerCore__Database__Host=mysql.fc-mysql.svc` ---
# points at nothing. Provision via the fc-mysql Manager UI/REST/MCP. apiVersion: v1
# 2. 1Password vault item `IAmWorkin/FlowerCore DeviceManagement Runtime` kind: PersistentVolumeClaim
# with 5 fields (DB-Password, mtls-ca.pem, mtls-client.crt, mtls-client.key, metadata:
# mtls-chain.pem) — see apps/fc-devicemgmt/1password-item.yaml. Mint mTLS name: fc-devicemgmt-web-data
# from step-ca-agent ClusterIssuer per ADR-126; DB-Password must match the namespace: fc-devicemgmt
# password configured for the MySQL user. labels:
# Re-enable: change replicas back to 2 after both gaps close. app: fc-devicemgmt-web
# app.kubernetes.io/name: fc-devicemgmt-web
# 2026-06-10 morning-routine refresh: image tag bumped to v20260610-bluejay — app.kubernetes.io/component: web
# built from master @ 1614fce (June 9 network/BT command plane PRs #30/#33/#34, app.kubernetes.io/part-of: flowercore
# Shared.Data 1.0.1, and the Blue Jay UI.Components restyle). Imported on app.kubernetes.io/managed-by: argocd
# rke2-server + rke2-agent1. Gap 1 is wider than noted above: the fc-mysql flowercore.io/tenant-id: system
# OPERATOR deployment itself is absent from the cluster (only mysql-web runs), flowercore.io/created-by: bluejay-infra
# so MySqlInstanceCrds would not reconcile — deploy the operator first. spec:
# Gap 2 (1P runtime item) also remains open; replicas stays 0. accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
@@ -42,7 +48,7 @@ metadata:
annotations: annotations:
flowercore.io/traceability-standard: k8s-pod-ownership-and-traceability-standard flowercore.io/traceability-standard: k8s-pod-ownership-and-traceability-standard
spec: spec:
replicas: 0 replicas: 1
revisionHistoryLimit: 3 revisionHistoryLimit: 3
selector: selector:
matchLabels: matchLabels:
@@ -88,24 +94,14 @@ spec:
- name: FlowerCore__DeviceManagement__DefaultTenantId - name: FlowerCore__DeviceManagement__DefaultTenantId
value: "system" value: "system"
- name: FlowerCore__Database__Provider - name: FlowerCore__Database__Provider
value: "MySql" value: "Sqlite"
- name: FlowerCore__Database__Host - name: FlowerCore__Database__ConnectionStrings__Sqlite
value: "mysql.fc-mysql.svc" value: "Data Source=/data/devicemgmt.db"
- name: FlowerCore__Database__Database
value: "flowercore_devicemgmt"
- name: FlowerCore__Database__User
value: "fc_devicemgmt"
- name: FlowerCore__Database__Password - name: FlowerCore__Database__Password
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: fc-devicemgmt-runtime name: fc-devicemgmt-runtime
key: DB-Password key: DB-Password
- name: FlowerCore__DeviceManagement__AgentMtls__CaPath
value: "/secrets/devicemgmt-mtls/mtls-ca.pem"
- name: FlowerCore__DeviceManagement__AgentMtls__ClientCertificatePath
value: "/secrets/devicemgmt-mtls/mtls-client.crt"
- name: FlowerCore__DeviceManagement__AgentMtls__ClientKeyPath
value: "/secrets/devicemgmt-mtls/mtls-client.key"
- name: FlowerCore__EventBus__Redis__Configuration - name: FlowerCore__EventBus__Redis__Configuration
value: "redis.fc-redis.svc:6379" value: "redis.fc-redis.svc:6379"
resources: resources:
@@ -142,19 +138,17 @@ spec:
drop: drop:
- ALL - ALL
volumeMounts: volumeMounts:
- name: data
mountPath: /data
- name: tmp - name: tmp
mountPath: /tmp mountPath: /tmp
- name: logs - name: logs
mountPath: /app/logs mountPath: /app/logs
- name: devicemgmt-mtls
mountPath: /secrets/devicemgmt-mtls
readOnly: true
volumes: volumes:
- name: data
persistentVolumeClaim:
claimName: fc-devicemgmt-web-data
- name: tmp - name: tmp
emptyDir: {} emptyDir: {}
- name: logs - name: logs
emptyDir: {} emptyDir: {}
- name: devicemgmt-mtls
secret:
secretName: fc-devicemgmt-runtime
defaultMode: 0400

View File

@@ -649,6 +649,7 @@ public sealed class FleetManifestLintTests
"certificate-web.yaml", "certificate-web.yaml",
"clusterrole-operator.yaml", "clusterrole-operator.yaml",
"clusterrolebinding-operator.yaml", "clusterrolebinding-operator.yaml",
"crds.yaml",
"deployment-operator.yaml", "deployment-operator.yaml",
"deployment-web.yaml", "deployment-web.yaml",
"ingressroute-web.yaml", "ingressroute-web.yaml",
@@ -738,7 +739,8 @@ public sealed class FleetManifestLintTests
.Single(document => document.Kind == "ClusterRole" && document.Name == "fc-devicemgmt-operator"); .Single(document => document.Kind == "ClusterRole" && document.Name == "fc-devicemgmt-operator");
var allScalars = clusterRole.AllScalars().ToList(); var allScalars = clusterRole.AllScalars().ToList();
allScalars.Should().Contain("devices.flowercore.io"); allScalars.Should().Contain("flowercore.io");
allScalars.Should().NotContain("devices.flowercore.io");
allScalars.Should().Contain("*"); allScalars.Should().Contain("*");
allScalars.Should().Contain("deployments"); allScalars.Should().Contain("deployments");
allScalars.Should().Contain("get"); allScalars.Should().Contain("get");
@@ -767,7 +769,7 @@ public sealed class FleetManifestLintTests
FcDeviceManagementDocuments().Should().NotContain(document => document.Kind == "Secret"); FcDeviceManagementDocuments().Should().NotContain(document => document.Kind == "Secret");
appText.Should().Contain("secretKeyRef:"); appText.Should().Contain("secretKeyRef:");
appText.Should().Contain("secretName: fc-devicemgmt-runtime"); appText.Should().Contain("name: fc-devicemgmt-runtime");
appText.Should().NotContain("stringData:"); appText.Should().NotContain("stringData:");
appText.Should().NotContain("from-literal"); appText.Should().NotContain("from-literal");
appText.Should().NotContain("tls.key:"); appText.Should().NotContain("tls.key:");