Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: opserver/Opserver
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
...
head repository: StackEng/Opserver
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref
Can’t automatically merge. Don’t worry, you can still create the pull request.

Commits on Jun 13, 2024

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    06a1641 View commit details
  2. Merge pull request #1 from StackEng/jzhang/fix_build

    chore(build): Add flag to fix build error (FOUND-3523)
    jzhang-sre authored Jun 13, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    b14819c View commit details

Commits on Jun 26, 2024

  1. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    c94f8bb View commit details

Commits on Jun 27, 2024

  1. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    7dc8f89 View commit details
  2. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    dcb1967 View commit details

Commits on Jun 28, 2024

  1. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    64fc111 View commit details
  2. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    e4d8fd6 View commit details
  3. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    d4ec91a View commit details

Commits on Jul 1, 2024

  1. Fix whitespace changes

    stephen-vakil committed Jul 1, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    1c62383 View commit details
  2. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    f6cc490 View commit details
  3. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    24c7245 View commit details
  4. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    1b0ebbe View commit details
  5. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    20fb1bd View commit details
  6. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    b83fae4 View commit details
  7. Merge pull request #2 from StackEng/vakil/ASCN-202

    ASCN-202:  Local k8s / docker / cnab for opserver
    stephen-vakil authored Jul 1, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    89e6e62 View commit details

Commits on Jul 15, 2024

  1. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    83eb2aa View commit details
  2. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    d1a522c View commit details
  3. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    34342fb View commit details

Commits on Jul 16, 2024

  1. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    b0e5510 View commit details
  2. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    efc401e View commit details
  3. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    db9dfb9 View commit details
  4. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    950d256 View commit details
  5. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    170c3df View commit details
  6. /github -> /.github

    stephen-vakil committed Jul 16, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    3e7c429 View commit details
  7. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    e6f0307 View commit details
  8. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    495676f View commit details
  9. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    8fa67cf View commit details

Commits on Jul 17, 2024

  1. Merge pull request #3 from StackEng/vakil/ASCN-229-GitHub-Workflows

    ASCN-229: Add workflows to build and publish app and cnab images
    stephen-vakil authored Jul 17, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    f690548 View commit details

Commits on Jul 18, 2024

  1. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    849052d View commit details
  2. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    35c0467 View commit details
  3. fix nginx class

    stephen-vakil committed Jul 18, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    68dfca4 View commit details
  4. Merge pull request #4 from StackEng/ASCN-230-Certs

    ASCN-230:  Ingress/Cert fixes for GKE
    stephen-vakil authored Jul 18, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    ab7e761 View commit details
  5. Configure okta

    stephen-vakil committed Jul 18, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    aaab213 View commit details
  6. Copy the full SHA
    03f39a3 View commit details
  7. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    52fba34 View commit details
  8. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    fcc2d5c View commit details
  9. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    b364fb0 View commit details
  10. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    37b2015 View commit details
  11. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    17abb2f View commit details
  12. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    6f70eaa View commit details
  13. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    9633c1a View commit details
  14. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    d397918 View commit details
  15. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    0a3719d View commit details

Commits on Jul 19, 2024

  1. Remove unused variable

    stephen-vakil committed Jul 19, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    aa2a65e View commit details
  2. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    7d947d5 View commit details
  3. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    5317cd9 View commit details
  4. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    d5e2234 View commit details
  5. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    f23510c View commit details
  6. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    34d18be View commit details
  7. Verified

    This commit was signed with the committer’s verified signature.
    stephen-vakil Stephen Vakil
    Copy the full SHA
    20e83e8 View commit details
Showing with 1,394 additions and 87 deletions.
  1. +66 −0 .github/actions/build_docker/action.yml
  2. +32 −0 .github/actions/date_version/action.yml
  3. +43 −0 .github/workflows/build_app_docker_image.yml
  4. +37 −0 .github/workflows/build_cnab.yml
  5. +0 −15 .github/workflows/docker.yml
  6. +4 −4 .github/workflows/main.yml
  7. +91 −0 .github/workflows/workflow_build_and_release_containers.yaml
  8. +7 −0 .gitignore
  9. +15 −0 .vscode/launch.json
  10. +9 −3 Dockerfile
  11. +24 −0 charts/opserver/.helmignore
  12. +24 −0 charts/opserver/Chart.yaml
  13. +237 −0 charts/opserver/templates/deployment.yaml
  14. +25 −0 charts/opserver/templates/fake-secretstore.yaml
  15. +28 −0 charts/opserver/templates/ingress.yaml
  16. +21 −0 charts/opserver/templates/opserver-config-secret.yaml
  17. +20 −0 charts/opserver/templates/opserver-secret.yaml
  18. +5 −0 charts/opserver/templates/service-account.yaml
  19. +12 −0 charts/opserver/templates/service.yaml
  20. +32 −0 charts/opserver/templates/sql-external-secret.yaml
  21. +89 −0 charts/opserver/values.yaml
  22. +193 −0 cnab/Invoke-CNAB.ps1
  23. +108 −0 cnab/app/app.ps1
  24. +3 −0 cnab/app/build-app-image.ps1
  25. +46 −0 cnab/app/variables.DockerDesktop.json
  26. +9 −0 cnab/build/Dockerfile
  27. +4 −4 docs/Configuration.md
  28. +1 −1 docs/Docs.csproj
  29. +1 −0 src/Directory.Build.props
  30. +9 −1 src/Opserver.Core/Data/Elastic/ElasticCluster.KnownNodes.cs
  31. +1 −1 src/Opserver.Core/Data/SQL/SQLAzureServer.cs
  32. +1 −1 src/Opserver.Core/Data/SQL/SQLInstance.cs
  33. +1 −1 src/Opserver.Core/Helpers/Connection.cs
  34. +1 −1 src/Opserver.Core/Helpers/OpserverConfigException.cs
  35. +19 −15 src/Opserver.Core/Opserver.Core.csproj
  36. +17 −16 src/Opserver.Web/Controllers/AuthController.OIDC.cs
  37. +22 −5 src/Opserver.Web/Opserver.Web.csproj
  38. +42 −10 src/Opserver.Web/Program.cs
  39. +5 −0 src/Opserver.Web/Security/OIDCSecuritySettings.cs
  40. +44 −3 src/Opserver.Web/Startup.cs
  41. +40 −0 src/Opserver.Web/appSettings.json
  42. +2 −2 src/Opserver.Web/opserverSettings.json
  43. +4 −4 tests/Opserver.Tests/Opserver.Tests.csproj
66 changes: 66 additions & 0 deletions .github/actions/build_docker/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Docker build and push
description: Build the image and pushes to registry

inputs:
version:
description: The version to use for the Docker image
required: true
dockerfile_path:
description: Dockerfile location
required: true
image_name:
description: The Docker image name, with the registry prefix
required: true
registry_prod:
description: Docker registry prod
required: true
registry_username:
description: Docker registry username
required: true
registry_password:
description: Docker registry password
required: true
build_args:
description: Arguments to pass to docker build
required: false
default: ''

runs:
using: composite
steps:
- name: Setup up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Docker Image Metadata
id: metadata
uses: docker/metadata-action@v5
with:
images: ${{ inputs.image_name }}
# https://github.com/docker/metadata-action/tree/master?tab=readme-ov-file#priority-attribute
# The default priority of sha is 100, and for custom/raw tags is 200. The highest the most priority.
# We want the sha tag to be the one used for the OCI label and the version output, so we set the priority of the custom date tag to the lowest.
tags: |
type=sha,priority=100
${{ inputs.version }},priority=1
type=ref,event=pr
flavor: latest=false

- name: Login to Docker Registry - prod
uses: docker/login-action@v3
with:
registry: ${{ inputs.registry_prod }}
username: ${{ inputs.registry_username }}
password: ${{ inputs.registry_password }}

