Is there a way to annotate a deployconfig with timestamp? - kubernetes

In short, I'm trying to add an annotation with the actual time.
cmd line should like (or not) :
oc annotate --overwrite dc webtest Last_Jmeter_test='timestamp'
Thanks for any advice!

So I've found a way .
node ('master'){
stage("date") {
date = sh(
script: """
date
""",
returnStdout: true
)
echo "${date}"
}
}
this is by using jenkins .
oc annotate --overwrite dc webtest Last_Jmeter_test='${date}'

Related

az cli/bicep targeted/single module deploys?

Is there an az/bicep equivalent to terraform apply -target=module.my_app.module.something?
Given a root bicep file:
module app '../../../projects/my/application/app.bicep' = {
name: 'app'
}
module test '../../../projects/my/application/test.bicep' = {
name: 'test'
}
module sample '../../../projects/my/application/sample.bicep' = {
name: 'sample'
params {
p1: 'p1'
}
}
Can I provision just the sample module somehow?
I could do something like: az deployment sub create --template-file ../../../projects/my/application/sample.bicep -l germanywestcentral
But this is not really the same thing, because this bypasses the params passed from the root module (which provides env separations) down to the actual module.
The command you have:
az deployment sub create --template-file ../../../projects/my/application/sample.bicep -l germanywestcentral will work just fine, you just pass the parameters you would normally pass to root.bicep that are needed by that module (e.g. p1)
If you have params that are created/manipulated in root.bicep you'd have to decide how you marshal those values manually.

List non-suspended cronjobs using kubectl

How to select SUSPEND=False cronjob?
--selector can't be used as suspend is not added in the labels.
By using a JSONPath expression and passing it via the --output=jsonpath= option to kubectl I was able to select only cronjobs which are unsuspended and print their names as follows:
kubectl get cronjob --output=jsonpath='{range .items[?(.spec.suspend==false)]}{.metadata.name}{"\n"}{end}'
In order yo invert the selection you can simply filter on spec.suspend==true instead of false, i.e.:
kubectl get cronjob --output=jsonpath='{range .items[?(.spec.suspend==true)]}{.metadata.name}{"\n"}{end}'
For explicitness you can additionally pass the --no-headers like so, even though the former command already does not print any headers:
kubectl get cronjob --no-headers --output=jsonpath='{range .items[?(.spec.suspend==false)]}{.metadata.name}{"\n"}{end}'
Last but not least you can combine the commands above with Kubernetes selector expressions; for example:
kubectl get cronjob --selector=sometagkey==sometagvalue --no-headers --output=jsonpath='{range .items[?(.spec.suspend==false)]}{.metadata.name}{"\n"}{end}'
you can't select spec.suspend on a kubectl filter.
You could make your own jq filter
(this is just an example and could be a lot cleaner)
k get cronjob --output=json |
jq -c 'select( .items[].spec.suspend == false)' |
jq '.items[] | .metadata.name + " " + .spec.schedule + " "
+ (.spec.suspend|tostring) + " " + .spec.active'
Or if you don't mind a little golang
// Look at https://github.com/kubernetes/client-go/blob/master/examples/out-of-cluster-client-configuration/main.go
// for the other parameters (like using current kubectl context).
func getCronsBySuspend(clientset *kubernetes.Clientset, namespace string) {
cjs, err := clientset.BatchV1().CronJobs(namespace).List(context.TODO(), metav1.ListOptions{})
if err != nil {
panic(err.Error())
}
var c []string
for _, cron := range cjs.Items {
if *cron.Spec.Suspend == false {
c = append(c, cron.Name)
}
}
fmt.Printf("%v", c)
}

kubectl output formatted : looking for a specific column

