diff --git a/apps/fc-devicemgmt/clusterrole-operator.yaml b/apps/fc-devicemgmt/clusterrole-operator.yaml index 400f91f..5237071 100644 --- a/apps/fc-devicemgmt/clusterrole-operator.yaml +++ b/apps/fc-devicemgmt/clusterrole-operator.yaml @@ -11,7 +11,7 @@ metadata: flowercore.io/created-by: bluejay-infra rules: - apiGroups: - - devices.flowercore.io + - flowercore.io resources: - '*' verbs: @@ -23,7 +23,7 @@ rules: - patch - delete - apiGroups: - - devices.flowercore.io + - flowercore.io resources: - devices/status - devices/finalizers @@ -33,6 +33,8 @@ rules: - devicepolicies/finalizers - remotecommands/status - remotecommands/finalizers + - desiredstatedocuments/status + - desiredstatedocuments/finalizers verbs: - get - update diff --git a/apps/fc-devicemgmt/crds.yaml b/apps/fc-devicemgmt/crds.yaml new file mode 100644 index 0000000..ba00f8a --- /dev/null +++ b/apps/fc-devicemgmt/crds.yaml @@ -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 diff --git a/apps/fc-devicemgmt/deployment-web.yaml b/apps/fc-devicemgmt/deployment-web.yaml index 49ba22f..9e9b3a2 100644 --- a/apps/fc-devicemgmt/deployment-web.yaml +++ b/apps/fc-devicemgmt/deployment-web.yaml @@ -5,27 +5,33 @@ # exist yet; import localhost/fc-devicemgmt-web: to all schedulable RKE2 # nodes before letting ArgoCD sync a live rollout. # -# SCALED TO 0 — 2026-05-19 morning-routine cleanup. -# The Web pod cannot start until TWO upstream gaps close: -# 1. MySQL DB instance `flowercore_devicemgmt` (user `fc_devicemgmt`) is -# provisioned via fc-mysql Manager. The cluster currently has ZERO -# MySqlInstanceCrds and no `mysql.fc-mysql.svc:3306` Service, so the -# deployment-web container env `FlowerCore__Database__Host=mysql.fc-mysql.svc` -# points at nothing. Provision via the fc-mysql Manager UI/REST/MCP. -# 2. 1Password vault item `IAmWorkin/FlowerCore DeviceManagement Runtime` -# with 5 fields (DB-Password, mtls-ca.pem, mtls-client.crt, mtls-client.key, -# mtls-chain.pem) — see apps/fc-devicemgmt/1password-item.yaml. Mint mTLS -# from step-ca-agent ClusterIssuer per ADR-126; DB-Password must match the -# password configured for the MySQL user. -# Re-enable: change replicas back to 2 after both gaps close. -# -# 2026-06-10 morning-routine refresh: image tag bumped to v20260610-bluejay — -# built from master @ 1614fce (June 9 network/BT command plane PRs #30/#33/#34, -# Shared.Data 1.0.1, and the Blue Jay UI.Components restyle). Imported on -# rke2-server + rke2-agent1. Gap 1 is wider than noted above: the fc-mysql -# OPERATOR deployment itself is absent from the cluster (only mysql-web runs), -# so MySqlInstanceCrds would not reconcile — deploy the operator first. -# Gap 2 (1P runtime item) also remains open; replicas stays 0. +# LIVE — 2026-06-11 DeviceManagement product-host enablement. +# The current DeviceManagement Web source is SQLite-backed in Program.cs, so +# Phase 1 production uses a Longhorn RWO PVC at /data/devicemgmt.db. The +# 1Password runtime item stays mounted through env for future MySQL/API-key +# cutover, but MySQL is not required for this first product-host rollout. +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: fc-devicemgmt-web-data + namespace: fc-devicemgmt + labels: + app: fc-devicemgmt-web + app.kubernetes.io/name: fc-devicemgmt-web + app.kubernetes.io/component: web + app.kubernetes.io/part-of: flowercore + app.kubernetes.io/managed-by: argocd + flowercore.io/tenant-id: system + flowercore.io/created-by: bluejay-infra +spec: + accessModes: + - ReadWriteOnce + storageClassName: longhorn + resources: + requests: + storage: 1Gi +--- apiVersion: apps/v1 kind: Deployment metadata: @@ -42,7 +48,7 @@ metadata: annotations: flowercore.io/traceability-standard: k8s-pod-ownership-and-traceability-standard spec: - replicas: 0 + replicas: 1 revisionHistoryLimit: 3 selector: matchLabels: @@ -88,24 +94,14 @@ spec: - name: FlowerCore__DeviceManagement__DefaultTenantId value: "system" - name: FlowerCore__Database__Provider - value: "MySql" - - name: FlowerCore__Database__Host - value: "mysql.fc-mysql.svc" - - name: FlowerCore__Database__Database - value: "flowercore_devicemgmt" - - name: FlowerCore__Database__User - value: "fc_devicemgmt" + value: "Sqlite" + - name: FlowerCore__Database__ConnectionStrings__Sqlite + value: "Data Source=/data/devicemgmt.db" - name: FlowerCore__Database__Password valueFrom: secretKeyRef: name: fc-devicemgmt-runtime 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 value: "redis.fc-redis.svc:6379" resources: @@ -142,19 +138,17 @@ spec: drop: - ALL volumeMounts: + - name: data + mountPath: /data - name: tmp mountPath: /tmp - name: logs mountPath: /app/logs - - name: devicemgmt-mtls - mountPath: /secrets/devicemgmt-mtls - readOnly: true volumes: + - name: data + persistentVolumeClaim: + claimName: fc-devicemgmt-web-data - name: tmp emptyDir: {} - name: logs emptyDir: {} - - name: devicemgmt-mtls - secret: - secretName: fc-devicemgmt-runtime - defaultMode: 0400 diff --git a/tests/bluejay-infra-lint/FleetManifestLintTests.cs b/tests/bluejay-infra-lint/FleetManifestLintTests.cs index edb2d0c..ec12f6d 100644 --- a/tests/bluejay-infra-lint/FleetManifestLintTests.cs +++ b/tests/bluejay-infra-lint/FleetManifestLintTests.cs @@ -649,6 +649,7 @@ public sealed class FleetManifestLintTests "certificate-web.yaml", "clusterrole-operator.yaml", "clusterrolebinding-operator.yaml", + "crds.yaml", "deployment-operator.yaml", "deployment-web.yaml", "ingressroute-web.yaml", @@ -738,7 +739,8 @@ public sealed class FleetManifestLintTests .Single(document => document.Kind == "ClusterRole" && document.Name == "fc-devicemgmt-operator"); 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("deployments"); allScalars.Should().Contain("get"); @@ -767,7 +769,7 @@ public sealed class FleetManifestLintTests FcDeviceManagementDocuments().Should().NotContain(document => document.Kind == "Secret"); 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("from-literal"); appText.Should().NotContain("tls.key:");