- name: Build Image
uses: docker/build-push-action@v6
with:
push: true
context: .
file: ${{ inputs.dockerfile_path }}
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
provenance: true
build-args: |
DOTNET_VERSION=${{ env.DOTNET_VERSION }}
BUNDLE_VERSION=${{ inputs.version }}
32 changes: 32 additions & 0 deletions .github/actions/date_version/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Date Based Version
description: Generates a version based on todays date and the github actions run number. Exposes this version as an output variable.
outputs:
version:
description: "Generated Date Based Version"
value: ${{ steps.generate-version.outputs.version }}

runs:
using: composite
steps:
- name: Generate Version
id: generate-version
shell: bash
run: |
set -euo pipefail
github_run_number=${{ github.run_number }}
github_ref=${{ github.ref }}
build_number=$(($github_run_number % 65535))
date=$(date +%Y.%-m.%-d)
version="${date}.${build_number}"
is_pr=0
echo $github_ref | grep "^refs\/pull\/" && is_pr=1
if [ $is_pr -eq 1 ]
then
version="${version}-pr"
fi
echo "Version: $version"
echo "version=$version" >> $GITHUB_OUTPUT
43 changes: 43 additions & 0 deletions .github/workflows/build_app_docker_image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Build docker

on:
workflow_call:
inputs:
version:
type: string
required: true
secrets:
registry_username:
required: true
registry_password:
required: true
nuget_user:
required: true
nuget_password:
required: true

env:
BUILDKIT_PROGRESS: plain
SERVICE_IMAGE_NAME: ${{ vars.CLOUDSMITH_DOCKER_REGISTRY_PROD }}/stackeng/opserver/opserver

jobs:
build_docker:
name: Docker build and push
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0 #Fetch entire history for NerdBank to calculate the version

- uses: ./.github/actions/build_docker
id: image
with:
version: ${{ inputs.version }}
dockerfile_path: ./Dockerfile
image_name: ${{ env.SERVICE_IMAGE_NAME }}
registry_prod: ${{ vars.CLOUDSMITH_DOCKER_REGISTRY_PROD }}
registry_username: ${{ secrets.registry_username }}
registry_password: ${{ secrets.registry_password }}
scan_image: true

37 changes: 37 additions & 0 deletions .github/workflows/build_cnab.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Build CNAB invocation image

on:
workflow_call:
inputs:
version:
description: The version to use for the Octopus release
type: string
required: true
secrets:
registry_username:
required: true
registry_password:
required: true

env:
CNAB_IMAGE_NAME: ${{ vars.CLOUDSMITH_DOCKER_REGISTRY_PROD }}/stackeng/opserver/opserver-cnab

jobs:
build_image:
name: Build and release CNAB invocation image
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: ./.github/actions/build_docker
with:
version: ${{ inputs.version }}
dockerfile_path: ./cnab/build/Dockerfile
image_name: ${{ env.CNAB_IMAGE_NAME }}
registry_prod: ${{ vars.CLOUDSMITH_DOCKER_REGISTRY_PROD }}
registry_username: ${{ secrets.registry_username }}
registry_password: ${{ secrets.registry_password }}

15 changes: 0 additions & 15 deletions .github/workflows/docker.yml

This file was deleted.

8 changes: 4 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -4,12 +4,12 @@ on: [push]

jobs:
build:
runs-on: windows-2019
runs-on: ubuntu-latest
steps:
- name: Setup .NET
uses: actions/setup-dotnet@v1
uses: actions/setup-dotnet@v4
with:
dotnet-version: 6.0.x
- uses: actions/checkout@v1
dotnet-version: 8.0.x
- uses: actions/checkout@v4
- name: Build with dotnet
run: dotnet build
91 changes: 91 additions & 0 deletions .github/workflows/workflow_build_and_release_containers.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
name: Build images and create Octopus release
run-name: 'Build images and create release'

on:
workflow_dispatch:
pull_request:
types: [opened, reopened, synchronize, labeled, ready_for_review]
paths-ignore:
- README.md
push:
branches:
- main
paths-ignore:
- README.md

jobs:
generate_date_version:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.date-version.outputs.version }}
steps:
- name: Checkout repo so we have local action file
uses: actions/checkout@v4
- name: Generate Date Version
id: date-version
uses: ./.github/actions/date_version

build_docker:
needs: [generate_date_version]
uses: ./.github/workflows/build_app_docker_image.yml
with:
version: ${{ needs.generate_date_version.outputs.version }}
secrets:
registry_username: ${{ secrets.CLOUDSMITH_API_ACCOUNT }}
registry_password: ${{ secrets.CLOUDSMITH_API_KEY }}
nuget_user: ${{ secrets.CLOUDSMITH_API_ACCOUNT }}
nuget_password: ${{ secrets.CLOUDSMITH_API_KEY }}

build_cnab:
uses: ./.github/workflows/build_cnab.yml
needs: [generate_date_version]
with:
version: ${{ needs.generate_date_version.outputs.version }}
secrets:
registry_username: ${{ secrets.CLOUDSMITH_API_ACCOUNT }}
registry_password: ${{ secrets.CLOUDSMITH_API_KEY }}
create_release:
needs: [build_docker, build_cnab, generate_date_version]
runs-on: ubuntu-latest
steps:
- name: Install Octopus CLI 🐙
uses: OctopusDeploy/install-octopus-cli-action@v3
with:
# Not pinning CLI version since we trust Octopus Deploy as one of our direct vendors and this ensures we
# keep up-to-date with Octopus Cloud changes
version: '*'

- name: determine if we should create release and deploy
id: should-create-release
run: |
if [[ ${{ github.ref_name == 'main' || github.pull_request.labels.*.name == 'deploy-to-ascn-dev' }} ]]; then
echo "SHOULD_CREATE_RELEASE=true" >> $GITHUB_ENV
else
echo "SHOULD_CREATE_RELEASE=false" >> $GITHUB_ENV
fi
- name: Create Octo Release if main or deploy to sandbox label present
# if: env.SHOULD_CREATE_RELEASE == 'true'
env:
OCTOPUS_URL: ${{ vars.OCTOPUS_CLOUD_URL }}
OCTOPUS_API_KEY: ${{ secrets.OCTOPUS_CLOUD_API_KEY }}
run: |
octoSpaceId="Default"
octoProjectId="opserver"
octopus release create -p $octoProjectId -s $octoSpaceId -v "${{ needs.generate_date_version.outputs.version }}"
- name: Deploy via Octopus if main or deploy to ascn-dev if label present
# if: env.SHOULD_CREATE_RELEASE == 'true'
env:
OCTOPUS_URL: ${{ vars.OCTOPUS_CLOUD_URL }}
OCTOPUS_API_KEY: ${{ secrets.OCTOPUS_CLOUD_API_KEY }}
run: |
octoSpaceId="Default"
octoProjectId="opserver"
environmentId="${{ github.ref_name == 'main' && 'test' || 'dev' }}"
tenantId="${{ github.ref_name == 'main' && 'main' || 'ascn' }}"
octopus release deploy -p $octoProjectId -s $octoSpaceId --version "${{ needs.generate_date_version.outputs.version }}" \
-e $environmentId --tenant $tenantId
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# These get copied locally when running Invoke-CNAB not in a container
# Temporarily including these while building out CNAB v2 support
cnab/app/container-registry-discovery.ps1
cnab/app/gcp-cluster-discovery.ps1
cnab/app/run.ps1
cnab/app/utils.ps1

#################
## Visual Studio
#################
15 changes: 15 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Invoke-CNAB",
"type": "PowerShell",
"request": "launch",
"script": "${workspaceFolder}/cnab/Invoke-CNAB.ps1",
"args": []
}
]
}
12 changes: 9 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /app

