# Question
Title: How does Hashicorp's Vault compare to Lastpass?
In this section Hashicorp compares `Vault` with other solutions. How does Hashicorp's Vault compare to Lastpass?

**Attempt to answer the question**

It is possible to login to LastPass from a web browser, create secrets and share these with other users. There does not seem to be an audit log. Imagine that a password of one of the users is retrieved one could retrieve a password from a database without knowing it.

# Answer
I don't have enough rep to comment but I'm going to expand on what RuBiCK said.

In the first case, if you have a password for JIRA that I'm going to use to log in to the website with and fiddle with some tasks, then this goes in LastPass. You can store it there and use the extension or the vault to help me remember a complex password. You can also use LastPass to send credentials to my team members and then they can use LastPass to log in with.

In the second case, if you have made a script which asks AWS for what instances you have running right now then that script is going to need some credentials to log in with. You could put them in LastPass if you wanted but every time you went to run the script it would mean you have to go and get them from LastPass, enter them into the script somehow and get my list of instances.

Vault however presents an API which your script can use to ask for credentials when it runs. The credentials are stored in a secure way by Vault and you can now store much more in there as well.

The above is also why Vault wouldn't be useful for most people to do what they want to do. You don't want to have to write something to talk to Vault and create browser extensions etc when LastPass is, kind of, affordable and good at what it does.

I hope this helps!
> 6 votes

# Answer
Lastpass is for your personal (or team) passwords. I would not use Lastpass for storing credentials of service accounts.

Use HashiCorp's Vault or any other solution like Amazon KMS for infrastructure secrets.
> 2 votes

# Answer
While this is a very old question, I’ll add a bit to it to anyone landing here.

I’m not familiar with Laspass specifically but assuming its internals are similar to others such as Bitwarden: server has no access to your secrets. They are decrypted client-side with your master password.
For organization/shared secrets, a separate key is used to encrypt them and then stored as a personal secret of each user (encrypted by their master password).

In vault, every secret is encrypted by a single master key. That key is split into 3 partial keys which *should* be kept by different people.
Not sure about the details but 2 out of those 3 keys are required to “unlock” vault for anyone to use.
Secrets are then decrypted server side and delivered in plaintext to the clients. Policies and ACLs prevent accessing secrets that you shouldn’t but anyone able to create/modify policies can read any secret.

In short, IMO, vault is nice for “organization” secrets but I would never put my personal ones there.
> 0 votes

---
Tags: hashicorp-vault
---


# Question
Title: I can't find the jenkins password to unlock the website
I'm trying to install Jenkins, but, in one part I need to unlock Jenkins, and I didn't find the file with the password, it doesn't exist on my pc. I tried to run this command on my terminal (Windows):

```
java -jar jenkins.war

```

