Monday, 20 December 2021

IBM Key Protect - Computer says "No"

Whilst tinkering with IBM Key Protect, the computer was most definitely saying "No" 

ic kp keys --instance-id $guid

Retrieving keys...

FAILED

kp.Error: correlation_id='8638482c-706f-4959-9d39-cb583f4e7692', msg='Unauthorized: The user does not have access to the specified resource'

Thankfully, the internet had the answer ( the internet is my friend ) : -


The error is actually described in the introduction to ibm_kms_key, but easily overread. The set region for the provider currently has to match the region of the KMS instance.

The referenced Terraform provider documentation - ibm_kms_key - adds some context: -

The region parameter in the provider.tf file must be set. If region parameter is not specified, us-south is used as default

I double-checked where my Key Protect instance was located: -

ic resource service-instances --output JSON | jq -r '.[] | select(.name | endswith("kms"))' | jq -r .region_id

eu-gb

and directed the CLI tool to target that region: -

ic kp region-set eu-gb

OK

and retried my command: -

ic kp keys --instance-id $guid

Retrieving keys...
OK
Key ID                                 Key Name   
595e2c8e-f99c-45c0-82c3-997dd646dcf3   terraform-state-key-davehay-1638264407   

Good to go!

JQ and output control and searching ... I must remember this

As per many many previous posts, I'm continuing to learn - and love - jq.

One thing that's especially useful is the ability to be able to corral multiple facets together using the pipe ( | ) symbol, especially when searching/listing.

I did, however, fall into a trap this AM.

So I'm querying my IBM Cloud account for a Key Protect instance: -

ic resource service-instances --output JSON | jq -r '.[] | {Name: .name} | select(.name | endswith("kms"))'

which resulted in: -

jq: error (at <stdin>:77): endswith() requires string inputs

So what did I do wrong ?

To break it down, this is what I'm doing: -

List my IBM Cloud Service Instances

ic resource service-instances

Print the output in JavaScript Object Notation (JSON)

ic resource service-instances --output JSON

Parse the output via jq

ic resource service-instances --output JSON | jq

Strip out double-quotes where possible ( i.e. raw text )

ic resource service-instances --output JSON | jq -r

Inspect the array that comprises the output

ic resource service-instances --output JSON | jq -r

Only print the name field, aka .name, *AND* format it as Name

ic resource service-instances --output JSON | jq -r '.[] | {Name: .name}

Use the name field for a select ( search )

ic resource service-instances --output JSON | jq -r '.[] | {Name: .name} | select(.name

Look at the end of the name field, for the characters "kms" - short for Key Management System

ic resource service-instances --output JSON | jq -r '.[] | {Name: .name} | select(.name | endswith("kms"))'

and that's where the borkage occur...

Can you see what I did wrong ?

I asked jq to format the output of the .name field as Name, and then tried to search the output for .name ....

In this case, jq is reformatting the output JSON from .name to .Name ...

Here's an example with the search removed: -

ic resource service-instances --output JSON | jq -r '.[] | {Name: .name}'

{
  "Name": "davehay-1638264407-kms"
}
{
  "Name": "davehay-1638264407-state"
}

Once I changed my search: -

ic resource service-instances --output JSON | jq -r '.[] | {Name: .name} | select(.Name | endswith("kms"))'

{
  "Name": "davehay-1638264407-kms"
}

I'm good to go ....

Sunday, 19 December 2021

Don't be blue - debugging Bluetooth in macOS Monterey

Having noticed that Apple quietly removed Reset the Bluetooth module option: -

in macOS 12 Monterey, I was pleased to "discover" that there is the "nuclear" option of kill the Bluetooth stack, via: -

sudo pkill bluetoothd

before rebooting.

For the record, I have NOT yet tried this, but I trust the source of this tip, namely 9to5mac.com : -


But, of course, YMMV

There's also this: -


from Apple themselves

Wednesday, 15 December 2021