# Global
@@ -22,7 +22,13 @@ WORKDIR /app/src/Opserver.Web
RUN dotnet publish -c Release -o publish

# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS web
FROM cr.stackoverflow.software/so-aspnet:8.0-jammy-chiseled-extra AS base

USER $APP_UID

WORKDIR /app
COPY --from=web-publish /app/src/Opserver.Web/publish ./
COPY --chown=app:app --from=web-publish /app/src/Opserver.Web/publish ./
COPY --chown=app:app --from=web-publish /app/src/Opserver.Web/opserverSettings.json ./Config/opserverSettings.json


ENTRYPOINT ["dotnet", "Opserver.Web.dll"]
24 changes: 24 additions & 0 deletions charts/opserver/.helmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
.github/CODEOWNERS
24 changes: 24 additions & 0 deletions charts/opserver/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: v2
name: opserver
description: A Helm chart for Kubernetes

# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application

# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 1.0.17

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "0.0.1" # we don't use this field
237 changes: 237 additions & 0 deletions charts/opserver/templates/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}
namespace: {{ .Release.Namespace }}
annotations:
reloader.stakater.com/auto: "true"
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
service: {{ .Release.Name }}
template:
metadata:
labels:
service: {{ .Release.Name }}
spec:
serviceAccountName: {{ .Release.Name }}
containers:
- name: opserver
image: "{{ .Values.images.containerRegistry }}/{{ .Values.images.opserver.name }}:{{ .Values.images.opserver.tag }}"
resources:
requests:
memory: {{ .Values.requests.memory }}
cpu: {{ .Values.requests.cpu }}
limits:
memory: {{ .Values.limits.memory }}
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsNonRoot: true
volumeMounts:
- name: writable-tmp #need our own read-write enabled temp directory because aspnet spills large requests over to disk
mountPath: /mnt/tmp
- name: opserver-config
mountPath: /app/Config
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.kestrel.endPoints.http.containerPort }}
livenessProbe:
httpGet:
path: /health-checks/live
port: {{ .Values.kestrel.endPoints.http.containerPort }}
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
readinessProbe:
httpGet:
path: /health-checks/ready
port: {{ .Values.kestrel.endPoints.http.containerPort }}
initialDelaySeconds: 10
periodSeconds: 1
successThreshold: 3
env:
- name: NODE_IP
valueFrom:
fieldRef:
fieldPath: status.hostIP

- name: DOTNET_EnableDiagnostics
value: "0"
- name: Logging__LogLevel__Microsoft
value: "Warning"
- name: ASPNETCORE_ENVIRONMENT
value: {{ .Values.aspnetcoreEnvironment }}
- name: PRODUCT
value: {{ .Values.product }}

- name: EXCEPTIONAL__STORE__APPLICATIONNAME
value: "{{ .Release.Name }}"
- name: EXCEPTIONAL__STORE__TYPE
value: "{{ .Values.exceptional.store.type }}"

- name: DATADOG__AGENTHOST
value: "{{- if eq .Values.datadog.agentHost "127.0.0.1"}}$(NODE_IP){{- else}}{{ .Values.datadog.agentHost }}{{- end}}"
- name: DATADOG__AGENTPORT
value: "{{ .Values.datadog.agentPort }}"

# this exact variable is required for our datadog configuration to work with tracing / APM
- name: DD_AGENT_HOST
value: "{{- if eq .Values.datadog.agentHost "127.0.0.1"}}$(NODE_IP){{- else}}{{ .Values.datadog.agentHost }}{{- end}}"

- name: DD_RUNTIME_METRICS_ENABLED
value: "true"

- name: DD_SERVICE
value: "opserver"

- name: DD_VERSION
value: {{ .Values.images.opserver.tag | quote }}

- name: KESTREL__ENDPOINTS__HTTP__URL
value: "http://0.0.0.0:{{ .Values.kestrel.endPoints.http.containerPort }}/"

- name: TMPDIR #tell OS to use our read-write volume mount as its temp directory
value: "/mnt/tmp"
- name: Security__Provider
value: {{ .Values.opserverSettings.security.provider }}

{{- if eq .Values.opserverSettings.security.provider "OIDC" }}
- name: Security__UseHttpsForRedirects
value: "true"
- name: Security__Name
value: "Okta"
- name: Security__ViewEverythingGroups
value: {{ .Values.opserverSettings.security.viewGroups | quote }}
- name: Security__AdminEverythingGroups
value: {{ .Values.opserverSettings.security.adminGroups | quote }}
- name: Security__ClientId
valueFrom:
secretKeyRef:
name: {{ .Values.opserverExternalSecret.targetName }}
key: oktaClientId
- name: Security__ClientSecret
valueFrom:
secretKeyRef:
name: {{ .Values.opserverExternalSecret.targetName }}
key: oktaClientSecret
- name: Security__AuthorizationUrl
value: "https://stackoverflow.okta.com/oauth2/v1/authorize"
- name: Security__AccessTokenUrl
value: "https://stackoverflow.okta.com/oauth2/v1/token"
- name: Security__UserInfoUrl
value: "https://stackoverflow.okta.com/oauth2/v1/userinfo"
- name: Security__NameClaim
value: "preferred_username"
- name: Security__GroupsClaim
value: "groups"
- name: Security__Scopes__0
value: "email"
- name: Security__Scopes__1
value: "groups"
- name: Security__Scopes__2
value: "profile"
{{- end }}

- name: SQL_STATUS_USERNAME
valueFrom:
secretKeyRef:
name: {{ .Values.sqlExternalSecret.targetName }}
key: {{ .Values.sqlExternalSecret.remoteRefs.sqlStatusUsername }}

- name: SQL_STATUS_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.sqlExternalSecret.targetName }}
key: {{ .Values.sqlExternalSecret.remoteRefs.sqlStatusPassword }}

- name: Modules__Sql__defaultConnectionString
value: "Server=$ServerName$;Database=master;User ID=$(SQL_STATUS_USERNAME);Password=$(SQL_STATUS_PASSWORD);TrustServerCertificate=True;MultiSubnetFailover=True"


{{- if hasKey .Values.opserverSettings "exceptions" }}
- name: SQL_EXCEPTIONAL_USERNAME
valueFrom:
secretKeyRef:
name: {{ .Values.sqlExternalSecret.targetName }}
key: {{ .Values.sqlExternalSecret.remoteRefs.exceptionalUsername }}
- name: SQL_EXCEPTIONAL_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.sqlExternalSecret.targetName }}
key: {{ .Values.sqlExternalSecret.remoteRefs.exceptionalPassword }}

{{- range $i, $instance := .Values.opserverSettings.exceptions }}
- name: Modules__Exceptions__stores__{{ $i }}__connectionString
value: "Server={{ $instance.serverName}};Database={{ $instance.database}};User ID=$(SQL_EXCEPTIONAL_USERNAME);Password=$(SQL_EXCEPTIONAL_PASSWORD);TrustServerCertificate=True;MultiSubnetFailover=True"
{{- end }}

- name: SQL_EXCEPTIONAL_SERVERNAME
valueFrom:
secretKeyRef:
name: {{ .Values.sqlExternalSecret.targetName }}
key: {{ .Values.sqlExternalSecret.remoteRefs.exceptionalServerName }}

- name: EXCEPTIONAL__STORE__CONNECTIONSTRING
value: Server=$(SQL_EXCEPTIONAL_SERVERNAME);Database={{ .Values.db.exceptionalDbName }};Persist Security Info=False;User ID=$(SQL_EXCEPTIONAL_USERNAME);Password=$(SQL_EXCEPTIONAL_PASSWORD);MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30;MultiSubnetFailover=True
{{- end }}

