dtk-node-agent 0.7.7 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +5 -13
  2. data/README.md +21 -4
  3. data/bin/dtk-node-agent +17 -0
  4. data/lib/config/install.config +2 -2
  5. data/lib/dtk-node-agent/installer.rb +30 -25
  6. data/lib/dtk-node-agent/version.rb +18 -1
  7. metadata +23 -110
  8. data/mcollective_additions/debian.mcollective.init +0 -92
  9. data/mcollective_additions/plugins/README.md +0 -1
  10. data/mcollective_additions/plugins/v1.2/agent/discovery.rb +0 -39
  11. data/mcollective_additions/plugins/v1.2/agent/get_log_fragment.ddl +0 -15
  12. data/mcollective_additions/plugins/v1.2/agent/get_log_fragment.rb +0 -79
  13. data/mcollective_additions/plugins/v1.2/agent/git_access.ddl +0 -9
  14. data/mcollective_additions/plugins/v1.2/agent/git_access.rb +0 -79
  15. data/mcollective_additions/plugins/v1.2/agent/netstat.ddl +0 -9
  16. data/mcollective_additions/plugins/v1.2/agent/netstat.rb +0 -34
  17. data/mcollective_additions/plugins/v1.2/agent/puppet_apply.ddl +0 -9
  18. data/mcollective_additions/plugins/v1.2/agent/puppet_apply.rb +0 -630
  19. data/mcollective_additions/plugins/v1.2/agent/rpcutil.ddl +0 -204
  20. data/mcollective_additions/plugins/v1.2/agent/rpcutil.rb +0 -101
  21. data/mcollective_additions/plugins/v1.2/facts/pbuilder_facts.rb +0 -35
  22. data/mcollective_additions/plugins/v2.2/agent/action_agent.ddl +0 -9
  23. data/mcollective_additions/plugins/v2.2/agent/action_agent.rb +0 -47
  24. data/mcollective_additions/plugins/v2.2/agent/dev_manager.ddl +0 -9
  25. data/mcollective_additions/plugins/v2.2/agent/dev_manager.rb +0 -111
  26. data/mcollective_additions/plugins/v2.2/agent/discovery.rb +0 -39
  27. data/mcollective_additions/plugins/v2.2/agent/dtk_node_agent_git_client.rb +0 -94
  28. data/mcollective_additions/plugins/v2.2/agent/execute_tests.ddl +0 -9
  29. data/mcollective_additions/plugins/v2.2/agent/execute_tests.rb +0 -111
  30. data/mcollective_additions/plugins/v2.2/agent/execute_tests_v2.ddl +0 -9
  31. data/mcollective_additions/plugins/v2.2/agent/execute_tests_v2.rb +0 -131
  32. data/mcollective_additions/plugins/v2.2/agent/get_log_fragment.ddl +0 -15
  33. data/mcollective_additions/plugins/v2.2/agent/get_log_fragment.rb +0 -79
  34. data/mcollective_additions/plugins/v2.2/agent/git_access.ddl +0 -9
  35. data/mcollective_additions/plugins/v2.2/agent/git_access.rb +0 -61
  36. data/mcollective_additions/plugins/v2.2/agent/netstat.ddl +0 -9
  37. data/mcollective_additions/plugins/v2.2/agent/netstat.rb +0 -34
  38. data/mcollective_additions/plugins/v2.2/agent/ps.ddl +0 -9
  39. data/mcollective_additions/plugins/v2.2/agent/ps.rb +0 -37
  40. data/mcollective_additions/plugins/v2.2/agent/puppet_apply.ddl +0 -9
  41. data/mcollective_additions/plugins/v2.2/agent/puppet_apply.rb +0 -818
  42. data/mcollective_additions/plugins/v2.2/agent/puppet_cancel.ddl +0 -10
  43. data/mcollective_additions/plugins/v2.2/agent/puppet_cancel.rb +0 -78
  44. data/mcollective_additions/plugins/v2.2/agent/rpcutil.ddl +0 -204
  45. data/mcollective_additions/plugins/v2.2/agent/rpcutil.rb +0 -101
  46. data/mcollective_additions/plugins/v2.2/agent/ssh_agent.ddl +0 -13
  47. data/mcollective_additions/plugins/v2.2/agent/ssh_agent.rb +0 -97
  48. data/mcollective_additions/plugins/v2.2/agent/sync_agent_code.ddl +0 -10
  49. data/mcollective_additions/plugins/v2.2/agent/sync_agent_code.rb +0 -85
  50. data/mcollective_additions/plugins/v2.2/agent/tail.ddl +0 -11
  51. data/mcollective_additions/plugins/v2.2/agent/tail.rb +0 -67
  52. data/mcollective_additions/plugins/v2.2/audit/logfile.rb +0 -26
  53. data/mcollective_additions/plugins/v2.2/connector/r8stomp.rb +0 -238
  54. data/mcollective_additions/plugins/v2.2/connector/stomp.rb +0 -349
  55. data/mcollective_additions/plugins/v2.2/connector/stomp_em.rb +0 -191
  56. data/mcollective_additions/plugins/v2.2/data/agent_data.ddl +0 -22
  57. data/mcollective_additions/plugins/v2.2/data/agent_data.rb +0 -17
  58. data/mcollective_additions/plugins/v2.2/data/collective_data.ddl +0 -20
  59. data/mcollective_additions/plugins/v2.2/data/collective_data.rb +0 -9
  60. data/mcollective_additions/plugins/v2.2/data/fact_data.ddl +0 -28
  61. data/mcollective_additions/plugins/v2.2/data/fact_data.rb +0 -55
  62. data/mcollective_additions/plugins/v2.2/data/fstat_data.ddl +0 -89
  63. data/mcollective_additions/plugins/v2.2/data/fstat_data.rb +0 -56
  64. data/mcollective_additions/plugins/v2.2/discovery/flatfile.ddl +0 -11
  65. data/mcollective_additions/plugins/v2.2/discovery/flatfile.rb +0 -48
  66. data/mcollective_additions/plugins/v2.2/discovery/mc.ddl +0 -11
  67. data/mcollective_additions/plugins/v2.2/discovery/mc.rb +0 -30
  68. data/mcollective_additions/plugins/v2.2/discovery/stdin.ddl +0 -11
  69. data/mcollective_additions/plugins/v2.2/discovery/stdin.rb +0 -66
  70. data/mcollective_additions/plugins/v2.2/facts/pbuilder_facts.rb +0 -37
  71. data/mcollective_additions/plugins/v2.2/facts/yaml_facts.rb +0 -61
  72. data/mcollective_additions/plugins/v2.2/registration/agentlist.rb +0 -10
  73. data/mcollective_additions/plugins/v2.2/security/sshkey.ddl +0 -9
  74. data/mcollective_additions/plugins/v2.2/security/sshkey.rb +0 -362
  75. data/mcollective_additions/plugins/v2.2/util/puppetrunner.rb +0 -36
  76. data/mcollective_additions/plugins/v2.2/validator/array_validator.ddl +0 -7
  77. data/mcollective_additions/plugins/v2.2/validator/array_validator.rb +0 -9
  78. data/mcollective_additions/plugins/v2.2/validator/ipv4address_validator.ddl +0 -7
  79. data/mcollective_additions/plugins/v2.2/validator/ipv4address_validator.rb +0 -16
  80. data/mcollective_additions/plugins/v2.2/validator/ipv6address_validator.ddl +0 -7
  81. data/mcollective_additions/plugins/v2.2/validator/ipv6address_validator.rb +0 -16
  82. data/mcollective_additions/plugins/v2.2/validator/length_validator.ddl +0 -7
  83. data/mcollective_additions/plugins/v2.2/validator/length_validator.rb +0 -11
  84. data/mcollective_additions/plugins/v2.2/validator/regex_validator.ddl +0 -7
  85. data/mcollective_additions/plugins/v2.2/validator/regex_validator.rb +0 -9
  86. data/mcollective_additions/plugins/v2.2/validator/shellsafe_validator.ddl +0 -7
  87. data/mcollective_additions/plugins/v2.2/validator/shellsafe_validator.rb +0 -13
  88. data/mcollective_additions/plugins/v2.2/validator/typecheck_validator.ddl +0 -7
  89. data/mcollective_additions/plugins/v2.2/validator/typecheck_validator.rb +0 -28
  90. data/mcollective_additions/redhat.mcollective.init +0 -139
  91. data/mcollective_additions/redhat.mcollective.service +0 -14
  92. data/mcollective_additions/server.cfg +0 -22
  93. data/src/etc/logrotate.d/mcollective +0 -10
  94. data/src/etc/mcollective.default +0 -6
