glazed 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/.rspec +3 -0
- data/.yardopts +5 -0
- data/CHANGELOG.md +18 -0
- data/LICENSE.txt +202 -0
- data/NOTICE +16 -0
- data/README.md +3 -0
- data/Rakefile +12 -0
- data/exe/glazed +8 -0
- data/lib/glazed/cli_session.rb +178 -0
- data/lib/glazed/collector.rb +113 -0
- data/lib/glazed/command/base.rb +146 -0
- data/lib/glazed/command/orchestrate.rb +78 -0
- data/lib/glazed/command/run.rb +51 -0
- data/lib/glazed/command/send_signal.rb +69 -0
- data/lib/glazed/command/status.rb +179 -0
- data/lib/glazed/command/version.rb +23 -0
- data/lib/glazed/command.rb +39 -0
- data/lib/glazed/command_result.rb +26 -0
- data/lib/glazed/dialect/actions.rb +95 -0
- data/lib/glazed/dialect/communication_config.rb +63 -0
- data/lib/glazed/dialect/interaction.rb +32 -0
- data/lib/glazed/dialect/run.rb +84 -0
- data/lib/glazed/dialect/runbook.rb +97 -0
- data/lib/glazed/dialect/sensitive_pattern.rb +31 -0
- data/lib/glazed/dialect.rb +12 -0
- data/lib/glazed/dialects/awplus.rb +84 -0
- data/lib/glazed/dialects/base.rb +246 -0
- data/lib/glazed/dialects/ios.rb +173 -0
- data/lib/glazed/dialects/junos.rb +78 -0
- data/lib/glazed/dialects/nec_ix.rb +71 -0
- data/lib/glazed/dialects/wlc.rb +56 -0
- data/lib/glazed/dialects.rb +65 -0
- data/lib/glazed/finder.rb +62 -0
- data/lib/glazed/must.rb +54 -0
- data/lib/glazed/orchestrator/policy.rb +184 -0
- data/lib/glazed/orchestrator.rb +288 -0
- data/lib/glazed/plugin_registry.rb +70 -0
- data/lib/glazed/proto.rb +20 -0
- data/lib/glazed/proto_json.rb +34 -0
- data/lib/glazed/redactor.rb +158 -0
- data/lib/glazed/runner.rb +176 -0
- data/lib/glazed/secret.rb +74 -0
- data/lib/glazed/secrets.rb +59 -0
- data/lib/glazed/shell_command.rb +90 -0
- data/lib/glazed/sources/base.rb +79 -0
- data/lib/glazed/sources/command.rb +67 -0
- data/lib/glazed/sources/inline.rb +56 -0
- data/lib/glazed/sources/json_files.rb +87 -0
- data/lib/glazed/sources.rb +105 -0
- data/lib/glazed/state_backends/base.rb +72 -0
- data/lib/glazed/state_backends/sqlite.rb +299 -0
- data/lib/glazed/state_backends.rb +75 -0
- data/lib/glazed/step_context.rb +65 -0
- data/lib/glazed/steps/base.rb +89 -0
- data/lib/glazed/steps/batch_shell.rb +57 -0
- data/lib/glazed/steps/fetch.rb +67 -0
- data/lib/glazed/steps/publish.rb +94 -0
- data/lib/glazed/steps/redact.rb +77 -0
- data/lib/glazed/steps/shell.rb +107 -0
- data/lib/glazed/steps.rb +83 -0
- data/lib/glazed/storages/base.rb +167 -0
- data/lib/glazed/storages/filesystem.rb +144 -0
- data/lib/glazed/storages/git.rb +181 -0
- data/lib/glazed/storages/github.rb +269 -0
- data/lib/glazed/storages/memory.rb +125 -0
- data/lib/glazed/storages.rb +88 -0
- data/lib/glazed/transports/base.rb +103 -0
- data/lib/glazed/transports/ssh.rb +177 -0
- data/lib/glazed/transports/telnet.rb +100 -0
- data/lib/glazed/transports.rb +28 -0
- data/lib/glazed/v1/config_pb.rb +25 -0
- data/lib/glazed/v1/inventory_pb.rb +27 -0
- data/lib/glazed/v1/orchestrator_pb.rb +27 -0
- data/lib/glazed/v1/redaction_pb.rb +23 -0
- data/lib/glazed/v1/secret_pb.rb +22 -0
- data/lib/glazed/v1/state_pb.rb +25 -0
- data/lib/glazed/v1/steps_pb.rb +25 -0
- data/lib/glazed/v1/storage_pb.rb +34 -0
- data/lib/glazed/v1/workflow_pb.rb +29 -0
- data/lib/glazed/validation.rb +31 -0
- data/lib/glazed/version.rb +9 -0
- data/lib/glazed/workflow.rb +70 -0
- data/lib/glazed.rb +18 -0
- metadata +245 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
|
|
6
|
+
require 'glazed/dialect'
|
|
7
|
+
|
|
8
|
+
module Glazed
|
|
9
|
+
module Dialect
|
|
10
|
+
# Edits that interactions and runbook steps apply to a text buffer.
|
|
11
|
+
#
|
|
12
|
+
# A String is shorthand for {Append} and nil does nothing.
|
|
13
|
+
module Actions
|
|
14
|
+
# Action applying content to a buffer.
|
|
15
|
+
class Content
|
|
16
|
+
# @param content [String] text the action carries
|
|
17
|
+
#: (content: String) -> void
|
|
18
|
+
def initialize(content:)
|
|
19
|
+
@content = content.dup.freeze #: String
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @return [String] text the action carries
|
|
23
|
+
#: String
|
|
24
|
+
attr_reader :content
|
|
25
|
+
|
|
26
|
+
# @param other [Object] object to compare
|
|
27
|
+
# @return [Boolean] whether other is the same action with the same content
|
|
28
|
+
#: (untyped other) -> bool
|
|
29
|
+
def ==(other) = other.class == self.class && other.content == content
|
|
30
|
+
|
|
31
|
+
alias eql? ==
|
|
32
|
+
|
|
33
|
+
# @return [Integer] hash consistent with {#==}
|
|
34
|
+
#: () -> Integer
|
|
35
|
+
def hash = [self.class, content].hash
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Appends content to the buffer.
|
|
39
|
+
class Append < Content; end
|
|
40
|
+
|
|
41
|
+
# Replaces the whole buffer with content.
|
|
42
|
+
class Replace < Content; end
|
|
43
|
+
|
|
44
|
+
# Applies several actions in order.
|
|
45
|
+
class Multi
|
|
46
|
+
# @param actions [Array<Append, Replace, Multi, String, nil>] actions, flattened and normalised
|
|
47
|
+
#: (*Actions::action? actions) -> void
|
|
48
|
+
def initialize(*actions)
|
|
49
|
+
@actions = actions.flat_map { Multi.normalize(it) }.freeze #: Array[Append | Replace]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @return [Array<Append, Replace>] flattened actions
|
|
53
|
+
#: Array[Append | Replace]
|
|
54
|
+
attr_reader :actions
|
|
55
|
+
|
|
56
|
+
# @param action [Append, Replace, Multi, String, nil] action to normalise
|
|
57
|
+
# @return [Array<Append, Replace>] equivalent plain actions
|
|
58
|
+
#: (Actions::action? action) -> Array[Append | Replace]
|
|
59
|
+
def self.normalize(action)
|
|
60
|
+
case action
|
|
61
|
+
when nil then []
|
|
62
|
+
when String then [Append.new(content: action)]
|
|
63
|
+
when Multi then action.actions
|
|
64
|
+
else [action]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @param other [Object] object to compare
|
|
69
|
+
# @return [Boolean] whether other holds the same actions
|
|
70
|
+
#: (untyped other) -> bool
|
|
71
|
+
def ==(other) = other.is_a?(Multi) ? other.actions == actions : false
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
#: type action = Append | Replace | Multi | String
|
|
75
|
+
|
|
76
|
+
# Applies an action to a buffer.
|
|
77
|
+
#
|
|
78
|
+
# @param buffer [String] text to edit
|
|
79
|
+
# @param action [Append, Replace, Multi, String, nil] action to apply
|
|
80
|
+
# @return [String] the edited text, a new string
|
|
81
|
+
# @example
|
|
82
|
+
# Actions.apply("a", Actions::Append.new(content: "b")) #=> "ab"
|
|
83
|
+
#: (String buffer, Actions::action? action) -> String
|
|
84
|
+
def self.apply(buffer, action)
|
|
85
|
+
Multi.normalize(action).inject(buffer.dup) do |result, step|
|
|
86
|
+
case step
|
|
87
|
+
when Append then result << step.content
|
|
88
|
+
when Replace then step.content.dup
|
|
89
|
+
else step #: absurd
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
|
|
6
|
+
require 'glazed/dialect'
|
|
7
|
+
|
|
8
|
+
module Glazed
|
|
9
|
+
module Dialect
|
|
10
|
+
# How a dialect talks to a device over one transport.
|
|
11
|
+
class CommunicationConfig
|
|
12
|
+
#: type hook = ^(Run run) -> void
|
|
13
|
+
|
|
14
|
+
#: () -> void
|
|
15
|
+
def initialize
|
|
16
|
+
@exec = false #: bool
|
|
17
|
+
@pty_options = {} #: Hash[Symbol, untyped]
|
|
18
|
+
@username_prompt = nil #: Regexp?
|
|
19
|
+
@password_prompt = nil #: Regexp?
|
|
20
|
+
@post_login_hooks = [] #: Array[CommunicationConfig::hook]
|
|
21
|
+
@pre_logout_hooks = [] #: Array[CommunicationConfig::hook]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @return [Boolean] run each command on its own exec channel when the transport supports it
|
|
25
|
+
#: bool
|
|
26
|
+
attr_accessor :exec
|
|
27
|
+
# @return [Hash{Symbol => Object}] PTY settings such as :term and :chars_wide, over the transport's defaults
|
|
28
|
+
#: Hash[Symbol, untyped]
|
|
29
|
+
attr_reader :pty_options
|
|
30
|
+
|
|
31
|
+
# @return [Regexp, nil] prompt for the user name; when set, the session logs in by answering it
|
|
32
|
+
#: Regexp?
|
|
33
|
+
attr_accessor :username_prompt
|
|
34
|
+
# @return [Regexp, nil] prompt for the password
|
|
35
|
+
#: Regexp?
|
|
36
|
+
attr_accessor :password_prompt
|
|
37
|
+
# @return [Array<Proc>] hooks run after login, in order
|
|
38
|
+
#: Array[CommunicationConfig::hook]
|
|
39
|
+
attr_reader :post_login_hooks
|
|
40
|
+
# @return [Array<Proc>] hooks run before logout, in order
|
|
41
|
+
#: Array[CommunicationConfig::hook]
|
|
42
|
+
attr_reader :pre_logout_hooks
|
|
43
|
+
|
|
44
|
+
# Adds a hook run after login and before the runbook.
|
|
45
|
+
#
|
|
46
|
+
# @yieldparam run [Run] the run in progress
|
|
47
|
+
# @return [void]
|
|
48
|
+
#: () { (Run run) -> void } -> void
|
|
49
|
+
def post_login(&hook)
|
|
50
|
+
@post_login_hooks << hook
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Adds a hook run after the runbook and before the connection closes.
|
|
54
|
+
#
|
|
55
|
+
# @yieldparam run [Run] the run in progress
|
|
56
|
+
# @return [void]
|
|
57
|
+
#: () { (Run run) -> void } -> void
|
|
58
|
+
def pre_logout(&hook)
|
|
59
|
+
@pre_logout_hooks << hook
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
|
|
6
|
+
require 'glazed/dialect'
|
|
7
|
+
require 'glazed/dialect/actions'
|
|
8
|
+
|
|
9
|
+
module Glazed
|
|
10
|
+
module Dialect
|
|
11
|
+
#: type responder = ^(CliSession session, String buffer, MatchData match) -> Actions::action?
|
|
12
|
+
#: type data_filter = ^(String fragment) -> String
|
|
13
|
+
|
|
14
|
+
# Responds to a pattern appearing in the session buffer, such as a pager prompt.
|
|
15
|
+
class Interaction
|
|
16
|
+
# @param pattern [Regexp] pattern matched against the session buffer
|
|
17
|
+
# @param responder [Proc] called with the session, a copy of the buffer and the match; returns an action applied to the buffer
|
|
18
|
+
#: (pattern: Regexp, responder: Dialect::responder) -> void
|
|
19
|
+
def initialize(pattern:, responder:)
|
|
20
|
+
@pattern = pattern #: Regexp
|
|
21
|
+
@responder = responder #: Dialect::responder
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @return [Regexp] pattern matched against the session buffer
|
|
25
|
+
#: Regexp
|
|
26
|
+
attr_reader :pattern
|
|
27
|
+
# @return [Proc] responder returning an action applied to the buffer
|
|
28
|
+
#: Dialect::responder
|
|
29
|
+
attr_reader :responder
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
|
|
6
|
+
require 'glazed/cli_session'
|
|
7
|
+
require 'glazed/command_result'
|
|
8
|
+
require 'glazed/dialect'
|
|
9
|
+
require 'glazed/dialect/actions'
|
|
10
|
+
require 'glazed/proto'
|
|
11
|
+
require 'glazed/secret'
|
|
12
|
+
|
|
13
|
+
module Glazed
|
|
14
|
+
module Dialect
|
|
15
|
+
# State of one runbook execution against one node.
|
|
16
|
+
class Run
|
|
17
|
+
# @param cli [CliSession] session to the node
|
|
18
|
+
# @param node [Proto::V1::Node] node being run against
|
|
19
|
+
# @param dialect [Class<Dialects::Base>] dialect of the node
|
|
20
|
+
#: (cli: CliSession, node: Proto::V1::Node, dialect: singleton(Dialects::Base)) -> void
|
|
21
|
+
def initialize(cli:, node:, dialect:)
|
|
22
|
+
@cli = cli #: CliSession
|
|
23
|
+
@node = node #: Proto::V1::Node
|
|
24
|
+
@dialect = dialect #: singleton(Dialects::Base)
|
|
25
|
+
@vars = {} #: Hash[Symbol, untyped]
|
|
26
|
+
@output = +'' #: String
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @return [CliSession] session to the node
|
|
30
|
+
#: CliSession
|
|
31
|
+
attr_reader :cli
|
|
32
|
+
# @return [Proto::V1::Node] node being run against
|
|
33
|
+
#: Proto::V1::Node
|
|
34
|
+
attr_reader :node
|
|
35
|
+
# @return [Class<Dialects::Base>] dialect of the node
|
|
36
|
+
#: singleton(Dialects::Base)
|
|
37
|
+
attr_reader :dialect
|
|
38
|
+
# @return [Hash{Symbol => Object}] scratch space shared by the steps of this run
|
|
39
|
+
#: Hash[Symbol, untyped]
|
|
40
|
+
attr_reader :vars
|
|
41
|
+
# @return [String] configuration collected so far
|
|
42
|
+
#: String
|
|
43
|
+
attr_reader :output
|
|
44
|
+
|
|
45
|
+
# Runs a command and passes its output, as bytes, through the dialect's
|
|
46
|
+
# output filters. Collected configuration must be UTF-8, so a dialect for
|
|
47
|
+
# a device using another encoding converts it in an output filter.
|
|
48
|
+
#
|
|
49
|
+
# @param line [String] command line
|
|
50
|
+
# @return [CommandResult] the filtered result, in UTF-8
|
|
51
|
+
# @raise [InvalidEncoding] when the filtered output is not valid UTF-8
|
|
52
|
+
#: (String line) -> CommandResult
|
|
53
|
+
def command(line)
|
|
54
|
+
result = cli.command(line)
|
|
55
|
+
filtered = dialect.output_filters.inject(result.output) { |text, output_filter| output_filter.call(text) }
|
|
56
|
+
output = filtered.dup.force_encoding(Encoding::UTF_8)
|
|
57
|
+
unless output.valid_encoding?
|
|
58
|
+
raise InvalidEncoding, "output of #{line.inspect} is not valid UTF-8; convert it in the dialect's filter_output"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
CommandResult.new(command: result.command, output:)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Applies an action to the collected configuration.
|
|
65
|
+
#
|
|
66
|
+
# @param action [Actions::Append, Actions::Replace, Actions::Multi, String, nil] action to apply
|
|
67
|
+
# @return [void]
|
|
68
|
+
#: (Actions::action? action) -> void
|
|
69
|
+
def emit(action)
|
|
70
|
+
@output = Actions.apply(@output, action)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# @param name [String] parameter name
|
|
74
|
+
# @return [String, nil] the node's parameter value
|
|
75
|
+
#: (String name) -> String?
|
|
76
|
+
def param(name) = node.params[name]
|
|
77
|
+
|
|
78
|
+
# @param name [String] secret name
|
|
79
|
+
# @return [Secret, nil] the node's secret
|
|
80
|
+
#: (String name) -> Secret?
|
|
81
|
+
def secret(name) = Secret.maybe(node.secrets[name])
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
|
|
6
|
+
require 'glazed/command_result'
|
|
7
|
+
require 'glazed/dialect'
|
|
8
|
+
require 'glazed/dialect/actions'
|
|
9
|
+
require 'glazed/dialect/run'
|
|
10
|
+
|
|
11
|
+
module Glazed
|
|
12
|
+
module Dialect
|
|
13
|
+
# Ordered steps that collect configuration from a node.
|
|
14
|
+
class Runbook
|
|
15
|
+
#: type step_block = ^(Run run) -> void
|
|
16
|
+
|
|
17
|
+
# One step of a runbook.
|
|
18
|
+
class Step
|
|
19
|
+
# @param description [String] what the step does, such as its command line
|
|
20
|
+
# @param block [Proc] called with the run
|
|
21
|
+
#: (description: String, block: Runbook::step_block) -> void
|
|
22
|
+
def initialize(description:, block:)
|
|
23
|
+
@description = description #: String
|
|
24
|
+
@block = block #: Runbook::step_block
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @return [String] what the step does
|
|
28
|
+
#: String
|
|
29
|
+
attr_reader :description
|
|
30
|
+
# @return [Proc] called with the run
|
|
31
|
+
#: Runbook::step_block
|
|
32
|
+
attr_reader :block
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Collects steps for a runbook.
|
|
36
|
+
#
|
|
37
|
+
# @example
|
|
38
|
+
# builder.command('show version') { |result| comment(result.output) }
|
|
39
|
+
# builder.raw { |run| run.vars[:model] = run.command('show model').output }
|
|
40
|
+
class Builder
|
|
41
|
+
#: () -> void
|
|
42
|
+
def initialize
|
|
43
|
+
@steps = [] #: Array[Step]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Adds a step that runs a command and emits what the block returns, or
|
|
47
|
+
# the output itself without a block.
|
|
48
|
+
#
|
|
49
|
+
# @param line [String] command line
|
|
50
|
+
# @yieldparam result [CommandResult] filtered command result
|
|
51
|
+
# @yieldreturn [Actions::Append, Actions::Replace, Actions::Multi, String, nil] action to emit
|
|
52
|
+
# @return [void]
|
|
53
|
+
#: (String line) ?{ (CommandResult result) -> Actions::action? } -> void
|
|
54
|
+
def command(line, &callback)
|
|
55
|
+
raw(line) do |run|
|
|
56
|
+
result = run.command(line)
|
|
57
|
+
run.emit(callback ? callback.call(result) : result.output)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Adds a step that drives the run directly.
|
|
62
|
+
#
|
|
63
|
+
# @param description [String] what the step does
|
|
64
|
+
# @yieldparam run [Run] the run in progress
|
|
65
|
+
# @return [void]
|
|
66
|
+
#: (?String description) { (Run run) -> void } -> void
|
|
67
|
+
def raw(description = '', &block)
|
|
68
|
+
@steps << Step.new(description:, block:)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# @return [Runbook] runbook of the collected steps
|
|
72
|
+
#: () -> Runbook
|
|
73
|
+
def build = Runbook.new(steps: @steps.dup)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# @param steps [Array<Step>] steps in order
|
|
77
|
+
#: (steps: Array[Step]) -> void
|
|
78
|
+
def initialize(steps:)
|
|
79
|
+
@steps = steps.freeze #: Array[Step]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# @return [Array<Step>] steps in order
|
|
83
|
+
#: Array[Step]
|
|
84
|
+
attr_reader :steps
|
|
85
|
+
|
|
86
|
+
# Runs every step.
|
|
87
|
+
#
|
|
88
|
+
# @param run [Run] run to execute against
|
|
89
|
+
# @return [String] the collected configuration
|
|
90
|
+
#: (Run run) -> String
|
|
91
|
+
def execute(run)
|
|
92
|
+
steps.each { it.block.call(run) }
|
|
93
|
+
run.output
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
|
|
6
|
+
require 'glazed/dialect'
|
|
7
|
+
|
|
8
|
+
module Glazed
|
|
9
|
+
module Dialect
|
|
10
|
+
# Locates secrets in configuration text.
|
|
11
|
+
class SensitivePattern
|
|
12
|
+
#: type determiner = ^(MatchData match) -> (String | Range[Integer])?
|
|
13
|
+
|
|
14
|
+
# @param pattern [Regexp] pattern matched against the whole configuration
|
|
15
|
+
# @param determiner [Proc] returns the secret within a match, or its offsets in the configuration,
|
|
16
|
+
# or nil when the match holds none
|
|
17
|
+
#: (pattern: Regexp, determiner: SensitivePattern::determiner) -> void
|
|
18
|
+
def initialize(pattern:, determiner:)
|
|
19
|
+
@pattern = pattern #: Regexp
|
|
20
|
+
@determiner = determiner #: SensitivePattern::determiner
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @return [Regexp] pattern matched against the whole configuration
|
|
24
|
+
#: Regexp
|
|
25
|
+
attr_reader :pattern
|
|
26
|
+
# @return [Proc] returns the secret within a match, or its offsets
|
|
27
|
+
#: SensitivePattern::determiner
|
|
28
|
+
attr_reader :determiner
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
|
|
6
|
+
# Derived from Oxidized (https://github.com/ytti/oxidized) lib/oxidized/model/awplus.rb,
|
|
7
|
+
# Copyright 2013-2015 Saku Ytti, Samer Abdel-Hafez and Oxidized contributors,
|
|
8
|
+
# licensed under the Apache License, Version 2.0. Modified for the glazed dialect API.
|
|
9
|
+
|
|
10
|
+
require 'glazed/dialects/base'
|
|
11
|
+
|
|
12
|
+
module Glazed
|
|
13
|
+
module Dialects
|
|
14
|
+
# Allied Telesis AlliedWare Plus.
|
|
15
|
+
class Awplus < Base
|
|
16
|
+
prompt(/^(\r?[\w.@:\/-]+[#>]\s?)$/)
|
|
17
|
+
comment_prefix '! '
|
|
18
|
+
|
|
19
|
+
interact(/--More--/) do |cli, _buffer, match|
|
|
20
|
+
cli.write(' ')
|
|
21
|
+
Actions::Replace.new(content: match.pre_match + match.post_match)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
filter_data { |fragment| fragment.gsub("\e[7m\e[m", '').delete("\r") }
|
|
25
|
+
|
|
26
|
+
sensitive_pattern(/^snmp-server community\s+(\S+)/) { it[1] }
|
|
27
|
+
sensitive_pattern(/^snmp-server user .+auth \S+ (\S+)$/) { it[1] }
|
|
28
|
+
sensitive_pattern(/^snmp-server user .+priv \S+ (\S+)$/) { it[1] }
|
|
29
|
+
sensitive_pattern(/^username \S+ privilege \d+ (?:password|secret) (?:\d+ )?(\S+)/) { it[1] }
|
|
30
|
+
sensitive_pattern(/^username .+? password \d+\s+(\S+).*/) { it[1] }
|
|
31
|
+
sensitive_pattern(/^username .+? secret \d+\s+(\S+).*/) { it[1] }
|
|
32
|
+
sensitive_pattern(/^enable (?:password|secret) (?:\d )?\s*(\S+)/) { it[1] }
|
|
33
|
+
sensitive_pattern(/\s+(?:password|secret) (?:\d )?(\S+)/) { it[1] }
|
|
34
|
+
sensitive_pattern(/^tacacs-server key (?:\d )?(\S+)/) { it[1] }
|
|
35
|
+
sensitive_pattern(/^radius-server key (\S+)/) { it[1] }
|
|
36
|
+
sensitive_pattern(/^auth-mac (?:encrypted )?password (\S+)/) { it[1] }
|
|
37
|
+
sensitive_pattern(/^\s*ppp password (?:encrypted )?(.+)$/) { it[1] }
|
|
38
|
+
sensitive_pattern(/^\s*key-string (?:encrypted )?(.+)$/) { it[1] }
|
|
39
|
+
sensitive_pattern(/^\s+password (?:encrypted )?(.+)$/) { it[1] }
|
|
40
|
+
sensitive_pattern(/^\s+key (?:encrypted )?(.+)$/) { it[1] }
|
|
41
|
+
sensitive_pattern(/^\s+neighbor \S+ password (.+?)(?: encrypted)?$/) { it[1] }
|
|
42
|
+
sensitive_pattern(/^\s+ip ospf \S+ message-digest-key \d+ md5 (?:encrypted )?(.+)$/) { it[1] }
|
|
43
|
+
sensitive_pattern(/^\s+ip ospf \S+ authentication-key (?:encrypted )?(.+)$/) { it[1] }
|
|
44
|
+
sensitive_pattern(/^\s*aes-key (?:encrypted )?(.+)$/) { it[1] }
|
|
45
|
+
|
|
46
|
+
runbook :get do |book|
|
|
47
|
+
book.command('show system') do |result|
|
|
48
|
+
stable = result.output.each_line.grep_v(
|
|
49
|
+
/\A\s*\n\z
|
|
50
|
+
|System\ Status
|
|
51
|
+
|RAM\s*:
|
|
52
|
+
|Uptime\s*:
|
|
53
|
+
|Flash\s*:
|
|
54
|
+
|Current\ software\s*:
|
|
55
|
+
|Software\ version\s*:
|
|
56
|
+
|Build\ date\s*:
|
|
57
|
+
/x,
|
|
58
|
+
)
|
|
59
|
+
comment("-- show system #{'-' * 66}\n#{stable.join}#{'-' * 80}\n")
|
|
60
|
+
end
|
|
61
|
+
book.command('show running-config')
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
communication :telnet do |config|
|
|
65
|
+
config.username_prompt = /^login:\s/i
|
|
66
|
+
config.password_prompt = /^password:\s/i
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
communication :ssh, :telnet do |config|
|
|
70
|
+
config.post_login do |run|
|
|
71
|
+
if (enable = run.secret('enable'))
|
|
72
|
+
run.cli.write("enable\n")
|
|
73
|
+
run.cli.expect(/^Password:\s/)
|
|
74
|
+
run.cli.write("#{enable.value}\n")
|
|
75
|
+
run.cli.expect(run.cli.prompt)
|
|
76
|
+
else
|
|
77
|
+
run.cli.command('enable')
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
config.pre_logout { |run| run.cli.write("exit\n") }
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|