{{- if .Values.nodeScheduling.scheduleOnSeparateNodes }}
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: service
operator: In
values:
- {{ .Release.Name }}
topologyKey: kubernetes.io/hostname
{{- end }}

topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
service: {{ .Release.Name }}
matchLabelKeys:
- pod-template-hash

{{- if and (hasKey .Values "nodeScheduling") (hasKey .Values.nodeScheduling "nodeSelectorLabel")}}
nodeSelector:
{{- range .Values.nodeScheduling.nodeSelectorLabel }}
{{ .name }}: {{ .value | quote }}
{{- end }}
{{- end }}

{{- if and (hasKey .Values "nodeScheduling") (hasKey .Values.nodeScheduling "tolerations")}}
tolerations:
{{- range .Values.nodeScheduling.tolerations }}
- key: {{ .key }}
operator: {{ .operator }}
value: {{ .value | quote }}
effect: {{ .effect }}
{{- end }}
{{- end }}

restartPolicy: Always
imagePullSecrets:
- name: "{{ .Values.image.pullSecretName }}"
volumes:
- name: data-volume
emptyDir: {}
- name: log-volume
emptyDir: {}
volumes:
- name: writable-tmp
emptyDir: {}
- name: opserver-config
secret:
secretName: {{ .Values.configSecret.targetName }}
25 changes: 25 additions & 0 deletions charts/opserver/templates/fake-secretstore.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{{ if .Values.secretStore.fake }}
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: fakeopserversecretstore
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-weight": "-5"
spec:
provider:
fake:
data:
- key: {{ .Values.sqlExternalSecret.remoteRefs.sqlStatusSqlServerName }}
value: "host.docker.internal"
- key: {{ .Values.sqlExternalSecret.remoteRefs.sqlStatusUsername }}
value: "opserver"
- key: {{ .Values.sqlExternalSecret.remoteRefs.sqlStatusPassword }}
value: "opserver"
- key: {{ .Values.sqlExternalSecret.remoteRefs.exceptionalServerName }}
value: "host.docker.internal"
- key: {{ .Values.sqlExternalSecret.remoteRefs.exceptionalUsername }}
value: "opserver"
- key: {{ .Values.sqlExternalSecret.remoteRefs.exceptionalPassword }}
value: "opserver"
{{ end }}
28 changes: 28 additions & 0 deletions charts/opserver/templates/ingress.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ .Release.Name }}
namespace: {{ .Release.Namespace }}
annotations:
cert-manager.io/cluster-issuer: {{ .Values.ingress.certIssuer }}
spec:
ingressClassName: {{ .Values.ingress.className }}
{{- if .Values.ingress.createTlsCert }}
tls:
- hosts:
- {{ .Values.ingress.host }}
secretName: {{ .Values.ingress.secretName }}
{{- end}}
rules:
- host: {{ .Values.ingress.host }}
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: {{ .Release.Name }}
port:
number: {{ .Values.kestrel.endPoints.http.containerPort }}
{{- end}}
21 changes: 21 additions & 0 deletions charts/opserver/templates/opserver-config-secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: {{ .Values.configSecret.name }}
spec:
refreshInterval: {{ .Values.configSecret.refreshInterval }}
secretStoreRef:
name: {{ .Values.configSecret.storeRefName }}
kind: ClusterSecretStore
target:
name: {{ .Values.configSecret.targetName }}
data:
- secretKey: ElasticSettings.json
remoteRef:
key: {{ .Values.configSecret.remoteRefs.ElasticSettings }}
- secretKey: RedisSettings.json
remoteRef:
key: {{ .Values.configSecret.remoteRefs.RedisSettings }}
- secretKey: SQLSettings.json
remoteRef:
key: {{ .Values.configSecret.remoteRefs.SQLSettings }}
20 changes: 20 additions & 0 deletions charts/opserver/templates/opserver-secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{{- if eq .Values.opserverSettings.security.provider "OIDC" }}
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: {{ .Values.opserverExternalSecret.name }}
spec:
refreshInterval: {{ .Values.opserverExternalSecret.refreshInterval }}
secretStoreRef:
name: {{ .Values.opserverExternalSecret.storeRefName }}
kind: ClusterSecretStore
target:
name: {{ .Values.opserverExternalSecret.targetName }}
data:
- secretKey: oktaClientId
remoteRef:
key: {{ .Values.opserverExternalSecret.remoteRefs.oktaClientId }}
- secretKey: oktaClientSecret
remoteRef:
key: {{ .Values.opserverExternalSecret.remoteRefs.oktaClientSecret }}
{{- end }}
5 changes: 5 additions & 0 deletions charts/opserver/templates/service-account.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ .Release.Name }}
namespace: {{ .Release.Namespace }}
12 changes: 12 additions & 0 deletions charts/opserver/templates/service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: v1
kind: Service
metadata:
namespace: {{ .Release.Namespace }}
name: {{ .Release.Name }}
spec:
selector:
service: {{ .Release.Name }}
ports:
- name: "80"
port: 80
targetPort: {{ .Values.kestrel.endPoints.http.containerPort }}
32 changes: 32 additions & 0 deletions charts/opserver/templates/sql-external-secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: {{ .Values.sqlExternalSecret.name }}
spec:
refreshInterval: {{ .Values.sqlExternalSecret.refreshInterval }}
secretStoreRef:
name: {{ .Values.sqlExternalSecret.storeRefName }}
kind: ClusterSecretStore
target:
name: {{ .Values.sqlExternalSecret.targetName }}
data:
# These secrets are used by the Sql module of OpServer
- secretKey: {{ .Values.sqlExternalSecret.remoteRefs.sqlStatusSqlServerName }}
remoteRef:
key: {{ .Values.sqlExternalSecret.remoteRefs.sqlStatusSqlServerName }}
- secretKey: {{ .Values.sqlExternalSecret.remoteRefs.sqlStatusUsername }}
remoteRef:
key: {{ .Values.sqlExternalSecret.remoteRefs.sqlStatusUsername }}
- secretKey: {{ .Values.sqlExternalSecret.remoteRefs.sqlStatusPassword }}
remoteRef:
key: {{ .Values.sqlExternalSecret.remoteRefs.sqlStatusPassword }}
# These secrets are used for the Exceptional module of OpServer
- secretKey: {{ .Values.sqlExternalSecret.remoteRefs.exceptionalServerName }}
remoteRef:
key: {{ .Values.sqlExternalSecret.remoteRefs.exceptionalServerName }}
- secretKey: {{ .Values.sqlExternalSecret.remoteRefs.exceptionalUsername }}
remoteRef:
key: {{ .Values.sqlExternalSecret.remoteRefs.exceptionalUsername }}
- secretKey: {{ .Values.sqlExternalSecret.remoteRefs.exceptionalPassword }}
remoteRef:
key: {{ .Values.sqlExternalSecret.remoteRefs.exceptionalPassword }}
89 changes: 89 additions & 0 deletions charts/opserver/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
appName: "opserver"
replicaCount: 1

tier: "Local"
product: "public" # used for datadog metrics and logs
aspnetcoreEnvironment: "Local"

requests:
cpu: "1m"
memory: "1M"

limits:
memory: "1Gi"

exceptional:
store:
type: "Memory"
connectionString: ""

datadog:
agentHost: ""
agentPort: "0"

secretStore:
fake: true

images:
containerRegistry: "local.software"
opserver:
name: "stackeng/opserver/opserver"
tag: "latest"

image:
pullPolicy: IfNotPresent
pullSecretName: cloudsmith-cr-prod

adminRolebindingGroupId: "not set"

kestrel:
endPoints:
http:
url: "http://0.0.0.0:8080/"
containerPort: 8080

ingress:
certIssuer: "letsencrypt-staging"
className: "nginx-external"
host: "opserver.local"
secretName: "opserver-secret"
enabled: true
createTlsCert: false

