I was wondering if anyone knows how to create a json file that would be the same as running:
docker run -p 80:80 -p 443:443 starblade/pydio-v4
I trying something very ambitious, I want to start my docker container in kubernetes-mesos cluster but can't seem to get the ports correct in the json file, alas I am still very new to this.
Thanks,
TT
Here are my json files:
`
{
"id": "frontend-controller",
"kind": "ReplicationController",
"apiVersion": "v1beta1",
"desiredState": {
"replicas": 3,
"replicaSelector": {"name": "frontend"},
"podTemplate": {
"desiredState": {
"manifest": {
"version": "v1beta1",
"id": "frontend-controller",
"containers": [{
"name": "pydio-v4",
"image": "starblade/pydio-v4",
"ports": [{"containerPort": 10001, "protocol": "TCP"}]
}]
}
},
"labels": {"name": "frontend"}
}},
"labels": {"name": "frontend"}
}
{
"id": "frontend",
"kind": "Service",
"apiVersion": "v1beta1",
"port": 80,
"port": 443,
"targetPort": 10001,
"selector": {
"name": "frontend"
},
"publicIPs": [
"${servicehost}"
]
}
Docker container Env info pulled from docker inspect command:
"Env": [
"FRONTEND_SERVICE_HOST=10.10.10.14",
"FRONTEND_SERVICE_PORT=443",
"FRONTEND_PORT=tcp://10.10.10.14:443",
"FRONTEND_PORT_443_TCP=tcp://10.10.10.14:443",
"FRONTEND_PORT_443_TCP_PROTO=tcp",
"FRONTEND_PORT_443_TCP_PORT=443",
"FRONTEND_PORT_443_TCP_ADDR=10.10.10.14",
"KUBERNETES_SERVICE_HOST=10.10.10.2",
"KUBERNETES_SERVICE_PORT=443",
"KUBERNETES_PORT=tcp://10.10.10.2:443",
"KUBERNETES_PORT_443_TCP=tcp://10.10.10.2:443",
"KUBERNETES_PORT_443_TCP_PROTO=tcp",
"KUBERNETES_PORT_443_TCP_PORT=443",
"KUBERNETES_PORT_443_TCP_ADDR=10.10.10.2",
"KUBERNETES_RO_SERVICE_HOST=10.10.10.1",
"KUBERNETES_RO_SERVICE_PORT=80",
"KUBERNETES_RO_PORT=tcp://10.10.10.1:80",
"KUBERNETES_RO_PORT_80_TCP=tcp://10.10.10.1:80",
"KUBERNETES_RO_PORT_80_TCP_PROTO=tcp",
"KUBERNETES_RO_PORT_80_TCP_PORT=80",
"KUBERNETES_RO_PORT_80_TCP_ADDR=10.10.10.1",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"PYDIO_VERSION=6.0.5"
],
"ExposedPorts": {
"443/tcp": {},
"80/tcp": {}
},
`
The pod and service both start and run ok.
However I am unable to access the running Pydio site on any of the master, minion or frontend ips.
Note:
I am running a modified version of the this docker container:
https://registry.hub.docker.com/u/kdelfour/pydio-docker/
My container has been tested and it runs as expected.
You should see the login screen once it is running.
Please let me know if I can provide any other information.
Thanks again.
So, I finally got this to work using the following .json files:
frontend-service.json
{
"id": "frontend",
"kind": "Service",
"apiVersion": "v1beta1",
"port": 443,
"selector": {
"name": "frontend"
},
"publicIPs": [
"${servicehost}"
]
}
frontend-controller.json
{
"id": "frontend-controller",
"kind": "ReplicationController",
"apiVersion": "v1beta1",
"desiredState": {
"replicas": 1,
"replicaSelector": {"name": "frontend"},
"podTemplate": {
"desiredState": {
"manifest": {
"version": "v1beta1",
"id": "frontend-controller",
"containers": [{
"name": "pydio-v4",
"image": "starblade/pydio-v4",
"ports": [{"containerPort": 443, "hostPort": 31000}]
}]
}
},
"labels": {"name": "frontend"}
}},
"labels": {"name": "frontend"}
}
I now have pydio with SSL running in a Mesos-Kubernetes env on GCE.
Going to run some tests using more hostPorts to see if I can get more than one replica running on one host. At this point I can resize up to 3.
Hope this helps someone.
Thanks,
TT
Related
Error: String cannot be coerced to a nodeId
Hi,
I was busy setting up a connection between the Orion Broker and an PLC with OPC-UA Server using the opcua iotagent agent.
I managed to setup all parts and I am able to receive (test) data, but I am unable to follow the tutorial with regards to adding an entity to the Orion-Broker using a json file:
curl http://localhost:4001/iot/devices -H "fiware-service: plcservice" -H "fiware-servicepath: /demo" -H "Content-Type: application/json" -d #add_device.json
The expected result would be an added entity to the OrionBroker with the supplied data, but this only results in a error message:
{"name":"Error","message":"String cannot be coerced to a nodeId : ns*4:s*MAIN.mainVar"}
suspected Error
Is it possible that the iotagent does not work nicely with nested Variables?
steps taken
doublechecked availability of OPC Data:
OPC data changes every second, can be seen in Broker log
reduced complexity of setup to only include Broker and IOT-agent
additional information:
add_device.json file:
{
"devices": [
{
"device_id": "plc1",
"entity_name": "PLC1",
"entity_type": "plc",
"attributes": [
{
"object_id": "ns*4:s*MAIN.mainVar",
"name": "main",
"type": "Number"
}
],
"lazy": [
],
"commands" : []
}
]
}
config of IOT-agent (from localhost:4081/config):
{
"config": {
"logLevel": "DEBUG",
"contextBroker": {
"host": "orion",
"port": 1026
},
"server": {
"port": 4001,
"baseRoot": "/"
},
"deviceRegistry": {
"type": "memory"
},
"mongodb": {
"host": "iotmongo",
"port": "27017",
"db": "iotagent",
"retries": 5,
"retryTime": 5
},
"types": {
"plc": {
"service": "plcservice",
"subservice": "/demo",
"active": [
{
"name": "main",
"type": "Int16"
},
{
"name": "test1",
"type": "Int16"
},
{
"name": "test2",
"type": "Int16"
}
],
"lazy": [],
"commands": []
}
},
"browseServerOptions": null,
"service": "plc",
"subservice": "/demo",
"providerUrl": "http://iotage:4001",
"pollingExpiration": "200000",
"pollingDaemonFrequency": "20000",
"deviceRegistrationDuration": "P1M",
"defaultType": null,
"contexts": [
{
"id": "plc_1",
"type": "plc",
"service": "plcservice",
"subservice": "/demo",
"polling": false,
"mappings": [
{
"ocb_id": "test1",
"opcua_id": "ns=4;s=test.TestVar.test1",
"object_id": null,
"inputArguments": []
},
{
"ocb_id": "test2",
"opcua_id": "ns=4;s=test.TestVar.test2",
"object_id": null,
"inputArguments": []
},
{
"ocb_id": "main",
"opcua_id": "ns=4;s=MAIN.mainVar",
"object_id": null,
"inputArguments": []
}
]
}
]
}
}
I'm one of the maintainers of the iotagent-opcua repo, we have identified and fixed the bug you were addressing, please update your agent to the latest version (1.4.0)
If you haven't ever heard about it, starting from 1.3.8 we have introduced a new configuration property called "relaxTemplateValidation" which let you use previously forbidden characters (e.g. = and ; ). I suggest you to have a look at it on the configuration examples provided.
Let me start by saying I just started Azure and by no means a pro and been following guides here and there. So, I'm following this article by deploying this repo in my own Azure DevOps subscription, after I changed the resource group, subscription, and function name, I build and run the CI pipeline, then at the "Deploy Azure Resources" I'd get this error even though after the pipeline exits, the resources are created the way its supposed to, I also notice if I re run the same pipeline the 2nd time, it works perfectly which is confusing. Here is the modified the YAML template that I have
name: DeployAzureFunction
variables:
FunctionAppName: 'test'
AzureConnection: 'DevOps-Test'
ResourcegGroupName: 'test'
trigger:
branches:
include:
- '*' # must quote since "*" is a YAML reserved character; we want a string
stages:
- stage: Build
jobs:
- job: Test_FA
pool:
vmImage: windows-2019
steps:
- task: AzureResourceGroupDeployment#2
displayName: 'Test ARM Deployment'
inputs:
azureSubscription: $(AzureConnection)
resourceGroupName: $(ResourcegGroupName)
location: 'East US 2'
csmFile: Deployment/azuredeploy.json
deploymentMode: Validation
- powershell: |
Install-PackageProvider -Name NuGet -Force -Scope CurrentUser
Install-Module -Name Pester -Force -Scope CurrentUser -SkipPublisherCheck
Install-Module -Name PSScriptAnalyzer -Force -Scope CurrentUser
displayName: 'Install Pester and import module'
- job: Build_FA
pool:
vmImage: windows-2019
steps:
- task: ArchiveFiles#2
displayName: 'Archive FunctionApp'
inputs:
rootFolderOrFile: FunctionApp
includeRootFolder: false
archiveFile: '$(System.DefaultWorkingDirectory)/zip/FunctionApp.zip'
- task: PublishPipelineArtifact#0
inputs:
artifactName: 'zip'
targetPath: '$(System.DefaultWorkingDirectory)/zip'
- stage: Deploy
jobs:
- job: Deploy_ARM
pool:
vmImage: windows-2019
steps:
- task: AzureResourceGroupDeployment#2
displayName: 'Deploy Azure Resources'
continueOnError: true
inputs:
azureSubscription: $(AzureConnection)
resourceGroupName: $(ResourcegGroupName)
location: 'East US 2'
csmFile: Deployment/azuredeploy.json
csmParametersFile: Deployment/azuredeploy.parameters.json
overrideParameters: '-functionAppName $(FunctionAppName)'
deploymentMode: Incremental
deploymentOutputs: DeploymentOutput
And this is the unmodified azuredeploy.json that I think is causing the issue but not sure why
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"functionAppName": {
"type": "string",
"defaultValue": "[uniqueString(resourceGroup().id)]",
"metadata": {
"description": "Specify the name of the function application"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Specify the location for the function application resources"
}
}
},
"variables": {
"hostingPlanName": "[parameters('functionAppName')]",
"storageacccount": "[toLower(parameters('functionAppName'))]",
"storageAccountName": "[concat('storage', variables('storageacccount'))]"
},
"resources": [
{
"apiVersion": "2017-06-01",
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('storageAccountName')]",
"location": "[parameters('location')]",
"kind": "Storage",
"sku": {
"name": "Standard_LRS"
}
},
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2018-11-01",
"name": "[variables('hostingPlanName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Y1",
"tier": "Dynamic",
"size": "Y1",
"family": "Y",
"capacity": 0
},
"properties": {
"name": "[variables('hostingPlanName')]"
}
},
{
"name": "[parameters('functionAppName')]",
"type": "Microsoft.Web/sites",
"apiVersion": "2018-02-01",
"location": "[parameters('location')]",
"kind": "functionapp",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms/', variables('hostingPlanName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]",
"[resourceId('microsoft.insights/components/', parameters('functionAppName'))]"
],
"identity": {
"type": "SystemAssigned"
},
"properties": {
"siteConfig": {
"appSettings": [
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "powershell"
},
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2017-06-01').keys[0].value)]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
},
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(resourceId('microsoft.insights/components/', parameters('functionAppName')), '2018-05-01-preview').InstrumentationKey]"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2017-06-01').keys[0].value)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[toLower(parameters('functionAppName'))]"
}
]
},
"name": "[parameters('functionAppName')]",
"clientAffinityEnabled": false,
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms/', variables('hostingPlanName'))]"
}
},
{
"apiVersion": "2015-05-01",
"name": "[parameters('functionAppName')]",
"type": "Microsoft.Insights/components",
"kind": "Web",
"location": "[parameters('location')]",
"tags": {
"[concat('hidden-link:', resourceId('Microsoft.Web/sites/', parameters('functionAppName')))]": "Resource"
},
"properties": {
"ApplicationId": "[parameters('functionAppName')]",
"Application_Type": "web"
}
}
],
"outputs": {
"principalId": {
"type": "string",
"value": "[reference(concat(resourceId('Microsoft.Web/sites/', parameters('functionAppName')), '/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-PREVIEW').principalId]"
}
}
}
If anyone could help me figure out why I get that error in the first run, I'd appreciate it, thanks!
The Resources are created yet the Deployment operation fails because there is a problem in caclulating the output variable.
Most likely it is because of the way you are trying to access the Service Principal Id of the App Service. The '/providers/Microsoft.ManagedIdentity/Identities/default' part.
You probably want something like this:
[reference(resourceId('Microsoft.Web/sites', parameters('functionAppName')), '2016-08-01', 'Full').identity.principalId]
I'm debugging log output from kubectl that states:
Error from server (BadRequest): a container name must be specified for pod postgres-operator-49202276-bjtf4, choose one of: [apiserver postgres-operator]
OK, so that's an explanatory error message, but looking at my JSON template it ought to just create both containers specified, correct? What am I missing? (please forgive my ignorance.)
I'm using just a standard kubectl create -f command to create the JSON file within a shell script. The JSON deployment file is as follows:
{
"apiVersion": "extensions/v1beta1",
"kind": "Deployment",
"metadata": {
"name": "postgres-operator"
},
"spec": {
"replicas": 1,
"template": {
"metadata": {
"labels": {
"name": "postgres-operator"
}
},
"spec": {
"containers": [{
"name": "apiserver",
"image": "$CCP_IMAGE_PREFIX/apiserver:$CO_IMAGE_TAG",
"imagePullPolicy": "IfNotPresent",
"env": [{
"name": "DEBUG",
"value": "true"
}],
"volumeMounts": [{
"mountPath": "/config",
"name": "apiserver-conf",
"readOnly": true
}, {
"mountPath": "/operator-conf",
"name": "operator-conf",
"readOnly": true
}]
}, {
"name": "postgres-operator",
"image": "$CCP_IMAGE_PREFIX/postgres-operator:$CO_IMAGE_TAG",
"imagePullPolicy": "IfNotPresent",
"env": [{
"name": "DEBUG",
"value": "true"
}, {
"name": "NAMESPACE",
"valueFrom": {
"fieldRef": {
"fieldPath": "metadata.namespace"
}
}
}, {
"name": "MY_POD_NAME",
"valueFrom": {
"fieldRef": {
"fieldPath": "metadata.name"
}
}
}],
"volumeMounts": [{
"mountPath": "/operator-conf",
"name": "operator-conf",
"readOnly": true
}]
}],
"volumes": [{
"name": "operator-conf",
"configMap": {
"name": "operator-conf"
}
}, {
"name": "apiserver-conf",
"configMap": {
"name": "apiserver-conf"
}
}]
}
}
}
}
If a pod has more than 1 containers then you need to provide the name of the specific container.
in your case, There is a pod (postgres-operator-49202276-bjtf4) which has 2 containers (apiserver and postgres-operator ).
following commands will provide logs for the specific containers
kubectl logs deployment/postgres-operator -c apiserver
kubectl logs deployment/postgres-operator -c postgres-operator
A container name must be given if the pod is having more than one containers (as mentioned in above answers).
To know all the containers inside a pod we can use:
kubectl -n <NAMESPACE> get pods <POD_NAME> -o jsonpath="{..image}"
i'm stuck with Openshift (Origin) and need some help.
Let's say i want to add a grafana deployment via CLI to a new started cluster.
What i do:
Upload a template to my openshift cluster (oc create -f openshift-grafana.yml)
Pull the necessary image from the docker hub (oc import-image --confirm grafana/grafana)
Build a new app based on my template (oc new-app grafana)
These steps creates the deployment config and the routes.
But then i'm not able to start a deployment via CLI.
# oc deploy grafana
grafana deployment #1 waiting on image or update
# oc rollout latest grafana
Error from server (BadRequest): cannot trigger a deployment for "grafana" because it contains unresolved imagesenter code here
In the openshift web console it looks like this:
The images is there, even the link is working. In the web console i can click "deploy" and it's working. But nevertheless i'm not able to rollout a new version via command line.
The only way it works is editing the deployment yml so openshift recognizes a change a starts a deployment based on "config change" (hint: i'm was not changing the image or image name)
There is nothing special in my template, it was just an export via oc export from a working config.
Any hint would be appreciated, i'm pretty much stuck.
Thanks.
I had this same issue and I solved it by adding:
lastTriggeredImage: >-
mydockerrepo.com/repo/myimage#sha256:xxxxxxxxxxxxxxxx
On:
triggers:
- type: ImageChange
imageChangeParams:
Of the deploymentconfig yaml. Looks like if it doesn't know what the last triggered image is, it wont be able to resolve it.
Included below is the template you can use as a starter. Just be aware that the grafana image appears to require it be run as root, else it will not startup. This means you have to override the default security model of OpenShift and enable allowing running of images as root in the project. This is not recommended. The grafana images should be fixed so as not to require they be run as root.
To enable running as root, you would need to run as a cluster admin:
oc adm policy add-scc-to-user anyuid -z default -n myproject
where myproject is the name of the project you are using.
I applied it to the default service account, but better you create a separate service account, apply it to that and then change the template so that only grafana runs as that service account.
It is possible that the intent is that you override the default settings through the grafana.ini file so it uses your mounted emptyDir directories and then it isn't an issue. I didn't attempt to provide any override config.
The template for grafana would then be as follows. Note I have used JSON as I find it easier to work with JSON, but also to avoid indenting being screwed up making the YAML impossible to use.
Before you use this template, you should obviously create the corresponding config map where name is of form ${APPLICATION_NAME}-config where ${APPLICATION_NAME} is grafana unless you override it when using the template. The key in the config map should be grafana.ini and then have as value the config file contents.
{
"apiVersion": "v1",
"kind": "Template",
"metadata": {
"name": "grafana"
},
"parameters": [
{
"name": "APPLICATION_NAME",
"value": "grafana",
"from": "[a-zA-Z0-9]",
"required": true
}
],
"objects": [
{
"apiVersion": "v1",
"kind": "ImageStream",
"metadata": {
"name": "${APPLICATION_NAME}-img",
"labels": {
"app": "${APPLICATION_NAME}"
}
},
"spec": {
"tags": [
{
"name": "latest",
"from": {
"kind": "DockerImage",
"name": "grafana/grafana"
}
}
]
}
},
{
"apiVersion": "v1",
"kind": "DeploymentConfig",
"metadata": {
"name": "${APPLICATION_NAME}",
"labels": {
"app": "${APPLICATION_NAME}",
"type": "monitoring"
}
},
"spec": {
"replicas": 1,
"selector": {
"app": "${APPLICATION_NAME}",
"deploymentconfig": "${APPLICATION_NAME}"
},
"template": {
"metadata": {
"labels": {
"app": "${APPLICATION_NAME}",
"deploymentconfig": "${APPLICATION_NAME}",
"type": "monitoring"
}
},
"spec": {
"containers": [
{
"name": "grafana",
"image": "${APPLICATION_NAME}-img:latest",
"imagePullPolicy": "Always",
"livenessProbe": {
"failureThreshold": 3,
"httpGet": {
"path": "/",
"port": 3000,
"scheme": "HTTP"
},
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 1
},
"ports": [
{
"containerPort": 3000,
"protocol": "TCP"
}
],
"volumeMounts": [
{
"mountPath": "/etc/grafana",
"name": "grafana-1"
},
{
"mountPath": "/var/lib/grafana",
"name": "grafana-2"
},
{
"mountPath": "/var/log/grafana",
"name": "grafana-3"
}
]
}
],
"volumes": [
{
"configMap": {
"defaultMode": 420,
"name": "${APPLICATION_NAME}-config"
},
"name": "grafana-1"
},
{
"emptyDir": {},
"name": "grafana-2"
},
{
"emptyDir": {},
"name": "grafana-3"
}
]
}
},
"test": false,
"triggers": [
{
"type": "ConfigChange"
},
{
"imageChangeParams": {
"automatic": true,
"containerNames": [
"grafana"
],
"from": {
"kind": "ImageStreamTag",
"name": "${APPLICATION_NAME}-img:latest"
}
},
"type": "ImageChange"
}
]
}
},
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": "${APPLICATION_NAME}",
"labels": {
"app": "${APPLICATION_NAME}",
"type": "monitoring"
}
},
"spec": {
"ports": [
{
"name": "3000-tcp",
"port": 3000,
"protocol": "TCP",
"targetPort": 3000
}
],
"selector": {
"deploymentconfig": "${APPLICATION_NAME}"
},
"type": "ClusterIP"
}
},
{
"apiVersion": "v1",
"kind": "Route",
"metadata": {
"name": "${APPLICATION_NAME}",
"labels": {
"app": "${APPLICATION_NAME}",
"type": "monitoring"
}
},
"spec": {
"host": "",
"port": {
"targetPort": "3000-tcp"
},
"to": {
"kind": "Service",
"name": "${APPLICATION_NAME}",
"weight": 100
}
}
}
]
}
For me, I had the image name incorrectly under 'from':
triggers:
- type: ConfigChange
- imageChangeParams:
automatic: true
containerNames:
- alcatraz-ha
from:
kind: ImageStreamTag
name: 'alcatraz-haproxy:latest'
namespace: alcatraz-ha-dev
type: ImageChange
I had name: 'alcatraz-ha:latest' so it could not find the image
Make sure that spec.triggers.imageChangeParams.from.name exists as image stream
triggers:
- imageChangeParams:
from:
kind: ImageStreamTag
name: 'myapp:latest' # Does "myapp" exist if you run oc get is ????!!!
I'm trying to use jq to parse a JSON (the output of the OpenShift oc process ... command, actually), and add/update the env array of a container with a new key/value pair.
Sample input:
{
"kind": "List",
"apiVersion": "v1",
"metadata": {},
"items": [
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"annotations": {
"description": "Exposes and load balances the node.js application pods"
},
"name": "myapp-web"
},
"spec": {
"ports": [
{
"name": "web",
"port": 3000,
"protocol": "TCP",
"targetPort": 3000
}
],
"selector": {
"name": "myapp"
}
}
},
{
"apiVersion": "v1",
"kind": "Route",
"metadata": {
"name": "myapp-web"
},
"spec": {
"host": "app.internal.io",
"port": {
"targetPort": "web"
},
"to": {
"kind": "Service",
"name": "myapp-web"
}
}
},
{
"apiVersion": "v1",
"kind": "DeploymentConfig",
"metadata": {
"annotations": {
"description": "Defines how to deploy the application server"
},
"name": "myapp"
},
"spec": {
"replicas": 1,
"selector": {
"name": "myapp"
},
"strategy": {
"type": "Rolling"
},
"template": {
"metadata": {
"labels": {
"name": "myapp"
},
"name": "myapp"
},
"spec": {
"containers": [
{
"env": [
{
"name": "A_ENV",
"value": "a-value"
}
],
"image": "node",
"name": "myapp-node",
"ports": [
{
"containerPort": 3000,
"name": "app",
"protocol": "TCP"
}
]
}
]
}
},
"triggers": [
{
"type": "ConfigChange"
}
]
}
}
]
}
In this JSON, I want to do the following:
Find the DeploymentConfig object
Check if it has the env array in the first container
If it does, add a new object {"name": "B_ENV", "value": "b-value"} in it
If it does not, add the env array, with the object {"name": "B_ENV", "value": "b-value"} in it
So far, I'm able to tackle part of this, where I'm able to find the concerned object, and add the new env var to the container:
oc process -f <dc.yaml> -o json | jq '.items | map(if .kind == "DeploymentConfig"
then .spec.template.spec.containers[0].env |= .+ [{"name": "B_ENV", "value": "b-value"}]
else .
end)'
This is able to insert the new env var as expected, but the output is an array as shown below. Also, it doesn't handle the part where the env array may not be there at all.
I want to be able to produce the same output as the input, but with the new env var added.
Sample output:
[
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"annotations": {
"description": "Exposes and load balances the node.js application pods"
},
"name": "myapp-web"
},
"spec": {
"ports": [
{
"name": "web",
"port": 3000,
"protocol": "TCP",
"targetPort": 3000
}
],
"selector": {
"name": "myapp"
}
}
},
{
"apiVersion": "v1",
"kind": "Route",
"metadata": {
"name": "myapp-web"
},
"spec": {
"host": "app.internal.io",
"port": {
"targetPort": "web"
},
"to": {
"kind": "Service",
"name": "myapp-web"
}
}
},
{
"apiVersion": "v1",
"kind": "DeploymentConfig",
"metadata": {
"annotations": {
"description": "Defines how to deploy the application server"
},
"name": "myapp"
},
"spec": {
"replicas": 1,
"selector": {
"name": "myapp"
},
"strategy": {
"type": "Rolling"
},
"template": {
"metadata": {
"labels": {
"name": "myapp"
},
"name": "myapp"
},
"spec": {
"containers": [
{
"env": [
{
"name": "A_ENV",
"value": "a-value"
},
{
"name": "B_ENV",
"value": "b-value"
}
],
"image": "node",
"name": "myapp-node",
"ports": [
{
"containerPort": 3000,
"name": "app",
"protocol": "TCP"
}
]
}
]
}
},
"triggers": [
{
"type": "ConfigChange"
}
]
}
}
]
Is this doable, or is it too much to do with jq, and I should probably do this in python or node?
EDIT 1:
I just realized that conditional add/update of env array is already handled by the |= syntax!
So, I basically just need to be able to get the same structure back as the input, with the relevant env var added in the concerned array.
You pretty much had it, but you'll want to restructure your filter to preserve the full results. You want to make sure that none of the filters changes the context. By starting off with .items, you changed it from your root object to the items array. That in of itself is not so much a problem but what you do with that matters. Keep in mind that assignments/updates preserves the original context as a result with the change applied. So if you wrote your filter in terms of an update, it will work for you.
So to do this, you'll want to find the env array of the first container in the DeploymentConfig item. First let's find that:
.items[] | select(.kind == "DeploymentConfig").spec.template.spec.containers[0].env
You don't need to do anything else in terms of error handling since select will simply produce no result. From there, you just need to update the array by adding the new value.
(.items[] | select(.kind == "DeploymentConfig").spec.template.spec.containers[0].env) +=
[{name:"B_ENV",value:"b-value"}]
If the array exists, it will add the new item. If not, it will create a new env array. If env is not an array, that would be a different problem.