ePortal API
You may need to create a separate ePortal account for API usage with:
kc.eportal user -a api-user -p <password>
It can be useful for SSO/LDAP setups to be able to pass HTTP API credentials via basic auth.
In general ePortal API is configuration management friendly and idempotent. You don't need to make additional request to check existing state. For example entity deletion doesn't raise an error in case there is no such entity. Or entity creation/modification is a single request that just works and simply brings desired final state.
List servers
GET /admin/api/servers
Filters servers on various criteria, iterate through list and get server counts.
Requires basic authorization with read only user permissions.
Query string parameters:
hostname
: String, optional. Return servers with a hostname like value. Value can contain%
placeholder to match any string.ip
: String, optional. Return servers with IP like value. Value can contain%
placeholder to match any string.service_id
: String, optional. Return a single server with the service ID equal to the provided value.feed
: String, optional. Return servers attached to feed. Usemain
for default feed.key
: String, optional. Return servers registered to key.registered_age
: Integer, optional. Return servers registered more thanregistered_age
days ago. Ifregistered_age
is negative then return servers registered less or equal -registered_age
days ago. For example:registered_age=-3
means to return servers registered 3 or less days ago. Hours can be specified by addingh
suffix:registered_age=4h
selects servers registered more than 4 hours ago.checkin_age
: Integer, optional. Return servers sent check-in more thancheckin_age
days ago. For negative values seeregistered_age
.updated_age
: Integer, optional. Return servers loaded patches more thanupdated_age
days ago. For negative values seeregistered_age
.is_updated
: Boolean, optional. Iftrue
then return servers updated to latest available patches. Iffalse
return servers without latest patches.limit
: Integer, optional. Limit result to a specified number of entries. By defaultlimit
is 10.offset
: Integer, optional. Set result to a specified offset.limit
andoffset
can be used to iterate through result.only_count
: Boolean, optional. Return server count only.tag
: String, optional. Adds filter by server tag. E.gtag=env:test
ortag=ubuntu
.
Response:
{
"count": 42,
"limit": 10,
"offset": 0,
"result": [
{
"id": "99c97tz44uKX13b5",
"ip": "10.51.16.72",
"hostname": "localhost.localdomain",
"key": "some-key",
"feed": "main",
"registered": "2021-04-08 16:43:23.907671",
"checkin": "2021-07-12 17:35:56.065077",
"updated": "2021-06-01 16:37:03.000000",
"euname": "3.10.0-1160.25.1.el7", // effective kernel version
"release": "3.10.0-957.5.1.el7.x86_64", // installed kernel version
"kernel_id": "9647204d2708cad906a75944ee56ac68fc5b5704",
"patch_level": 49,
"patch_type": "default",
"tags": null,
"uptime": 6394092,
"version": "#1 SMP Fri Feb 1 14:54:57 UTC 2019",
"virt": "kvm",
"kcare_version": "2.44-2",
"distro": "CentOS Linux",
"distro_version": "7.6.1810",
"machine": "x86_64",
"processor": "x86_64"
},
...
]
}
Register host
POST /admin/api/register
Registers host by provided key and hostname.
Form (urlencoded) parameters:
key
: String, required. ePortal key to use for registration.hostname
: String, optional. Server's hostname to use.
Success response (200):
{
"server_id": "some-server-id"
}
Error response (400):
{
"error": "error code" # invalid-key | key-limit-reached
}
Example:
curl -X POST https://eportal.corp.com/admin/api/register -F key=test
{"server_id":"lw1MO1Du5sF3Cj39"}
Unregister host
POST /admin/api/delete_server
Removes registered servers by IP, hostname or server_id
Requires basic authorization with admin user permissions.
Query string parameters:
hostname
: String, optional. Server's hostname to delete.ip
: String, optional. Server's IP to delete.server_id
: String, optional. Server's id to delete.
Endpoint requires at least one parameter hostname
, ip
or server_id
.
Response:
Response contains number of deleted servers.
{
"result": 1
}
For example:
curl --user admin:admin-password -X POST https://eportal.corp.com/admin/api/delete_server?ip=192.168.1.1
Below are examples of using /admin/api/delete_server
endpoint with various CM products. Take note, you need a host IP, a hostname or a server_id to delete it via API. It can be more convenient to use on of:
- if you have an access to a host (it is alive) it's a way more simpler to call
kcarectl --unregister
to delete the host. - if host is already destroyed you can consider using bulk inactive server cleanup.
Create/modify feed
POST /admin/api/feeds/
If feed already exists request modifies it.
Requires write permissions and accepts basic authorization.
Query string/Form/JSON parameters:
name
: String, required. Name of created or modified feed.auto
: Boolean, optional. Sets auto-update property. Default is false.deploy_after
: Integer, optional. Sets delayed period in hours. Default is 0 (not delayed).channel
: String, optional. Sets patchset channel to use. Default isdefault
. Available channels:default
: stable patches.test
: testing patches.
Response:
{
"result": {
"name": "test-feed",
"auto": true,
"deploy_after": 0
}
}
Example:
curl -X POST -u admin -d name=test-feed -d auto=true https://eportal.corp.com/admin/api/feeds/
List feeds
GET /admin/api/feeds/
Returns list of existing feeds. Take note: main
feed is alway present and couldn't be modified.
Requires read permissions and accepts basic authorization.
Response:
{
"result": [
{
"auto": false,
"deploy_after": 0,
"name": "feed-name"
},
...
]
}
Example:
curl -u admin https://eportal.corp.com/admin/api/feeds/
Delete feed
DELETE /admin/api/feeds/:feed-name
Requires write permissions and accepts basic authorization.
Response:
{
"result": 1 // number of deleted records, 0 if there is no such feed.
}
Example:
curl -X DELETE -u admin https://eportal.corp.com/admin/api/feeds/test-feed
Create/modify registration key
POST /admin/api/keys/
If key already exists request modifies it.
Requires write permissions and accepts basic authorization.
Query string/Form/JSON parameters:
key
: String, optional. Name of created or modified key. If it's empty random key is generated.feed
: String, optional. Name of attached feed.main
by default.note
: String, optional. Description of the key.server_limit
: Integer, optional. Advisory limit of a maximum number of hosts one can register on the key.
Response:
{
"result": {
"key": "key",
"feed": "feed-name",
"note": "some-note",
"server_limit": 0
}
}
Example:
curl -X POST -u admin -d key=test-key -d feed=test-feed https://eportal.corp.com/admin/api/keys/
List keys
GET /admin/api/keys/
Returns list of existing keys.
Requires read permissions and accepts basic authorization.
Response:
{
"result": [
{
"key": "test",
"feed": "main",
"note": null,
"server_limit": 0
},
...
]
}
Example:
curl -u admin https://eportal.corp.com/admin/api/keys/
Delete key
DELETE /admin/api/keys/:key
Requires write permissions and accepts basic authorization.
Response:
{
"result": 1 // number of deleted records, 0 if there is no such key.
}
Example:
curl -X DELETE -u admin https://eportal.corp.com/admin/api/keys/test-key
List patchsets
GET /admin/api/patchsets/
Endpoint lists available patchsets for a feed and product. Sort order is from oldest to newest patchsets.
Requires read permissions and accepts basic authorization.
Query string parameters:
feed
: String, optional. Name of the feed to list patchsets for.main
by default.product
: String, optional. Possible values are:kernel
,user
,qemu
,db
. Selects a patchstore for a specified product.kernel
by default.
Response:
{
"result": [
{
"patchset": "patchset-name",
"status": "enabled" // possible values are: enabled, disabled, not-downloaded, undeployed
},
...
]
}
Example:
curl -u admin 'https://eportal.corp.com/admin/api/patchsets/?feed=main&product=kernel'
Manage patchsets
POST /admin/api/patchsets/manage
Allows to perform deploy actions on the patchsets.
Requires write permissions and accepts basic authorization.
Query string parameters:
patchset
: String, required. Name of the patchset to operate on.feed
: String, required. Name of the feed to operate on. Can be specified multiple times.action
: String, requred. Operartion to perform:enable
: enable specified patchset.disable
: disable specified patchset.enable-upto
: enable all patchset up to (older than) specified.undeploy-downto
: undeploy all patchsets down to (newer than) specified.
product
: String, optional. Possible values are:kernel
,user
,qemu
,db
. Selects a patchstore for a specified product.kernel
by default.
Response:
{
"result": "ok"
}
Example:
Enable libcare patchset U20200506_01
in main
and test-feed
feeds:
curl -X POST -u admin 'https://eportal.corp.com/admin/api/patchsets/manage?patchset=U20200506_01&feed=main&feed=test-feed&product=user&action=enable'
List users
GET /admin/api/users/
Returns list of existing users.
Requires read permissions and accepts basic authorization.
Response:
{
"result": [
{
"id": 1,
"username": "test",
"description": "test user",
"readonly": false
},
...
]
}
Example:
curl -u admin https://eportal.corp.com/admin/api/users/
Set tags
POST /admin/api/set_tags
Allows assign tags to server
Requires write permissions and accepts basic authorization.
Query string parameters:
server_id
: String, required. ID of the server to attach tags.tags
: String, optional. String with semicolon divided tags. If the parameter is not presented, all tags will be removed
These parameters can also be provided in the JSON body with the header Content-Type: application/json
Response:
{
"result": "ok"
}
Example:
Assign tags test
and stage
to server with id test-centos
curl -X POST -u admin 'https://eportal.corp.com/admin/api/set_tags?server_id=test-centos&tags=test;stage'
Configuration manager integration
Ansible playbook
Integrating ePortal API access with Ansible is now possible. Rather than calling the kernelcare agent to perform tasks, it is possible to replace it with direct calls to ePortal to achieve the same results.
Unregister KernelCare agent through API playbook:
- hosts: kernelcare
vars:
eportal_srv: http://eportal.address.here[:port if needed]
tasks:
- name: unregister kernelcare agent through API
uri:
url: "{{ eportal_srv }}/admin/api/delete_server?ip={{ ansible_default_ipv4.address|default(ansible_all_ipv4_addresses[0]) }}"
method: POST
user: your-api-user
password: your-api-user-password
force_basic_auth: yes
Example:
- hosts: kernelcare
vars:
eportal_srv: http://192.168.246.110
tasks:
- name: unregister kernelcare agent through API
uri:
url: "{{ eportal_srv }}/admin/api/delete_server?ip={{ ansible_default_ipv4.address|default(ansible_all_ipv4_addresses[0]) }}"
method: POST
user: api-user
password: dummy
force_basic_auth: yes
Ad hoc run with:
ansible-playbook -u ansible ./kernelcare.yml
This can be called during machine tear down to properly remove the server from ePortal.
Chef recipe
Having tighter integration with automation tools like Chef has always been a goal for KernelCare and related tools like ePortal. The following recipe demonstrates how to use the delete_server api to correctly remove a server from ePortal during tear down, and can be integrated with your other recipes to avoid manual operations.
Unregister KernelCare agent through API recipe:
eportal_url = "EPORTAL URL"
eportal_user = "EPORTAL API USER NAME"
eportal_password = "EPORTAL API USER PASSWORD"
# the ip to unregister can be pulled automatically from the system where the recipe is applied, or specified manually (by replacing the following line with a simple assignment)
ip_to_unregister = "#{node['network']['interfaces'][node['network']['default_interface']]['addresses'].select{|k,v| v['family'] == "inet"}.keys.first}"
http_request "kernelcare-unregister-api" do
url "#{eportal_url}/admin/api/delete_server?ip=#{ip_to_unregister}"
action :post
headers({'AUTHORIZATION' => "Basic #{
Base64.encode64("#{eportal_user}:#{eportal_password}")}",
})
end
Example (kernelcare-unregister-api.rb):
eportal_url = "http://192.168.246.110"
eportal_user = "api-user"
eportal_password = "dummy"
ip_to_unregister = "#{node['network']['interfaces'][node['network']['default_interface']]['addresses'].select{|k,v| v['family'] == "inet"}.keys.first}"
http_request "kernelcare-unregister-api" do
url "#{eportal_url}/admin/api/delete_server?ip=#{ip_to_unregister}"
action :post
headers({'AUTHORIZATION' => "Basic #{
Base64.encode64("#{eportal_user}:#{eportal_password}")}",
})
end
Ad hoc run with:
chef-apply kernelcare-unregister-api.rb
Output:
Recipe: (chef-apply cookbook)::(chef-apply recipe)
* http_request[kernelcare-unregister-api] action post
- http_request[kernelcare-unregister-api] POST to http://192.168.246.110/admin/api/delete_server?ip=192.168.246.40
This can be called during machine tear down to properly remove the server from ePortal.
Puppet task
Puppet provides the framework to run tasks on target systems. The following is a bash script that can run as such a task and demonstrates how to use the delete_server api to correctly remove a server from ePortal during tear down. It can be integrated with your other removal scripts or tasks to avoid manual operations.
Unregister KernelCare agent through API call:
#!/bin/bash
EPORTAL_API_USERNAME=<your ePortal api user name>
EPORTAL_API_PASSWORD=<your ePortal api user password>
EPORTAL_URL='your ePortal URL'
#this is taken from the primary ip in the system. If awk is available, it is used, but a fallback using other common tools is also provided
if hash awk 2>/dev/null; then
IP_TO_UNREGISTER=`ip route get 1 | awk '{print $(NF-2);exit}'` # using awk
else
IP_TO_UNREGISTER=`ip route get 1 | cut -f 3 -d" "| head -1` # simpler alternative for when awk is not available
fi
curl -kL -u "${EPORTAL_API_PASSWORD}"':'"${EPORTAL_API_PASSWORD}" -X POST "${EPORTAL_URL}"'/admin/api/delete_server?ip='"${IP_TO_UNREGISTER}"
Example (unregister_server.sh):
#!/bin/bash
EPORTAL_API_USERNAME=admin
EPORTAL_API_PASSWORD=admin
EPORTAL_URL='http://192.168.246.110'
#this is taken from the primary ip in the system. If you want to pick a different one, adjust the next line.
if hash awk 2>/dev/null; then
IP_TO_UNREGISTER=`ip route get 1 | awk '{print $(NF-2);exit}'` # using awk
else
IP_TO_UNREGISTER=`ip route get 1 | cut -f 3 -d" "| head -1` # simpler alternative for when awk is not available
fi
curl -kL -u "${EPORTAL_API_PASSWORD}"':'"${EPORTAL_API_PASSWORD}" -X POST "${EPORTAL_URL}"'/admin/api/delete_server?ip='"${IP_TO_UNREGISTER}"
Puppet Plan
If you prefer to have a plan rather than a task, then you can create one from this script with the following steps:
- Create a new directory called
eportal_puppet
- Inside this directory, create a bolt project:
bolt project init
- Create a scripts directory inside it
- Place the script above inside of it (call it
unregister_server.sh
) - Create the bolt plan using:
bolt plan new eportal_puppet::unregister_server --script eportal_puppet/scripts/unregister_server.sh
- Now your plan is ready and can be called directly with:
bolt plan run eportal_puppet:unregister_server -t <TARGETS>
Ad hoc run example with:
bolt plan run eportal_puppet::unregister_server -t 192.168.246.110
This can be called during machine tear down to properly remove the server from ePortal.