db:
exceptionalDbName: Local.Exceptions

opserverExternalSecret:
name: opserver-secret
refreshInterval: 5m
storeRefName: fakeopserversecretstore
targetName: opserver-secret
remoteRefs:
oktaClientId: opserver-okta-client-id
oktaClientSecret: opserver-okta-client-secret

sqlExternalSecret:
name: opserver-sqldb-external-secret
refreshInterval: 5m
storeRefName: fakeopserversecretstore
targetName: sql-secret
remoteRefs:
sqlStatusSqlServerName: SqlStatusSqlServerName
sqlStatusUsername: db-Opserver-Sql-Status-User
sqlStatusPassword: db-Opserver-Sql-Status-Password
exceptionalServerName: ExceptionsSqlServerName
exceptionalUsername: db-Exceptions-User
exceptionalPassword: db-Exceptions-Password

nodeScheduling:
scheduleOnSeparateNodes: false

configSecret:
name: opserver-config
refreshInterval: 5m
storeRefName: fakeopserversecretstore
targetName: opserver-config
remoteRefs:
ElasticSettings: opserver-elastic-config
RedisSettings: opserver-redis-config
SQLSettings: opserver-sql-config
193 changes: 193 additions & 0 deletions cnab/Invoke-CNAB.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
[CmdletBinding()]
param (
[ValidateSet("pre-install", "install")]
[string]
$Action = "install",
[bool]
$RunAsContainer = $true,
[ValidateSet("GCP", "DockerDesktop")]
[string]
$Target = "GCP",
[bool]
$DownloadLocalScriptsForLocalDebugging = $true,
[string]
$Version = "pr-21",
[string]
$PathToDeploymentPipelineVariables = "file:///D:/code/deployment-pipeline-variables"
)

# Function to check if a command exists
function Check-CommandExists {
param (
[string]$Command
)

if ($null -eq (Get-Command "$Command.exe" -ErrorAction SilentlyContinue)) {
Write-Host "Unable to find $Command. Please install $Command before continuing"
exit 1
}
}

function Setup-GCP {
Check-CommandExists -Command "gcloud-crc32c"

# Check if user is signed in to gcloud
$gcloudAuthStatus = gcloud auth list --format="value(account)"
if (-not $gcloudAuthStatus) {
& gcloud auth login
}
}

function Setup-DockerDesktop {
Check-CommandExists -Command "kubectl"
Check-CommandExists -Command "helm"

& kubectl config use-context "docker-desktop"

Write-Host "Check if Kubernetes is enabled in Docker Desktop"
$output = & kubectl get node docker-desktop 2>&1 | Out-String

if ( $output.Trim() -eq "Unable to connect to the server: EOF") {
Write-Error "Kubernetes is not enabled in Docker Desktop. Please enable Kubernetes before continuing or change the target."
exit 1
}

Write-Host "Kubernetes is enabled in Docker Desktop"

$repoExists = (helm repo list | Select-String -Pattern "external-secrets")
$chartExists = (helm list -n local-external-secrets | Select-String -Pattern "external-secrets")

if (-not $repoExists) {
Write-Host "Adding external-secrets repo to Kubernetes"
& helm repo add external-secrets https://charts.external-secrets.io
}

if (-not $chartExists) {
Write-Host "Adding external-secrets chart to Kubernetes"
& helm repo update
& helm install external-secrets external-secrets/external-secrets -n local-external-secrets --create-namespace --set installCRDs=true
}
}

$env:PIPELINE_CONFIG_URI=$PathToDeploymentPipelineVariables

Write-Host "Rendering pipeline variables for CNAB"
$TempFilePath = [System.IO.Path]::GetTempFileName()
$MetaJsonPath = [System.IO.Path]::ChangeExtension($TempFilePath, ".json")

pipeline-variables render "opserver" --cloud "gcp" --product "pubplat" --env "dev" --deployment-group "ascn" --output $MetaJsonPath --json

if (-not (Test-Path $MetaJsonPath)) {
Write-Error "File not found: $MetaJsonPath. Something went wrong rendering pipeline variables."
exit 1
}

if ($Target -eq "DockerDesktop") {

Write-Error "Docker Desktop is currently not supported for CNAB v2. For now, please target GCP until we've added back support for Docker Desktop"
exit 1
Setup-DockerDesktop

# Build local app images for Docker Desktop
if (Test-Path "$PSScriptRoot/app/build-app-image.ps1") {
. "$PSScriptRoot/app/build-app-image.ps1"
}
else {
Write-Error "File not found: $PSScriptRoot/app/build-app-image.ps1"
exit 1
}

if ( Get-Command 'Build-Local-App-Image' -errorAction SilentlyContinue ) {
Build-Local-App-Image
}
else {
Write-Warning "Cannot find function Build-Local-App-Image in build-app-image.ps1. Assuming local images exists and can be used by Docker Desktop."
}
}
elseif ($Target -eq "GCP") {
Setup-GCP
}

if ($RunAsContainer) {
$appScriptPath = "$PSScriptRoot/app/app.ps1"
if (Test-Path $appScriptPath) {
. $appScriptPath
}
else {
Write-Error "File not found: $appScriptPath"
exit 1
}

if (Get-Command 'Get-AppName' -ErrorAction SilentlyContinue) {
$appName = Get-AppName
}
else {
Write-Error "Function Get-AppName not found. Please define the function before continuing."
exit 1
}

$CNABImage = "$appName-cnab:local"
# Build a local copy of CNAB image
docker build -t $CNABImage -f $PSScriptRoot/build/Dockerfile --build-arg BUNDLE_VERSION=$Version .

$dockerRunArgs = @()

if ($Target -eq "GCP") {
# Get current config path
$gcloudConfigDir = gcloud info --format='value(config.paths.global_config_dir)'
$dockerRunArgs += @(
"-v", "$($gcloudConfigDir):/root/.config/gcloud",
"--env", "GOOGLE_APPLICATION_CREDENTIALS=/gcp/creds.json"
)
}
elseif ($Target -eq "DockerDesktop") {
if ($IsWindows) {
$kubeConfigPath = "$env:USERPROFILE\.kube\config"
}
else {
$kubeConfigPath = "~/.kube/config"
}

$dockerRunArgs += @(
"-v", "$($kubeConfigPath):/.kube/config:ro",
"--env", "KUBECONFIG=/.kube/config"
)
}

$dockerRunArgs += @(
"-v", "$($MetaJsonPath):/variables.json",
"--env", "CNAB_ACTION=$Action",
"--env", "INSTALLATION_METADATA=/variables.json",
"--rm", "$CNABImage", "/cnab/app/run"
)

docker run $dockerRunArgs
}
else {

$env:CNAB_ACTION = $Action
$env:INSTALLATION_METADATA = $MetaJsonPath
$env:BUNDLE_VERSION = $Version

if ($DownloadLocalScriptsForLocalDebugging) {
# Read the CNAB base image from the Dockerfile
$DockerfilePath = "$PSScriptRoot/build/Dockerfile"
if (-not (Test-Path $DockerfilePath)) {
Write-Error "Dockerfile not found: $DockerfilePath"
exit 1
}

$CNABBaseImage = Select-String -Path $DockerfilePath -Pattern "^FROM\s+(.*)" | ForEach-Object { $_.Matches[0].Groups[1].Value }
if (-not $CNABBaseImage) {
Write-Error "Unable to find the base image in the Dockerfile"
exit 1
}

# Run the CNAB base image container to copy required files
$containerId = docker run -d --rm $CNABBaseImage tail -f /dev/null
docker cp "${containerId}:/cnab/app/" "$PSScriptRoot\"
docker rm -f $containerId
}

& "$PSScriptRoot\app\run.ps1"
}
108 changes: 108 additions & 0 deletions cnab/app/app.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
function Get-AppName() {
$app = 'opserver'
return $app
}