I'm looking to have a specific column, through my initial kubectl command
kubectl --context oam-ska-yo_jonnylee -n ebzz get -o json ingressroute zz-oamtoto
This give me the json below
{
"apiVersion":"traefik.containo.us/v1alpha1",
"kind":"IngressRoute",
"metadata":{
"annotations":{
"kubectl.kubernetes.io/last-applied-configuration":"{"sum-up"}\n"
},
"creationTimestamp":"2021-02-23T11:17:56Z",
"generation":1,
"labels":{
"instance":"webzz"
},
"managedFields":[
{
"apiVersion":"traefik.containo.us/v1alpha1",
"fieldsType":"FieldsV1",
"fieldsV1":{
"f:metadata":{
"f:annotations":{
".":{
},
"f:kubectl.kubernetes.io/last-applied-configuration":{
}
},
"f:labels":{
".":{
},
"f:instance":{
}
}
},
"f:spec":{
".":{
},
"f:entryPoints":{
},
"f:routes":{
}
}
},
"manager":"kubectl",
"operation":"Update",
"time":"2021-02-23T11:17:56Z"
}
],
"name":"zz-oamtoto",
"namespace":"ebzz",
"resourceVersion":"61112315",
"selfLink":"/apis/traefik.containo.us/v1alpha1/namespaces/ebzz/ingressroutes/zz-oamtoto",
"uid":"42727XXX-dd9e-45e4-9c7d-1225aea125"
},
"spec":{
"entryPoints":[
"http"
],
"routes":[
{
"kind":"Rule",
"match":"Host(`ebzz.acme.com`)",
"middlewares":[
{
"name":"ebzz-ebzz-basicauth"
}
],
"services":[
{
"kind":"Service",
"name":"zz-oamtoto",
"port":1234
}
]
}
]
}
}
What I'm looking at is to find a specific column, the routes one and most of all, one of its specific sub-column
"match":"Host('ebzz.acme.com')"
I tried the command below
kubectl --context oam-ska-yo_jonnylee -n ebzz get -o=custom-columns=svc:.spec.routes.-kind ingressroute zz-oamtoto
Which gives me this:
[map[kind:Rule match:Host(`ebzz.acme.com`) middlewares:[map[name:ebzz-ebzz-basicauth]] services:[map[kind:Service name:zz-oamtoto port:1234]]]]
What i've tried so far
kubectl --context oam-ska-yo_jonnylee -n ebzz get -o=custom-columns=svc:.spec.routes[kind] ingressroute zz-oamtoto
It gives me this
svc
error: invalid array index kind
I've tried this as well
kubectl --context oam-ska-yo_jonnylee -n ebzz get -o=custom-columns=svc:.spec.routes["kind"] ingressroute zz-oamtoto
But it gives me this
svc
error: invalid array index kind
After many trials, this one works
kubectl --context oam-ska-yo_jonnylee -n ebz get -o=custom-columns=.spec.routes[0].match ingressroute zz-oamtoto
The option custom-columns should give you the tuning if you are looking for a column.
For the first column, you are aiming to, you need to put a .spec followed by a dot and the column name, like this .spec.column_name
Once there, the routes column part, in this example, is an array. Therefore you need to put the [], followed by the number and then followed by the subname, here match. it gives you .spec.routes[0].match
Note: I use a svc in my initial kubectly query. It was a mistake, there is no use for that.
If I understood you correctly, you need
kubectl --context oam-ska-yo_jonnylee -n ebz get ingressroute zz-oamtoto --output=jsonpath={.spec.routes.match}
Here you can find more examples: kubectl Cheat Sheet

Obtaining Azure VM scale set private IP addresses through Azure REST API