More fun with JQ - formatting

Following on from prior posts, a bit more tinkering with JQ, this time formatting the output.

So here's my starting point, a JSON document: -

simpsons.json 

[

    {

        "givenName": "Maggie",

        "familyName": "Simpson"

    },

    {

        "givenName": "Lisa",

        "familyName": "Simpson"

    },

    {

        "givenName": "Marge",

        "familyName": "Simpson"

    },

    {

        "givenName": "Homer",

        "familyName": "Simpson"

    },

    {

        "givenName": "Bart",

        "familyName": "Simpson"

    }

]

and here's my going through it and formatting the output: -

cat simpsons.json | jq -r '.[] | {"Given Name": .givenName, "Family Name": .familyName}'

{

  "Given Name": "Maggie",

  "Family Name": "Simpson"

}

{

  "Given Name": "Lisa",

  "Family Name": "Simpson"

}

{

  "Given Name": "Marge",

  "Family Name": "Simpson"

}

{

  "Given Name": "Homer",

  "Family Name": "Simpson"

}

{

  "Given Name": "Bart",

  "Family Name": "Simpson"

}

and here's an example, searching for given names beginning with "M" and then formatting the output: -

cat simpsons.json | jq -r '.[] | select(.givenName | startswith("M")) | {"Given Name": .givenName, "Family Name": .familyName}'

{

  "Given Name": "Maggie",

  "Family Name": "Simpson"

}

{

  "Given Name": "Marge",

  "Family Name": "Simpson"

}

Note that, in both examples, I wrap the to-be-displayed "labels" in double-quotes because they have space characters therein.

Otherwise, JQ is sick: -

cat simpsons.json | jq -r '.[] | select(.givenName | startswith("M")) | {Given Name: .givenName, Family Name: .familyName}'

jq: error: syntax error, unexpected IDENT, expecting '}' (Unix shell quoting issues?) at <top-level>, line 1:
.[] | select(.givenName | startswith("M")) | {Given Name: .givenName, Family Name: .familyName}                                                    
jq: error: May need parentheses around object key expression at <top-level>, line 1:
.[] | select(.givenName | startswith("M")) | {Given Name: .givenName, Family Name: .familyName}                                              
jq: error: syntax error, unexpected IDENT, expecting '}' (Unix shell quoting issues?) at <top-level>, line 1:
.[] | select(.givenName | startswith("M")) | {Given Name: .givenName, Family Name: .familyName}                                                                             
jq: error: May need parentheses around object key expression at <top-level>, line 1:
.[] | select(.givenName | startswith("M")) | {Given Name: .givenName, Family Name: .familyName}                                              
jq: 4 compile errors

Tuesday, 7 December 2021

Fun with Python and PyEnv on macOS

Via the Advent of Code 2021 I've been doing more with Python on macOS, and was struggling with versions, given that Apple kindly include Python 2 embedded in the OS, whereas I needed Python 3.10.0 for the work that I was doing.

This was of use: -

How to Install Python 3 on Mac – Brew Install Update Tutorial

and introduced me to PyEnv via Homebrew: -

brew install pyenv

One thing that didn't work was the way that PyEnv sets up $PATH in terms of different Python versions.

Looking at this: -

cat ~/.pyenv/version

I could see: -

3.10.0

but I couldn't initially work out how to add this to my PATH.

PyEnv uses the concept of a shim, as defined in: -

pyenv works by inserting a directory of shims at the front of your PATH:

$(pyenv root)/shims:/usr/local/bin:/usr/bin:/bin

Through a process called rehashing, pyenv maintains shims in that directory to match every Python command across every installed version of Python—python, pip, and so on.

Shims are lightweight executables that simply pass your command along to pyenv. So with pyenv installed, when you run, say, pip, your operating system will do the following:

    Search your PATH for an executable file named pip
    Find the pyenv shim named pip at the beginning of your PATH
    Run the shim named pip, which in turn passes the command along to pyenv


