PUT k8s deployment returns 404 - kubernetes

According to the Replacement section of Kubernetes API reference v1.24 I should be able to create a deployment with a PUT /apis/apps/v1/namespaces/{namespace}/deployments/{name} HTTP request. The success response here is 201 Created. However, when I try the following, I get a 404 Not Found which is of course correct but unwanted: PUT requests should be treated as Create statements if the resource does not yet exist as documented. Updating a deployment does work (and returns the expected 200 OK HTTP response). Is there any documentation regarding this? Or is the request somehow incorrect? Ty.
➜ ~ curl --request PUT \
--url http://localhost:8080/apis/apps/v1/namespaces/ns/deployments/nginx-deployment \
--header 'content-type: application/json' \
--data '{
"apiVersion":"apps/v1",
"kind":"Deployment",
"metadata":{
"name":"nginx-deployment",
"labels":{
"app":"nginx"
}
},
"spec": {
"replicas" : 3,
"selector": {
"matchLabels" : {
"app":"nginx"
}
},
"template" : {
"metadata" : {
"labels" : {
"app":"nginx"
}
},
"spec":{
"containers":[
{
"name":"ngnix",
"image":"nginx:1.7.9",
"ports":[
{
"containerPort": 80
}
]
}
]
}
}
}
}'
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "deployments.apps \"nginx-deployment\" not found",
"reason": "NotFound",
"details": {
"name": "nginx-deployment",
"group": "apps",
"kind": "deployments"
},
"code": 404
}%

According to the documentation you provided,
PUT /apis/apps/v1/namespaces/{namespace}/deployments/{name}
is meant to "replace the specified Deployment", while a Deployment is created with a POST:
create a Deployment
HTTP Request
POST /apis/apps/v1/namespaces/{namespace}/deployments
You are correct that the documentation also states:
For PUT requests, Kubernetes internally classifies these as either create or update based on the state of the existing object
so there seems to be a contradiction, but the Deployment API spec states that POST should be used to create a deployment and PUT to update it.

Related

Using REST API to create alerting rule in Kibana fails on 400 "Invalid action groups: default"