But this is the result: (I'm running the terminal as Administrator)

So what do I do now?

# Answer
> 1 votes
Try finding this file: C:\Program Files (x86)\Jenkins\secrets\initialAdminPassword

# Answer
> 0 votes
If you unable to find the the Initial password folder, then follow the below steps.

1. Install git bash on our system.
2. Open git bash
3. check your working directory and move to `C:\Program Files\Jenkins.`
4. Do `ls` command and you will see the `jenkins.war` folder.
5. execute the command `java jar jenkins.war`
6. Now do `ls` , you can see the `jenkins.err.log` file.
7. Do `cat jenkins.err.log` -- Now you can see the password within it copy it and post it on jenkins login.

---
Tags: jenkins
---


title: Variable for Terraform Workspace name?

text:
# Question
Title: Variable for Terraform Workspace name?
When I run `terraform apply` in a new workspace, I get

```
openstack_networking_port_secgroup_associate_v2.network_project_k3s: Creation complete after 1s [id=4543b73b-541e-40c3-a311-5b1f553b9d58]
╷
│ Error: Error trying to get network information from the Network API: More than one network found for name net_project
│
│   with openstack_compute_instance_v2.test-server,
│   on main.tf line 137, in resource "openstack_compute_instance_v2" "test-server":
│  137: resource "openstack_compute_instance_v2" "test-server" {

```

I suppose I'm getting this because OpenStack's network names are globally unique. How can I incorporate the workspace name in the network name?

```
resource "openstack_networking_network_v2" "net_project" {
  name           = "net_project_${WORKSPACE}"
  admin_state_up = "true"
}

```

# Answer
The variable I ended up using was

```
${terraform.workspace}

```

You can find more information about it under "Current Workspace Interpolation"
> 2 votes

---
Tags: terraform, openstack
---


# Question
Title: How to link containers in a "icc=false" bridge?
I'd like to connect several services with a reverse proxy. But the services can't communicate with each others.

I'm using a compose file for each service.

I'm trying to use the same external bridge (icc=false).

After that, I don't understand how to allow the different communication with the reverse proxy. I've tried links and external\_links but it doesn't work. Then, I have read that link will be deprecated...

Sorry for my english, I'm not a native speaker. Thanks, have a good day.

```
#Example of Test1 compose file:
version: '3'
services:
  app:
    image: nicolaka/netshoot:latest
    tty: true
    restart: always
    networks:
      app-net:
    external_links:
      - test2-app-1

networks:
  app-net:
    external:
      name: bridge_icc_false #created with com.docker.network.bridge.enable_icc=false

```

# Answer
`icc=false` means that inter-container communications are not allowed. If you want to allow inter-container communications, you need to run your containers on a network without this setting.
> 1 votes

---
Tags: docker, docker-compose, network
---


# Question
Title: Does Jenkins 2.289.2 have a customizable workspace?
I don't know where this is set, but jobs from my Jenkins 2.289.2 server appear to be working out of the directory `/home/jenkins/workspace/${job_name}`. E.g. if I have a minimal pipeline script that just `touch`es a path-unspecified file, it ends up in that directory.

**Question:** where is this setting viewable or editable in the Jenkins web UI?
**Question:** (assuming this is an editable setting) is this editable per-job, or is this only a global configuration?
**Question:** is this setting viewable in "Configuration as Code"? I don't see the directory anywhere in the yml generated by the `View Configuration` button at `${jenkins_url}:8080/configuration-as-code/`

# Answer
Your first question is a duplicate of this question.

Your second question. Each machine has a setting. So the Jenkins controller and the Jenkins Agent/s will each have its own setting.

You can change the workspace inside a pipeline. But I have never seen anyone do it.

I can't answer your last question because I don't have a jenkins with that plugin to look at but it is something that can be configured. I see in the README an example for setting it on an Agent.

EDIT: Thanks to @Ian we now know that those setters were moves to system properties. With that information I was able to research more on JasC and found that you can set the `rawBuildsDir` if you use the `restricted` flag. But you can set the `workspacedDir` unless you drop into a groovy init file. You can find all the information in this GitHub issue.
> 1 votes

---
Tags: jenkins
---


# Question
Title: Incorporating python linter(flake8) in the CI/CD pipeline that use GitHub, Github Actions in a code base that is not in compliance
I have a codebase that is not in compliance with flake8. The CI/CD pipeline uses GitHub/GitHub actions. I would like to start adding python flake8 (to check for complexity, errors and code smells) progressively. How can I accomplish this task?

# Answer
This should get you started: https://github.com/py-actions/flake8

Or if you prefer to do it more manually you can use this:

```
name: Python

on:
  push:
    branches: [main]
  pull_request:

jobs:
  flake8:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Set up Python
        uses: actions/setup-python@v4.1.0
        with:
          python-version: 3

      - name: Install flake8
        run: pip --disable-pip-version-check install flake8

      - name: Lint with flake8
        run: flake8 --count

```
> 0 votes

---
Tags: continuous-integration, continuous-deployment, github, github-actions, linting
---


# Question
Title: Guarantee latest version of Chrome on Azure VM
We have automated tests run by an Azure pipeline on an Azure VM and would like to guarantee that the latest version of Chrome is installed before running the tests. Is there any way to do this?

We use WebDriverManager.Net to automate the Selenium WebDriver binaries management which means we always use the latest versions of those binaries, but that also means that whenever the version changes we get this error on the next test run:

> System.InvalidOperationException: session not created: This version of ChromeDriver only supports Chrome version 104. Current browser version is 103.0.5060.134 with binary path C:\Program Files (x86)\Google\Chrome\Application\chrome.exe (SessionNotCreated).

The "solution" we've been using is to remote into the VM, open Chrome, and update it. Sometimes a VM restart is necessary as well. While this works, it's quite cumbersome, and ideally it would happen automatically before each test run.

Is there a better way to achieve this?

# Answer
> 1 votes
Create a PowerShell task in Azure DevOps and add this command to it

```
"C:\Program Files (x86)\Google\Update\GoogleUpdate.exe" /c | cmd

```

So we are running the google update exe in the command line which will update the google chrome before you run the other task. We are piping the command to cmd in PowerShell.

---
Tags: azure-devops, azure, azure-pipelines, vm, selenium
---


# Question
Title: Routing traffic from abc.com to xyz.com/abc
What is the most reliable way to route traffic from `abc.com` to `xyz.com/abc`? How does the server at `xyz.com` know for sure how to route the traffic to the `/abc` path?

I understand that it might be a lot easier to route traffic from `abc.com` to `abc.xyz.com`, but looking to do something potentially more dynamic here.

# Answer
> 2 votes
You are looking for a reverse proxy. Lots of loadbalancer type software has this functionality. Nginx and apache are very popular ones.

# Answer
> 1 votes
I'm not sure if it's the best option, but I would do as you described, first routing `abc.com` to `abc.xyz.com` via DNS records, and then letting the webserver, through a virtual host (at least that's how Apache calls it), take care of the redirection from `abc.xyz.com` to `xyz.com/abc`.

---
Tags: networking
---


title: Kubernetes Job Metrics in Prometheus

text:
# Question
Title: Kubernetes Job Metrics in Prometheus
I want to create a Kubernetes Job object like the example: https://kubernetes.io/docs/concepts/workloads/controllers/job/

Now imagine I want to have the result (in this case the value of Pi: `3.14159...`) available in Prometheus.

Is this possible?

In a more complex example, imagine the output of my pod was JSON:

```
{
  "foo": 200,
  "bar": 10,
  "baz": 999
}

```

I somehow need to denote that I'm interested in `foo` and `baz` (but not `bar`) "being available" in Prom (note I'm not opinionated on whether the solution is push or pull.

## Option 1

The first option I've thought of is somehow attaching the result `3.14159` to the job and Prom can scrape it as normal.

## Option 2

Don't run the Pi-generator container at all, instead run something like a Python script that runs the Pi process. Then we can push from Python to Prom.

## Option 3

Some other way?

# Answer
> 1 votes
I think your need may be an anti-pattern but I'm unsure.

Metrics are used to measure things and Metrics are correlated with time.

In your example, the job's output is a constant and not correlated with a time.

Metrics are often (!) measurements of the health (of the state) of a system rather than the output (product) of a system.

The job's duration, CPU, memory, success|failure etc. are conventional (!) measurements.

While it's entirely reasonable to want to capture time-series data (from Jobs), it may be (!) that a database or some other persistence mechanism would be a better sink for your data.

Answering your question as stated: Jobs are challenging because they are potentially unscrapeable (because they don't live sufficiently long) by Prometheus as part of its 'pull' mechanism.

Batch jobs are a valid use-case for Pushgateway. So, your Jobs could push metrics to Pushgateway to ensure that these are captured.

If the logs produced by your Jobs are persisted beyond the life of the Job, another approach is to derive metrics (by parsing) logs. This approach biases towards aggregation of log data. The examplar is counting HTTP 500s in log entries to determine a failure rate.

---
Tags: kubernetes, prometheus
---


title: kubernetes nginx ingress confusion

text:
# Question
Title: kubernetes nginx ingress confusion
I'm trying to get a feel for the Kubernetes Nginx ingress controller. Trying to deploy it to an AKS cluster, however I can't figure out the following. According to Create an ingress controller in Azure Kubernetes Service (AKS)

`To control image versions, you'll want to import them into your own Azure Container Registry. The NGINX ingress controller Helm chart relies on three container images. Use az acr import to import those images into your ACR.`

So, I've pulled, tagged and pushed the controller, patch and default backend images to ACR.

Next, did `helm show values ingress/nginx/ingress-nginx > values.yaml` and created a new `.yaml` to reference it a installation time (so that it can grab the images from ACR rather than the default repo).

However, after install I'm surprised to find only 1 pod related to nginx

```
NAME                                           READY   STATUS    RESTARTS   AGE
ingress-nginx-controller-764784f688-qbbq8      1/1     Running   0          49m

```

I've even tried to install it with the defaults without providing my own `.yaml` with `-f foo.yaml` like this:

```
 helm upgrade --install ingress-nginx ingress-nginx   --repo https://kubernetes.github.io/ingress-nginx   --namespace ingress-nginx --create-namespace

```

But still only 1 pod:

```
NAME                                        READY   STATUS    RESTARTS   AGE
ingress-nginx-controller-6bf7bc7f94-ml4js   1/1     Running   0          55s

```

Per my understanding this is what gets created:

What am I missing please ?

# Answer
ingress-nginx-controller-6bf7bc7f94-ml4js looks like a pod. Pods are not containers but they can contain containers. Why don't you describe it and see what containers it contains.
> 0 votes

# Answer
Did you include the line that said there should be two replicas?

> For added redundancy, two replicas of the NGINX ingress controllers are deployed with the `--set controller.replicaCount` parameter. To fully benefit from running replicas of the ingress controller, make sure there's more than one node in your AKS cluster.
> 0 votes

---
Tags: kubernetes, kubernetes-helm, ingress-nginx
---


# Question
Title: How to understand and resolve Jenkin job failure - Angular 13 app?
I'm new to Jenkins environment.

I was asked to upgrade **Angular 7.x** app which was built 3 to 5 yrs back into **Angular 13**. Upgrading the Angular app is done. now I want to deploy my UI changes through JENKINs. But my build getting failed. its been 4 days I'm trying to resolve the issues but couldn't make it,

Could someone help me to point out what the exact issue am facing and what needs to be done in order to resolve the build issue.

package.json

```
{
  "name": "@xxx-some-theme/this-is-my-angular-app-ui",
  "version": "4.1.0",
  "description": "Angular Frontend UI for Fraud Center APP TCC Limits",
  "scripts": {
    "ng": "ng",
    "build": "ng build",
    "build:watch": "ng build --watch",
    "test:ci": "ng test --browsers=ChromeHeadless --watch=false",
    "lint": "eslint --ext .js,.ts src",
    "jenkins": "run-s lint test:jenkins build:jenkins",
    "prebuild": "npm run lint",
    "pretest": "npm run lint",
    "build:jenkins": "ng build --prod --aot --build-optimizer --optimization --progress false",
    "test:jenkins": "ng test --code-coverage --watch false --progress false",
    "postbuild": "save-build-version",
    "postjenkins": "save-build-version"
  },
  "files": [
    "/dist",
    "nginx.conf",
    "mime.types"
  ],
  "dependencies": {
    "@angular/animations": "13.3.11",
    "@angular/cdk": "7.3.5",
    "@angular/common": "13.3.11",
    "@angular/compiler": "13.3.11",
    "@angular/core": "13.3.11",
    "@angular/forms": "13.3.11",
    "@angular/http": "7.2.15",
    "@angular/platform-browser": "13.3.11",
    "@angular/platform-browser-dynamic": "13.3.11",
    "@angular/router": "13.3.11",
    "@ngx-translate/core": "11.0.1",
    "@ngx-translate/http-loader": "4.0.0",
    "cerialize": "0.1.18",
    "chart.js": "3.8.0",
    "core-js": "2.5.3",
    "font-awesome": "4.7.0",
    "lodash": "4.17.5",
    "moment": "2.24.0",
    "moment-timezone": "0.5.23",
    "ngx-bootstrap": "5.5.0",
    "ngx-cookie": "2.0.1",
    "ngx-toastr": "8.2.1",
    "primeicons": "1.0.0",
    "primeng": "9.1.3",
    "quill": "1.3.7",
    "rxjs": "6.5.2",
    "rxjs-compat": "6.6.7",
    "tslib": "^2.4.0",
    "zone.js": "~0.11.5"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "13.3.8",
    "@angular-eslint/builder": "13.5.0",
    "@angular-eslint/eslint-plugin": "13.5.0",
    "@angular-eslint/eslint-plugin-template": "13.5.0",
    "@angular-eslint/schematics": "13.5.0",
    "@angular-eslint/template-parser": "13.5.0",
    "@angular/cli": "13.3.8",
    "@angular/compiler-cli": "13.3.11",
    "@angular/language-service": "13.3.11",
    "@types/jasmine": "3.3.12",
    "@types/jasminewd2": "2.0.6",
    "@types/lodash": "4.14.123",
    "@types/moment-timezone": "0.5.12",
    "@types/node": "11.11.6",
    "@typescript-eslint/eslint-plugin": "5.27.1",
    "@typescript-eslint/parser": "5.27.1",
    "codelyzer": "4.5.0",
    "eslint": "^8.17.0",
    "jasmine-core": "3.3.0",
    "jasmine-spec-reporter": "4.2.1",
    "karma": "6.4.0",
    "karma-chrome-launcher": "2.2.0",
    "karma-coverage": "2.2.0",
    "karma-coverage-istanbul-reporter": "2.0.5",
    "karma-jasmine": "2.0.1",
    "karma-jasmine-html-reporter": "1.4.0",
    "karma-phantomjs-launcher": "1.0.4",
    "lodash-es": "4.17.21",
    "npm-run-all": "4.1.5",
    "sass": "1.22.9",
    "sonar-scanner": "3.1.0",
    "ts-node": "8.0.3",
    "tsconfig-paths": "4.0.0",
    "tslib": "2.4.0",
    "tslint": "6.1.3",
    "tslint-sonarts": "1.9.0",
    "typescript": "4.6.4"
  }
}

```

karma.config.js

```
module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', '@angular-devkit/build-angular'],
    plugins: [
      require('karma-jasmine'),
      require('karma-phantomjs-launcher'),
      require('karma-jasmine-html-reporter'),
      require('karma-coverage-istanbul-reporter'),
      require('@angular-devkit/build-angular/plugins/karma')
    ],
    client:{
      clearContext: false, // leave Jasmine Spec Runner output visible in browser
    },
    coverageIstanbulReporter: {
      dir: require('path').join(__dirname, '../coverage/ngx-this-is-my-app'),
      reports: ['html', 'lcovonly', 'text-summary'],
      fixWebpackSourcePaths: true,
      thresholds: {
        global: {
          statements: 80,
          lines: 80,
          branches: 80,
          functions: 80,
        },
      }
    },
    reporters: ['progress', 'kjhtml'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['PhantomJS', 'ChromeHeadless'],
    singleRun: false,
    restartOnFileChange: true,
    customLaunchers: {
      ChromeHeadless: {
        base: "Chrome",
        flags: [
          "--headless",
          "--disable-gpu",
          "--no-sandbox",
          "--remote-debugging-port=9222"
        ],
      }
    },
  });
};

```

**part 1 Error**

```
Key: srcDir Value: null
[Pipeline] echo
Key: nodeVersion Value: 14
[Pipeline] echo
Key: npmCommand Value: npm run jenkins
[Pipeline] echo
Key: preScript Value: [npm ci]
[Pipeline] echo
Key: postScript Value: null
[Pipeline] echo
Key: phantomjs Value: true
[Pipeline] deleteDir
[Pipeline] unstash
[Pipeline] echo
NODE PATH: /SOME-LOCATION/javascript/node-v14.17.3-linux-x64
[Pipeline] tool
[Pipeline] sh
+ curl -f -o phantomjs-2.1.1.zip https://artifacts.TEST-COMPANY.int/artifactory/maven-external-release/phantomjs/phantomjs/2.1.1/phantomjs-2.1.1.zip
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
 43 24.9M   43 10.8M    0     0  9277k      0  0:00:02  0:00:01  0:00:01 9277k
100 24.9M  100 24.9M    0     0  17.6M      0  0:00:01  0:00:01 --:--:-- 17.6M
[Pipeline] sh
+ unzip -o phantomjs-2.1.1.zip
Archive:  phantomjs-2.1.1.zip
  inflating: phantomjs-static
[Pipeline] sh
+ mkdir -p bin
[Pipeline] sh
+ mv phantomjs-static bin/phantomjs
[Pipeline] withEnv
[Pipeline] {
[Pipeline] sh
+ npm ci

> nice-napi@1.0.2 install /SOME-LOCATION/jenkins/workspace/we-dont-need-this/PLEASE/IGNORE/THIS/node_modules/nice-napi
> node-gyp-build

gyp WARN install got an error, rolling back install
gyp ERR! configure error
gyp ERR! stack Error: connect ETIMEDOUT dummy-ip-address:443
gyp ERR! stack     at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1148:16)
gyp ERR! System Linux 3.10.0-1160.59.1.el7.x86_64
gyp ERR! command "/SOME-LOCATION/javascript/node-v14.17.3-linux-x64/bin/node" "/SOME-LOCATION/javascript/node-v14.17.3-linux-x64/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /SOME-LOCATION/jenkins/workspace/we-dont-need-this/PLEASE/IGNORE/THIS/node_modules/nice-napi
gyp ERR! node -v v14.17.3
gyp ERR! node-gyp -v v5.1.0
gyp ERR! not ok

```

**part 2 Error**

```
- primeng/spinner [es2015/esm2015] (https://github.com/primefaces/primeng)
- primeng/splitbutton [es2015/esm2015] (https://github.com/primefaces/primeng)
- primeng/steps [es2015/esm2015] (https://github.com/primefaces/primeng)
- primeng/table [es2015/esm2015] (https://github.com/primefaces/primeng)
- primeng/tabmenu [es2015/esm2015] (https://github.com/primefaces/primeng)
- primeng/tabview [es2015/esm2015] (https://github.com/primefaces/primeng)
- primeng/terminal [es2015/esm2015] (https://github.com/primefaces/primeng)
- primeng/tieredmenu [es2015/esm2015] (https://github.com/primefaces/primeng)
- primeng/toast [es2015/esm2015] (https://github.com/primefaces/primeng)
- primeng/togglebutton [es2015/esm2015] (https://github.com/primefaces/primeng)
- primeng/toolbar [es2015/esm2015] (https://github.com/primefaces/primeng)
- primeng/treetable [es2015/esm2015] (https://github.com/primefaces/primeng)
- primeng/tree [es2015/esm2015] (https://github.com/primefaces/primeng)
- primeng/tristatecheckbox [es2015/esm2015] (https://github.com/primefaces/primeng)
- primeng/virtualscroller [es2015/esm2015] (https://github.com/primefaces/primeng)
- @another-custom/lib-common [es2015/esm2015] (git+https://globalrepository.company-local.int/stash/scm/app-name/ngx-demo.git)
- @another-custom-2/lib-common [es2015/esm2015] (git+https://globalrepository.company-local.int/stash/scm/app-name/ngx-demo-utils.git)
- @another-custom-3/lmodel-data [es2015/esm2015] (git+https://globalrepository.company-local.int/stash/scm/app-name/cc-demo-data-model.git)
- primeng [es2015/esm2015] (https://github.com/primefaces/primeng)
Encourage the library authors to publish an Ivy distribution.
09 08 2022 01:13:36.349:INFO [karma-server]: Karma v6.4.0 server started at http://localhost:9876/
09 08 2022 01:13:36.352:INFO [launcher]: Launching browsers Chrome with concurrency unlimited
09 08 2022 01:13:36.357:INFO [launcher]: Starting browser Chrome
09 08 2022 01:13:36.358:ERROR [launcher]: No binary for Chrome browser on your platform.
  Please, set "CHROME_BIN" env variable.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! CUSTOM/LIBRARY/WE/CAN/IGNORE/THIS-ui@4.1.0 test:jenkins: `ng test --code-coverage --watch false --progress false`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the CUSTOM/LIBRARY/WE/CAN/IGNORE/THIS-ui@4.1.0 test:jenkins script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     SOME-LOCATION/jenkins/workspace/WE/CAN/IGNORE/THIS/nodejs_data/.npm/_logs/2022-08-09T06_13_36_812Z-debug.log
ERROR: "test:jenkins" exited with 1.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! CUSTOM/LIBRARY/WE/CAN/IGNORE/THIS-ui@4.1.0 jenkins: `run-s lint test:jenkins build:jenkins`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the CUSTOM/LIBRARY/WE/CAN/IGNORE/THIS-ui@4.1.0 jenkins script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     SOME-LOCATION/jenkins/workspace/WE/CAN/IGNORE/THIS/nodejs_data/.npm/_logs/2022-08-09T06_13_36_957Z-debug.log
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] echo
Error during processing of stage BuildNodeApplication caused by script returned exit code 1
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // stage
[Pipeline] echo
hudson.AbortException: script returned exit code 1

```

What am I doing wrong? What needs to be done here?

# Answer
Part one is a failure to install node-gyp. The error is a connection timeout to some ipaddress:

```
stack Error: connect ETIMEDOUT dummy-ip-address:443

```

The second error is because chrome is not installed on the Jenkins Agents where you are running the build.

```
09 08 2022 01:13:36.358:ERROR [launcher]: No binary for Chrome browser on your platform.
  Please, set "CHROME_BIN" env variable.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! CUSTOM/LIBRARY/WE/CAN/IGNORE/THIS-ui@4.1.0 test:jenkins: `ng test --code-coverage --watch false --progress false`
npm ERR! Exit status 1

```

Neither of these are really "Jenkins" issues.
> 0 votes

---
Tags: jenkins, jenkins-pipeline
---


# Question
Title: How does one perform systems testing against multiple interdependent machines?
I'm looking for a platform that allows me to run tests against multiple, closely-coupled systems. We deploy different products to Red Hat family machines - think Rocky Linux, CentOS, Fedora, RHEL, etc. This is done using SaltStack, which allows us to completely set up blank VMs (in development they are built on QEMU using Vagrant, on a linux host). To date, regression testing has been done by hand, and the extent of our automation has been Test Kitchen ensuring that highstates return clean, coupled with some basic InSpec profiles in some cases (is port listening, etc).

It has become necessary to perform more testing as these systems become more complicated. For example, take a cluster of three VMs, which each have services used by the others, all heavily configured with SaltStack. It seems that the standard advice for testing is to test each system individually with tools like Chef's InSpec, or testinfra. However, I'm looking for a way to test the cluster overall.

I'm looking for a way to test all my services in different cases. For example, I should be able to kick off a test that:

1. Highstates one blank machine
2. Uses a client VM to access the public service of the first (i.e. a basic MySQL query)
3. Highstates a second server VM
4. Tests both services again
5. Disables a network interface on one VM to test split-brain functionality

... etc

I could do all of this with a long bash or Python script and many SSH commands to each VM, but I would prefer to not reinvent the wheel. Is there a testing framework that can run tests on multiple machines, in order as I define, that allows me to test the whole system in aggregate?

# Answer
Testinfra lets you use the pytest test framework to interact with and run tests against remote hosts.

A simple test suite might look like:

```
def test_mariadb_query(host):
    '''Connect to a remote host, run a SQL query using the `mariadb`
    CLI, record the result, and verify it matches our expectations.
    '''

    expected = "count\n15\n"
    res = host.run(
        '''mariadb example -e "select count from widgets where name='doodad'"'''
    )
    assert res.rc == 0
    assert res.stdout == expected

```

The above would run the `test_mariadb_query` test on any hosts specified on the command line, e.g:

```
pytest --hosts=ssh://root@node1

```

You can specify a list of hosts in the test file instead of on the command line:

```
import pytest
import testinfra

testinfra_hosts = ["ssh://root@node1"]

def test_mariadb_query(host):
    expected = "count\n15\n"
    res = host.run(
        '''mariadb example -e "select count from widgets where name='doodad'"'''
    )
    assert res.rc == 0
    assert res.stdout == expected

```

With this, you can just run `pytest` and it will do what you expect.

If you have tests that interact with *specific* hosts, you can create pytest fixtures for those hosts:

```
import pytest
import testinfra

@pytest.fixture
def node1():
    return testinfra.get_host("ssh://root@node1")

def test_kernel_version(host):
    res = host.run("uname -r")
    assert res.stdout.startswith("5.17")

def test_mariadb_query(node1):
    expected = "count\n15\n"
    res = node1.run(
        '''mariadb example -e "select count from widgets where name='doodad'"'''
    )
    assert res.rc == 0
    assert res.stdout == expected

```

The above will run the `test_kernel_version` test against all hosts specified on the command line, but `test_mariadb_query` will run only against host `node1`, regardless of the command line.

The downside to this solution is that it's built on top of a unit testing framework; since tests are supposed to be independent, there's not a built-in mechanism to run them in a specific order. However, there are plugins that attempt to address this issue.

If your ordering requirements can be written as setup/teardown tasks, pytest fixtures may be a viable solution.

---

You can use Ansible itself to run your tests, and this gives you complete control over the order of execution of things, but you will generally "fail fast" rather than "fail last" (execution stops with the first failure, rather than continuing and showing you all test failures).
> 1 votes

---
Tags: testing, chef, vagrant, salt
---


# Question
Title: How can I get everything to use the same load balancer on DigitalOcean?
I have a `LoadBalancer` service, and an `Ingress` that routes to various `ClusterIP` services. I've given both of them the following annotation:

```
annotations:
  kubernetes.digitalocean.com/load-balancer-id: 'myproject-dev-lb'

```

A new load balancer was created, although I see no reference to `myproject-dev-lb` on it. The `LoadBalancer` service (a Pulsar server) works fine, but my ingresses have stopped working. When I `kubectl get` my ingress, I get what looks like a previous IP address (might just be similar). When I `describe` it, it says it's not found. If I delete it and recreate it, it gets the same IP address. The address is pingable, but not listening on port 80. The created load balancer only has a rule for port 6650 (Pulsar).

I'm not really familiar with the relationship between Ingress, load balancers and services.

# Answer
> 0 votes
A service is a way to route traffic to an internal IP. By internal I mean inside Kubernetes. I mean you don't really point it to an IP, you point it to a deployment or w/e and Kubernetes takes care of the IP and routing traffic for you to the pods that make up that deployment.

Now not all services work the same. ClusterIP will create an internal hostname and then route traffic to the Pods's IP. This make the service only reachable from other pods inside the cluster.

Then you have NodePort, which opens a port on all worker nodes and routes the traffic to the deployment/pods or w/e. This exposes the service externally. So now it's reachable by a worker nodes IP and whatever port was selected by the service. You can also hard code a port but I wouldn't recommend it.

But who wants to deal with IP's and port numbers? Thats lame. We want hostnames. you know like myapp.dev.coolcompany.com or w/e.

That is where a Loadbalancer comes in. If you have a cluster running on a cloud provider then your cluster is likely already setup to use a LoadBalancer service. This service does two things. First it creates a nodePort service and then it configured a load balancer on your cloud provider to point traffic to all worker nodes and the NodePort for your service.

When your LoadBalncer is created it likely came with a public DNS name to reach it by. Now you can just create a DNS record to point from myapp.dev.coolcompany.com -\> my.lb.dns.cloudprovider.com. Now your app is reachable externally and without knowing about IP's and ports.

Everything I just explained is explained even better and more accurately by the Kubernetes Service documentation. You should probably give it a read.

So what's an Ingress? Well an Ingress is like creating a "LoadBalancer" but inside the cluster. We call this the Ingress Controler and there are a ton of options like Nginx, Apache and Traeffik to name a few. This likely does not come included by default on your cluster. You will need to create and configure an ingress controller before you can use the "ingress" API object.

An ingress controller works like any other deployment running on your cluster. You will need to expose this application externally. Most often using a "LoadBalancer" Service. Confused yet? It will look like this: ExternalLB --\> IngressLBService(NodePort) --\> IngressController

Once your Ingress Controller is configured you can then expose your deployments externally without using a "LoadBalancer" service. You can instead use a "ClusterIP" service + an "ingresss" object configured to point at the service. It will look like this: ExternalLB --\> IngressLBService(NodePort) --\> IngressController --\> DeploymentService(ClusterIP) --\> DeploymentPods

As you can see the "LoadBalancer" service and IngressController work very similarly. So why do you need an IngressController?

Well if your application stack is simple then you probably don't. Some of the cloud providers "LoadBalancers" are pretty feature rich. Like on AWS. But some of these Ingress Controllers offer some pretty nice features. Like path bases routing, integrating with Authentication providers, Automatic TLS certificate provisioning and tracing+montioring etc. Basically, if you need these features and your cloud provider's Loadbalancer doesn't have these things then an Ingress Controller is the best way to get them.

Another tiny advantage is that an Ingress can help abstract away the cloud provider. Meaning less vendor lockin. If I have an application that is exposed externally via an Ingress controller then I can re-deploy that application on any cluster on any cloud provider as long as that cluster has an ingress controller.

If I'm depending on a "LoadBalancer" service then its likely that service is configured with a bunch of Annotations and that is often not compatible with other clouds. Meaning I cant just redeploy that application to another cloud provider. This use case isn't very important to many people and it wouldn't be a big deal to fix a service to use a different cloud LB but it is something to consider.

You can find a lot more in the Kubernetes Ingress documentation.

---
Tags: kubernetes, load-balance
---


title: Continuous deployment question

text:
# Question
Title: Continuous deployment question
This question is not in case of kubernetes but when you use servers or docker for deployment using CICD tool like Jenkins or gitlab. In jenkins or gitlab I've agents/runners and in pipeline stages I've a deploy stage. Now, where should this deployment ideally happen? On the agent? or or some other server (through ssh)?

# Answer
Your question is a little bit confusing and led to some interpretations.

First, for Jenkins, you should always run your pipelines using Jenkins agents, it is a good practice.

The deploy stage is to - well, as the name -- deploy to somewhere. The way you are going to deploy totally depends on what you are deploying and where, you can use an API, a CLI, SSH, or even an SFTP. You can also store your artifact in a artifact server (Nexus, Docker Hub, Artifactory) and then tell your server to pull the image from there.

Wrapping up: In the deploy stage, put the code to deploy the artifact (.exe, .war, .zip...) anywhere you want. The deploy stage will run inside an agent/runner, this runner will connect to the destination system through CLI, API... to deploy the artifact.
> 1 votes

---
Tags: jenkins, containers, continuous-deployment
---


# Question
Title: How to define global variables in groovy file, which I want to load and consume?
I have a Jenkins parent groovy file which consumes the child groovy file

**Parent grooy file:**

```
...
def child = load 'child-groovy-file';
child.execute();

```

**Child groovy file:**

```
a = "first letter";
b = "second letter;
def execute
{
echo "a is "+a;
...
}

```

> But this is not working. Unable to access variables, which are defined in Child Groovy file, when trying to access from Parent groovy file. When I create a node block and trying to consume directly the child groovy file, It is working.

Is the Environment variables only the solution to access globally?

# Answer
try this one

```
static void main(String[] args) {
      // Initializing 2 variables
      def x = 5;
      def y = 10;

      //Performing addition of 2 operands
      println(x+y);
 }

```

}

check this URL
> 0 votes

# Answer
It just could be that:

```
import groovy.transform.Field

@Field public a = "first letter"
@Field public b = "second letter"

```

works (I got hint from https://stackoverflow.com/questions/37800195/)

When referencing (environment variables) I saw the format did not exactly work, but the following did:

```
@Field public c; c = 'prefix ' + VAR + ' suffix'

```

(probably "prefix ${VAR} suffix" worked but did not try that (either))
> 0 votes

# Answer
Your example code has a typo: `b = "second letter;` is missing the closing quote. Even if you fix that typo your code still won't work.

If you print the `child` variable it will be `null`?

That is because you are missing `return this` at the bottom of `child-groovy-file`.

It's mentioned in the Jenkins load documentation:

> Where `pipeline.groovy` defines `functionA` and `functionB` functions (among others) before ending with `return this`;

I fixed your code and ran this POC:

This resulted in:

While loading scripts like this might have some use cases, they are not very common. If you are looking to have reusable code you should use Jenkins Shared Libraries feature. If you want to see an example of what can be done with a shared-library see The Jenkins Standard Library, which can do things like run Github Actions! I also happen to be the author of that library.
> 0 votes

---
Tags: jenkins-pipeline, jenkinsfile, groovy, environment-variables
---


# Question
Title: is there a standard or common approach to defining Service Level Indicators?
I've come to the point where I am starting to adopt principles from Site Reliability Engineering to operate Cloud Native applications in a modern way.

From my reading to date, I have established that one of the core practices is monitoring. The way that SRE approaches monitoring is by defining *Service Level Indicators (SLI)* which measure an aspect of the end-user experience, then identifying a threshold around the SLI which is called a *Service Level Objective (SLO)*.

is there a standard or common approach to defining Service Level Indicators?

# Answer
> 3 votes
Whilst not strictly a standard approach, Google has published an SLI Menu and a process for developing SLIs for user journies:

1. For each User Journey/Data Flow identify from the SLI Menu suitable types of SLI:
2. Make a decision about how to measure **good** and **valid** events,
3. Decide where to measure the SLI From out of the following: End User, Client-side Instrumentation, Synthetic Clients, Front-end Metrics, Application Metrics or Server-side Logging.

The document then goes on to describe, how you collate all of your SLIs for all of your user journies then walk the journey to look for coverage gaps. Then finally set SLOs based upon the SLIs either based upon **business need** or **past performance**.

# Answer
> 0 votes
You have to define what matters the most to the customers (or users) in a cross functional manner, e.g dev, PM, Support, execs, SRE.

For example, memory usage alone does NOT usually directly matter to the customers and most of the roles above. It does matter for capacity planning though -- so while it is not an application SLI/SLO, it may be important for devs/SRE and eventually execs (funding). There may be an internal SLI/SLO around keeping efficiency high.

A mobile application taking too long to perform an operation or failing too often are likely to negatively impact many customers or a subset of customers that's very relevant to the business. These often turn out to be a customer facing cross functional issue, i.e support tickets are filed, execs may get called, SRE may be oncall trying to resolve the issue and will need to loop in feature \[dev\]elopers.

Given all that, there is a need for cross functional metrics (SLIs) and boundaries (SLOs) that will represent customer pain/unhappiness. The absence of such common metrics tend to cause the following effect: "memory usage is low" (devs/SREs), "features have been shipped" (PM), "I didn't get a call" (execs), "users are not happy" (Support).

Google has also published their workshop (under CC-BY 4.0) on how to define SLIs and SLOs: https://cloud.google.com/blog/products/management-tools/learn-how-to-set-slos-for-an-sre-or-cre-practice

There is also a blog post on how to tune-up the SLIs (and SLOs) over time: https://cloud.google.com/blog/products/management-tools/tune-up-your-sli-metrics-cre-life-lessons

Disclaimer: I work for Google.

# Answer
> 0 votes
I thought I'd add on one point... SLIs/SLOs are not a tool for monitoring in and by themselves.

They are the basis for proactive and continuous site reliability engineering. With only a set of SLIs/SLOs you will be able to assess the service reliability over a prolonged period of time and plan around that (e.g. prioritize reliability enhancing activities over new functionality in order to improve your SLI).

In order to add the monitoring aspect (i.e. early detection of a degradation of the service) you will need to add Burn Rate Alerts on top of your SLIs. Only with those you will have acceptable detection and reset time that serve the monitoring of potential issues. Burn Rate Alert Implementation is covered in Chapter 5 of the SRE Workbook: https://sre.google/workbook/alerting-on-slos/

# Answer
> 0 votes
Keptn has a specification for SLIs and SLOs. OpenSLO also provide a slightly different take.

---
Tags: sre, operations, operating-model
---


title: Docker Compose on AWS

text:
# Question
Title: Docker Compose on AWS
I have no experience with AWS and I would like to know what the best approach is when it comes to embedding an environment built using Docker Compose (a simple application with two services, API and Redis), I came across such possibilities at the moment:

* making an EC2 instance, connecting via SSH, configuring the environment and manually building and running the environment (can you somehow automate it?)
* making an ECS, uploading a docker image to the ECR, setting a cluster and a ribbon to start building the environment based on the image from the ECR
* using Elastic Beanstalk, making applications using Docker and managing from the CLI level (eb init, create, deploy) They are different? (additionally connecting CodePipeline and maybe GH Actions)

What approach in such situations is practiced in your companies and what should you be most careful about?

# Answer
This question risks being flagged as "too broad", and invites opinion-based answers. With that caveat out of the way I'll try to answer in an unbiased way.

In these cases, it's best to go back to first principles and architect the application from scratch using the relevant AWS services. If you're deploying an application that is really just a few services that can be composed, you're probably best off using Fargate.

**In any case, I would not suggest using EC2 instances**

In terms of how to go about doing that:

* Create the VPC if you need it
* define security groups that will define what traffic is allowed
* set up the ECR repositories for the images in the application stack
* convert the services in the docker compose file to ECS task definitions
* decide how you will manage persistent data? If part of the application is redis, you might consider using an ElasticCache component in the stack.
* decide how you want to expose the services (ENI? Load balancer?)

There is also the issue of IAM policies that would need to be attached to various entities, in order to read / write to ECR, *etc*.

I would write this all as one or two Terraform modules. One for the network configuration (VPC, subnets) and one for the application itself (ECS cluster, Capacity providers, load balancers, ECR repositories, *etc*). This is a purely personal choice though, and you could just as well create a CloudFormation stack.

Continuous deployment could indeed be done with Github Actions, if that's where you are storing the code which describes the app.
> 0 votes

# Answer
Ultimately the answer will depend on your business needs. Each implementation you listed will result in different environments:

1. An EC2-only environment is possible, but you'll have to do a fair bit of work to automate this. The servers will need access to your docker repository. Additionally, you will need a Virtual Private Cloud (VPC) and Security Groups (SGs) setup to restrict access to it. Data will need to persist somehow. You'll also be stuck maintaining the servers.
2. ECS opens up additional options for you while removing several of the concerns listed above. Launching to "serverless" solutions such as AWS Fargate are also supported.
3. Elastic Beanstalk would require you uploading your code directly and configuring the deployment from there.

AWS also offers managed API services and Redis services which could be an option as well.
> 0 votes

---
Tags: amazon-web-services, continuous-integration, amazon-ec2, deployment, amazon-ecs
---


title: Rename Terraform template script

text:
# Question
Title: Rename Terraform template script
In the example below if I were to rename "script1.ps1" to a new name this would normally result in the destruction and recreation of server1.

```
data "template_file" "server1" {
    template = file("${path.module}/script1.ps1")
    vars = {}
}

```

Is it possible to update the script name without recreating the server?

# Answer
> 3 votes
Yes you can move it in state.

Something like:

```
terraform state mv template_file.server1 template_file.new_name

```

Once you move it in the terraform state, then you can rename it in the file.

```
data "template_file" "new_name" {
    template = file("${path.module}/script1.ps1")
    vars = {}
}

```

If you run `terraform plan` you shouldnt see any changes.

You will also need to update any references to the old name to point to the new name.

If you are using a version of terraform greater than 0.12 you might want to remove the data source template\_file completly and replace it with a call to the templatefile function.

---
Tags: terraform
---


# Question
Title: Jenkins trigger the 2nd job when the first job fails
There is a system that periodically runs on Jenkins and that I follow with selenium. (I'm checking its performance on "manager/status" page in Tomcat). I want it to trigger the second job, which will make detailed logging (\*1) only when there is an error in the job. How can I do it?

When the first job is successful I can trigger the 2nd job but **what I need is to trigger the 2nd job when the first job fails**

(\*1) I'm checking the geoserver performance. "http://serverip:port/geoserver/rest/monitor/requests.csv?order=totalTime;ASC" will download the performance values on geoserver server in "xls" format on jenkins server.

# Answer
> 0 votes
I see your using a `freestyle` job, but this is where Jenkins `pipelines` shine.

```
node() {

    try {
        // do your testing
    } catch (Exception e) {
        build(job: 'detailed_logging')
    }
}

```

You can find more detail in the build step documentation.

# Answer
> 0 votes
Use the Parameterized Trigger (https://plugins.jenkins.io/parameterized-trigger/) in your Post Build Actions. In my example I did not pass any parameters to the new job.

---
Tags: jenkins
---


# Question
Title: Is running linux container on windows aws instance possible?
what I'm trying to achieve is running a Linux(ubuntu LST) container inside a windows server 2019 OS. The problem is that the windows OS runs as an AWS instance.

There have been problem for me trying to achieve this and I've been reading somewhat different opinions on the internet regarding whether or not it is possible. Some say it will be possible on a .metal instance which is bare metal. Currently I've been trying running it on a regular t3 instance with has virtualization type HVM.

To sum up my questions are:

1. Is running a linux container on windows aws instance possible?
2. If yes, how?
3. If not, will it be possible on a bare metal instance?

Please keep in mind that I need the container to run in a Windows environment due to multiple tasks the the OS needs to achieve (and I don't want multiple instances)

# Answer
Containers run sharing resources from the host operating system in a controlled manner, so you can't run Windows containers on Linux as you can't run Linux containers on Windows.

That said, you *can* run Linux on Windows through WSL (Windows Subsystem from Linux) and then you can run a Linux container in it.

See: Docker Desktop WSL 2 backend
> 0 votes

---
Tags: docker, amazon-web-services, linux, windows, virtualization
---


# Question
Title: How to run a task from a playbook to a specific host
I'm writing an ansible playbook to manage backup and I want two different tasks :

```
- name: Setup local machine for backup
  cron:
    cron_file: /etc/cron.d/backup
    hour: 4
    minute: 0
    job: /root/do_backup.sh
    state: present
    name: backup

- name: Setup backup server for new machine
  shell:
    cmd: "mkdir /backups/{{inventory_hostname}}"

```

Is it possible to tell ansible that second task is intended to be executed on another machine of my inventory ?

I don't want a dedicated playbook, because some later tasks should be executed after the task on backup server.

# Answer
> 1 votes
This is a duplicate of this StackOverflow question.

But I will combine and summarize all the answers here.

* If your "other\_host" is in the playbooks inventory then you can use the when keyword: `when: inventory_hostname is "other_host"`. Which will only run that task once and only for "other\_host".
* If your playbook inventory does not include "other\_host" then you can use the delegate\_to keyword. `delegate_to: other_host_ip`. Not that you have to use the IP or DNS name of the machine unless you use add\_host module. This will run the task for EVERY host in the playbooks inventory but will run the tasks on `other_host`.

---
Tags: ansible, backup
---


# Question
Title: What can Terraform be used to configure for hosting a web application?
I am new to Terraform. How can I use Terraform to configure EC2 instance for hosting a flask web application?

* Is it to configure a security group for the instance? How is that done in Terraform?
* what else can Terraform be used to configure for hosting a web application?
* Does Terraform also perform deployment of web application to the infrastructure, besides creating the infrastructure?

I also wonder how? (links to documents are also appreciated.)

Thanks.

# Answer
I think it is better if you containerize your flask application. So:

1. Containerize your flask application.
2. Create and configure an EC2 server to deploy your application container on it.

---

1. Containerize your flask application.

I'm not gonna walk you through this but basically you should create a `Dockerfile` and create an image based on that. then push it to any repo you like (e.g. Docker Hub).

---

2. Create and configure an EC2 server to deploy your application container on it.

Here is an example that will create and config an EC2 server, install Docker on it and then run an container from your image (in this example: Nginx)

```
provider "aws" {
  region = "eu-central-1"
}

variable vpc_cidr_block {}
variable subnet_1_cidr_block {}
variable avail_zone {}
variable env_prefix {}
variable instance_type {}
variable ssh_key {}
variable my_ip {}

data "aws_ami" "amazon-linux-image" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-gp2"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
}

output "ami_id" {
  value = data.aws_ami.amazon-linux-image.id
}

resource "aws_vpc" "myapp-vpc" {
  cidr_block = var.vpc_cidr_block
  tags = {
      Name = "${var.env_prefix}-vpc"
  }
}

resource "aws_subnet" "myapp-subnet-1" {
  vpc_id = aws_vpc.myapp-vpc.id
  cidr_block = var.subnet_1_cidr_block
  availability_zone = var.avail_zone
  tags = {
      Name = "${var.env_prefix}-subnet-1"
  }
}

resource "aws_security_group" "myapp-sg" {
  name   = "myapp-sg"
  vpc_id = aws_vpc.myapp-vpc.id

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = [var.my_ip]
  }

  ingress {
    from_port   = 8080
    to_port     = 8080
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port       = 0
    to_port         = 0
    protocol        = "-1"
    cidr_blocks     = ["0.0.0.0/0"]
    prefix_list_ids = []
  }

  tags = {
    Name = "${var.env_prefix}-sg"
  }
}

resource "aws_internet_gateway" "myapp-igw" {
    vpc_id = aws_vpc.myapp-vpc.id

    tags = {
     Name = "${var.env_prefix}-internet-gateway"
   }
}

resource "aws_route_table" "myapp-route-table" {
   vpc_id = aws_vpc.myapp-vpc.id

   route {
     cidr_block = "0.0.0.0/0"
     gateway_id = aws_internet_gateway.myapp-igw.id
   }

   # default route, mapping VPC CIDR block to "local", created implicitly and cannot be specified.

   tags = {
     Name = "${var.env_prefix}-route-table"
   }
 }

# Associate subnet with Route Table
resource "aws_route_table_association" "a-rtb-subnet" {
  subnet_id      = aws_subnet.myapp-subnet-1.id
  route_table_id = aws_route_table.myapp-route-table.id
}

resource "aws_key_pair" "ssh-key" {
  key_name   = "myapp-key"
  public_key = file(var.ssh_key)
}

output "server-ip" {
    value = aws_instance.myapp-server.public_ip
}

resource "aws_instance" "myapp-server" {
  ami                         = data.aws_ami.amazon-linux-image.id
  instance_type               = var.instance_type
  key_name                    = "myapp-key"
  associate_public_ip_address = true
  subnet_id                   = aws_subnet.myapp-subnet-1.id
  vpc_security_group_ids      = [aws_security_group.myapp-sg.id]
  availability_zone               = var.avail_zone

  tags = {
    Name = "${var.env_prefix}-server"
  }

  user_data = <<EOF
                 #!/bin/bash
                 apt-get update && apt-get install -y docker-ce
                 systemctl start docker
                 usermod -aG docker ec2-user
                 docker run -p 8080:8080 nginx
              EOF
}

```

---

Sources:
> 3 votes

---
Tags: amazon-web-services, terraform, amazon-ec2
---


# Question
Title: build pipeline with repository: is it advisable to build both on repo and end server
I am doing a classic build with install (pip/python), lint,test,format on my github repository with github actions, then deploying with ssh (copying the repo on server and deploying with docker/docker-compose).

Im wondering if it is adviseable to re-run the lint,test,format, install on the server?

Note the install is not the app install which occurs in docker but the install of yapf, pytest, pylint

Thank you

# Answer
> 0 votes
Usually, your pipeline would produce a docker image as an artifact. For a feature branch, it might be tagged with the branch name.

For changes to the default branch (main/master), you should tag the image with some kinda version string. Typically a SemVer string.

You should not be copying the repo or git pulling the repo from the server. This is because the docker build is not guaranteed to be reproducible. Meaning that tests that passed in the pipeline might all of a sudden fail on the server.

Instead, after you have tested the docker image you should push the docker image to a repository and then pull that image to the application server when you want to deploy it.

You shouldn't install or run any development tooling on your production server.

---
Tags: pipeline
---


# Question
Title: Is it possible to log into a new EC2 instance for the first time using a non-default user?
1. After launching a EC2 instance, do I have to always log into the instance for the first time, by SSH with the default user for the image of the instance? Or is it possible to first time log into a new instance, by a user not the default one?
2. When launching a EC2 instance using either AWS CLI2 or Terraform, is it possible to specify a user to create and its authentication method (by specifying a EC2 private/public key pair created for AWS already), so that I will have a non-default user to log into the instance for the first time? Or creating a non-default user for a new instance can only be done under the default user's login session?

Thanks.

# Answer
The users who are present in a newly launched EC2 instance are the ones that exist in the image you launch it from.

The images provided by the Linux distros tend to have only one default user, but you can build your own custom image with other users, and launch your EC2 servers from your image/images.

And there's cloud-init config that can create a user at launch time, too (as a comment pointed out already).
> 2 votes

---
Tags: terraform, amazon-ec2
---


# Question
Title: Azure KQL query to display list of VMs which were not patch for since 1 months
Is there a KQL query to get a list of VMs which are not patched since last month. Below is the sample I have

```
Update
| where Classification in ("Security Updates", "Critical Updates")
| where UpdateState == 'Needed' and Optional == false and Approved == true
| summarize count() by Classification, Computer, _ResourceId
// This query requires the Security or Update solutions

```

How to apply the filter to just show the ones which are due since one month

# Answer
I was able to achieve that

```
Update
//|where OSType != "Linux" and UpdateState == "Needed" and Optional == "false"
| where Classification in ("Security Updates", "Critical Updates")
| where PublishedDate <= ago(30d)
| where startofday(TimeGenerated) == startofday(now())
| project TimeGenerated, Computer, Title, KBID, Classification, MSRCSeverity, PublishedDate, _ResourceId
| sort by TimeGenerated desc
| summarize any(KBID) by KBID, Title, Computer

```
> 0 votes

---
Tags: azure, vm
---


# Question
Title: Force jenkins job to fail if stage did not run long enough
I am using Jenkins to build an `rpm` for some custom software.

During the build there must be a race condition that only seems to appear when building the RPM, which results in the job finishing successfully, but the software not being built correctly.

The most obvious way to tell the build is a false positive is to **check how quickly the `build stage` finished**.

During an actually successful run, the build stage will take approximately **an hour**. When a false positive occurs it will finish in **less than 25 minutes**.

The end goal of course is to **fix the race condition**, but preventing the pipeline from creating a bad RPM and saying the pipeline was successful in the mean time would be a great help.

# Answer
> 1 votes
In Jenkins scripted pipelines you could do something like this:

```
node() {

   Date startTime = new Date()

   long currentTimeMilli = startTime.getTime()

   long hourMilli = currentTimeMilli + 3600000

   Date cutoffTime = new Date(hourMilli)

   // Call the "build" function

   Date currentTime = new Date()

   if (currentTime.before(cutoffTime)) {
       // Call the "build" function again
   }

}

```

---
Tags: jenkins, jenkins-pipeline
---


# Question
Title: Jenkins pipeline pass upstream build number to downstream job using Pipeline script
How to pass upstream build number to downstream job in Pipeline job using (Trigger parameter build on other projects) ?

Agenda: To pass upstream job build number to downstream job to download upstream artefacts in downstream, here's my Jenkins pipeline script

Upstream job script:

```
node
{
    stage('Build parameters')
    {
    properties([parameters([string(defaultValue: '***', description: '', name: 'version', trim: false)])])
    }/*
    echo env.BUILD_NUMBER
    def Latest_Build_Number=env.BUILD_NUMBER
    build job: 'Downstream', parameters: [[$class: 'StringParameterValue', name: 'Latest_Build_Number', value: 'env.BUILD_NUMBER', propagate:false]]
}

**Downstream job script**:
node
{
    stage('Downstream')
    {
    properties([[$class: 'ScannerJobProperty', doNotScan: false], parameters([string(defaultValue: '', description: '', name: 'Latest_Build_Number', trim: false)])])
echo Latest_Build_Number
}
}

Error:
*[Pipeline] {
[Pipeline] properties
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
java.lang.UnsupportedOperationException: no known implementation of class hudson.model.JobProperty is named ScannerJobProperty
    at org.jenkinsci.plugins.structs.describable.DescribableModel.resolveClass(DescribableModel.java:478)
    at org.jenkinsci.plugins.structs.describable.DescribableModel.coerce(DescribableModel.java:402)
    at org.jenkinsci.plugins.structs.describable.DescribableModel.coerceList(DescribableModel.java:514)
    at org.jenkinsci.plugins.structs.describable.DescribableModel.coerce(DescribableModel.java:388)
    at org.jenkinsci.plugins.structs.describable.DescribableModel.buildArguments(DescribableModel.java:341)
    at org.jenkinsci.plugins.structs.describable.DescribableModel.instantiate(DescribableModel.java:282)
    at org.jenkinsci.plugins.workflow.steps.StepDescriptor.newInstance(StepDescriptor.java:201)
    at org.jenkinsci.plugins.workflow.cps.DSL.invokeStep(DSL.java:264)
    at org.jenkinsci.plugins.workflow.cps.DSL.invokeMethod(DSL.java:178)
    at org.jenkinsci.plugins.workflow.cps.CpsScript.invokeMethod(CpsScript.java:122)
    at sun.reflect.GeneratedMethodAccessor237.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1213)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:42)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
    at org.kohsuke.groovy.sandbox.impl.Checker$1.call(Checker.java:157)
    at org.kohsuke.groovy.sandbox.GroovyInterceptor.onMethodCall(GroovyInterceptor.java:23)
    at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onMethodCall(SandboxInterceptor.java:155)
    at org.kohsuke.groovy.sandbox.impl.Checker$1.call(Checker.java:155)
    at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:159)
    at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:129)
    at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.methodCall(SandboxInvoker.java:17)*

```

# Answer
Remove the quotes around `env.BUILD_NUMBER`.

Instead of:

```
value: 'env.BUILD_NUMBER'

```

Try:

```
value: env.BUILD_NUMBER

```
> 2 votes

# Answer
Looks like you're missing a plugin. Remove the `[$class: 'ScannerJobProperty', doNotScan: false]` portion. This works:

*Upstream Job*

```
node {
    stage('Build parameters') {
        properties(
            [parameters(
                [string(
                    defaultValue: '***',
                    description: '',
                    name: 'version',
                    trim: false)
                ])
            ])
    }
    echo env.BUILD_NUMBER
    def Latest_Build_Number = env.BUILD_NUMBER
    build(
        job: 'Downstream',
        parameters: [
            [$class: 'StringParameterValue',
             name: 'Latest_Build_Number',
             value: env.BUILD_NUMBER,
             propagate: false]
        ]
    )
}

```

*Downstream Job*

```
node {
    stage('Downstream') {
        properties([
            parameters([string(
                defaultValue: '',
                description: '',
                name: 'Latest_Build_Number',
                trim: false)
            ])
        ])
        echo Latest_Build_Number
    }
}

```
> 0 votes

# Answer
**Build Failure Analyzer** is the missing plugin name for this.
> 0 votes

---
Tags: jenkins-pipeline, jenkinsfile
---


# Question
Title: How do I load a Jenkins Shared Library in a Jenkins Job DSL seed?
I have a seed job using the plugin Jenkins Job DSL. I also have a shared library.

I have tried using the `@Library` annotation to load the script and the `library` method. It cannot find the annotation and using `library` yields the following error:

`No signature of method: simple_pipeline.library() is applicable for argument types: (java.lang.String) values: [platform-engineering-library@master]`

How do I load a Jenkins Shared Library in a Jenkins Job DSL seed?

# Answer
It's possible to use jobDSL from Pipeline. (Im using multibranch pipeline as it allows to configure pipelineTriggers) You can configure your seed job to be a pipeline like this:

```
def gitCredentialsId      = 'github-jenkins'
def jobsRepoName          = 'https://github.com/my-jobs-repo.git'
def sharedLibraryRepoName = 'https://github.com/shared-library-repo.git'

properties([
   pipelineTriggers([githubPush()])
])

pipeline {
    agent any
    stages{
        stage('Seed Job') {
            agent any
            steps {

                checkout([
                    $class: 'GitSCM',
                    branches: [[name: '*/main']],
                    doGenerateSubmoduleConfigurations: false,
                    extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: 'shared-library']],
                    submoduleCfg: [],
                    userRemoteConfigs: [[credentialsId:  gitCredentialsId, url: sharedLibraryRepoName ]]
                    ])

                git url: jobsRepoName, changelog: false, credentialsId: gitCredentialsId, poll: false, branch: 'main'
                jobDsl targets: 'jobs/**/*_job.groovy', additionalClasspath: 'shared-library/src'
            }
        }
    }
}

```

This way we can configure our seed job to checkout shared libraries repo into workspace subdirectory *shared-library* and specify **additionalClasspath** for jobDSL groovy scripts

So in your groovy scripts you can simply use import without @Library annotation
> 4 votes

# Answer
Setup pipeline name and default version (e.g. master) in "Global Pipeline Libraries" settings. Then use them in your Jenkinsfile as following

```
#!/usr/bin/env groovy
@Library('YourGlobalPipelineName@YourDefaultVersion') _

pipeline {

}

```
> 1 votes

# Answer
There are two option

1. Using jenkins global shared lib setting in gui see documation https://www.jenkins.io/doc/book/pipeline/shared-libraries/
2. Importing shared library inside jenkins file similart like this follow this blog https://tomd.xyz/jenkins-shared-library/

```
library identifier: 'mylibraryname@master',
     //'master' refers to a valid git-ref
     //'mylibraryname' can be any name you like
     retriever: modernSCM([
       $class: 'GitSCMSource',
       credentialsId: 'your-credentials-id',
       remote: 'https://git.yourcompany.com/yourrepo/private-library.git'
 ])

 pipeline {
     agent any
     stages {
         stage('Demo') {
             steps {
                 echo 'Hello world'
                 yourCustomStep 'your_arg'
             }
         }
     }

```

P.S. When using "@Library \_" the this means importing all libraries
> 0 votes

# Answer
I've stumbled in this issue as well. I'm configuring all jobs via DSL but find the need to define constants in a shared-library that are shared with jobDSL and pipelines.

According to https://github.com/sheehan/job-dsl-gradle-example it seems that you could have your jobs specified in a location that is shared with the library, and hence access those files directly.

This is the solution I intend to try out. In the projects I'm working this makes sense. I have a git repo for each jenkins server and each jenkins server can read configurations from a single repo. Anything that is specific to that jenkins server is stored in the repo. Anything that is shared among different jenkins servers, we can simply configure different different jenkins servers to use other jenkins's git repo libraries.
> 0 votes

---
Tags: jenkins, job-dsl
---


# Question
Title: Deployment with manual confirmation of each change
I am new to CI/CD and Gitlab. I have a Python project for parsing a LaTeX book to HTML and uploading those HTMLs to our online course platform.

Without CI/CD my pipeline would look like this:

1. Fix LaTeX source files of my book
2. Run scripts for creating HTML files (some artifacts from my changes)
3. Running script which compares old and new version of each HTML file and asks for a confirmation to upload those changes to the online platform.

I can handle the first step with the Gitlab version control system. I've learned to build artifacts for step 2 with Gitlab's CI pipeline.

My question is: How can I perform 3rd stage of my pipeline (checking what is updated and confirming what should be uploaded/deployed) with Gitlab CD?

# Answer
> 0 votes
I see two scenarios here:

1. Script compares old and new. You could check that output on the stage, e.g. `stage: compare`. Then you could use `when: manual` to apply the changes when you are fine with it.
2. You could do step 1 for each file separately, so you have a stage for every file like `stage: compare_file1` and so on.

---
Tags: gitlab, cicd
---


title: Jenkins JDK17 Docker still using JDK9?

text:
# Question
Title: Jenkins JDK17 Docker still using JDK9?
I installed docker for Jenkins `JDK17`

```
docker pull jenkins/jenkins:jdk17

```

Reason being I run a single node (I know isn't the best practice, but for trying out) and my target application is also a **Java build**.

Now, the issue is when I checked the version in a build, it is still Java `9` Not `17`! Results in build failures.

```
+ java -version
java version "9.0.4"
Java(TM) SE Runtime Environment (build 9.0.4+11)
Java HotSpot(TM) 64-Bit Server VM (build 9.0.4+11, mixed mode)

```

How can I get `JDK 17` so that I can build my application using Jenkins Docker?

# Answer
Actually looks like I haven't done a great build-setup here. The way to correctly do this is not trying to change the default JDK (even though I still think there's an issue in the Docker..). What really required is a "Tool" section under JDK section for the builds to work with the custom JDK. So the notion from Jenkins, the Agent JDK is what I need, and not to worry about the Controller JDK really.

A great video that I came across that helped:

How to Configure a JDK in Jenkins
> 1 votes

---
Tags: docker, jenkins, java
---


# Question
Title: Jenkins - restrict which nodes can be selected by user when creating jobs
I have a situation where I have a Jenkins installation that is used by multiple teams. Each team gets their own Jenkins node, which has access to certain parts of the organization that the team is responsible of.

I want to allow the teams to create their own Jenkins jobs, but they should only be allowed to set those jobs to run on their respective Jenkins node. So I need a way to **allow users to create jobs, but restrict the nodes they can choose**.

The only thing we found is Job Restrictions plugin, which is no longer maintained at this time and up to adoption. And we had some trouble with it.

What are my options?

# Answer
## How Do I Restrict Access to Agents (previously called Slaves)?

You haven't specified what Jenkins you're running or whether you have licensed Cloudbees plugins. If you have the Cloudbees folder plugin together with the Cloudbees Folders Plus plugin, there is a "simple" way to do what you ask.

To take advantage of the power of the folder and folder plus plugin, you need a well organized hierarchy of jobs. If all of your jobs live in the top level (root) folder this strategy will require some significant work.

* Create FOLDERs for each of your job/jobsets. And even better a parent folder to contain them all. E.g. /teams/Team1, /teams/Team2, ... and perhaps a separate folder for all of the agents /agents (or /admin)
* In essence you'll allow Team1 to have a separate set of resources from Team2 - as well as a SHARED set of resources if appropriate for your situation.
* Create and label Agents as usual, but set them to "Only accept builds from approved folders" I also HIGHLY suggest you only allow agents to accept builds for matching labels... otherwise chaos can occur.
* Assign all the agents to the /admin folder. (So that any admin job can use any agent) - optional, but recommended. See below for how to make that assignment.
* Assign any shared agents to the /teams folder.
* Assign individual team agents to the /teams/TeamN folder to enforce that Team1 only has the agents available it is allowed to use.
* Repeat the assignment process for each teamN + Agent combination.

## How to Assign Agents to Folders

This is a bit tricky as there are several steps required - and since those steps may change, I'll suggest you consult Jenkins documentation, but here is the generic process. I recommend you open at least two browser windows, one to navigate agents, one (or more) to navigate folder(s).

1. Select a folder you want to have access to an agent e.g. /teams or /teams/team1
2. Select "Controlled Agents"
3. Create a Request. This generates a Request Key.
4. In another window, navigate to the Agent, select Approved Folders
5. Paste the request key into the Agent/Approved folders - this generates a Request Secret.
6. Navigate to the Folder/Controlled agents, paste the key from step 5 into the open request and click Authorize.

Now your agent has been associated with the specific folder. Repeat this process for ALL of your agents and all of the folders you wish to pair them with.

Note if you want shared-agent-1 to be usable by anyone in teams/Team1, or Team2... you only need to add it to the teams folder. However it would NOT be incorrect to add a shared agent to every sub-folder. There are advantages to both approaches.

There are also some subtleties about the use of the request keys... you can reuse them, but the best security is achieved by creating new request keys for every pairing, that way you can revoke one without revoking others.

### NOTE:

The Jenkins CLI has the ability to automate all the steps described above.

## What if I DO NOT have Licensed Plugins?

I can't answer that question because I believe the assignment of agents to folders is exclusive to the licensed cloudbees plugins.
> 2 votes

# Answer
You could use Project-based Matrix Authorization Strategy for user authorisation in Jenkins.

Works well with Folders plugin, then you have each project in a separate folder and permissions on each folder are set to a team that looks after the project.

Each node/slave can have access permissions specified. For example, for node A you will only list Team A as users/team who can have Build and Configure permissions. Team B for node B etc. It is a pain if you have dozens of nodes though.

If integrated with AD, then groups as they are defined in AD can be used to restrict/give access without having to list all members of the team who needs access to which node/project.

Authorisation strategy is defined in "Manage Jenkins" -\> “Configure Global Security Option" -\> "Authorisation" -\> "Project-based Matrix Authorization Strategy" This article describes it to a degree: https://www.thegeekstuff.com/2016/06/jenkins-security/

You could do the same with just Matrix Authorization Strategy, only you won't have projects. You might not need them at all (depends on how many project/teams you have) and then you will only restrict node permissions.
> 1 votes

# Answer
If all of the jobs are running k8s agents then you can use a combination of node attributes and podSpec nodeSelector. For example, if you assign an attribute identifying the team ownership these nodes for the purpose of jenkins.

```
kind: node
apiVerson: v1
-- some node specific stuff like name resource type ..
labels:
   type: jenkins
   team: qa

```

Than in the agent pod specification you can include a nodeSelector in the pod specification:

```
[.... yaml ...
nodeSelector:
     type: jenkins
     team: qa
.... more yaml]

```

Openshift description of using nodeSelectors
> 0 votes

---
Tags: jenkins, jenkins-plugins, jenkins2
---


# Question
Title: What is manual, what is automatic in Continuous Delivery?
I've read lots of articles about the concept on the internet. I thought I got it, but some statements in other articles make me confused.

In order to simplify and clarify things, I'll presume I use Git as VCS, I have only master branch (and feature branches based on it), only production environment, and it is a Node.js project.

Continuous Deployment is clear. Everything will be released automatically.

Continuous Integration is about making sure that changes don't break things in the code base: master. Once a PR is created from the feature branch to master, my CI tool will run tests, lint, style etc. and the PR will be able to be merged once the pipeline passes.

**My first question:** Is it considered as part of "Continuous Integration" to create a deliverable (a js bundle, a docker image etc.) and push it to a registry once the PR is merged to master? My own answer is, no, it should be part of "Continuous Delivery". Is that correct?

**My second question:** Do I have to have at least one staging/test environment (and another branch corresponding to this environment) to implement Continuous Delivery? I'm asking that because I read some articles implying that: e.g. https://aws.amazon.com/devops/continuous-integration/ https://www.atlassian.com/continuous-delivery/principles/continuous-integration-vs-delivery-vs-deployment

If I create a staging/test environment, will the meaning of Continuous Delivery change? The same article implies that deploying to a test environment is done automatically in Continuous Delivery.

I'm sure there might be different implementations and approaches for CI/CD. To summarize, I'm confused what exactly will be done automatically and manually in Continuous Delivery.

Thanks in advance.

# Answer
The first thing to do is to define what is meant by "Continuous Integration", "Continuous Delivery", and "Continuous Deployment". They've come to mean different things to different people.

Continuous Integration comes from Extreme Programming, developed by Kent Beck and others. In Extreme Programming Explained: Embrace Change, Beck says this about Continuous Integration:

> Integrate and build a complete product. If the goal is to burn a CD, burn a CD. If the goal is to deploy a web site, deploy a web site, even if it is to a test environment. Continuous integration should be complete enough that the first deployment of the system is no big deal.

From an Extreme Programming perspective, Continuous Integration would result in a deliverable, such as a library or package or container in a registry. If the goal is to make the package, that would be sufficient. However, if the team handles building the system, true Continuous Integration would go further and deploy that package or container to an environment. The team would need to define what its goal and deliverable would be - is it a user-facing software system or a package?

Having a well-controlled staging or test environment is almost certainly required when performing Extreme Programming's form of Continuous Integration or what is often referred to as Continuous Delivery today. These practices require that you have confidence in the ability to deploy software to the production environment on-demand. Without deploying it somewhere, preferably to an environment that is sufficiently like the production environment, how do you intend to have the necessary confidence? This only applies to teams building systems, though - teams building packages may be confident by creating a package somewhere and not publishing it.

As far as branching, you don't need a branch-per-environment. You can continue to use trunk-based development (committing straight to trunk or using short-lived feature branches) with releases made from the trunk or branching for releases. If you are practicing XP's definition of CI or Continuous Delivery, each commit to trunk would result in a build created and deployed somewhere. When you decide to go to production, a person would make the decision to promote the artifacts associated with a specific build to production. If you are branching for release, this would be associated with creating a release branch from trunk. Otherwise, it would be promoting a particular commit hash or tag.
> 2 votes

---
Tags: continuous-integration, git, continuous-delivery
---


title: Multi-language Monorepo

text:
# Question
Title: Multi-language Monorepo
We currently have a "front-end" git repository that is all of our JavaScript client apps, and a "back-end" git repository containing all back end APIs written in .NET Core. There is also a few other random repositories built on differing technologies. This is all managed via Azure DevOps, which I believe will let us trigger builds on particular paths.

```
front-end repo
-- applications
----app1
----app2
-- common-library

back-end repo
-- apis
----api1
----api2
--common-library

some .net-core-product repo

```

We were considering putting everything in a single mono-repo because it is easier for the developers to manage with git clients such as Visual Studio. I cannot find an example of a multi-language monorepo - is there an example on github? What are the pros/cons?

# Answer
> 10 votes
Monorepos have been getting a lot of attention in recent years since google popularized them. If you aren't on a similar scale as google it might not work out as well for you. I've been in a startup that moved to monorepos and we quickly found that:

* most tools are built with one repo leading to one artifact that gets deployed. You will have to rework all of those tools to handle the monorepo. There are tools that are designed for monorepos.
* a monorepo puts all of your eggs in one basket. If somebody steals a laptop would you rather them get half of your code or all of it? Keeping different things in their own repos reduces exposure.
* your CI for code validation is now much more complicated. You need to support multiple languages in your code conformance tests. Developers will get upset when you check backend stuff and they've only made frontend changes. Now you're stuck trying to figure out how to disable some CI checks, but make sure they're enabled when needed.

All of this adds up to a load of work for release engineers. Do you have people focused on release engineering with free time to tackle multiple complicated projects? Google can make this work because they have hordes of engineers and they can dedicate ten folks to this sort of thing for months until it is smooth enough to develop on top of. If you are not at the same scale as google you might not be able to follow their example. The folks that have succeeded with this tend to be big organizations. You may not have found an open source example because none exists.

These points are also noted in this article:

> The frank reality is that, at scale, how well an organization does with code sharing, collaboration, tight coupling, etc. is a direct result of engineering culture and leadership, and has nothing to do with whether a monorepo or a polyrepo is used. The two solutions end up looking identical to the developer. In the face of this, why use a monorepo in the first place? Please don’t!

So focus on improving your engineering culture and don't get worried about not following the latest tech trends.

# Answer
> 5 votes
You can put two or more projects into the same repository without opting in to a "monorepo" where *every* project goes into the same repository by default.

If you have multiple products that need to be released in tandem putting them in the same repository allows you to release all of them at once with the same commit, "atomically". **This is the principle consideration** as far as I can tell.

Like in your example, if each release of the frontend requires an equivalent release in the backend. With separate repos you have to coordinate multiple pull requests between repos. This takes effort and that effort multiplies the more projects you have that depend on each other. As opposed to having a single PR that contains changes for both which are guaranteed to be released at the same time with no additional coordination effort.

An API and frontend might not be a good example since APIs are *typically* designed to be versioned separately from any client\*. But say you have some integration tests for your UI. Both code bases are tightly coupled; a trivial change in your UI will likely require an equivalent change in your tests. Regardless of language, conceptually they are meant to "change together" and therefore, its far easier to manage them when they are in the same repository. Similar to unit tests, though those are usually the same language at least.

Another issue with multiple repos is that code reviews that require cross cutting changes have a little more friction because you have to update multiple branches in multiple repositories. Especially when doing multiple rounds of review.

Deployments are affected as well, they will have to be carefully coordinated. Merging a PR in one repo and triggering a deployment, might break the other deployments because the other PRs haven't been approved yet. Alternatively you will have to write all your projects to be backwards compatible always.

Automation across multiple repositories can alleviate *some* of these problems, but usually it still requires some form of manual syncing.

Realistically, either path has tradeoffs, making the answer to this question a deeply unsatisfying "it depends". My rule of thumb is that **code that changes together, lives together in the same repository**. Only when the burdens of keeping it in the same repository outweigh the burdens of keeping them separate do I make the split.

### Regarding mixing languages

Git is language agnostic so it doesn't care. Your other tooling might. You will have to weigh that against the above benefit.

Some CI/CD tools need extra configuration when the root of your repository is not the root of your project. I would consider that tool poorly designed if it can't support that extra configuration and I have not yet run into such a tool\**.

For language specific tools like linters, etc, as long as each project is in it's own folder, they're not going to be aware of each other. Running these tools at the CI/CD level now may require an extra `cd <subdirectory>` statement.

Your IDE might get confused when you open the project from the root. For example if you had a Python, C#, and Typescript in the same repo, one VSCode instance would have 3 "language servers" it would be communicating to, potentially 3 plugin UIs to hide and show depending on the file you're looking at, 3 places to pull debug configurations from and so on. So far in my experience, this only results in some minor configuration changes to workspace settings and otherwise everything works fine. Worst case I end up opening another instance VSCode per project which is what I'd be doing anyway if they were separate.

### Teams play a role as well

This also touches on your team structure. If you have separate teams for each product, it *might* make sense to separate them because the cross team coordination needs to happen anyway because no one member commits in multiple repos.

I personally don't partition teams like this because I prefer teams that are able to write code in any part of the application system, front, back, side whatever. But I recognize this is not always desirable or possible.

### Why does Google, Twitter, etc do it?

At Google scale, their projects' dependencies are probably developed by their own internal teams. I suspect this means that in any given piece of work, they're mostly making commits that affect many projects at once.

Since that was the default case for them they decided to put *everything* in the same repo. They incurred a significant cost in doing so but for them, it makes sense because cross cutting changes are the norm because of all these internally managed dependencies.

For typical projects, the dependencies are mostly projects managed by 3rd parties outside of the company. Think nuget and npm packages. And your other projects are largely independent from each other. So putting *every project* in a single repo by default doesn't make sense.

Overall, keep in mind, Google, Twitter, etc are all managing products *they own* and have total control over. Whereas your company may be developing multiple projects *for different clients*. In which case, you are facing challenges that Google does not despite how massive they are and Google has not considered those challenges in their solution.

Here is a self-proclaimed Google engineer discussing why they like the monorepo. It is a confirmation of the above.

> Say I make a change to a commonly used library (let's say deprecating a function, and replacing it with another):
>
> * I can see literally *every use* of the old function.
> * I can run the tests for everyone who uses that function.
> * + this is automated; the build/test tooling can figure out the transitive set of build/test targets that are affected by such a change.
> * I can (relatively) easily update *every use* of the deprecated call with the new hotness
> * I can do that all within the same commit (or set of commits, realistically)
>
> ---
>
> None of this is impossible with multiple repos, it's just a lot more difficult to coordinate

**Asides**

\*In the case of an API and a frontend that uses that API. I would typically consider them independent and version them separately. An API should be designed to service many clients and not just one frontend. Otherwise a server side UI framework like ASPnet or PHP would be the more appropriate choice imo. I recognize though that this is often not the case and we have frontends tightly coupled into backends designed just for them.

\**SonarQube in the distant past had issues with scanning repositories with multiple languages. So there is some precedent for important tools not being able to handle mixed language projects. Though that issue may have been before the project really took off. Certainly it was before I had heard about it.

---
Tags: continuous-integration, git, azure-devops, monorepo
---


# Question
Title: How best to delay startup of a kubernetes container until another container has done something?
I'm migrating a chunk of applications to k8s. Some of them have large amounts of config files which are best held in GIT as their size exceeds the max size for configmaps. I have a simple git-sync image which I can configure to keep a persistent volume in sync with a git repository and had hoped to use it as a sidecar in some deployments.

Here's the crux. Some applications (like vendor apps that I can't control) require the configuration files to be there before the application starts. This means I can't just run the git-sync container as a sidecar as there's no guarantee it will have cloned the git repo before the main app starts. I've worked around this by having a separate deployment for the git sync and then having an initContainer for my main application which checks for the existence of the cloned git repo before starting.

This works but it feels a little messy. Any thoughts on a cleaner approach to this?

Here's a yaml snippet of my deployments:

```
#main-deployment
...
initContainers:
- name: wait-for-git-sync
  image: my-git-sync:1.0
  command: ["/bin/bash"]
  args: [ "-c", "until [ -d /myapp-config/stuff ] ; do echo \"config not present yet\"; sleep 1; done; exit;" ]
  volumeMounts:
  - mountPath: /myapp-config
    name: myapp-config
containers:
- name: myapp
  image: myapp:1.0
  volumeMounts:
  - mountPath: /myapp-config
    name: myapp-config

volumes:
- name: myapp-config
  persistentVolumeClaim:
    claimName: myapp-config
...
---
#git-sync-deployment
...
containers:
- name: myapp-git-sync
  image: my-git-sync:1.0
  env:
    - name: GIT_REPO
      value: ssh://mygitrepo
    - name: SYNC_DIR
      value: /myapp-config/stuff
  volumeMounts:
  - mountPath: /myapp-config
    name: myapp-config
volumes:
- name: myapp-config
  persistentVolumeClaim:
    claimName: myapp-config
...

```

# Answer
> 1 votes
Maybe a readiness probe will help. The api server will in this case call your pods on /health and a http status error code means not ready, else ready. As long as the service is not ready, calls will not be routed.

```
  - name: name
    image: "docker.io/app:1.0"
    imagePullPolicy: Always
    readinessProbe:
      httpGet:
        path: /health
        port: 5000
      initialDelaySeconds: 5

```

And in your code

```
@app.route("/health")
def health():
    if not os.path.exists('gitfile'):
        return "not ok", 500
    return "OK", 200

```

or else a livenessprobe with checks the return value of the utilities called. zero means success, else fail.

```
livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5

```

# Answer
> 1 votes
You should use your initContainer to clone the repository. Don't wait for a file to be present: just pull or clone your conf.

---
Tags: kubernetes
---