kscript 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +169 -0
- data/Rakefile +35 -0
- data/bin/kscript +6 -0
- data/kscript.gemspec +45 -0
- data/lib/kscript/banner.rb +12 -0
- data/lib/kscript/base.rb +50 -0
- data/lib/kscript/cli.rb +184 -0
- data/lib/kscript/logger.rb +94 -0
- data/lib/kscript/plugins/kk_apnic_utils.rb +87 -0
- data/lib/kscript/plugins/kk_cleaner_utils.rb +83 -0
- data/lib/kscript/plugins/kk_es_fingerprint_utils.rb +92 -0
- data/lib/kscript/plugins/kk_ffmpeg_utils.rb +140 -0
- data/lib/kscript/plugins/kk_ip_utils.rb +90 -0
- data/lib/kscript/plugins/kk_jenkins_utils.rb +143 -0
- data/lib/kscript/plugins/kk_kibana_utils.rb +237 -0
- data/lib/kscript/plugins/kk_lvm_utils.rb +200 -0
- data/lib/kscript/plugins/kk_optimize_utils.rb +85 -0
- data/lib/kscript/plugins/kk_portscan_utils.rb +90 -0
- data/lib/kscript/plugins/kk_projscan_utils.rb +90 -0
- data/lib/kscript/plugins/kk_rename_utils.rb +82 -0
- data/lib/kscript/plugins/kk_sh_utils.rb +112 -0
- data/lib/kscript/plugins/kk_syscheck_utils.rb +82 -0
- data/lib/kscript/plugins/kk_top_utils.rb +74 -0
- data/lib/kscript/plugins/kk_usd_utils.rb +71 -0
- data/lib/kscript/plugins/kk_wg_acl_utils.rb +95 -0
- data/lib/kscript/plugins/kk_wg_pass_utils.rb +50 -0
- data/lib/kscript/plugins.rb +32 -0
- data/lib/kscript/utils.rb +64 -0
- data/lib/kscript/version.rb +10 -0
- data/lib/kscript.rb +43 -0
- metadata +130 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2025 Kk
|
4
|
+
#
|
5
|
+
# This software is released under the MIT License.
|
6
|
+
# https://opensource.org/licenses/MIT
|
7
|
+
|
8
|
+
require 'kscript'
|
9
|
+
|
10
|
+
module Kscript
|
11
|
+
class KkApnicUtils < Base
|
12
|
+
attr_reader :country_sn, :cache_file
|
13
|
+
|
14
|
+
# Initialize class instance, set country code and cache file path
|
15
|
+
def initialize(country_sn = 'CN', *_args, **opts)
|
16
|
+
super(**opts.merge(service: 'kk_apnic'))
|
17
|
+
@country_sn = country_sn
|
18
|
+
@cache_file = RUBY_PLATFORM.match?(/(linux|darwin)/) ? '/tmp/apnic.txt' : 'apnic.txt'
|
19
|
+
end
|
20
|
+
|
21
|
+
# Download data from APNIC or read from cache
|
22
|
+
def download_data
|
23
|
+
if File.exist?(cache_file) && File.size?(cache_file)
|
24
|
+
logger.kinfo("Using cached data from #{cache_file}")
|
25
|
+
else
|
26
|
+
url = 'https://ftp.apnic.net/stats/apnic/delegated-apnic-latest'
|
27
|
+
response = HTTP.get(url)
|
28
|
+
|
29
|
+
raise "Failed to download the APNIC data. HTTP Status: #{response.status}" unless response.status.success?
|
30
|
+
|
31
|
+
File.write(cache_file, response.body.to_s)
|
32
|
+
logger.kinfo("Data downloaded and saved to #{cache_file}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Parse data and return IPv4 address ranges (CIDR format) for specified country
|
37
|
+
def parse_ip_ranges
|
38
|
+
download_data # Ensure data is downloaded first
|
39
|
+
|
40
|
+
pattern = /apnic\|#{country_sn}\|ipv4\|(?<ip>\d+\.\d+\.\d+\.\d+)\|(?<hosts>\d+)\|\d+\|allocated/mi
|
41
|
+
ip_ranges = []
|
42
|
+
|
43
|
+
File.readlines(cache_file).each do |line|
|
44
|
+
next unless line.match(pattern)
|
45
|
+
|
46
|
+
val = line.match(pattern)
|
47
|
+
netmask = calculate_netmask(val[:hosts].to_i)
|
48
|
+
ip_ranges << "#{val[:ip]}/#{netmask}"
|
49
|
+
end
|
50
|
+
|
51
|
+
logger.kinfo('IP ranges', ip_ranges: ip_ranges)
|
52
|
+
ip_ranges
|
53
|
+
end
|
54
|
+
|
55
|
+
# Calculate CIDR netmask based on number of hosts
|
56
|
+
def calculate_netmask(hosts)
|
57
|
+
# Calculate minimum CIDR netmask
|
58
|
+
32 - Math.log2(hosts).to_i
|
59
|
+
end
|
60
|
+
|
61
|
+
def run
|
62
|
+
with_error_handling do
|
63
|
+
parse_ip_ranges
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.arguments
|
68
|
+
'[country_code]'
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.usage
|
72
|
+
"kscript apnic CN\nkscript apnic US"
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.group
|
76
|
+
'network'
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.author
|
80
|
+
'kk'
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.description
|
84
|
+
'Get APNIC IPv4 ranges for a country.'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2025 Kk
|
4
|
+
#
|
5
|
+
# This software is released under the MIT License.
|
6
|
+
# https://opensource.org/licenses/MIT
|
7
|
+
|
8
|
+
require 'kscript'
|
9
|
+
|
10
|
+
module Kscript
|
11
|
+
class KkCleanerUtils < Base
|
12
|
+
DEFAULT_RETAIN_VERSIONS = 10
|
13
|
+
|
14
|
+
attr_reader :source_path, :retain_count
|
15
|
+
|
16
|
+
# Initialize the cleaner with path and retention settings
|
17
|
+
# @param source_path [String] path to source code directory
|
18
|
+
# @param retain_count [Integer] number of versions to keep
|
19
|
+
def initialize(source_path = '/data/sources/*/**', retain_count = DEFAULT_RETAIN_VERSIONS, *_args, **opts)
|
20
|
+
super(**opts.merge(service: 'kk_source_cleaner'))
|
21
|
+
@source_path = source_path
|
22
|
+
@retain_count = retain_count
|
23
|
+
end
|
24
|
+
|
25
|
+
def run
|
26
|
+
with_error_handling do
|
27
|
+
clean
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Clean old versions while keeping the specified number of recent versions
|
32
|
+
def clean
|
33
|
+
Dir.glob(@source_path).each do |app_path|
|
34
|
+
process_application(app_path)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.arguments
|
39
|
+
'[src_path]'
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.usage
|
43
|
+
"kscript source_cleaner ~/projects/src\nkscript source_cleaner . --exclude=vendor"
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.group
|
47
|
+
'project'
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.author
|
51
|
+
'kk'
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.description
|
55
|
+
'Clean old source code versions, keep N latest.'
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
# Process a single application directory
|
61
|
+
# @param app_path [String] path to application directory
|
62
|
+
def process_application(app_path)
|
63
|
+
versions = Dir.glob("#{app_path}/*")
|
64
|
+
version_count = versions.length
|
65
|
+
return if version_count <= @retain_count
|
66
|
+
|
67
|
+
logger.info("Processing #{app_path}", version_count: version_count, retain: @retain_count)
|
68
|
+
cleanup_old_versions(versions, version_count)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Remove old versions of an application
|
72
|
+
# @param versions [Array<String>] list of version directories
|
73
|
+
# @param total_count [Integer] total number of versions
|
74
|
+
def cleanup_old_versions(versions, total_count)
|
75
|
+
sorted_versions = versions.sort_by { |dir| File.mtime(dir) }
|
76
|
+
versions_to_delete = total_count - @retain_count
|
77
|
+
sorted_versions[0, versions_to_delete].each do |dir|
|
78
|
+
logger.info("Removing #{dir}", mtime: File.mtime(dir))
|
79
|
+
FileUtils.rm_rf(dir)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2025 Kk
|
4
|
+
#
|
5
|
+
# This software is released under the MIT License.
|
6
|
+
# https://opensource.org/licenses/MIT
|
7
|
+
|
8
|
+
require 'kscript'
|
9
|
+
|
10
|
+
module Kscript
|
11
|
+
class KkEsFingerprintUtils < Base
|
12
|
+
DEFAULT_CERT_PATH = 'elasticsearch.crt'
|
13
|
+
|
14
|
+
attr_reader :cert_path
|
15
|
+
|
16
|
+
# Initialize with certificate path
|
17
|
+
# @param cert_path [String] path to the certificate file
|
18
|
+
def initialize(cert_path = DEFAULT_CERT_PATH)
|
19
|
+
@cert_path = cert_path
|
20
|
+
end
|
21
|
+
|
22
|
+
def run
|
23
|
+
with_error_handling do
|
24
|
+
generate
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.arguments
|
29
|
+
'<cert_file>'
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.usage
|
33
|
+
"kscript es_fingerprint <cert_file>\nkscript es_fingerprint ./ca.crt"
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.group
|
37
|
+
'elastic'
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.author
|
41
|
+
'kk'
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.description
|
45
|
+
'Generate Elasticsearch certificate SHA256 fingerprint.'
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
# Generate and display the certificate fingerprint
|
51
|
+
def generate
|
52
|
+
validate_certificate_file
|
53
|
+
cert = load_certificate
|
54
|
+
fingerprint = calculate_fingerprint(cert)
|
55
|
+
display_fingerprint(fingerprint)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Validate certificate file existence
|
59
|
+
def validate_certificate_file
|
60
|
+
return if File.exist?(cert_path)
|
61
|
+
|
62
|
+
raise "Certificate file not found: #{cert_path}"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Load X509 certificate from file
|
66
|
+
# @return [OpenSSL::X509::Certificate] loaded certificate
|
67
|
+
def load_certificate
|
68
|
+
OpenSSL::X509::Certificate.new(File.read(cert_path))
|
69
|
+
end
|
70
|
+
|
71
|
+
# Calculate SHA256 fingerprint
|
72
|
+
# @param cert [OpenSSL::X509::Certificate] certificate to process
|
73
|
+
# @return [String] formatted fingerprint
|
74
|
+
def calculate_fingerprint(cert)
|
75
|
+
raw_fingerprint = OpenSSL::Digest::SHA256.hexdigest(cert.to_der)
|
76
|
+
format_fingerprint(raw_fingerprint)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Format fingerprint with colons
|
80
|
+
# @param fingerprint [String] raw fingerprint
|
81
|
+
# @return [String] formatted fingerprint
|
82
|
+
def format_fingerprint(fingerprint)
|
83
|
+
fingerprint.scan(/../).join(':').upcase
|
84
|
+
end
|
85
|
+
|
86
|
+
# Display the formatted fingerprint
|
87
|
+
# @param fingerprint [String] formatted fingerprint to display
|
88
|
+
def display_fingerprint(fingerprint)
|
89
|
+
logger.kinfo(fingerprint)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2025 Kk
|
4
|
+
#
|
5
|
+
# This software is released under the MIT License.
|
6
|
+
# https://opensource.org/licenses/MIT
|
7
|
+
|
8
|
+
require 'kscript'
|
9
|
+
|
10
|
+
module Kscript
|
11
|
+
class KkFfmpegUtils < Base
|
12
|
+
def run
|
13
|
+
with_error_handling do
|
14
|
+
install
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def install
|
19
|
+
logger.kinfo('FFmpeg installer executed.')
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.arguments
|
23
|
+
'[version]'
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.usage
|
27
|
+
"kscript ffmpeg 6.0\nkscript ffmpeg latest"
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.group
|
31
|
+
'media'
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.author
|
35
|
+
'kk'
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.description
|
39
|
+
'Install and verify FFmpeg on Linux.'
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# Detect OS family and version
|
45
|
+
# @return [Hash] OS family and version information
|
46
|
+
def detect_os_info
|
47
|
+
content = File.read('/etc/os-release')
|
48
|
+
{
|
49
|
+
family: detect_os_family(content),
|
50
|
+
version: detect_os_version(content)
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
# Detect OS family from os-release content
|
55
|
+
# @param content [String] contents of os-release file
|
56
|
+
# @return [String] OS family name
|
57
|
+
def detect_os_family(content)
|
58
|
+
if content =~ /ID_LIKE=.*rhel|centos|fedora/i || content =~ /ID=.*(rhel|centos|rocky|alma|fedora)/i
|
59
|
+
'redhat'
|
60
|
+
elsif content =~ /ID_LIKE=.*debian/i || content =~ /ID=.*(debian|ubuntu)/i
|
61
|
+
'debian'
|
62
|
+
else
|
63
|
+
'unknown'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Detect OS version from os-release content
|
68
|
+
# @param content [String] contents of os-release file
|
69
|
+
# @return [Integer] major version number
|
70
|
+
def detect_os_version(content)
|
71
|
+
version_str = content[/VERSION_ID="?([\d.]+)"?/, 1] || '0'
|
72
|
+
version_str.split('.').first.to_i
|
73
|
+
end
|
74
|
+
|
75
|
+
# Update system package lists
|
76
|
+
def update_system
|
77
|
+
logger.kinfo('👉 Updating system packages...')
|
78
|
+
case @os_info[:family]
|
79
|
+
when 'redhat'
|
80
|
+
run_command('sudo yum update -y')
|
81
|
+
when 'debian'
|
82
|
+
run_command('sudo apt update -y')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Install prerequisite repositories
|
87
|
+
def install_prerequisites
|
88
|
+
return unless @os_info[:family] == 'redhat'
|
89
|
+
|
90
|
+
install_epel
|
91
|
+
install_rpm_fusion if @os_info[:version].between?(7, 9)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Install EPEL repository
|
95
|
+
def install_epel
|
96
|
+
logger.kinfo('👉 Installing EPEL repository...')
|
97
|
+
run_command('sudo yum install -y epel-release')
|
98
|
+
end
|
99
|
+
|
100
|
+
# Install RPM Fusion repository
|
101
|
+
def install_rpm_fusion
|
102
|
+
logger.kinfo("👉 Installing RPM Fusion repository for EL#{@os_info[:version]}...")
|
103
|
+
run_command("sudo yum install -y https://download1.rpmfusion.org/free/el/rpmfusion-free-release-#{@os_info[:version]}.noarch.rpm")
|
104
|
+
end
|
105
|
+
|
106
|
+
# Install FFmpeg packages
|
107
|
+
def install_ffmpeg
|
108
|
+
logger.kinfo('👉 Installing FFmpeg...')
|
109
|
+
case @os_info[:family]
|
110
|
+
when 'redhat'
|
111
|
+
run_command('sudo yum install -y ffmpeg ffmpeg-devel')
|
112
|
+
when 'debian'
|
113
|
+
run_command('sudo apt install -y ffmpeg')
|
114
|
+
else
|
115
|
+
fail_with_error('Unsupported OS')
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Verify FFmpeg installation
|
120
|
+
def verify_installation
|
121
|
+
logger.kinfo('👉 Verifying FFmpeg installation...')
|
122
|
+
run_command('ffmpeg -version')
|
123
|
+
logger.kinfo('✅ FFmpeg installation completed successfully!')
|
124
|
+
end
|
125
|
+
|
126
|
+
# Execute shell command
|
127
|
+
# @param cmd [String] command to execute
|
128
|
+
def run_command(cmd)
|
129
|
+
logger.kinfo("👉 Running: #{cmd}")
|
130
|
+
system(cmd) || fail_with_error("Command failed: #{cmd}")
|
131
|
+
end
|
132
|
+
|
133
|
+
# Display error and exit
|
134
|
+
# @param msg [String] error message
|
135
|
+
def fail_with_error(msg)
|
136
|
+
logger.kerror("❌ #{msg}")
|
137
|
+
exit 1
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2025 Kk
|
4
|
+
#
|
5
|
+
# This software is released under the MIT License.
|
6
|
+
# https://opensource.org/licenses/MIT
|
7
|
+
|
8
|
+
require 'kscript'
|
9
|
+
|
10
|
+
require 'http'
|
11
|
+
require 'json'
|
12
|
+
|
13
|
+
module Kscript
|
14
|
+
class KkIpUtils < Base
|
15
|
+
IP_API_BASE_URL = 'http://ip-api.com/json'
|
16
|
+
IP_CHECK_URL = 'https://api.ipify.org?format=json'
|
17
|
+
|
18
|
+
attr_reader :ip_address
|
19
|
+
|
20
|
+
def initialize(ip_address = nil, *_args, **opts)
|
21
|
+
super(**opts.merge(service: 'kk_ip_api'))
|
22
|
+
@ip_address = ip_address || fetch_public_ip
|
23
|
+
end
|
24
|
+
|
25
|
+
def run
|
26
|
+
with_error_handling do
|
27
|
+
fetch_location
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def fetch_location
|
32
|
+
validate_ip_address!
|
33
|
+
response = make_api_request
|
34
|
+
handle_response(response)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.arguments
|
38
|
+
'<ip_address>'
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.usage
|
42
|
+
"kscript ip <ip_address>\nkscript ip 8.8.8.8"
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.group
|
46
|
+
'network'
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.author
|
50
|
+
'kk'
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.description
|
54
|
+
'Query IP geolocation and ISP info.'
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def fetch_public_ip
|
60
|
+
response = HTTP.get(IP_CHECK_URL)
|
61
|
+
raise "Failed to detect public IP: #{response.status}" unless response.status.success?
|
62
|
+
|
63
|
+
data = JSON.parse(response.body.to_s)
|
64
|
+
logger.info("Detected public IP: #{data['ip']}")
|
65
|
+
data['ip']
|
66
|
+
end
|
67
|
+
|
68
|
+
def validate_ip_address!
|
69
|
+
return if valid_ip_format?
|
70
|
+
|
71
|
+
raise ArgumentError, 'Invalid IP address format'
|
72
|
+
end
|
73
|
+
|
74
|
+
def valid_ip_format?
|
75
|
+
/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match?(@ip_address)
|
76
|
+
end
|
77
|
+
|
78
|
+
def make_api_request
|
79
|
+
HTTP.get("#{IP_API_BASE_URL}/#{@ip_address}")
|
80
|
+
end
|
81
|
+
|
82
|
+
def handle_response(response)
|
83
|
+
if response.status.success?
|
84
|
+
logger.kinfo('IP location result', data: response.parse(:json))
|
85
|
+
else
|
86
|
+
logger.kerror("API request failed: #{response.status}")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2025 Kk
|
4
|
+
#
|
5
|
+
# This software is released under the MIT License.
|
6
|
+
# https://opensource.org/licenses/MIT
|
7
|
+
|
8
|
+
require 'kscript'
|
9
|
+
require 'http'
|
10
|
+
require 'base64'
|
11
|
+
require 'rexml/document'
|
12
|
+
require 'json'
|
13
|
+
require 'fileutils'
|
14
|
+
require 'kscript/base'
|
15
|
+
|
16
|
+
module Kscript
|
17
|
+
class KkJenkinsUtils < Base
|
18
|
+
def run
|
19
|
+
with_error_handling do
|
20
|
+
logger.kinfo('Jenkins job manager executed.')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(jenkins_url, user, password)
|
25
|
+
@jenkins_url = jenkins_url
|
26
|
+
@user = user
|
27
|
+
@password = password
|
28
|
+
@auth_header = "Basic #{Base64.strict_encode64("#{@user}:#{@password}")}"
|
29
|
+
@output = $stdout
|
30
|
+
@output.sync = true
|
31
|
+
end
|
32
|
+
|
33
|
+
def export_all_jobs
|
34
|
+
FileUtils.mkdir_p('jobs')
|
35
|
+
|
36
|
+
job_names = get_all_job_names
|
37
|
+
job_names.each do |job_name|
|
38
|
+
config_xml = export_job(job_name)
|
39
|
+
if config_xml
|
40
|
+
File.write("jobs/#{job_name}.xml", config_xml)
|
41
|
+
logger.kinfo("Exported job: #{job_name}")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def import_job_from_file(job_name)
|
47
|
+
file_path = "jobs/#{job_name}.xml"
|
48
|
+
if File.exist?(file_path)
|
49
|
+
config_xml = File.read(file_path)
|
50
|
+
import_or_update_job(job_name, config_xml)
|
51
|
+
else
|
52
|
+
logger.kerror("Job file #{file_path} does not exist!")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def import_all_jobs_from_files
|
57
|
+
job_files = Dir.glob('jobs/*.xml')
|
58
|
+
job_files.each do |file_path|
|
59
|
+
job_name = File.basename(file_path, '.xml')
|
60
|
+
logger.kinfo("Importing or updating job: #{job_name}")
|
61
|
+
config_xml = File.read(file_path)
|
62
|
+
import_or_update_job(job_name, config_xml)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_all_job_names
|
67
|
+
url = "#{@jenkins_url}/api/json?tree=jobs[name]"
|
68
|
+
response = HTTP.get(url, headers: { 'Authorization' => @auth_header })
|
69
|
+
if response.status.success?
|
70
|
+
jobs = JSON.parse(response.body.to_s)['jobs']
|
71
|
+
jobs.map { |job| job['name'] }
|
72
|
+
else
|
73
|
+
logger.kerror("Error fetching job list: #{response.status}")
|
74
|
+
[]
|
75
|
+
end
|
76
|
+
rescue StandardError => e
|
77
|
+
logger.kerror("Exception fetching job list: #{e.message}")
|
78
|
+
[]
|
79
|
+
end
|
80
|
+
|
81
|
+
def export_job(job_name)
|
82
|
+
url = "#{@jenkins_url}/job/#{job_name}/config.xml"
|
83
|
+
response = HTTP.get(url, headers: { 'Authorization' => @auth_header })
|
84
|
+
return response.body.to_s if response.status.success?
|
85
|
+
|
86
|
+
logger.kerror("Error exporting job #{job_name}: #{response.status}")
|
87
|
+
nil
|
88
|
+
rescue StandardError => e
|
89
|
+
logger.kerror("Exception exporting job #{job_name}: #{e.message}")
|
90
|
+
nil
|
91
|
+
end
|
92
|
+
|
93
|
+
def import_or_update_job(job_name, config_xml)
|
94
|
+
url = "#{@jenkins_url}/job/#{job_name}/config.xml"
|
95
|
+
logger.kinfo(url)
|
96
|
+
begin
|
97
|
+
logger.kinfo("Creating new job #{job_name}")
|
98
|
+
create_new_job(job_name, config_xml)
|
99
|
+
rescue StandardError
|
100
|
+
logger.kinfo("Updating existing job #{job_name}")
|
101
|
+
HTTP.put(url, body: config_xml, headers: {
|
102
|
+
'Authorization' => @auth_header,
|
103
|
+
'Content-Type' => 'application/xml'
|
104
|
+
})
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.arguments
|
109
|
+
'[subcommand] [options]'
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.usage
|
113
|
+
"kscript jenkins list --host=jenkins.local\nkscript jenkins trigger --job=build"
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.group
|
117
|
+
'ci'
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.author
|
121
|
+
'kk'
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.description
|
125
|
+
'Jenkins job export/import automation.'
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
def create_new_job(job_name, config_xml)
|
131
|
+
url = "#{@jenkins_url}/createItem?name=#{job_name}"
|
132
|
+
response = HTTP.post(url, body: config_xml, headers: {
|
133
|
+
'Authorization' => @auth_header,
|
134
|
+
'Content-Type' => 'application/xml'
|
135
|
+
})
|
136
|
+
if response.status.success?
|
137
|
+
logger.kinfo("Successfully created new job #{job_name}")
|
138
|
+
else
|
139
|
+
logger.kerror("Failed to create job #{job_name}: #{response.status}")
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|