Skip to content

Commit

Permalink
Changes to support Unix Domain Socket (#777)
Browse files Browse the repository at this point in the history
* Splunk API Module

* Squash changes for UDS changes

---------

Co-authored-by: Abdul K <abdulk@splunk.com>
  • Loading branch information
adityapinglesf and abdulk-splunk committed Mar 6, 2024
1 parent 09ce318 commit fa8c308
Show file tree
Hide file tree
Showing 47 changed files with 608 additions and 344 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ test*.xml
**/*.xml
.pytest_cache
version.txt
env
78 changes: 78 additions & 0 deletions default.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
hide_password: false
retry_delay: 3
retry_num: 60
wait_for_splunk_retry_num: 60
shc_sync_retry_num: 60
splunk_home_ownership_enforcement: true

config:
baked: default.yml
defaults_dir: /tmp/defaults
env:
headers: null
var: SPLUNK_DEFAULTS_URL
verify: true
host:
headers: null
url: null
verify: true
max_delay: 60
max_retries: 3
max_timeout: 1200

splunk:
role: splunk_standalone
enable_tcp_mode: false
upgrade: false
build_location: /tmp/splunk.tgz
apps_location: null
license_uri: null
admin_user: admin
app_paths:
default: /opt/splunk/etc/apps
deployment: /opt/splunk/etc/deployment-apps
httpinput: /opt/splunk/etc/apps/splunk_httpinput
idxc: /opt/splunk/etc/master-apps
shc: /opt/splunk/etc/shcluster/apps
enable_service: false
exec: /opt/splunk/bin/splunk
group: splunk
hec:
enable: True
ssl: True
port: 8088
token: 4a8a737d-5452-426c-a6f7-106dca4e813f
home: /opt/splunk
http_enableSSL: 0
http_enableSSL_cert: null
http_enableSSL_privKey: null
http_enableSSL_privKey_password: null
http_port: 8000
idxc:
enable: false
label: idxc_label
replication_factor: 3
replication_port: 9887
search_factor: 3
secret: dmwHG97SpM+GzeGPUELwr7xXowSAVmLW
ignore_license: false
license_download_dest: /tmp/splunk.lic
opt: /opt
password: helloworld
pid: /opt/splunk/var/run/splunk/splunkd.pid
s2s_enable: true
s2s_port: 9997
search_head_captain_url: null
secret: null
splunk_http_enabled: True
shc:
enable: false
label: shc_label
replication_factor: 3
replication_port: 9887
secret: EpcUlTUHMSOhdjRZb3QqPYf9Lf7L991c
smartstore: null
svc_port: 8089
tar_dir: splunk
user: splunk
wildcard_license: false
5 changes: 4 additions & 1 deletion inventory/environ.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ def getDefaultVars():
environment variables to return a consolidated inventory object
"""
defaultVars = loadDefaults()
defaultVars["splunk"]["role"] = os.environ.get('SPLUNK_ROLE', defaultVars["splunk"].get("role") or "splunk_standalone")
overrideEnvironmentVars(defaultVars)
getAnsibleContext(defaultVars)
getASan(defaultVars)
Expand All @@ -124,7 +125,6 @@ def getDefaultVars():
getSplunkdSSL(defaultVars)
getDistributedTopology(defaultVars)
getLicenses(defaultVars)
defaultVars["splunk"]["role"] = os.environ.get('SPLUNK_ROLE', defaultVars["splunk"].get("role") or "splunk_standalone")
# Determine DMC settings
defaultVars["dmc_forwarder_monitoring"] = os.environ.get('DMC_FORWARDER_MONITORING', False)
defaultVars["dmc_asset_interval"] = os.environ.get('DMC_ASSET_INTERVAL', '3,18,33,48 * * * *')
Expand Down Expand Up @@ -574,6 +574,7 @@ def overrideEnvironmentVars(vars_scope):
vars_scope["cert_prefix"] = os.environ.get("SPLUNK_CERT_PREFIX", vars_scope.get("cert_prefix", "https"))
vars_scope["splunk"]["root_endpoint"] = os.environ.get('SPLUNK_ROOT_ENDPOINT', vars_scope["splunk"]["root_endpoint"])
vars_scope["splunk"]["svc_port"] = os.environ.get('SPLUNK_SVC_PORT', vars_scope["splunk"]["svc_port"])
vars_scope["splunk"]["splunk_http_enabled"] = os.environ.get('ENABLE_TCP_MODE', vars_scope["splunk"]["enable_tcp_mode"])
vars_scope["splunk"]["s2s"]["port"] = int(os.environ.get('SPLUNK_S2S_PORT', vars_scope["splunk"]["s2s"]["port"]))
vars_scope["splunk"]["enable_service"] = os.environ.get('SPLUNK_ENABLE_SERVICE', vars_scope["splunk"]["enable_service"])
vars_scope["splunk"]["service_name"] = os.environ.get('SPLUNK_SERVICE_NAME', vars_scope["splunk"]["service_name"])
Expand All @@ -582,6 +583,8 @@ def overrideEnvironmentVars(vars_scope):
vars_scope["splunk"]["kvstore"]["port"] = os.environ.get('SPLUNK_KVSTORE_PORT', vars_scope["splunk"]["kvstore"]["port"])
vars_scope["splunk"]["connection_timeout"] = int(os.environ.get('SPLUNK_CONNECTION_TIMEOUT', vars_scope["splunk"]["connection_timeout"]))

if vars_scope["splunk"]["splunk_http_enabled"] == "false" and "forwarder" not in vars_scope["splunk"]["role"].lower():
vars_scope["splunk"]["splunk_http_enabled"] = "true"
# Set set_search_peers to False to disable peering to indexers when creating multisite topology
if os.environ.get("SPLUNK_SET_SEARCH_PEERS", "").lower() == "false":
vars_scope["splunk"]["set_search_peers"] = False
Expand Down
2 changes: 2 additions & 0 deletions inventory/splunk_defaults_linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ config:
verify: True

splunk:
enable_tcp_mode: False
build_location:
allow_upgrade: True
tar_dir: "splunk"
Expand All @@ -31,6 +32,7 @@ splunk:
user: "splunk"
group: "splunk"
exec: !!python/object/apply:os.path.join [*home, "bin", "splunk"]
uds_socket_path_url: "%2Fopt%2Fsplunkforwarder%2Fvar%2Frun%2Fsplunk%2Fcli.socket"
pid: !!python/object/apply:os.path.join [*home, "var", "run", "splunk", "splunkd.pid"]
admin_user: "admin"
root_endpoint:
Expand Down
1 change: 1 addition & 0 deletions inventory/splunk_defaults_windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ config:
verify: True

splunk:
enable_tcp_mode: False
build_location:
allow_upgrade: True
tar_dir: "splunk"
Expand Down
1 change: 1 addition & 0 deletions inventory/splunkforwarder_defaults_linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ config:

splunk:
build_location:
enable_tcp_mode: False
allow_upgrade: True
tar_dir: "splunkforwarder"
opt: &opt "/opt"
Expand Down
1 change: 1 addition & 0 deletions inventory/splunkforwarder_defaults_windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ config:

splunk:
build_location:
enable_tcp_mode: False
allow_upgrade: True
tar_dir: "splunkforwarder"
opt: &opt "/opt"
Expand Down
116 changes: 116 additions & 0 deletions library/splunk_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#!/usr/bin/python

from ansible.module_utils.basic import AnsibleModule
import os
import requests
import requests_unixsocket
import json

UDS_SOCKET_PATH = "/opt/splunkforwarder/var/run/splunk/cli.socket"
UDS_SOCKET_PATH_URL = "%2Fopt%2Fsplunkforwarder%2Fvar%2Frun%2Fsplunk%2Fcli.socket"

def supports_uds():
return os.path.exists(UDS_SOCKET_PATH)

def api_call_tcp(cert_prefix_mode, method, endpoint, username, password, svc_port, payload=None, headers=None, verify=False, status_code=None, timeout=None):
if not cert_prefix_mode or cert_prefix_mode not in ['http', 'https']:
cert_prefix_mode = 'https'
if not svc_port:
svc_port = 8089
url = "{}://127.0.0.1:{}{}".format(cert_prefix_mode, svc_port, endpoint)
if headers is None:
headers = {}
headers['Content-Type'] = 'application/json'
auth = (username, password)

session = requests.Session()
# Disable SSL verification for the session
session.verify = False

response = None
excep_str = "No Exception"
try:
response = session.request(method, url, headers=headers, auth=auth, data=json.dumps(payload), verify=verify, timeout=timeout)
if status_code is not None and response.status_code not in status_code:
raise ValueError("API call for {} and data as {} failed with status code {}: {}".format(url, payload, response.status_code, response.text))
except Exception as e:
excep_str = "{}".format(e)
cwd = os.getcwd()
return response, excep_str

def api_call_uds(method, endpoint, username, password, svc_port, payload=None, headers=None, verify=False, status_code=None, timeout=None):
url = "http+unix://{}{}".format(UDS_SOCKET_PATH_URL,endpoint)
if headers is None:
headers = {}
headers['Content-Type'] = 'application/json'
auth = (username, password)

session = requests_unixsocket.Session()
# Disable SSL verification for the session
session.verify = False

excep_str = "No Exception"
response = None
try:
response = session.request(method, url, headers=headers, auth=auth, data=json.dumps(payload), verify=verify, timeout=timeout)
if status_code is not None and response.status_code not in status_code:
raise ValueError("API call for {} and data as {} failed with status code {}: {}".format(url, payload, response.status_code, response.text))
except Exception as e:
excep_str = "{}".format(e)
return response, excep_str

def main():
module_args = dict(
method=dict(type='str', required=True),
url=dict(type='str', required=True),
username=dict(type='str', required=True),
password=dict(type='str', required=True, no_log=True),
cert_prefix_mode=dict(type='str', required=False),
body=dict(type='dict', required=False),
headers=dict(type='dict', required=False),
verify=dict(type='bool', required=False),
status_code=dict(type='list', required=False),
timeout=dict(type='int', required=False),
svc_port=dict(type='int', required=False)
)

module = AnsibleModule(
argument_spec=module_args,
supports_check_mode=True
)

if module.check_mode:
module.exit_json(changed=False)

method = module.params['method']
endpoint = module.params['url']
username = module.params['username']
password = module.params['password']
cert_prefix_mode = module.params.get('cert_prefix_mode', 'http')
payload = module.params.get('body', None)
headers = module.params.get('headers', None)
verify = module.params.get('verify', False)
status_code = module.params.get('status_code', None)
timeout = module.params.get('timeout', None)
svc_port = module.params.get('svc_port', 8089)

s = "{}{}{}{}{}{}{}{}{}".format(method, endpoint, username, password, svc_port, payload, headers, verify, status_code, timeout)
if supports_uds():
response, excep_str = api_call_uds(method, endpoint, username, password, svc_port, payload, headers, verify, status_code, timeout)
else:
response, excep_str = api_call_tcp(cert_prefix_mode, method, endpoint, username, password, svc_port, payload, headers, verify, status_code, timeout)

if response is not None and ((status_code and response.status_code in status_code) or (status_code is None and response.status_code >= 200 and response.status_code < 300)):
try:
content = response.json()
except:
content = response.text
module.exit_json(changed=True, status = response.status_code ,json=content,excep_str=excep_str)
else:
if response is None:
module.fail_json(msg="{};;; failed with NO RESPONSE and EXCEP_STR as {}".format(s, excep_str))
else:
module.fail_json(msg="{};;; failed with status code {}: {}".format(s, response.status_code, response.text))

if __name__ == '__main__':
main()
11 changes: 1 addition & 10 deletions roles/splunk_cluster_master/tasks/generate_ess_bundle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,7 @@
mode: 0777

- name: Get ESS version
uri:
url: "{{ cert_prefix }}://127.0.0.1:{{ splunk.svc_port }}/services/apps/local/SplunkEnterpriseSecuritySuite?output_mode=json"
method: GET
user: "{{ splunk.admin_user }}"
password: "{{ splunk.password }}"
force_basic_auth: yes
validate_certs: false
status_code: 200
timeout: 10
use_proxy: no
command: "/opt/splunk/bin/splunk display app -auth {{ splunk.admin_user }}:{{ splunk.password }} SplunkEnterpriseSecuritySuite"
register: ess_info
no_log: "{{ hide_password }}"

Expand Down
1 change: 1 addition & 0 deletions roles/splunk_cluster_master/tasks/setup_multisite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
vars:
splunk_instance_address: "{{ splunk.multisite_master }}"

# UPDATE
- name: Convert Extrenal Cluster Master Name into Internal URI
set_fact:
multisite_master_uri: "{{ cert_prefix }}://{{ splunk.multisite_master }}:{{ splunk.svc_port }}"
Expand Down
1 change: 1 addition & 0 deletions roles/splunk_common/handlers/restart_splunk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@
- name: "Wait for splunkd management port"
wait_for:
port: "{{ splunk.svc_port }}"
when: splunk.splunk_http_enabled|bool == true
21 changes: 11 additions & 10 deletions roles/splunk_common/tasks/check_for_required_restarts.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
---
- name: Check for required restarts
uri:
url: "{{ cert_prefix }}://127.0.0.1:{{ splunk.svc_port }}/services/messages/restart_required?output_mode=json"
splunk_api:
method: GET
user: "{{ splunk.admin_user }}"
endpoint: /services/messages/restart_required?output_mode=json
username: "{{ splunk.admin_user }}"
password: "{{ splunk.password }}"
force_basic_auth: yes
svc_port: "{{ splunk.svc_port }}"
cert_prefix: "{{ cert_prefix }}"
validate_certs: false
status_code: 200,404
status_code: "200,404"
timeout: 10
use_proxy: no
notify:
- Restart the splunkd service
register: restart_required
changed_when: restart_required.status == 200
until: restart_required is succeeded
changed_when: restart_required.content
until: restart_required.content
retries: 5
delay: "{{ retry_delay }}"
no_log: "{{ hide_password }}"
notify:
- Restart the splunkd service
ignore_errors: yes
8 changes: 8 additions & 0 deletions roles/splunk_common/tasks/configure_uds.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
- name: Deploy UDS configuration
copy:
src: ../../../roles/splunk_universal_forwader/uds_inputs.conf
dest: "{{ splunk.home }}/etc/apps/your_app/local/uds_inputs.conf"
owner: "{{ splunk.user }}"
group: "{{ splunk.group }}"
mode: 0644
notify: restart splunk
26 changes: 12 additions & 14 deletions roles/splunk_common/tasks/disable_popups.yml
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
---
- name: GET OptInVersion
uri:
url: "{{ cert_prefix }}://127.0.0.1:{{ splunk.svc_port }}/servicesNS/nobody/splunk_instrumentation/admin/telemetry/general?output_mode=json"
splunk_api:
method: GET
user: "{{ splunk.admin_user }}"
endpoint: "/servicesNS/nobody/splunk_instrumentation/admin/telemetry/general?output_mode=json"
username: "{{ splunk.admin_user }}"
password: "{{ splunk.password }}"
force_basic_auth: yes
svc_port: "{{ splunk.svc_port }}"
validate_certs: false
status_code: 200
status_code: [200]
timeout: 10
return_content: yes
use_proxy: no
register: telemetry
no_log: "{{ hide_password }}"

- name: Disable Popups
uri:
url: "{{ cert_prefix }}://127.0.0.1:{{ splunk.svc_port }}/{{ item.key }}"
splunk_api:
method: POST
user: "{{ splunk.admin_user }}"
endpoint: "{{ item.key }}"
username: "{{ splunk.admin_user }}"
password: "{{ splunk.password }}"
force_basic_auth: yes
svc_port: "{{ splunk.svc_port }}"
body: "{{ item.value }}"
validate_certs: false
status_code: 200,201,409
use_proxy: no
with_items:
- { key: "servicesNS/admin/user-prefs/data/user-prefs/general", value: "hideInstrumentationOptInModal=1&notification_python_3_impact=false&showWhatsNew=0" }
- { key: "servicesNS/nobody/splunk_instrumentation/admin/telemetry/general", value: "showOptInModal=0&optInVersionAcknowledged={{ telemetry['json']['entry'][0]['content']['optInVersion'] }}" }
- { key: "servicesNS/admin/search/data/ui/ui-tour/search-tour", value: "tourPage=search&viewed=1" }
- { key: "/servicesNS/admin/user-prefs/data/user-prefs/general", value: "hideInstrumentationOptInModal=1&notification_python_3_impact=false&showWhatsNew=0" }
- { key: "/servicesNS/nobody/splunk_instrumentation/admin/telemetry/general", value: "showOptInModal=0&optInVersionAcknowledged={{ telemetry['json']['entry'][0]['content']['optInVersion'] }}" }
- { key: "/servicesNS/admin/search/data/ui/ui-tour/search-tour", value: "tourPage=search&viewed=1" }
Loading

0 comments on commit fa8c308

Please sign in to comment.