I have ELK cloud v. 7.13.2 and trying to create alert rule with slack action via REST API. This is my curl invocation:
curl -u ****** -s -H 'kbn-xsrf: true' -H 'Content-Type: application/json' https://***********.westeurope.azure.elastic-cloud.com:9243/api/alerting/rule -X POST -d #src/rules/cpu_utilization.json
I am expecting that new rule is created, but unfortunately I am getting following error:
{
"statusCode": 400,
"error": "Bad Request",
"message": "Invalid action groups: default"
}
The contents of src/rules/cpu_utilization.json are:
{
"params": {
"nodeType": "host",
"criteria": [
{
"comparator": ">",
"timeSize": 1,
"metric": "cpu",
"threshold": [
80
],
"timeUnit": "m"
}
],
"sourceId": "default"
},
"consumer": "alerts",
"schedule": {
"interval": "1m"
},
"tags": [],
"name": "CPU2",
"throttle": "1000d",
"enabled": true,
"rule_type_id": "metrics.alert.inventory.threshold",
"notify_when": "onThrottleInterval",
"actions": [
{
"group": "default",
"id": "fce4c27f-d22a-4209-858c-253a06511c1b",
"params": {
"message": "{{alertName}} - {{context.group}} is in a state of {{context.alertState}}\n\nReason:\n{{context.reason}}"
}
}
]
}
Documentation says clearly:
Properties of the action objects:
group
(Required, string) Grouping actions is recommended for escalations for different types of alerts. If you don’t need this, set this value to default.
Is this a bug in ELK or I am doing something wrong? I am able to use API for other purposes, like listing rules, deleting rules etc. I am also capable of creating a rule without an action, but this doen`t seem to be too useful...
OKAY, I got an answer from ELK support. Apparently, you can use another endpoint to list all rule types GET /api/alerting/rule_types. Then you need to find your type and lookup property default_action_group_id - it will hold the correct value. Eg. in the above example it was:
"default_action_group_id": "metrics.inventory_threshold.fired"

Kubernetes API server filtering by field - in request time

I'm trying to get all the secrets in the cluster of type helm.sh/release.v1:
$ curl -X GET $APISERVER/api/v1/secrets --header "Authorization: Bearer $TOKEN" --insecure
{
"kind": "SecretList",
"apiVersion": "v1",
"metadata": {
"selfLink": "/api/v1/secrets",
"resourceVersion": "442181"
},
"items": [
{
"metadata": {
...
},
"data": {
...
},
"type": "helm.sh/release.v1"
},
{
"metadata": {
...
},
"data": {
...
},
"type": "kubernetes.io/service-account-token"
},
{
"metadata": {
...
},
"data": {
...
},
"type": "kubernetes.io/service-account-token"
},
...
}
I can use the command above and then filter by myself (jq or whatever) but I wonder if there's an option to filter in the API by adding query parameters or something, for example (didn't work):
curl -X GET $APISERVER/api/v1/secrets?type=<value>
any idea how to filter by specific field? (type) can I also request specific fields in the response (if I don't care about the data for instance)?
I'm going to use HTTP requests from my application (python) that runs
within a pod in the cluster. I am trying to be more efficient and ask
only for what I need (only specific type and not all secrets in the
cluster)
If your application is written in Python, maybe it's a good idea to use Kubernetes Python Client library to get the secrets ?
If you want to get all the secrets in the cluster of type helm.sh/release.v1, you can do it with the following Python code:
from kubernetes import client , config
config.load_kube_config()
v1 = client.CoreV1Api()
list_secrets = v1.list_secret_for_all_namespaces(field_selector='type=helm.sh/release.v1')
If you also want to count them, use:
print(len(list_secrets.items))
to print secret's name use:
print(list_secrets.items[0].metadata.name)
to retrieve it's data:
print(list_secrets.items[0].data)
and so on...
More details, including arguments that can be used with this method, you can find here (just search for list_secret_for_all_namespaces):
# **list_secret_for_all_namespaces**
> V1SecretList list_secret_for_all_namespaces(allow_watch_bookmarks=allow_watch_bookmarks, _continue=_continue, field_selector=field_selector, label_selector=label_selector, limit=limit, pretty=pretty, resource_version=resource_version, timeout_seconds=timeout_seconds, watch=watch)

how can i use RestApi to update deployment in k8s?

I want to use the RestApi to update the deployment.
and I test it with postman, but always got 415 back.
the info is as follows:
type:
PATCH
url: https://k8sClusterUrl:6443/apis/extensions/v1beta1/namespaces/ns/deployments/peer0
header:
Authorization: bearer token
Content-Type:application/json
body:
{
"kind": "Deployment",
"spec":
{
"template":
{
"spec":
{
"containers":[
{
"$setElementOrder/volumeMounts":[{"mountPath":"/host/var/run/"},{"mountPath":"/mnt"}],
"name":"peer0",
"image":"hyperledger/fabric-peer:x86_64-1.1.0"}
]
}
}
}
}
response:
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "the server responded with the status code 415 but did not return more information",
"details": {},
"code": 415
}
I have muti-containers in this pod, and only want to apply for the specific container: peer0.
Any different for the $setElementOrder var?
415 is invalid media type.
In this case, you should be setting the media type as application/json+patch+json (you can see this in the documentation here)
You can try using body and using Content-Type to application/json-patch+json, method PATCH:
[{
"op" : "replace",
"path" : "/spec/template/spec/container/0/$setElementOrder/volumeMounts",
"value" : "<value you want to replace>"
}]

Add pod annotation through Kubernetes REST API

I can add labels to a pod as described here
But no luck to create annotations likewise
$ KUBE_TOKEN=$(</var/run/secrets/kubernetes.io/serviceaccount/token)
$ cat > patch.json <<EOF
]
{
"op": "add", "path": "/metadata/annotations/test", "value": "world"
}
]
EOF
$ curl -sSk -H "Authorization: Bearer $KUBE_TOKEN" --request PATCH --data "$(cat patch.json)" -H "Content-Type:application/json-patch+json" https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/api/v1/namespaces/$POD_NAMESPACE/pods/$POD_NAME
the response is:
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "jsonpatch add operation does not apply: doc is missing path: /metadata/annotations/test",
"code": 500
}
The error is related to non-existing path.
[
{
"op": "add", "path": "/metadata/annotations/", "value": { "test" : "world" }
}
]
Check out https://www.rfc-editor.org/rfc/rfc6902#section-4.1
AFAIR, you cannot add new annotations on existing resources. You can only update existing ones.

How can I set a node to unschedulable status via the Kubernetes api?

I am attempting to emulate the behavior of kubectl patch. I'm sending an HTTP PATCH with a json payload of the following:
{
"apiVersion": "v1",
"kind": "Node",
"metadata": {
"name": "my-node-hostname"
},
"spec": {
"unschedulable": true
}
}
However, no matter how I seem to tweak this JSON, I keep getting a 415 and the following JSON status back:
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "the server responded with the status code 415 but did not return more information",
"details": {},
"code": 415
}
Even with debug on kube-apiserver set to 1000, I get no feedback about why the payload is wrong!
Is there a particular format that one should use in the JSON payload sent via PATCH to enable this to work?
After a helpful member of the Kubernetes Slack channel mentioned I could get the payload from kubectl patch via the --verbose flag, it turns out that Kubernetes expects to get "Content-Type: application/strategic-merge-patch+json" when you are sending the PATCH payload.