function Is-SingleRegistry() {
return $True
}

function Generate-Values($vars, $environment, $containerRegistryUrl, $releaseTag, $pullSecretName) {
Write-MajorStep "Generating Helm values"
$values = @{
tier = $environment
replicaCount = $vars.replicaCount
aspnetcoreEnvironment = $vars.aspnetcoreEnvironment
product = "pubplat"

db = @{
exceptionalDbName = $vars.exceptionalDbName;
}

images = @{
containerRegistry = "$containerRegistryUrl"
opserver = @{
tag = $releaseTag
}
}

requests = @{
cpu = $vars.requestsCPU
memory = $vars.requestsMemory
}

limits = @{
memory = $vars.limitsMemory
}

podDisruptionBudget = @{
minAvailable = $vars.podDisruptionBudgetMinAvailable
}

exceptional = @{
store = @{
type = $vars.exceptionalStoreType
}
}

datadog = @{
agentHost = $vars.datadogAgentHost
agentPort = $vars.datadogAgentPort
}

kestrel = @{
endPoints = @{
http = @{
url = "http://0.0.0.0:8080/"
containerPort = "8080"
}
}
}

secretStore = @{
fake = $vars.useFakeSecretStore
}

image = @{
pullSecretName = $pullSecretName
}

ingress = @{
className = "nginx-internal"
certIssuer = "letsencrypt-dns-prod"
host = $vars.opserverSettings.hostUrl
enabled = $vars.includeIngress
secretName = "opserver-tls"
createTlsCert = $true
}

sqlExternalSecret = @{
storeRefName = $vars.secretStore
}

configSecret = @{
storeRefName = $vars.secretStore
}

opserverExternalSecret = @{
storeRefName = $vars.secretStore
}

opserverSettings = $vars.opserverSettings

adminRolebindingGroupId = $vars.adminRolebindingGroupId

nodeScheduling = @{
# change to false if deploying locally to docker, or uninstall before installing the app to prevent node affinity issues
scheduleOnSeparateNodes = $true
}
}



# Helm expects a YAML file but YAML is also a superset of JSON, so we can use ConvertTo-Json here
$valuesFileContent = $values | ConvertTo-Json -Depth 100
Write-MinorStep "Populated Helm values:"
Write-MinorStep $valuesFileContent
return $valuesFileContent
}
3 changes: 3 additions & 0 deletions cnab/app/build-app-image.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function Build-Local-App-Image() {
docker build -t local.software/stackeng/opserver/opserver -t cr.stackoverflow.software/stackeng/opserver/opserver:local .
}
46 changes: 46 additions & 0 deletions cnab/app/variables.DockerDesktop.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"pipeline": {
"environment": "local",
"product": "pubplat",
"project": "opserver",
"releaseTag": "local"
},
"runtime": {
"cd": false,
"local": true,
"name": "DockerDesktop"
},
"vars": {
"secretStore": "fakeopserversecretstore",
"imagePullPolicy": "IfNotPresent",
"replicaCount": "1",
"aspnetcoreEnvironment": "Local",
"exceptionalStoreType": "Memory",
"exceptionalDbName": "",
"datadogAgentHost": "127.0.0.1",
"datadogAgentPort": "8125",
"includeIngress": "true",
"adminRolebindingGroupId": "",
"requestsCPU": "",
"requestsMemory": "",
"limitsMemory": "",
"isHADRPrimary": "true",
"podDisruptionBudgetMinAvailable": "1",
"opserverSettings": {
"hostUrl": "opserver.docker.local",

"sql": [
{ "name": "host.docker.internal" }
],
"exceptions": [
{ "serverName": "host.docker.internal", "database": "Local.Exceptions" }
],
"security": {
"adminGroups": "",
"viewGroups": "",
"provider": "EveryonesAnAdmin"
}

}
}
}
9 changes: 9 additions & 0 deletions cnab/build/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM cr.stackoverflow.software/so-pubplat-cnab:2025.1.7.92116@sha256:e1c7397eaa8b5d6b11db49b1150290782675b3dfae2b886770e5a2048b2fa745

COPY ./cnab/app /cnab/app
COPY ./charts /cnab/app/charts

ARG BUNDLE_VERSION
ENV BUNDLE_VERSION=${BUNDLE_VERSION}