Can you get a list of Azure VM scale set instance private IP addresses through the Azure REST API?
It seems that Microsoft does not publish the VMSS IP configuration objects under the normal methods for retrieving a list of "ipConfigurations".
Here are some relevant API doc pages:
https://learn.microsoft.com/en-us/rest/api/compute/virtualmachinescalesets/listall
https://learn.microsoft.com/en-us/rest/api/compute/virtualmachinescalesets/get
https://learn.microsoft.com/en-us/rest/api/compute/virtualmachines/listall
In particular, this one only gives you the IP configuration of VMs, not VMSSes:
https://learn.microsoft.com/en-us/rest/api/virtualnetwork/networkinterfaces/listall
Here's how to get a list of private IP addresses for VMs and VMSS instances through Ruby:
require 'openssl'
require 'azure_mgmt_network'
require 'azure_mgmt_compute'
require 'awesome_print'
options = {
tenant_id: '<tenant_id>',
client_id: '<client_id>',
client_secret: '<client_secret>',
subscription_id: '<subscription_id>'
}
def net_interface_to_ip_mapping(client)
network_interfaces = client.network_interfaces.list_all
pairs = network_interfaces.collect { |ni| [ni.id.split('/').last, ni.ip_configurations.collect { |ip| ip.private_ipaddress }.flatten.compact[0] ] }
[network_interfaces, pairs]
end
def net_interface_to_vm(ni)
interface_vm_set = ni.collect { |prof| [prof.id, prof.virtual_machine, prof.ip_configurations.collect(&:id)] }
ipconf_to_host = interface_vm_set.collect { |x| [x[2][0], x[1]&.id&.split('/')&.last] }.to_h
conf_ip_map = ni.collect(&:ip_configurations).flatten.compact.collect { |ipconf| [ipconf&.id, ipconf&.private_ipaddress] }.to_h
[ipconf_to_host, conf_ip_map]
end
puts "*** Network Interfaces"
puts
client = Azure::Network::Profiles::Latest::Mgmt::Client.new(options)
ni, pairs = net_interface_to_ip_mapping(client)
pairs.to_h.each do |ni, ip|
puts " #{ni}: #{ip}"
end
puts
puts "*** Virtual Machines"
puts
ipconf_to_host, conf_ip_map = net_interface_to_vm(ni)
ipconf_to_host.each do |ipconf, host|
ni_name = ipconf.split('/')[-3]
puts " #{host || '# ' + ni_name} - #{conf_ip_map[ipconf]}"
end
puts
puts "*** Virtual Machine Scale Sets"
puts
vns = client.virtual_networks.list_all
vns.each do |vn|
resource_group = vn.id.split('/')[4]
puts
vn_details = client.virtual_networks.get(resource_group, vn.name, expand: 'subnets/ipConfigurations')
ip_configs = vn_details&.subnets&.collect { |subnet| subnet&.ip_configurations&.collect { |ip| [ip&.id, ip&.name, ip&.private_ipaddress] } }.compact
vmss_ipconf = ip_configs.collect { |subnet| subnet.select { |ipconf| ipconf[0].include?('/virtualMachineScaleSets/') } }
vmss_ipconf.each do |subnet|
subnet.each do |ipconf|
vmss_name = ipconf[0].split('/')[8]
vmss_instance = ipconf[0].split('/')[10]
puts "#{vmss_name} ##{vmss_instance} - #{ipconf[2]}"
end
end
end
Looking at the Azure CLI, there is az vmss nic list which returns all network interfaces in a virtual machine scale set. Looking at the results, there is
{
"dnsSettings": {
...
},
"ipConfigurations": [
{
privateIpAddress: "..."
}
]
}
You can use the --query syntax to get all private IPs.
az vmss nic list -g <resource_group> --vmss-name <vmss_name> --query [].{ip:ipConfigurations[0].privateIpAddress} -o tsv
you can get VM hostnames that will resolve to IPs thanks to Azure DNS
$ curl -H "Authorization: Bearer $JWT_TOCKEN" -sf https://management.azure.com/subscriptions/${subscription_id}/resourceGroups/${resourc_group}/providers/Microsoft.Compute/virtualMachineScaleSets/${scale_set}/virtualMachines?api-version=2018-10-01 | jq '.value[].properties.osProfile.computerName'
"influx-meta000000"
"influx-meta000001"
$ getent hosts influx-meta000001
10.120.10.7 influx-meta000001.l55qt5nuiezudgvyxzyvtbihmf.gx.internal.cloudapp.net