The first article describes how to setup $PATH: -

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile

This didn't work for me for one simple reason - I don't have $PYENV_ROOT/bin : -

ls $PYENV_ROOT/bin

ls: /Users/hayd/.pyenv/bin: No such file or directory

However, I do have $PYENV_ROOT/shims: -

ls $PYENV_ROOT/shims

2to3 easy_install-3.7 pip pydoc python-config python3.10-gdb.py python3.7m-config
2to3-3.10 idle pip3 pydoc3 python3 python3.7 pyvenv
2to3-3.7 idle3 pip3.10 pydoc3.10 python3-config python3.7-config pyvenv-3.7
autopep8 idle3.10 pip3.7 pydoc3.7 python3.10 python3.7-gdb.py
easy_install idle3.7 pycodestyle python python3.10-config python3.7m

Therefore, I setup ~/.bash_profile accordingly : -

export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/shims:$PATH"
if command -v pyenv 1>/dev/null 2>&1; then
  eval "$(pyenv init -)"
fi

And now I have Python 3.10 

python3 --version

Python 3.10.0

For the record, this helped massively: -

 As Vadorequest said, if pyenv is installed using homebrew, you have to add $PYENV_ROOT/shims to the path as $PYENV_ROOT/bin does not exist. I think that is unique to homebrew installs of pyenv. 


Thursday, 2 December 2021

Automated creation of a Red Hat OpenShift cluster on IBM Cloud using the existing CLIs and plugins

Talking of plugins, this is my post pluggin' someone else's blog: -

Automated creation of a Red Hat OpenShift cluster on IBM Cloud using the existing CLIs and plugins

This blog post is about automating the creation of a Red Hat OpenShift cluster on IBM Cloud in a Virtual Private Cloud. I used bash scripting with the IBM Cloud CLI and and the associated IBM Cloud CLI plugins vpc-infrastructure and kubernetes-service. I also use jq to handle json output.

Thomas Suedbroecker is an IBM colleague, and this definitely worth a read.....

Wednesday, 1 December 2021

A reminder - querying Kubernetes nodes by their labels

I have a requirement to inspect a particular label of the nine nodes that comprise my Kubernetes ( actually Red Hat OpenShift Container Platform ) cluster.

The label in question is ibm-cloud.kubernetes.io/worker-id as the OCP cluster is hosted on IBM Cloud.

Here's up with what I ended: -

kubectl get nodes --output wide --label-columns ibm-cloud.kubernetes.io/worker-id | grep -v NAME | awk '{print $12}'

and here's the JSON / jq variant: -

kubectl get nodes --output JSON --label-columns ibm-cloud.kubernetes.io/worker-id | jq '.items[].metadata.labels.ibm-cloud.kubernetes.io/worker-id'

which borks with: -

jq: error: cloud/0 is not defined at <top-level>, line 1:

.items[].metadata.labels.ibm-cloud.kubernetes.io/worker-id                             

jq: error: worker/0 is not defined at <top-level>, line 1:

.items[].metadata.labels.ibm-cloud.kubernetes.io/worker-id                                                 

jq: error: id/0 is not defined at <top-level>, line 1:

.items[].metadata.labels.ibm-cloud.kubernetes.io/worker-id                                                        

jq: 3 compile errors

Ewww, hang on

This helps: -


TL;DR: the answer is: -

If the key contains special characters or starts with a digit, you need to surround it with double quotes like this: ."foo$", or else .["foo$"]

So, here's an amended version: -

kubectl get nodes --output JSON --label-columns ibm-cloud.kubernetes.io/worker-id | jq '.items[].metadata.labels."ibm-cloud.kubernetes.io/worker-id"'

which does the trick.

I love the internet ....

More fun with pip

Again with the Python and pip  fun, this time on my Mac, where commands such as:  pip3 list and: - pip3 install --upgrade pip were failing w...