CMD ["/cnab/app/run"]
8 changes: 4 additions & 4 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
@@ -197,7 +197,7 @@ The dashboard can currently monitor via SignalFx, Bosun, Orion or limited amount
/* If using Orion, a host (for links, not API) and a connection string needs to be provided */
//"orion": {
// "host": "orion.mydomain.com",
// "connectionString": "Data Source=ny-orionsql01;Initial Catalog=SolarWindsOrion;Integrated Security=SSPI;Timeout=10"
// "connectionString": "Data Source=ny-orionsql01;Initial Catalog=SolarWindsOrion;Integrated Security=SSPI;Timeout=10;TrustServerCertificate=True"
//}
},
/* General dashboard UI settings */
@@ -319,7 +319,7 @@ Exceptions from a [StackExchange.Exceptional](https://nickcraver.com/StackExchan
"queryTimeoutMs": 2000, // (Optional - default: 30000) The query timeout before giving up on this store (when shit hits the fan...maybe a store isn't available)
"pollIntervalSeconds": 30, // (Optional - default: 300) How often to poll this store for new/changed exceptions
// SQL Server connection string to the Exceptional store
"connectionString": "Server=ny-sql01;Database=NY.Exceptions;Integrated Security=SSPI;"
"connectionString": "Server=ny-sql01;Database=NY.Exceptions;Integrated Security=SSPI;TrustServerCertificate=True"
}
],
/* (Optional) Replacements for Stack Trace descriptions. It's general purpose with specific uses in mind.
@@ -494,7 +494,7 @@ Because AlwaysOn AGs can get into a state where the master does not know about t
{
// (Optional) The default connection string used unless specifically provided on a node
// $ServerName$ gets replaces with the name property of the instance
"defaultConnectionString": "Data Source=$ServerName$;Initial Catalog=master;Integrated Security=SSPI;",
"defaultConnectionString": "Data Source=$ServerName$;Initial Catalog=master;Integrated Security=SSPI;TrustServerCertificate=True",
"refreshIntervalSeconds": 30, // (Optional - default: 60) How often to poll all servers
"clusters": [ // (Optional) Always On Availability Group Clusters
{
@@ -510,7 +510,7 @@ Because AlwaysOn AGs can get into a state where the master does not know about t
"instances": [ // (Optional) Standalone instances
{ // An example with all the options configured
"name": "NY-DB05",
"connectionString": "Data Source=NY-DB05;Initial Catalog=bob;Integrated Security=SSPI;",
"connectionString": "Data Source=NY-DB05;Initial Catalog=bob;Integrated Security=SSPI;TrustServerCertificate=True",
"refreshIntervalSeconds": 200
},
// Some standalone servers (default instance) using default refresh and connection strings:
2 changes: 1 addition & 1 deletion docs/Docs.csproj
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<Project Sdk="Microsoft.Build.NoTargets/3.2.14">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
</Project>
1 change: 1 addition & 0 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@
<IncludeSymbols>false</IncludeSymbols>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<!--<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>-->
<NuGetAudit>false</NuGetAudit>
</PropertyGroup>
<!-- File nesting! -->
<ItemGroup>
10 changes: 9 additions & 1 deletion src/Opserver.Core/Data/Elastic/ElasticCluster.KnownNodes.cs
Original file line number Diff line number Diff line change
@@ -60,7 +60,15 @@ public ElasticNode(string hostAndPort, ElasticSettings.Cluster clusterSettings)
Host = hostAndPort;
Port = DefaultElasticPort;
}
Url = $"http://{Host}:{Port}/";

if (Port == 443)
{
Url = $"https://{Host}/";
}
else
{
Url = $"http://{Host}:{Port}/";
}
}

public override string ToString() => Host;
2 changes: 1 addition & 1 deletion src/Opserver.Core/Data/SQL/SQLAzureServer.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data.SqlClient;
using Microsoft.Data.SqlClient;

namespace Opserver.Data.SQL
{
2 changes: 1 addition & 1 deletion src/Opserver.Core/Data/SQL/SQLInstance.cs
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.SqlClient;
using Microsoft.Data.SqlClient;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Opserver.Helpers;
2 changes: 1 addition & 1 deletion src/Opserver.Core/Helpers/Connection.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using Microsoft.Data.SqlClient;
using System.Threading;
using System.Threading.Tasks;
using StackExchange.Profiling;
2 changes: 1 addition & 1 deletion src/Opserver.Core/Helpers/OpserverConfigException.cs
Original file line number Diff line number Diff line change
@@ -8,6 +8,6 @@ public class OpserverConfigException : Exception
public OpserverConfigException() { }
public OpserverConfigException(string message) : base(message) { }
public OpserverConfigException(string message, Exception innerException) : base(message, innerException) { }
protected OpserverConfigException(SerializationInfo info, StreamingContext context) : base(info, context) { }

}
}
34 changes: 19 additions & 15 deletions src/Opserver.Core/Opserver.Core.csproj
Original file line number Diff line number Diff line change
@@ -2,31 +2,35 @@
<PropertyGroup>
<RootNamespace>Opserver</RootNamespace>
<AssemblyName>Opserver.Core</AssemblyName>
<TargetFrameworks>net6.0</TargetFrameworks>
<TargetFrameworks>net8.0</TargetFrameworks>
<DebugSymbols>true</DebugSymbols>
<DebugType>embedded</DebugType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dapper" Version="2.0.123" />
<PackageReference Include="Enums.NET" Version="4.0.0" />
<PackageReference Include="Dapper" Version="2.1.35" />
<PackageReference Include="Enums.NET" Version="5.0.0" />
<PackageReference Include="Jil" Version="2.17.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.8" />
<PackageReference Include="MiniProfiler.Shared" Version="4.3.8" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.2" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.0" />
<PackageReference Include="Microsoft.Net.Http.Headers" Version="8.0.11" />
<PackageReference Include="MiniProfiler.Shared" Version="4.5.4" />
<PackageReference Include="Sigil" Version="5.0.0" />
<PackageReference Include="StackExchange.Exceptional.Shared" Version="2.2.32" />
<PackageReference Include="StackExchange.Redis" Version="2.6.122" />
<PackageReference Include="StackExchange.Exceptional.Shared" Version="3.0.1" />
<PackageReference Include="StackExchange.Redis" Version="2.8.22" />
<PackageReference Include="StackExchange.Utils.Http" Version="0.3.48" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.5" />
<PackageReference Include="System.DirectoryServices" Version="6.0.0" />
<PackageReference Include="System.Management" Version="6.0.0" />
<PackageReference Include="System.Runtime.Caching" Version="6.0.0" />
<PackageReference Include="System.DirectoryServices" Version="9.0.0" />
<PackageReference Include="System.Management" Version="9.0.0" />
<PackageReference Include="System.Runtime.Caching" Version="9.0.0" />
</ItemGroup>
<ItemGroup>
<Compile Update="Data\SQL\QueryPlans\ShowPlanXML.cs" SubType="Code" />
<Compile Update="Data\SQL\QueryPlans\ShowPlanXML.generated.cs" SubType="Code" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageReference Update="Nerdbank.GitVersioning" Version="3.7.112" />
</ItemGroup>
</Project>
33 changes: 17 additions & 16 deletions src/Opserver.Web/Controllers/AuthController.OIDC.cs
Original file line number Diff line number Diff line change
@@ -27,6 +27,21 @@ partial class AuthController
private const string OidcIdentifierKey = "id";
private const string OidcReturnUrlKey = "returnUrl";

private string GetRedirectUri()
{
var oidcSettings = (OIDCSecuritySettings) Current.Security.Settings;
var scheme = (oidcSettings.UseHttpsForRedirects ? "https" : Request.Scheme);
var redirectUri = Url.Action(
nameof(OAuthCallback),
ControllerContext.ActionDescriptor.ControllerName,
null,
scheme,
Request.Host.Value,
null
);
return redirectUri;
}

[AllowAnonymous]
[HttpGet("login/oauth/callback")]
public async Task<IActionResult> OAuthCallback(string code, string state, string error = null)
@@ -74,14 +89,7 @@ public async Task<IActionResult> OAuthCallback(string code, string state, string
// hooray! we're all set, let's go fetch our access token
var oidcSettings = (OIDCSecuritySettings) Current.Security.Settings;
var scopes = oidcSettings.Scopes ?? OIDCSecuritySettings.DefaultScopes;
var redirectUri = Url.Action(
nameof(OAuthCallback),
ControllerContext.ActionDescriptor.ControllerName,
null,
Request.Scheme,
Request.Host.Value,
null
);
var redirectUri = GetRedirectUri();

var form = new NameValueCollection
{
@@ -216,14 +224,7 @@ private IActionResult RedirectToProvider(string returnUrl)
});

var oidcSettings = (OIDCSecuritySettings) Current.Security.Settings;
var redirectUri = Url.Action(
nameof(OAuthCallback),
ControllerContext.ActionDescriptor.ControllerName,
null,
Request.Scheme,
Request.Host.Value,
null
);
var redirectUri = GetRedirectUri();

// construct the URL to the authorization endpoint
var authorizationUrl = new UriBuilder(oidcSettings.AuthorizationUrl);
27 changes: 22 additions & 5 deletions src/Opserver.Web/Opserver.Web.csproj
Original file line number Diff line number Diff line change
@@ -2,16 +2,29 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<RootNamespace>Opserver</RootNamespace>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.0" />
<ProjectReference Include="..\Opserver.Core\Opserver.Core.csproj" />
<PackageReference Include="BuildBundlerMinifier" Version="3.2.449" PrivateAssets="all" />
<PackageReference Include="BuildWebCompiler" Condition="'$(OS)' == 'Windows_NT'" Version="1.12.405" PrivateAssets="all" />
<PackageReference Include="MiniProfiler.AspNetCore.Mvc" Version="4.2.22" />
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="6.15.0" />
<PackageReference Include="StackExchange.Exceptional.AspNetCore" Version="2.2.32" />
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="6.0.0" />
<PackageReference Include="MiniProfiler.AspNetCore.Mvc" Version="4.5.4" />
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.3.0" />
<PackageReference Include="Serilog" Version="4.2.0" />
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" />
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageReference Include="Serilog.Enrichers.Environment" Version="3.0.1" />
<PackageReference Include="Serilog.Enrichers.Sensitive" Version="1.7.3" />
<PackageReference Include="Serilog.Enrichers.Thread" Version="4.0.0" />
<PackageReference Include="Serilog.Exceptions" Version="8.4.0" />
<PackageReference Include="Serilog.Expressions" Version="5.0.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="9.0.0" />
<PackageReference Include="Serilog.Sinks.Async" Version="2.1.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.Debug" Version="3.0.0" />
<PackageReference Include="StackExchange.Exceptional.AspNetCore" Version="3.0.1" />
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="9.0.0" />
<Reference Include="System.Management" />
</ItemGroup>
<ItemGroup>
@@ -23,4 +36,8 @@
<None Include="Config\*.example.json" />
<None Include="compilerconfig.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageReference Update="Nerdbank.GitVersioning" Version="3.7.112" />
</ItemGroup>
</Project>
52 changes: 42 additions & 10 deletions src/Opserver.Web/Program.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Opserver.Helpers;

using Opserver.Helpers;
using Serilog;
using Serilog.Enrichers.Sensitive;
using Serilog.Exceptions;
namespace Opserver
{
public static class Program
@@ -17,6 +22,7 @@ private static async Task<int> Main(string[] args)
{
try
{

var host = WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(
(_, config) =>
@@ -36,17 +42,43 @@ private static async Task<int> Main(string[] args)
// End compat
.AddJsonFile("Config/opserverSettings.json", optional: true, reloadOnChange: true)
.AddJsonFile("opserverSettings.json", optional: true, reloadOnChange: true)
.AddJsonFile("localSettings.json", optional: true, reloadOnChange: true);
}
)
.ConfigureLogging(
(hostingContext, config) =>
{
var loggingConfig = hostingContext.Configuration.GetSection("Logging");
config.AddConfiguration(loggingConfig)
.AddConsole();
.AddJsonFile("localSettings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
}
)
.ConfigureLogging(
(hostingContext, config) =>
{
config.ClearProviders();

var dataDogServiceName = Environment.GetEnvironmentVariable("DD_SERVICE") ?? "opserver";
var product = hostingContext.Configuration.GetValue<string>("Product");
var tier = hostingContext.Configuration.GetValue<string>("Tier");

var loggerconfig = new LoggerConfiguration()
.ReadFrom.Configuration(hostingContext.Configuration)
.Enrich.FromLogContext()
.Enrich.WithEnvironmentUserName()
.Enrich.WithEnvironmentName()
.Enrich.WithProperty("dd_service", dataDogServiceName)
.Enrich.WithMachineName()
.Enrich.WithThreadId()
.Enrich.WithExceptionDetails()
.Enrich.WithSensitiveDataMasking(options =>
{
options.MaskingOperators = new List<IMaskingOperator>
{
new EmailAddressMaskingOperator()
};
});

loggerconfig.Filter.ByExcluding("StartsWith(SourceContext, 'StackExchange.Exceptional.')");
loggerconfig.Filter.ByExcluding("SourceContext='Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware' and @mt='An unhandled exception has occurred while executing the request.'");

Log.Logger = loggerconfig.CreateLogger();
config.AddSerilog(Log.Logger);
}
)
.UseStartup<Startup>()
.Build();

5 changes: 5 additions & 0 deletions src/Opserver.Web/Security/OIDCSecuritySettings.cs
Original file line number Diff line number Diff line change
@@ -46,5 +46,10 @@ public class OIDCSecuritySettings : SecuritySettings
/// Gets or sets the name of the "name" claim.
/// </summary>
public string GroupsClaim { get; set; } = "groups";

/// <summary>
/// When redirecting to an OIDC provider, whether to always use https for the redirect/referral.
/// </summary>
public bool UseHttpsForRedirects { get; set; } = false;
}
}
47 changes: 44 additions & 3 deletions src/Opserver.Web/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;
using Opserver.Data;
using Opserver.Helpers;
using Opserver.Security;
using Serilog;
using StackExchange.Exceptional;
using StackExchange.Profiling;

namespace Opserver
@@ -59,8 +66,9 @@ public void ConfigureServices(IServiceCollection services)
_configuration.GetSection("Exceptional"),
settings =>
{
settings.UseExceptionalPageOnThrow = true;
settings.UseExceptionalPageOnThrow = false;
settings.DataIncludeRegex = new Regex("^(Redis|Elastic|ErrorLog|Jil)", RegexOptions.Singleline | RegexOptions.Compiled);
settings.OnAfterLog += ExceptionalAfterLog;
settings.GetCustomData = (ex, data) =>
{
// everything below needs a context
@@ -158,14 +166,15 @@ public void ConfigureServices(IServiceCollection services)
foreach (var knownNetwork in knownNetworks)
{
var ipNet = IPNet.Parse(knownNetwork);
options.KnownNetworks.Add(new IPNetwork(ipNet.IPAddress, ipNet.CIDR));
options.KnownNetworks.Add(new Microsoft.AspNetCore.HttpOverrides.IPNetwork(ipNet.IPAddress, ipNet.CIDR));
}
}
}
);
services.AddSingleton<SecurityManager>();
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);
services.AddMvc();
services.AddHealthChecks();
}

private static readonly StringValues DefaultCacheControl = new CacheControlHeaderValue
@@ -212,9 +221,41 @@ IEnumerable<StatusModule> modules
return next();
})
.UseResponseCaching()
.UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute());
.UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute())
.UseHealthChecks("/health-checks/ready",
// Readiness:
// Signal that the application has started and is ready to accept traffic.
// This also allows the application to signal that it is live but currently
// cannot accept new requests because for example it's currently overloaded.
// Kubernetes will not restart the application if this endpoint returns unhealthy.
new HealthCheckOptions
{
AllowCachingResponses = false,
Predicate = registration => registration.Tags.Contains("ready")
})
// Liveliness:
// Signal that the application is running and is ready to accept traffic. This
// endpoint is used to continually determine whether the entire application is
// still in a healthy state.
// Kubernetes _will_ restart the application if this endpoint returns unhealthy.
.UseHealthChecks("/health-checks/live",
new HealthCheckOptions
{
AllowCachingResponses = false,
Predicate =
_ => false // We don't use any healthchecks for liveliness, just that the app responds
});
NavTab.ConfigureAll(modules); // TODO: UseNavTabs() or something
Cache.Configure(settings);
}

private void ExceptionalAfterLog(object sender, ErrorAfterLogEventArgs args)
{
if (args != null)
{
string message = args.Error.Message;
Serilog.Log.Error(args.Error.Exception, "{Message}", message);
}
}
}
}
40 changes: 40 additions & 0 deletions src/Opserver.Web/appSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"Exceptional": {
"DataIncludeRegex": "^(Redis|Elastic|ErrorLog|Jil|ProtoBuf)",
"Store": {
"ApplicationName": "Core",
"Type": "Memory",
"ConnectionString": ""
}
},
"Serilog": {
"Using": [
"Serilog.Sinks.Console"
],
"Properties": {
"Application": "OpServer"
},
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "Async",
"Args": {
"configure": [
{
"Name": "Console",
"Args": {
"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact"
}
}
]
}
}
]
}
}
4 changes: 2 additions & 2 deletions src/Opserver.Web/opserverSettings.json
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@
"Modules": {
/* Configuration for the SQL Server dashboard */
"Sql": {
//"defaultConnectionString": "Data Source=$ServerName$;Initial Catalog=master;Integrated Security=SSPI;",
//"defaultConnectionString": "Data Source=$ServerName$;Initial Catalog=master;Integrated Security=SSPI;TrustServerCertificate=True",
//"refreshIntervalSeconds": 30,
//"instances": [
// { "name": "localhost" }
@@ -42,7 +42,7 @@
// {
// "name": "Local",
// "queryTimeoutMs": 2000,
// "connectionString": "Server=.;Database=Local.Exceptions;Integrated Security=SSPI;"
// "connectionString": "Server=.;Database=Local.Exceptions;Integrated Security=SSPI;TrustServerCertificate=True"
// }
//],
"stackTraceReplacements": [
8 changes: 4 additions & 4 deletions tests/Opserver.Tests/Opserver.Tests.csproj
Original file line number Diff line number Diff line change
@@ -2,11 +2,11 @@
<PropertyGroup>
<RootNamespace>Opserver.Tests</RootNamespace>
<AssemblyName>Opserver.Tests</AssemblyName>
<TargetFrameworks>net6.0</TargetFrameworks>
<TargetFrameworks>net8.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../src/Opserver.Web/Opserver.Web.csproj" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="6.0.1" />
</ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="8.0.11" />
</ItemGroup>
</Project>