@@ -1,204 +0,0 @@
1
- metadata :name => "rpcutil",
2
- :description => "General helpful actions that expose stats and internals to SimpleRPC clients",
3
- :author => "R.I.Pienaar <rip@devco.net>",
4
- :license => "Apache License, Version 2.0",
5
- :version => "1.0",
6
- :url => "http://marionette-collective.org/",
7
- :timeout => 10
8
-
9
- action "collective_info", :description => "Info about the main and sub collectives" do
10
- display :always
11
-
12
- output :main_collective,
13
- :description => "The main Collective",
14
- :display_as => "Main Collective"
15
-
16
- output :collectives,
17
- :description => "All Collectives",
18
- :display_as => "All Collectives"
19
-
20
- summarize do
21
- aggregate summary(:collectives)
22
- end
23
- end
24
-
25
- action "inventory", :description => "System Inventory" do
26
- display :always
27
-
28
- output :agents,
29
- :description => "List of agent names",
30
- :display_as => "Agents"
31
-
32
- output :facts,
33
- :description => "List of facts and values",
34
- :display_as => "Facts"
35
-
36
- output :classes,
37
- :description => "List of classes on the system",
38
- :display_as => "Classes"
39
-
40
- output :version,
41
- :description => "MCollective Version",
42
- :display_as => "Version"
43
-
44
- output :main_collective,
45
- :description => "The main Collective",
46
- :display_as => "Main Collective"
47
-
48
- output :collectives,
49
- :description => "All Collectives",
50
- :display_as => "All Collectives"
51
-
52
- output :data_plugins,
53
- :description => "List of data plugin names",
54
- :display_as => "Data Plugins"
55
- end
56
-
57
- action "get_fact", :description => "Retrieve a single fact from the fact store" do
58
- display :always
59
-
60
- input :fact,
61
- :prompt => "The name of the fact",
62
- :description => "The fact to retrieve",
63
- :type => :string,
64
- :validation => '^[\w\-\.]+$',
65
- :optional => false,
66
- :maxlength => 40
67
-
68
- output :fact,
69
- :description => "The name of the fact being returned",
70
- :display_as => "Fact"
71
-
72
- output :value,
73
- :description => "The value of the fact",
74
- :display_as => "Value"
75
-
76
- summarize do
77
- aggregate summary(:value)
78
- end
79
- end
80
-
81
- action "daemon_stats", :description => "Get statistics from the running daemon" do
82
- display :always
83
-
84
- output :threads,
85
- :description => "List of threads active in the daemon",
86
- :display_as => "Threads"
87
-
88
- output :agents,
89
- :description => "List of agents loaded",
90
- :display_as => "Agents"
91
-
92
- output :pid,
93
- :description => "Process ID of the daemon",
94
- :display_as => "PID"
95
-
96
- output :times,
97
- :description => "Processor time consumed by the daemon",
98
- :display_as => "Times"
99
-
100
- output :validated,
101
- :description => "Messages that passed security validation",
102
- :display_as => "Security Validated"
103
-
104
- output :unvalidated,
105
- :description => "Messages that failed security validation",
106
- :display_as => "Failed Security"
107
-
108
- output :passed,
109
- :description => "Passed filter checks",
110
- :display_as => "Passed Filter"
111
-
112
- output :filtered,
113
- :description => "Didn't pass filter checks",
114
- :display_as => "Failed Filter"
115
-
116
- output :starttime,
117
- :description => "Time the server started",
118
- :display_as => "Start Time"
119
-
120
- output :total,
121
- :description => "Total messages received",
122
- :display_as => "Total Messages"
123
-
124
- output :replies,
125
- :description => "Replies sent back to clients",
126
- :display_as => "Replies"
127
-
128
- output :configfile,
129
- :description => "Config file used to start the daemon",
130
- :display_as => "Config File"
131
-
132
- output :version,
133
- :description => "MCollective Version",
134
- :display_as => "Version"
135
-
136
- output :ttlexpired,
137
- :description => "Messages that did pass TTL checks",
138
- :display_as => "TTL Expired"
139
-
140
- summarize do
141
- aggregate summary(:version)
142
- aggregate summary(:agents)
143
- end
144
- end
145
-
146
- action "agent_inventory", :description => "Inventory of all agents on the server" do
147
- display :always
148
-
149
- output :agents,
150
- :description => "List of agents on the server",
151
- :display_as => "Agents"
152
- end
153
-
154
- action "get_config_item", :description => "Get the active value of a specific config property" do
155
- display :always
156
-
157
- input :item,
158
- :prompt => "Configuration Item",
159
- :description => "The item to retrieve from the server",
160
- :type => :string,
161
- :validation => '^.+$',
162
- :optional => false,
163
- :maxlength => 50
164
-
165
- output :item,
166
- :description => "The config property being retrieved",
167
- :display_as => "Property"
168
-
169
- output :value,
170
- :description => "The value that is in use",
171
- :display_as => "Value"
172
-
173
- summarize do
174
- aggregate summary(:value)
175
- end
176
- end
177
-
178
- action "get_data", :description => "Get data from a data plugin" do
179
- display :always
180
-
181
- input :source,
182
- :prompt => "Data Source",
183
- :description => "The data plugin to retrieve information from",
184
- :type => :string,
185
- :validation => '^\w+$',
186
- :optional => false,
187
- :maxlength => 50
188
-
189
- input :query,
190
- :prompt => "Query",
191
- :description => "The query argument to supply to the data plugin",
192
- :type => :string,
193
- :validation => '^.+$',
194
- :optional => true,
195
- :maxlength => 50
196
- end
197
-
198
- action "ping", :description => "Responds to requests for PING with PONG" do
199
- display :always
200
-
201
- output :pong,
202
- :description => "The local timestamp",
203
- :display_as => "Timestamp"
204
- end
@@ -1,101 +0,0 @@
1
- module MCollective
2
- module Agent
3
- class Rpcutil<RPC::Agent
4
- # Basic system inventory, same as the basic discovery agent
5
- action "inventory" do
6
- reply[:agents] = Agents.agentlist
7
- reply[:facts] = PluginManager["facts_plugin"].get_facts
8
- reply[:version] = MCollective.version
9
- reply[:classes] = []
10
- reply[:main_collective] = config.main_collective
11
- reply[:collectives] = config.collectives
12
- reply[:data_plugins] = PluginManager.grep(/_data$/)
13
-
14
- cfile = Config.instance.classesfile
15
- if File.exist?(cfile)
16
- reply[:classes] = File.readlines(cfile).map {|i| i.chomp}
17
- end
18
- end
19
-
20
- # Retrieve a single fact from the node
21
- action "get_fact" do
22
- validate :fact, String
23
-
24
- reply[:fact] = request[:fact]
25
- reply[:value] = Facts[request[:fact]]
26
- end
27
-
28
- # Get the global stats for this mcollectied
29
- action "daemon_stats" do
30
- stats = PluginManager["global_stats"].to_hash
31
-
32
- reply[:threads] = stats[:threads]
33
- reply[:agents] = stats[:agents]
34
- reply[:pid] = stats[:pid]
35
- reply[:times] = stats[:times]
36
- reply[:configfile] = Config.instance.configfile
37
- reply[:version] = MCollective.version
38
-
39
- reply.data.merge!(stats[:stats])
40
- end
41
-
42
- # Builds an inventory of all agents on teh machine
43
- # including license, version and timeout information
44
- action "agent_inventory" do
45
- reply[:agents] = []
46
-
47
- Agents.agentlist.sort.each do |target_agent|
48
- agent = PluginManager["#{target_agent}_agent"]
49
- actions = agent.methods.grep(/_agent/)
50
-
51
- agent_data = {:agent => target_agent,
52
- :license => "unknown",
53
- :timeout => agent.timeout,
54
- :description => "unknown",
55
- :name => target_agent,
56
- :url => "unknown",
57
- :version => "unknown",
58
- :author => "unknown"}
59
-
60
- agent_data.merge!(agent.meta)
61
-
62
- reply[:agents] << agent_data
63
- end
64
- end
65
-
66
- # Retrieves a single config property that is in effect
67
- action "get_config_item" do
68
- validate :item, String
69
-
70
- reply.fail! "Unknown config property #{request[:item]}" unless config.respond_to?(request[:item])
71
-
72
- reply[:item] = request[:item]
73
- reply[:value] = config.send(request[:item])
74
- end
75
-
76
- # Responds to PING requests with the local timestamp
77
- action "ping" do
78
- reply[:pong] = Time.now.to_i
79
- end
80
-
81
- # Returns all configured collectives
82
- action "collective_info" do
83
- config = Config.instance
84
- reply[:main_collective] = config.main_collective
85
- reply[:collectives] = config.collectives
86
- end
87
-
88
- action "get_data" do
89
- validate :source, String
90
-
91
- query = Data.ddl_transform_input(Data.ddl(request[:source]), request[:query].to_s)
92
-
93
- data = Data[ request[:source] ].lookup(query)
94
-
95
- data.keys.each do |key|
96
- reply[key] = data[key]
97
- end
98
- end
99
- end
100
- end
101
- end
@@ -1,35 +0,0 @@
1
- require 'open-uri'
2
- require 'timeout'
3
- require 'yaml'
4
-
5
- module MCollective
6
- module Facts
7
- # A factsource for pbuilder
8
- class Pbuilder_facts < Base
9
-
10
- def load_facts_from_source
11
- ret = {"pbuilderid" => get_pbuilderid()}
12
- yaml_file = '/etc/mcollective/facts.yaml'
13
- if File.exists?(yaml_file)
14
- yaml_facts = YAML.load_file(yaml_file)
15
- ret.merge!(yaml_facts)
16
- end
17
- ret
18
- end
19
-
20
- def get_pbuilderid()
21
- ret = nil
22
- begin
23
- addr = "169.254.169.254"
24
- wait_sec = 2
25
- Timeout::timeout(wait_sec) {open("http://#{addr}:80/")}
26
- ret = OpenURI.open_uri("http://#{addr}/2008-02-01/meta-data/instance-id").read
27
- rescue Timeout::Error
28
- rescue
29
- #TODO: unexpected; write to log what error is
30
- end
31
- ret
32
- end
33
- end
34
- end
35
- end
@@ -1,9 +0,0 @@
1
- metadata :name => "action agent",
2
- :description => "Action Agent allows us to run native bash commands on target system",
3
- :author => "Reactor8",
4
- :license => "",
5
- :version => "",
6
- :url => "",
7
- :timeout => 0
8
- action "run_command", :description => "Run provided command on system" do
9
- end
@@ -1,47 +0,0 @@
1
- require 'json'
2
- require 'cgi'
3
-
4
- module MCollective
5
- module Agent
6
- class Action_agent < RPC::Agent
7
- action "run_command" do
8
- #validate :action_agent_request, String
9
-
10
- payload = request[:action_agent_request].to_json
11
- Log.info "Run command has been started with params: "
12
- Log.info payload
13
-
14
- # we encode payload
15
- encoded_payload = CGI.escape(payload)
16
- result = `/opt/puppet-omnibus/embedded/bin/dtk-action-agent '#{encoded_payload}'`
17
-
18
- json_result = JSON.parse(result)
19
- reply[:results] = json_result['results']
20
- reply[:errors] = json_result['errors']
21
-
22
- Log.info "Results: "
23
- Log.info reply[:results]
24
-
25
- Log.info "Errors: "
26
- Log.info reply[:errors]
27
-
28
-
29
- reply[:pbuilderid] = Facts["pbuilderid"]
30
-
31
- if reply[:errors].empty?
32
- Log.info "DTK Action Agent has finished successfully sending proper response"
33
- reply[:status] = :ok
34
- else
35
- reply[:status] = :failed
36
- reply[:statusmsg] = :failed
37
- reply[:statuscode] = 1
38
-
39
- Log.error "DTK Action Agent has errors:"
40
- reply[:errors].each { |a| Log.error a }
41
- end
42
-
43
- end
44
-
45
- end
46
- end
47
- end
@@ -1,9 +0,0 @@
1
- metadata :name => "development manager",
2
- :description => "Manager which allows manipulation of nodes",
3
- :author => "Reactor8",
4
- :license => "",
5
- :version => "",
6
- :url => "",
7
- :timeout => 60
8
- action "inject_agent", :description => "Injects agent content and restarts mcollective" do
9
- end
@@ -1,111 +0,0 @@
1
- require 'base64'
2
- require 'tmpdir'
3
- require 'fileutils'
4
-
5
- module MCollective
6
- module Agent
7
- class Dev_manager < RPC::Agent
8
-
9
- AGENT_MCOLLECTIVE_LOCATION = "#{::MCollective::Config.instance.libdir.join}/mcollective/agent/"
10
- DTK_AA_TEMP_DIR = File.join(Dir.tmpdir(), 'dtk-action-agent')
11
-
12
- action "inject_agent" do
13
- begin
14
-
15
- ret ||= Response.new()
16
-
17
- # make sure default `service` command paths are set
18
- ENV['PATH'] += ":/usr/sbin:/sbin"
19
-
20
- (request[:agent_files]||[]).each do |k,v|
21
- if v == :deleted
22
- File.delete("#{AGENT_MCOLLECTIVE_LOCATION}#{k}")
23
- next
24
- end
25
- content = Base64.decode64(v)
26
- File.open("#{AGENT_MCOLLECTIVE_LOCATION}#{k}",'w') do |file|
27
- file << content
28
- end
29
- end
30
-
31
- ret.set_status_succeeded!()
32
-
33
- dtk_aa_url = request[:action_agent_remote_url]
34
- dtk_aa_branch = request[:action_agent_branch]
35
-
36
- # DTK Action Agent Sync
37
- if dtk_aa_url && dtk_aa_branch
38
- begin
39
- Log.instance.info("Started DTK Action Agent sync, temp dir '#{DTK_AA_TEMP_DIR}'")
40
- output = `git clone #{dtk_aa_url} -b #{dtk_aa_branch} #{DTK_AA_TEMP_DIR}`
41
- result = $?
42
-
43
- if result.success?
44
- Log.instance.info("Cloned latest code from branch '#{dtk_aa_branch}' for DTK Action Agent.")
45
-
46
- output = `cd #{DTK_AA_TEMP_DIR} && /opt/puppet-omnibus/embedded/bin/gem build #{DTK_AA_TEMP_DIR}/dtk-action-agent.gemspec && /opt/puppet-omnibus/embedded/bin/gem install #{DTK_AA_TEMP_DIR}/dtk-action-agent-*.gem --no-ri --no-rdoc`
47
- result = $?
48
- if result.success?
49
- Log.instance.info("DTK Action Agent has been successfully update from branch '#{dtk_aa_branch}'")
50
- else
51
- Log.instance.error("DTK Action Agent could not be updated, reason: #{output}")
52
- end
53
- else
54
- Log.instance.error("Not able to clone latest code from '#{dtk_aa_url} branch #{dtk_aa_branch}', aborting DTK Action Agent Sync. #{output}")
55
- end
56
- ensure
57
- FileUtils.rm_rf DTK_AA_TEMP_DIR
58
- end
59
- end
60
-
61
- t1 = Thread.new do
62
- sleep(2)
63
- Log.instance.info "Initiating mcollective restart..."
64
- system("#{service_command} restart")
65
- end
66
-
67
- def self.service_command
68
- cmd = `which service`.chomp
69
- cmd.empty? ? "/etc/init.d/mcollective" : "#{cmd} mcollective"
70
- end
71
-
72
- return ret
73
-
74
- rescue Exception => e
75
- Log.instance.error e
76
- ret.set_status_failed!()
77
- error_info = { :error => { :message => "Error syncing agents: #{e}" } }
78
- ret.merge!(error_info)
79
- end
80
-
81
- return ret
82
- end
83
- end
84
- #TODO: this should be common accross Agents
85
- class Response < Hash
86
- def initialize(hash={})
87
- super()
88
- self.merge!(hash)
89
- self[:status] = :unknown unless hash.has_key?(:status)
90
- end
91
-
92
- def to_hash()
93
- Hash.new.merge(self)
94
- end
95
-
96
- def failed?()
97
- self[:status] == :failed
98
- end
99
-
100
- def set_status_failed!()
101
- self[:status] = :failed
102
- end
103
- def set_status_succeeded!()
104
- self[:status] = :succeeded
105
- end
106
- def set_dynamic_attributes!(dynamic_attributes)
107
- self[:dynamic_attributes] = dynamic_attributes
108
- end
109
- end
110
- end
111
- end