Handling attributes in InSpec

I was trying to create some basic inspec tests to validate a set of HTTP URLs. The way I started is like this -
control 'http-url-checks' do
impact 1.0
title 'http-url-checks'
desc '
Specify the URLs which need to be up and working.
'
tag 'http-url-checks'
describe http('http://example.com') do
its('status') { should eq 200 }
its('body') { should match /abc/ }
its('headers.name') { should eq 'header' }
end
describe http('http://example.net') do
its('status') { should eq 200 }
its('body') { should match /abc/ }
its('headers.name') { should eq 'header' }
end
end
We notice that the URLs are hard-coded in the controls and isn't a lot of fun. I'd like to move them to some 'attributes' file of some sort and loop through them in the control file.
My attempt was to use the 'files' folder structure inside the profile.I created a file - httpurls.yml and had the following content in it -
- url: http://example.com
- url: http://example.net
..and in my control file, I had the construct -
my_urls = yaml(content: inspec.profile.file('httpurls.yml')).params
my_urls.each do |s|
describe http(s['url']) do
its('status') { should eq 200 }
end
end
However, when I execute the compliance profile, I get an error - 'httpurls.yml not found' (not sure about the exact error message though though). The following is the folder structure I had for my compliance profile.
What I am doing wrong?
Is there a better way to achieve what I am trying to do?
The secret is to use profile attributes, as defined near the bottom of this page:
https://www.inspec.io/docs/reference/profiles/
First, create a profile attributes YML file. I name mine profile-attribute.yml.
Second, put your array of values in the YML file, like so:
urls:
- http://example.com
- http://example.net
Third, create an attribute at the top of your InSpec tests:
my_urls = attribute('urls', description: 'The URLs that I am validating.')
Fourth, use your attribute in your InSpec test:
my_urls.each do |s|
describe http(s['url']) do
its('status') { should eq 200 }
end
end
Finally, when you call your InSpec test, point to your YML file using --attrs:
inspec exec mytest.rb --reporter=cli --attrs profile-attribute.yml
There is another way to do this using files (instead of the profile attributes and the --attrs flag). You can use JSON or YAML.
First, create the JSON and/or YAML file and put them in the files directory. A simple example of the JSON file might look like this:
{
"urls": ["https://www.google.com", "https://www.apple.com"]
}
And a simple example of the YAML file might look like this:
urls:
- https://www.google.com
- https://www.apple.com
Second, include code at the top of your InSpec file to read and parse the JSON and/or YAML, like so:
jsoncontent = inspec.profile.file("tmp.json")
jsonparams = JSON.parse(jsoncontent)
jsonurls = jsonparams['urls']
yamlcontent = inspec.profile.file("tmp.yaml")
yamlparams = YAML.load(yamlcontent)
yamlurls = yamlparams['urls']
Third, use the variables in your InSpec tests, like so:
jsonurls.each do |jsonurl|
describe http(jsonurl) do
puts "json url is " + jsonurl
its('status') { should eq 200 }
end
end
yamlurls.each do |yamlurl|
describe http(yamlurl) do
puts "yaml url is " + yamlurl
its('status') { should eq 200 }
end
end
(NOTE: the puts line is for debugging.)
The result is what you would expect:
json url is https://www.google.com
json url is https://www.apple.com
yaml url is https://www.google.com
yaml url is https://www.apple.com
Profile: InSpec Profile (inspec-file-test)
Version: 0.1.0
Target: local://
http GET on https://www.google.com
✔ status should eq 200
http GET on https://www.apple.com
✔ status should eq 200
http GET on https://www.google.com
✔ status should eq 200
http GET on https://www.apple.com
✔ status should eq 200