-
Notifications
You must be signed in to change notification settings - Fork 21
[ITEP:83537] Orchestrator Component Status Service #1322
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
Merged
Merged
Changes from 8 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
bbd3108
Orch Component Status Service Implementation
guptagunjan c893c5b
correct profile for tenancy
guptagunjan c3c7556
update profile name
guptagunjan fb9ea56
Merge branch 'main' into feat/ITEP-83537
guptagunjan 0f25811
fix lint
guptagunjan a5fbbe2
Update component-status.yaml
guptagunjan 558d0e1
add more profile/component
guptagunjan a02278e
Merge branch 'main' into feat/ITEP-83537
guptagunjan 086344a
update fectures profile
guptagunjan 6fb631e
fix componenet status syntax
guptagunjan 70bc334
resolve review comments and updtae tests
guptagunjan 79df439
Merge branch 'main' into feat/ITEP-83537
guptagunjan 126e3b7
fix lint issues
guptagunjan 3aa4ca2
fix ci issues
guptagunjan f8e7860
split observability for Orch and EN
guptagunjan ec36837
fix lint in tests
guptagunjan 0dc9843
Merge branch 'main' into feat/ITEP-83537
guptagunjan f46299e
fix more lint issues
guptagunjan d039ec6
add day2 config back
guptagunjan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| # SPDX-FileCopyrightText: 2025 Intel Corporation | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| # Component status service configuration | ||
| # This will be populated by the installer based on which features are enabled | ||
|
|
||
| resources: null |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| # SPDX-FileCopyrightText: 2025 Intel Corporation | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| image: | ||
| registry: {{.Values.argo.containerRegistryURL }} | ||
| repository: common/component-status | ||
| imagePullSecrets: | ||
| {{- with .Values.argo.imagePullSecrets }} | ||
| {{- toYaml . | nindent 2 }} | ||
| {{- end }} | ||
|
|
||
| {{- with .Values.argo.resources.componentStatus }} | ||
| resources: | ||
| {{- toYaml . | nindent 2 }} | ||
| {{- end }} | ||
|
|
||
| # Traefik IngressRoute configuration | ||
| # Priority must be > 30 to override nexus-api-gw's generic /v route (priority 30) | ||
| traefikRoute: | ||
| enabled: true | ||
| matchHost: Host(`api.{{ .Values.argo.clusterDomain }}`) | ||
| matchPath: PathPrefix(`/v1/orchestrator`) | ||
| priority: 40 | ||
| namespace: orch-gateway | ||
| secretName: tls-orch | ||
| # Authentication required - component status contains sensitive installation information | ||
| middlewares: | ||
| - validate-jwt | ||
| - secure-headers | ||
| {{- if .Values.argo.traefik }} | ||
| tlsOption: {{ .Values.argo.traefik.tlsOption | default "" | quote }} | ||
| {{- end }} | ||
|
|
||
| # Component status configuration | ||
| # This configuration reflects which features are ACTUALLY installed in the orchestrator | ||
| # Detection method: Checks which profile files are loaded in root-app (source of truth) | ||
| componentStatus: | ||
| schema-version: "1.0" | ||
| orchestrator: | ||
| version: {{ .Values.argo.orchestratorVersion | default .Chart.Version | quote }} | ||
| features: | ||
| # Application Orchestration: Enabled when app-orch profile is loaded | ||
| # Detection: enable-app-orch.yaml in root-app valueFiles | ||
| application-orchestration: | ||
| installed: {{ index .Values.argo.enabled "app-orch-catalog" | default false }} | ||
|
|
||
| # Cluster Orchestration: Enabled when cluster-orch profile is loaded | ||
| # Detection: enable-cluster-orch.yaml in root-app valueFiles | ||
| cluster-orchestration: | ||
| installed: {{ index .Values.argo.enabled "cluster-manager" | default false }} | ||
|
|
||
| # Edge Infrastructure Manager: Enabled when edgeinfra profile is loaded | ||
| # Detection: enable-edgeinfra.yaml in root-app valueFiles | ||
| # Profile enables 4 core apps: infra-core, infra-managers, infra-onboarding, infra-external | ||
| # We report the overall feature as installed if ANY infra app is enabled | ||
| edge-infrastructure-manager: | ||
| installed: {{ or (index .Values.argo.enabled "infra-core") (index .Values.argo.enabled "infra-managers") (index .Values.argo.enabled "infra-onboarding") (index .Values.argo.enabled "infra-external") | default false }} | ||
guptagunjan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| infra-core: | ||
| installed: {{ index .Values.argo.enabled "infra-core" | default false }} | ||
| infra-manager: | ||
| installed: {{ index .Values.argo.enabled "infra-managers" | default false }} | ||
| device-provisioning: | ||
| installed: {{ index .Values.argo.enabled "infra-onboarding" | default false }} | ||
|
|
||
| # Observability: Enabled when o11y profile is loaded | ||
| # Detection: enable-o11y.yaml in root-app valueFiles | ||
| observability: | ||
| installed: {{ index .Values.argo.enabled "orchestrator-observability" | default false }} | ||
guptagunjan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| # Web UI: Enabled when full-ui profile is loaded | ||
| # Detection: enable-full-ui.yaml in root-app valueFiles | ||
| web-ui: | ||
| installed: {{ or (index .Values.argo.enabled "web-ui-root") (index .Values.argo.enabled "web-ui-app-orch") (index .Values.argo.enabled "web-ui-cluster-orch") (index .Values.argo.enabled "web-ui-infra") | default false }} | ||
| orchestrator-ui: | ||
| installed: {{ index .Values.argo.enabled "web-ui-root" | default false }} | ||
| application-orchestration-ui: | ||
| installed: {{ index .Values.argo.enabled "web-ui-app-orch" | default false }} | ||
| cluster-orchestration-ui: | ||
| installed: {{ index .Values.argo.enabled "web-ui-cluster-orch" | default false }} | ||
| infrastructure-ui: | ||
| installed: {{ index .Values.argo.enabled "web-ui-infra" | default false }} | ||
|
|
||
| # Multitenancy: Tenancy services are part of the platform | ||
| multitenancy: | ||
| installed: {{ index .Values.argo.enabled "tenancy-manager" | default false }} | ||
| default-tenant-only: | ||
| installed: {{ index .Values.argo.enabled "defaultTenancy" | default false }} | ||
|
|
||
| # Detection: enable-kyverno.yaml in root-app valueFiles | ||
| kyverno: | ||
| installed: {{ index .Values.argo.enabled "kyverno" | default false }} | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| # SPDX-FileCopyrightText: 2025 Intel Corporation | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| {{- $appName := "component-status" }} | ||
| {{- $namespace := "orch-platform" }} | ||
| {{- $syncWave := "2000" }} | ||
| --- | ||
| {{- if (index .Values.argo.enabled $appName) }} | ||
| apiVersion: argoproj.io/v1alpha1 | ||
| kind: Application | ||
| metadata: | ||
| annotations: | ||
| argocd.argoproj.io/sync-wave: "{{ $syncWave }}" | ||
| name: {{$appName}} | ||
| namespace: {{ required "A valid namespace entry required!" .Values.argo.namespace }} | ||
| finalizers: | ||
| - resources-finalizer.argocd.argoproj.io | ||
| spec: | ||
| project: {{ required "A valid projectName entry required!" .Values.argo.project }} | ||
| sources: | ||
| - repoURL: {{ required "A valid chartRepoURL entry required!" .Values.argo.chartRepoURL }} | ||
| chart: common/charts/{{$appName}} | ||
| targetRevision: 26.0.1 | ||
| helm: | ||
| releaseName: {{$appName}} | ||
| valuesObject: | ||
| {{- $customFile := printf "custom/%s.tpl" $appName }} | ||
| {{- $customConfig := tpl (.Files.Get $customFile) . | fromYaml }} | ||
| {{- $baseFile := printf "configs/%s.yaml" $appName }} | ||
| {{- $baseConfig := .Files.Get $baseFile|fromYaml}} | ||
| {{- $overwrite := (get .Values.postCustomTemplateOverwrite $appName ) | default dict }} | ||
| {{- mergeOverwrite $baseConfig $customConfig $overwrite | toYaml | nindent 10 }} | ||
| destination: | ||
| namespace: {{$namespace}} | ||
| server: {{ required "A valid targetServer entry required!" .Values.argo.targetServer }} | ||
| syncPolicy: | ||
| {{- if .Values.argo.autosync }} | ||
| automated: | ||
| prune: true | ||
| selfHeal: true | ||
| retry: | ||
| limit: 5 | ||
| backoff: | ||
| duration: 5s | ||
| maxDuration: 3m0s | ||
| factor: 2 | ||
| {{- end }} | ||
| syncOptions: | ||
| - CreateNamespace=true | ||
| - ApplyOutOfSyncOnly=true | ||
| {{- end }} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,189 @@ | ||
| // SPDX-FileCopyrightText: 2025 Intel Corporation | ||
| // | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| package orchestrator_test | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "fmt" | ||
| "io" | ||
| "net/http" | ||
|
|
||
| . "github.com/onsi/ginkgo/v2" | ||
| . "github.com/onsi/gomega" | ||
| ) | ||
|
|
||
| const ( | ||
| componentStatusLabel = "component-status" | ||
| ) | ||
|
|
||
| type ComponentStatus struct { | ||
| SchemaVersion string `json:"schema-version"` | ||
| Orchestrator OrchestratorStatus `json:"orchestrator"` | ||
| } | ||
|
|
||
| type OrchestratorStatus struct { | ||
| Version string `json:"version"` | ||
| Features map[string]Feature `json:"features"` | ||
| } | ||
|
|
||
| type Feature struct { | ||
| Installed bool `json:"installed"` | ||
| SubFeatures map[string]Feature `json:",inline"` | ||
| } | ||
|
|
||
| var _ = Describe("Component Status Service", Label(componentStatusLabel), func() { | ||
| var cli *http.Client | ||
| var token string | ||
|
|
||
| BeforeEach(func() { | ||
| cli = &http.Client{ | ||
| Transport: &http.Transport{ | ||
| TLSClientConfig: tlsConfig, | ||
| }, | ||
| } | ||
| fmt.Printf("serviceDomain: %v\n", serviceDomain) | ||
| // Get authentication token - component status contains sensitive information | ||
| user := fmt.Sprintf("%s-api-user", "sample-project") | ||
| token = getKeycloakJWT(cli, user) | ||
| }) | ||
|
|
||
| Describe("Component Status API", Label(componentStatusLabel), func() { | ||
| componentStatusURL := "https://api." + serviceDomainWithPort + "/v1/orchestrator" | ||
|
|
||
| It("should be accessible over HTTPS with valid authentication", func() { | ||
| req, err := http.NewRequest(http.MethodGet, componentStatusURL, nil) | ||
| Expect(err).ToNot(HaveOccurred()) | ||
| req.Header.Add("Authorization", "Bearer "+token) | ||
|
|
||
| resp, err := cli.Do(req) | ||
| Expect(err).ToNot(HaveOccurred()) | ||
| defer resp.Body.Close() | ||
|
|
||
| Expect(resp.StatusCode).To(Equal(http.StatusOK)) | ||
| }) | ||
|
|
||
| It("should return valid JSON with correct schema", func() { | ||
| req, err := http.NewRequest(http.MethodGet, componentStatusURL, nil) | ||
| Expect(err).ToNot(HaveOccurred()) | ||
| req.Header.Add("Authorization", "Bearer "+token) | ||
|
|
||
| resp, err := cli.Do(req) | ||
| Expect(err).ToNot(HaveOccurred()) | ||
| defer resp.Body.Close() | ||
|
|
||
| Expect(resp.StatusCode).To(Equal(http.StatusOK)) | ||
|
|
||
| body, err := io.ReadAll(resp.Body) | ||
| Expect(err).ToNot(HaveOccurred()) | ||
|
|
||
| var status ComponentStatus | ||
| err = json.Unmarshal(body, &status) | ||
| Expect(err).ToNot(HaveOccurred()) | ||
|
|
||
| // Verify schema version is present | ||
| Expect(status.SchemaVersion).ToNot(BeEmpty()) | ||
| Expect(status.SchemaVersion).To(Equal("1.0")) | ||
|
|
||
| // Verify orchestrator section exists | ||
| Expect(status.Orchestrator.Version).ToNot(BeEmpty()) | ||
|
|
||
| // Verify features section exists | ||
| Expect(status.Orchestrator.Features).ToNot(BeNil()) | ||
| }) | ||
|
|
||
| It("should return expected feature flags", func() { | ||
| req, err := http.NewRequest(http.MethodGet, componentStatusURL, nil) | ||
| Expect(err).ToNot(HaveOccurred()) | ||
| req.Header.Add("Authorization", "Bearer "+token) | ||
|
|
||
| resp, err := cli.Do(req) | ||
| Expect(err).ToNot(HaveOccurred()) | ||
| defer resp.Body.Close() | ||
|
|
||
| Expect(resp.StatusCode).To(Equal(http.StatusOK)) | ||
|
|
||
| body, err := io.ReadAll(resp.Body) | ||
| Expect(err).ToNot(HaveOccurred()) | ||
|
|
||
| var status ComponentStatus | ||
| err = json.Unmarshal(body, &status) | ||
| Expect(err).ToNot(HaveOccurred()) | ||
|
|
||
| // Check that expected top-level features are present | ||
| expectedFeatures := []string{ | ||
| "application-orchestration", | ||
| "cluster-orchestration", | ||
| "edge-infrastructure-manager", | ||
| "observability", | ||
| "multitenancy", | ||
| "web-ui", | ||
| "kyverno", | ||
| } | ||
|
|
||
| for _, feature := range expectedFeatures { | ||
| _, exists := status.Orchestrator.Features[feature] | ||
| Expect(exists).To(BeTrue(), fmt.Sprintf("Feature %s should be present", feature)) | ||
| } | ||
| }) | ||
|
|
||
| It("should have proper Content-Type header", func() { | ||
| req, err := http.NewRequest(http.MethodGet, componentStatusURL, nil) | ||
| Expect(err).ToNot(HaveOccurred()) | ||
| req.Header.Add("Authorization", "Bearer "+token) | ||
|
|
||
| resp, err := cli.Do(req) | ||
| Expect(err).ToNot(HaveOccurred()) | ||
| defer resp.Body.Close() | ||
|
|
||
| Expect(resp.StatusCode).To(Equal(http.StatusOK)) | ||
| Expect(resp.Header.Get("Content-Type")).To(ContainSubstring("application/json")) | ||
| }) | ||
|
|
||
| It("should return 404 for non-existent paths", func() { | ||
| req, err := http.NewRequest(http.MethodGet, "https://api."+serviceDomainWithPort+"/v1/orchestrator/nonexistent", nil) | ||
| Expect(err).ToNot(HaveOccurred()) | ||
| req.Header.Add("Authorization", "Bearer "+token) | ||
|
|
||
| resp, err := cli.Do(req) | ||
| Expect(err).ToNot(HaveOccurred()) | ||
| defer resp.Body.Close() | ||
|
|
||
| Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) | ||
| }) | ||
|
|
||
| It("should support GET method only", func() { | ||
| // Test POST should fail | ||
| req, err := http.NewRequest(http.MethodPost, componentStatusURL, nil) | ||
| Expect(err).ToNot(HaveOccurred()) | ||
| req.Header.Add("Authorization", "Bearer "+token) | ||
|
|
||
| resp, err := cli.Do(req) | ||
| Expect(err).ToNot(HaveOccurred()) | ||
| defer resp.Body.Close() | ||
|
|
||
| Expect(resp.StatusCode).To(Equal(http.StatusMethodNotAllowed)) | ||
| }) | ||
| }) | ||
|
|
||
| Describe("Health and Readiness endpoints", Label(componentStatusLabel), func() { | ||
| It("should have /healthz endpoint", func() { | ||
| req, err := http.NewRequest(http.MethodGet, "https://api."+serviceDomainWithPort+"/v1/orchestrator/healthz", nil) | ||
| if err != nil { | ||
| Skip("Health endpoint may not be exposed externally") | ||
| } | ||
|
|
||
| resp, err := cli.Do(req) | ||
| if err != nil { | ||
| Skip("Health endpoint may not be exposed externally") | ||
| } | ||
| defer resp.Body.Close() | ||
|
|
||
| // If accessible, should return 200 | ||
| if resp.StatusCode == http.StatusOK { | ||
| Expect(resp.StatusCode).To(Equal(http.StatusOK)) | ||
| } | ||
| }) | ||
| }) | ||
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.