From c5e6405fdc4ec71f49bcb9a3fc337a2aac589733 Mon Sep 17 00:00:00 2001 From: "delamain-network[bot]" <119858046+delamain-network[bot]@users.noreply.github.com> Date: Fri, 14 Jun 2024 13:39:29 +0000 Subject: [PATCH] Initial commit --- .container/Dockerfile | 34 ++ .github/CODEOWNERS | 7 + .github/ISSUE_TEMPLATE/bug_report.md | 24 ++ .github/ISSUE_TEMPLATE/feature_request.md | 20 ++ .github/dependabot.yml | 12 + .github/pull_request_template.md | 18 ++ .github/workflows/build.yaml | 137 ++++++++ .github/workflows/deploy.yaml | 82 +++++ .github/workflows/release.yaml | 21 ++ .gitignore | 355 +++++++++++++++++++++ .helm/.helmignore | 23 ++ .helm/Chart.yaml | 24 ++ .helm/templates/_helpers.tpl | 58 ++++ .helm/templates/cluster-role-binding.yaml | 12 + .helm/templates/configmap-akka.yaml | 24 ++ .helm/templates/configmap-app-tracer.yaml | 16 + .helm/templates/configmap-appsettings.yaml | 19 ++ .helm/templates/deployment.yaml | 86 +++++ .helm/templates/secret-provider.yaml | 31 ++ .helm/templates/service-account.yaml | 12 + .helm/templates/service.yaml | 15 + .helm/values.yaml | 51 +++ DotnetProject.sln | 22 ++ README.md | 22 ++ src/DotnetProject.csproj | 11 + src/Program.cs | 5 + test/DotnetProjectTests.csproj | 32 ++ test/UnitTest1.cs | 11 + 28 files changed, 1184 insertions(+) create mode 100644 .container/Dockerfile create mode 100644 .github/CODEOWNERS create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/dependabot.yml create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/build.yaml create mode 100644 .github/workflows/deploy.yaml create mode 100644 .github/workflows/release.yaml create mode 100644 .gitignore create mode 100644 .helm/.helmignore create mode 100644 .helm/Chart.yaml create mode 100644 .helm/templates/_helpers.tpl create mode 100644 .helm/templates/cluster-role-binding.yaml create mode 100644 .helm/templates/configmap-akka.yaml create mode 100644 .helm/templates/configmap-app-tracer.yaml create mode 100644 .helm/templates/configmap-appsettings.yaml create mode 100644 .helm/templates/deployment.yaml create mode 100644 .helm/templates/secret-provider.yaml create mode 100644 .helm/templates/service-account.yaml create mode 100644 .helm/templates/service.yaml create mode 100644 .helm/values.yaml create mode 100644 DotnetProject.sln create mode 100644 README.md create mode 100644 src/DotnetProject.csproj create mode 100644 src/Program.cs create mode 100644 test/DotnetProjectTests.csproj create mode 100644 test/UnitTest1.cs diff --git a/.container/Dockerfile b/.container/Dockerfile new file mode 100644 index 0000000..bdbb63d --- /dev/null +++ b/.container/Dockerfile @@ -0,0 +1,34 @@ +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env +ARG NUGET_TOKEN +ARG PROJECT_NAME + +WORKDIR /app + +# Copy csproj and restore as distinct layers +COPY src/*.csproj ./ +RUN dotnet nuget add source --username USERNAME --password $NUGET_TOKEN --store-password-in-clear-text --name github "https://nuget.pkg.github.com/SneaksAndData/index.json" +RUN dotnet restore + +# Copy everything else and build +COPY src/. ./ +RUN dotnet publish "$PROJECT_NAME.csproj" -c Release -o out + +# Build runtime image +FROM mcr.microsoft.com/dotnet/aspnet:6.0-bullseye-slim +ARG TRACER_VERSION="2.32.0" +ARG PROJECT_NAME +ENV PROJECT_ASSEMBLY=$PROJECT_NAME + +RUN apt-get update -y && apt-get install -y curl jq + +# Download and install the Datadog Tracer +RUN mkdir -p /opt/datadog \ + && mkdir -p /var/log/datadog \ + && curl -LO https://github.com/DataDog/dd-trace-dotnet/releases/download/v${TRACER_VERSION}/datadog-dotnet-apm_${TRACER_VERSION}_amd64.deb \ + && dpkg -i ./datadog-dotnet-apm_${TRACER_VERSION}_amd64.deb \ + && rm ./datadog-dotnet-apm_${TRACER_VERSION}_amd64.deb + + +WORKDIR /app +COPY --from=build-env /app/out . +ENTRYPOINT "dotnet" "$PROJECT_ASSEMBLY.dll" diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..815c5da --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,7 @@ +# This is a comment. +# Each line is a file pattern followed by one or more owners. + +# These owners will be the default owners for everything in +# the repo. Unless a later match takes precedence, these people will be requests a review +# review when someone opens a pull request. +* @SneaksAndData/platform-engineering diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..3be1bc5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,24 @@ +--- +name: Bug report +about: Create a report to help us improve +title: "[BUG]" +labels: code/bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..43bfbb2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "[FEATURE]" +labels: code/new-feature +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..a4c88af --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + - package-ecosystem: "nuget" + directory: "src/" + schedule: + interval: "weekly" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates to GitHub Actions every week + interval: "weekly" + day: "monday" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..e07a012 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,18 @@ +Fixes/Implements #. + +## Scope + +Implemented: +- Awesome new feature +- And another awesome new feature + +Additional changes: +- Refactored `AwesomeClass` +- Removed deprecated `AnotherClass` and `get_awesomeness` from `AwesomeClass` + +## Checklist + +- [ ] GitHub issue exists for this change. +- [ ] Unit tests added and they pass. +- [ ] Line Coverage is at least 80%. +- [ ] Review requested on `latest` commit. \ No newline at end of file diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..9270649 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,137 @@ +name: Run tests with coverage + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +# ! Replace DotnetProject and dotnet-project with project name in real repository +env: + PROJECT_NAME: DotnetProject + PROJECT_NAME_LOWER: dotnet-project + +jobs: + validate_commit: + name: Validate commit + runs-on: ubuntu-latest + if: ${{ github.ref != 'refs/heads/main' }} + permissions: + id-token: write # required for dependabot PRs + pull-requests: write # required for dependabot PRs + contents: read # required for dependabot PRs + steps: + - uses: actions/checkout@v4 + - name: Setup .NET + uses: actions/setup-dotnet@v4.0.0 + with: + dotnet-version: 6.0.x + - name: Restore dependencies + env: + NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }} + run: | + set -e + dotnet nuget add source --username USERNAME --password $NUGET_TOKEN --store-password-in-clear-text --name github "https://nuget.pkg.github.com/SneaksAndData/index.json" + dotnet clean && dotnet nuget locals all --clear + dotnet restore + - name: Build + run: dotnet build --no-restore + - name: Test + working-directory: ./test + run: | + dotnet add package coverlet.msbuild && + dotnet test ${PROJECT_NAME}Tests.csproj --configuration Debug --runtime linux-x64 /p:CollectCoverage=true /p:CoverletOutput=Coverage/ /p:CoverletOutputFormat=lcov --logger GitHubActions + - name: Publish Code Coverage + if: ${{ github.event_name == 'pull_request' && always() }} + uses: romeovs/lcov-reporter-action@v0.3.1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + lcov-file: ./test/Coverage/coverage.info + + build_image_and_chart: + name: Build Docker Image and Helm Charts + runs-on: ubuntu-latest + needs: [ validate_commit ] + # Remove the line below and uncomment the next one + if: ${{ false }} + # if: ${{ always() && (needs.validate_commit.result == 'success' || needs.validate_commit.result == 'skipped') }} + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@v4 + name: Checkout head commit + if: ${{ github.ref != 'refs/heads/main' && always() }} + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - uses: actions/checkout@v4 + name: Checkout main + if: ${{ github.ref == 'refs/heads/main' && always() }} + with: + fetch-depth: 0 + - name: Import Secrets (DEV) + uses: hashicorp/vault-action@v2.7.4 + with: + url: https://hashicorp-vault.production.sneaksanddata.com/ + role: github + method: jwt + secrets: | + /secret/data/applications/${{ env.PROJECT_NAME_LOWER }}/test/build acr_user ; + /secret/data/applications/${{ env.PROJECT_NAME_LOWER }}/test/build acr_name ; + /secret/data/applications/${{ env.PROJECT_NAME_LOWER }}/test/build acr_token ; + id: vault_secrets_dev + - name: Build and Push Image (DEV) + env: + AZCR_USER: ${{steps.vault_secrets_dev.outputs.acr_user}} + AZCR_TOKEN: ${{steps.vault_secrets_dev.outputs.acr_token}} + AZCR_REPO: ${{steps.vault_secrets_dev.outputs.acr_name}} + NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }} + run: | + set -e + echo "$AZCR_TOKEN" | docker login $AZCR_REPO.azurecr.io --username $AZCR_USER --password-stdin + version=$(git describe --tags --abbrev=7) + docker build -f .container/Dockerfile . \ + --tag=$AZCR_REPO.azurecr.io/$PROJECT_NAME_LOWER:$version \ + --build-arg NUGET_TOKEN=$NUGET_TOKEN \ + --build-arg PROJECT_NAME=$PROJECT_NAME && \ + docker push $AZCR_REPO.azurecr.io/$PROJECT_NAME_LOWER:$version + - name: Build and Push Chart (DEV) + uses: SneaksAndData/github-actions/build_helm_chart@v0.1.6 + with: + application: ${{ env.PROJECT_NAME_LOWER }} + container_registry_user: ${{steps.vault_secrets_dev.outputs.acr_user}} + container_registry_token: ${{steps.vault_secrets_dev.outputs.acr_token}} + container_registry_address: ${{steps.vault_secrets_dev.outputs.acr_name}}.azurecr.io + - name: Import Secrets (PROD) + uses: hashicorp/vault-action@v2.7.4 + if: ${{ github.ref == 'refs/heads/main' }} + with: + url: https://hashicorp-vault.production.sneaksanddata.com/ + role: github + method: jwt + secrets: | + /secret/data/applications/${{ env.PROJECT_NAME_LOWER }}/production/build acr_user ; + /secret/data/applications/${{ env.PROJECT_NAME_LOWER }}/production/build acr_name ; + /secret/data/applications/${{ env.PROJECT_NAME_LOWER }}/production/build acr_token ; + id: vault_secrets_production + - name: Push Image (PROD) + if: ${{ github.ref == 'refs/heads/main' }} + env: + AZCR_USER: ${{steps.vault_secrets_production.outputs.acr_user}} + AZCR_TOKEN: ${{steps.vault_secrets_production.outputs.acr_token}} + AZCR_REPO: ${{steps.vault_secrets_production.outputs.acr_name}} + AZCR_DEV_REPO: ${{steps.vault_secrets_dev.outputs.acr_name}} + run: | + set -e + echo "$AZCR_TOKEN" | docker login $AZCR_REPO.azurecr.io --username $AZCR_USER --password-stdin + version=$(git describe --tags --abbrev=7) + docker tag $AZCR_DEV_REPO.azurecr.io/$PROJECT_NAME_LOWER:$version $AZCR_REPO.azurecr.io/$PROJECT_NAME_LOWER:$version && docker push $AZCR_REPO.azurecr.io/$PROJECT_NAME_LOWER:$version + - name: Build and Push Chart (PROD) + if: ${{ github.ref == 'refs/heads/main' }} + uses: SneaksAndData/github-actions/build_helm_chart@v0.1.6 + with: + application: ${{ env.PROJECT_NAME_LOWER }} + container_registry_user: ${{steps.vault_secrets_production.outputs.acr_user}} + container_registry_token: ${{steps.vault_secrets_production.outputs.acr_token}} + container_registry_address: ${{steps.vault_secrets_production.outputs.acr_name}}.azurecr.io diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 0000000..c2e2194 --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,82 @@ +name: Deploy to AKS +run-name: Deploy ${{github.ref_name}} to ${{ inputs.environment }} by @${{ github.actor }} + +permissions: + pull-requests: write + contents: read + +on: + workflow_dispatch: + inputs: + environment: + description: Deployment target + required: true + type: environment + default: test +# ! Replace DotnetProject and dotnet-project with project name in real repository +env: + PROJECT_NAME: DotnetProject + PROJECT_NAME_LOWER: dotnet-project + +jobs: + deploy: + name: Deploy + runs-on: ubuntu-latest + environment: ${{ github.event.inputs.environment }} + permissions: + contents: read + id-token: write + # Remove the line below and uncomment the next one + if: ${{ false }} + steps: + - uses: actions/checkout@v4 + if: ${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/tags') && always() }} + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + - uses: actions/checkout@v4 + if: ${{ (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags')) && always() }} + with: + fetch-depth: 0 + - uses: azure/setup-helm@v3 + with: + version: '3.9.2' + id: install_helm + - name: Import Secrets + uses: hashicorp/vault-action@v2.7.4 + with: + url: https://hashicorp-vault.production.sneaksanddata.com/ + role: github + method: jwt + secrets: | + /secret/data/applications/${{ env.PROJECT_NAME_LOWER }}/${{github.event.inputs.environment}}/build acr_user ; + /secret/data/applications/${{ env.PROJECT_NAME_LOWER }}/${{github.event.inputs.environment}}/build acr_name ; + /secret/data/applications/${{ env.PROJECT_NAME_LOWER }}/${{github.event.inputs.environment}}/build aks_name ; + /secret/data/applications/${{ env.PROJECT_NAME_LOWER }}/${{github.event.inputs.environment}}/build cluster_sp_client_id ; + /secret/data/applications/${{ env.PROJECT_NAME_LOWER }}/${{github.event.inputs.environment}}/build cluster_sp_client_password ; + /secret/data/applications/${{ env.PROJECT_NAME_LOWER }}/${{github.event.inputs.environment}}/build acr_token ; + - name: Deployment + working-directory: .helm + env: + DEPLOY_ENVIRONMENT: ${{ github.event.inputs.environment }} + run: | + set -e + echo 'Getting cluster credentials' + az login --service-principal --username $CLUSTER_SP_CLIENT_ID --password $CLUSTER_SP_CLIENT_PASSWORD --tenant 06152121-b4c5-4544-abf5-9268e75db448 + az aks get-credentials --name $AKS_NAME --resource-group $AKS_NAME + chart_version=$(git describe --tags --abbrev=7) + + echo 'Logging to ACR' + helm registry login $ACR_NAME.azurecr.io --username $ACR_NAME --password $ACR_TOKEN + + echo 'Installing chart' + helm pull oci://$ACR_NAME.azurecr.io/helm/$PROJECT_NAME_LOWER --version $chart_version + mkdir -p ./$PROJECT_NAME_LOWER + tar xzf "$PROJECT_NAME_LOWER-${chart_version}.tgz" -C ./$PROJECT_NAME_LOWER + + helm upgrade --install $PROJECT_NAME_LOWER -n $PROJECT_NAME_LOWER --values ./values.yaml \ + --set environment=${DEPLOY_ENVIRONMENT^} \ + --set image.repository=$ACR_NAME.azurecr.io/$PROJECT_NAME_LOWER \ + --set image.tag=$chart_version \ + --set secretStorage.deploymentClusterName=$AKS_NAME \ + ./$PROJECT_NAME_LOWER/$PROJECT_NAME_LOWER diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..82e3d80 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,21 @@ +name: Release a new version + +on: workflow_dispatch + +jobs: + create_release: + name: Create Release + runs-on: ubuntu-latest + # Remove the line below and uncomment the next one + if: ${{ false }} + #if: ${{ github.ref == 'refs/heads/main' }} + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Create Release + uses: SneaksAndData/github-actions/semver_release@v0.1.6 + with: + major_v: 0 + minor_v: 0 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ca116ed --- /dev/null +++ b/.gitignore @@ -0,0 +1,355 @@ +# VS launchsettings +src/Properties/launchSettings.json + +.idea/ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ +NuGet.Config diff --git a/.helm/.helmignore b/.helm/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/.helm/.helmignore @@ -0,0 +1,23 @@ +# 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/ diff --git a/.helm/Chart.yaml b/.helm/Chart.yaml new file mode 100644 index 0000000..a6d5ea8 --- /dev/null +++ b/.helm/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: dotnet-project +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: 0.0.0 + +# 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.0" diff --git a/.helm/templates/_helpers.tpl b/.helm/templates/_helpers.tpl new file mode 100644 index 0000000..6815276 --- /dev/null +++ b/.helm/templates/_helpers.tpl @@ -0,0 +1,58 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "app.name" -}} +{{- default .Chart.Name | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "app.fullname" -}} +{{- $name := .Chart.Name }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "app.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "app.labels" -}} +helm.sh/chart: {{ include "app.chart" . }} +{{ include "app.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "app.selectorLabels" -}} +app.kubernetes.io/name: {{ include "app.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "app.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "app.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/.helm/templates/cluster-role-binding.yaml b/.helm/templates/cluster-role-binding.yaml new file mode 100644 index 0000000..eabf8bc --- /dev/null +++ b/.helm/templates/cluster-role-binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "app.serviceAccountName" . }}-auth-delegator +subjects: + - kind: ServiceAccount + name: {{ template "app.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator diff --git a/.helm/templates/configmap-akka.yaml b/.helm/templates/configmap-akka.yaml new file mode 100644 index 0000000..fb3712e --- /dev/null +++ b/.helm/templates/configmap-akka.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "app.name" . }}-akka-config + labels: + app.kubernetes.io/name: {{ template "app.name" . }} + {{- include "app.labels" . | nindent 4 }} +data: + akka.conf: | + akka { + stdout-loglevel = INFO + loggers=["Akka.Logger.Serilog.SerilogLogger, Akka.Logger.Serilog"] + loglevel = INFO + log-config-on-start = on + actor { + debug { + receive = on + autoreceive = on + lifecycle = on + event-stream = on + unhandled = on + } + } + } diff --git a/.helm/templates/configmap-app-tracer.yaml b/.helm/templates/configmap-app-tracer.yaml new file mode 100644 index 0000000..f9c839c --- /dev/null +++ b/.helm/templates/configmap-app-tracer.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "app.name" . }}-tracer + labels: + app.kubernetes.io/name: {{ template "app.name" . }} + {{- include "app.labels" . | nindent 4 }} +data: + DD_ENV: "{{ .Values.environment }}" + DD_SERVICE: "{{ template "app.name" . }}" + DD_VERSION: "{{ .Values.image.tag }}" + DD_LOGS_INJECTION: "true" + DD_APPSEC_ENABLED: "false" + DD_TRACE_SAMPLE_RATE: "1.0" + DD_RUNTIME_METRICS_ENABLED: "true" + DD_PROFILING_ENABLED: "0" diff --git a/.helm/templates/configmap-appsettings.yaml b/.helm/templates/configmap-appsettings.yaml new file mode 100644 index 0000000..183243c --- /dev/null +++ b/.helm/templates/configmap-appsettings.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "app.name" . }}-config + labels: + app.kubernetes.io/name: {{ template "app.name" . }} + {{- include "app.labels" . | nindent 4 }} +data: + appsettings.json: | + { + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" + } + diff --git a/.helm/templates/deployment.yaml b/.helm/templates/deployment.yaml new file mode 100644 index 0000000..d0b4a23 --- /dev/null +++ b/.helm/templates/deployment.yaml @@ -0,0 +1,86 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "app.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "app.selectorLabels" . | nindent 8 }} + spec: + serviceAccountName: {{ include "app.serviceAccountName" . }} + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: {{ .Values.nodes.taint }} + operator: In + values: + - {{ .Values.nodes.taintValue }} + tolerations: + - key: {{ .Values.nodes.taint }} + operator: Equal + value: {{ .Values.nodes.taintValue }} + effect: NoSchedule + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + env: + - name: ASPNETCORE_ENVIRONMENT + value: {{ .Values.environment }} + - name: APPLICATION_VERSION + value: {{ .Values.image.tag }} + - name: PROTEUS__DATADOG_SITE + value: {{ .Values.logs.datadogSite }} + - name: PROTEUS__DD_STATSD_HOST + value: {{ .Values.metrics.statsd_host }} + - name: PROTEUS__DD_STATSD_PORT + value: {{ .Values.metrics.statsd_port | quote }} + - name: PROTEUS__DEFAULT_LOG_LEVEL + value: {{ .Values.logs.logLevel | quote }} + {{- toYaml .Values.apm.environment | nindent 12 }} + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + path: /health + port: http + readinessProbe: + httpGet: + path: /health/ready + port: http + resources: + limits: + cpu: {{ .Values.resources.cpu }} + memory: {{ .Values.resources.memory }} + requests: + cpu: {{ .Values.resources.cpu }} + memory: {{ .Values.resources.memory }} + volumeMounts: + - name: apmsocketpath + mountPath: /var/run/datadog + - name: {{ template "app.name" . }}-akka-config + mountPath: /app/akka.conf + subPath: akka.conf + - name: {{ template "app.name" . }}-secrets + mountPath: /app/kube-config/ + readOnly: true + volumes: + - name: apmsocketpath + hostPath: + path: /var/run/datadog/ + - name: {{ template "app.name" . }}-config + configMap: + name: {{ template "app.name" . }}-config + - name: {{ template "app.name" . }}-akka-config + configMap: + name: {{ template "app.name" . }}-akka-config diff --git a/.helm/templates/secret-provider.yaml b/.helm/templates/secret-provider.yaml new file mode 100644 index 0000000..f198e54 --- /dev/null +++ b/.helm/templates/secret-provider.yaml @@ -0,0 +1,31 @@ +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: {{ template "app.name" . }}-secret-provider +spec: + provider: vault + secretObjects: + - secretName: {{ template "app.name" . }}-secrets + data: + {{- range .Values.secretStorage.secrets }} + {{- range .keys }} + - key: {{ . }} + objectName: {{ . }} + {{- end }} + {{- end }} + type: Opaque + parameters: + roleName: {{ .Values.secretStorage.roleName }} + vaultAddress: {{ .Values.secretStorage.address }} + vaultKubernetesMountPath: kubernetes/{{ .Values.secretStorage.deploymentClusterName }} + {{- if .Values.secretStorage.secrets }} + objects: | + {{- range .Values.secretStorage.secrets }} + {{- $path := .path }} + {{- range .keys }} + - objectName: {{ . }} + secretPath: {{ lower (tpl $path $) }} + secretKey: {{ . }} + {{- end }} + {{- end }} + {{- end }} diff --git a/.helm/templates/service-account.yaml b/.helm/templates/service-account.yaml new file mode 100644 index 0000000..bfeb176 --- /dev/null +++ b/.helm/templates/service-account.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "app.serviceAccountName" . }} + labels: + {{- include "app.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/.helm/templates/service.yaml b/.helm/templates/service.yaml new file mode 100644 index 0000000..1d66d1f --- /dev/null +++ b/.helm/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "app.fullname" . }} + labels: + {{- include "app.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + {{- include "app.selectorLabels" . | nindent 4 }} diff --git a/.helm/values.yaml b/.helm/values.yaml new file mode 100644 index 0000000..e6b7a94 --- /dev/null +++ b/.helm/values.yaml @@ -0,0 +1,51 @@ +environment: "Development" +replicaCount: 1 + +image: + repository: dotnet-project + # Overrides the image tag whose default is the chart appVersion. + tag: "v0.0.0" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +metrics: + statsd_host: "datadog-statsd.datadog.svc.cluster.local" + statsd_port: 8125 +logs: + datadogSite: "https://http-intake.logs.datadoghq.eu" + logLevel: "INFO" + +resources: + cpu: 100m + memory: 128Mi + +apm: + environment: + - name: CORECLR_ENABLE_PROFILING + value: "1" + - name: CORECLR_PROFILER + value: "{846F5F1C-F9AE-4B07-969E-05C26BC060D8}" + - name: CORECLR_PROFILER_PATH + value: "/opt/datadog/Datadog.Trace.ClrProfiler.Native.so" + - name: DD_DOTNET_TRACER_HOME + value: "/opt/datadog" + - name: DD_INTEGRATIONS + value: "/opt/datadog/integrations.json" + - name: LD_PRELOAD + value: "/opt/datadog/continuousprofiler/Datadog.Linux.ApiWrapper.x64.so" + +nodes: + taint: "kubernetes.sneaksanddata.com/servicenodetype" + taintValue: "dotnet-project" + +secretStorage: + address: "https://hashicorp-vault.production.sneaksanddata.com" + roleName: "application" + deploymentClusterName: "" diff --git a/DotnetProject.sln b/DotnetProject.sln new file mode 100644 index 0000000..9e3e7a8 --- /dev/null +++ b/DotnetProject.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetProject", "src\DotnetProject.csproj", "{67711D50-E64C-4A18-871B-DC6A485DD9E4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetProjectTests", "test\DotnetProjectTests.csproj", "{B74A1EEE-CC43-4FFF-A6AB-129387D32F40}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {67711D50-E64C-4A18-871B-DC6A485DD9E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {67711D50-E64C-4A18-871B-DC6A485DD9E4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {67711D50-E64C-4A18-871B-DC6A485DD9E4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {67711D50-E64C-4A18-871B-DC6A485DD9E4}.Release|Any CPU.Build.0 = Release|Any CPU + {B74A1EEE-CC43-4FFF-A6AB-129387D32F40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B74A1EEE-CC43-4FFF-A6AB-129387D32F40}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B74A1EEE-CC43-4FFF-A6AB-129387D32F40}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B74A1EEE-CC43-4FFF-A6AB-129387D32F40}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/README.md b/README.md new file mode 100644 index 0000000..e86109b --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# Template repository for .NET projects + +Use this repo to create new python projects with ready-to-go build and deploy pipelines. + +## Checklist + +Remember to do the following after creating a new repo: + +- :heavy_check_mark: Search and replace `dotnet-project` and `dotnet_project` with your desired project name +- :heavy_check_mark: Select build and deploy pipelines to use in `workflows/` dir. + - Remove dummy code and uncomment real code + - Remove pipelines you won't need +- :heavy_check_mark: Set up helm chart in .helm directory +- :heavy_check_mark: Rename solution file in root of the repository +- :heavy_check_mark: Rename project file under /src directory in the repository +- :heavy_check_mark: Rename test project file under /test directory in the repository +- :heavy_check_mark: Update the CODEOWNERS file with real code owners +- :heavy_check_mark: Update all versions of actions to the latest release of [github-actions](https://github.com/SneaksAndData/github-actions) repository +- :heavy_check_mark: Update this README. + +Happy coding! + diff --git a/src/DotnetProject.csproj b/src/DotnetProject.csproj new file mode 100644 index 0000000..4cc95ce --- /dev/null +++ b/src/DotnetProject.csproj @@ -0,0 +1,11 @@ + + + + Exe + net6.0 + + + + + + diff --git a/src/Program.cs b/src/Program.cs new file mode 100644 index 0000000..71e7a3a --- /dev/null +++ b/src/Program.cs @@ -0,0 +1,5 @@ +// See https://aka.ms/new-console-template for more information + +using System; + +Console.WriteLine("Hello, World!"); \ No newline at end of file diff --git a/test/DotnetProjectTests.csproj b/test/DotnetProjectTests.csproj new file mode 100644 index 0000000..764ee4d --- /dev/null +++ b/test/DotnetProjectTests.csproj @@ -0,0 +1,32 @@ + + + + net6.0 + + false + + DotnetProject.Tests + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/test/UnitTest1.cs b/test/UnitTest1.cs new file mode 100644 index 0000000..269095c --- /dev/null +++ b/test/UnitTest1.cs @@ -0,0 +1,11 @@ +using Xunit; + +namespace DotnetProject.Tests; + +public class UnitTest1 +{ + [Fact] + public void Test1() + { + } +} \ No newline at end of file