cvprac 1.0.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/.gitignore +51 -0
- data/.rspec +4 -0
- data/.rubocop.yml +8 -0
- data/.rubocop_todo.yml +24 -0
- data/CHANGELOG.md +26 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +36 -0
- data/Gemfile +6 -0
- data/Guardfile +11 -0
- data/Jenkinsfile +239 -0
- data/LICENSE +29 -0
- data/README.md +152 -0
- data/Rakefile +55 -0
- data/cvprac.gemspec +57 -0
- data/lib/cvprac.rb +41 -0
- data/lib/cvprac/api.rb +79 -0
- data/lib/cvprac/api/configlet.rb +309 -0
- data/lib/cvprac/api/info.rb +53 -0
- data/lib/cvprac/api/inventory.rb +61 -0
- data/lib/cvprac/api/provisioning.rb +119 -0
- data/lib/cvprac/api/task.rb +108 -0
- data/lib/cvprac/client.rb +560 -0
- data/lib/cvprac/client_errors.rb +67 -0
- data/lib/cvprac/version.rb +34 -0
- metadata +433 -0
data/LICENSE
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
BSD 3-Clause License
|
2
|
+
|
3
|
+
Copyright (c) 2016, Arista Networks EOS+
|
4
|
+
All rights reserved.
|
5
|
+
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
8
|
+
|
9
|
+
* Redistributions of source code must retain the above copyright notice, this
|
10
|
+
list of conditions and the following disclaimer.
|
11
|
+
|
12
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
14
|
+
and/or other materials provided with the distribution.
|
15
|
+
|
16
|
+
* Neither the name Arista nor the names of its
|
17
|
+
contributors may be used to endorse or promote products derived from
|
18
|
+
this software without specific prior written permission.
|
19
|
+
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
# Cvprac - CloudVision Portal RESTful API Client
|
2
|
+
|
3
|
+
#### Table of Contents
|
4
|
+
|
5
|
+
1. [Overview](#overview)
|
6
|
+
2. [Installation](#installation)
|
7
|
+
3. [Usage](#usage)
|
8
|
+
4. [Development](#development)
|
9
|
+
5. [Contributing](#contributing)
|
10
|
+
6. [Support](#support)
|
11
|
+
|
12
|
+
[](https://badge.fury.io/rb/cvprac)
|
13
|
+
[](https://revproxy.arista.com/eosplus/ci/job/Pipeline_jerearista_test/cvprac-rb/develop)
|
14
|
+
|
15
|
+
## Overview
|
16
|
+
|
17
|
+
The cvprac rubygem is a Ruby RESTful API Client for Arista CloudVision®
|
18
|
+
Portal (CVP) which can be used for building applications that work with Arista
|
19
|
+
CVP. If you are looking for a Python version, see [cvprac on
|
20
|
+
PyPI](https://pypi.python.org/pypi/cvprac) or
|
21
|
+
[GitHub](https://pypi.python.org/pypi/cvprac).
|
22
|
+
|
23
|
+
When the class is instantiated the logging is configured. Either syslog,
|
24
|
+
file logging, both, or none can be enabled. If neither syslog nor
|
25
|
+
filename is specified then no logging will be performed.
|
26
|
+
|
27
|
+
This class supports creating a connection to a CVP node and then issuing
|
28
|
+
subsequent GET and POST requests to CVP. A GET or POST request will be
|
29
|
+
automatically retried on the same node if the request times out. A GET or POST
|
30
|
+
request will be automatically retried on the same node if the request receives
|
31
|
+
a CvpSessionLogOutError. For this case a login will be performed before the
|
32
|
+
request is retried. For either case, the maximum number of times a request will
|
33
|
+
be retried on the same node is specified by the class attribute
|
34
|
+
NUM\_RETRY\_REQUESTS.
|
35
|
+
|
36
|
+
If more than one CVP node is specified when creating a connection, and a GET or
|
37
|
+
POST request receives a ConnectionError, HTTPError, or TooManyRedirects it will
|
38
|
+
be retried on the next CVP node in the list. If a GET or POST request receives
|
39
|
+
a Timeout or CvpSessionLogOutError and the retries on the same node exceed
|
40
|
+
NUM\_RETRY\_REQUESTS, then the request will be retried on the next node on the
|
41
|
+
list.
|
42
|
+
|
43
|
+
If any of the errors persists across all nodes then the GET or POST
|
44
|
+
request will fail and the last error that occurred will be raised.
|
45
|
+
|
46
|
+
The class provides connect, get, and post methods that allow the user to
|
47
|
+
make RESTful API calls to CVP. See the example below using the get
|
48
|
+
method.
|
49
|
+
|
50
|
+
The class provides a wrapper function around the CVP RESTful API
|
51
|
+
operations. Each API method takes the RESTful API parameters as method
|
52
|
+
parameters to the operation method. The API class was added to the
|
53
|
+
client class because the API functions are required when using the CVP
|
54
|
+
RESTful API and placing them in this library avoids duplicating the
|
55
|
+
calls in every application that uses this class. See the examples below
|
56
|
+
using the API methods.
|
57
|
+
|
58
|
+
## Requirements
|
59
|
+
|
60
|
+
- Ruby 1.9.3 or later
|
61
|
+
|
62
|
+
## Installation
|
63
|
+
|
64
|
+
Add this line to your application's Gemfile:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
gem 'cvprac'
|
68
|
+
```
|
69
|
+
|
70
|
+
And then execute:
|
71
|
+
|
72
|
+
$ bundle
|
73
|
+
|
74
|
+
Or install it yourself as:
|
75
|
+
|
76
|
+
$ gem install cvprac
|
77
|
+
|
78
|
+
## Usage
|
79
|
+
|
80
|
+
Basic usage:
|
81
|
+
|
82
|
+
```
|
83
|
+
require ‘cvprac’
|
84
|
+
cvp = CvpClient.new
|
85
|
+
cvp.connect(['192.0.2.101', '192.0.2.102, '192.0.2.103'],
|
86
|
+
'cvpadmin', 'arista123')
|
87
|
+
result = cvp.get('/cvpInfo/getCvpInfo.do')
|
88
|
+
print result
|
89
|
+
{“appVersion”=>”Phase_2_Sprint_34_HF09”, “version”=>”2017.1.0.1”}
|
90
|
+
|
91
|
+
result = cvp.get('/user/getUsers.do',
|
92
|
+
data: { queryparam: nil, startIndex: 0, endIndex: 0 })
|
93
|
+
|
94
|
+
cvp.post('/some/endpoint.do', body: '{"some":"data"}')
|
95
|
+
```
|
96
|
+
|
97
|
+
Modifying logging settings:
|
98
|
+
|
99
|
+
```
|
100
|
+
require ‘cvprac’
|
101
|
+
|
102
|
+
# Log to Syslog
|
103
|
+
cvp = CvpClient.new(syslog: true)
|
104
|
+
|
105
|
+
# Log to a file or ‘STDOUT’ and increase the logging level
|
106
|
+
cvp = CvpClient.new(filename: 'STDOUT', file_log_level: Logger::DEBUG)
|
107
|
+
|
108
|
+
```
|
109
|
+
|
110
|
+
API Class example:
|
111
|
+
|
112
|
+
```
|
113
|
+
require ‘cvprac’
|
114
|
+
cvp = CvpClient.new
|
115
|
+
cvp.connect(['192.0.2.101', '192.0.2.102, '192.0.2.103'],
|
116
|
+
'cvpadmin', 'arista123')
|
117
|
+
|
118
|
+
result = cvp.api.get_cvp_info
|
119
|
+
print result
|
120
|
+
=> {“appVersion”=>”Phase_2_Sprint_34_HF09”, “version”=>”2017.1.0.1”}
|
121
|
+
```
|
122
|
+
|
123
|
+
### Notes for API Class Usage
|
124
|
+
|
125
|
+
#### Containers
|
126
|
+
|
127
|
+
With the API the containers are added for all cases. If you add the container
|
128
|
+
to the original root container ‘Tenant’ then you have to do a refresh from the
|
129
|
+
GUI to see the container after it is added or deleted. If the root container
|
130
|
+
has been renamed or the parent container is not the root container then an add
|
131
|
+
or delete will update the GUI without requiring a manual refresh.
|
132
|
+
|
133
|
+
## Development
|
134
|
+
|
135
|
+
See [CONTRIBUTING](CONTRUBUTING.md)
|
136
|
+
|
137
|
+
## Contributing
|
138
|
+
|
139
|
+
Bug reports and pull requests are welcome on
|
140
|
+
[GitHub](https://github.com/arista-aristanetworks/cvprac-rb). Pull-requests
|
141
|
+
must include relevant unittests and updated docstrings to be accepted.
|
142
|
+
|
143
|
+
This project is intended to be a safe, welcoming space for collaboration, and
|
144
|
+
contributors are expected to adhere to the [Contributor
|
145
|
+
Covenant](http://contributor-covenant.org) code of conduct.
|
146
|
+
|
147
|
+
## Support
|
148
|
+
|
149
|
+
For support, please open an
|
150
|
+
[issue](https://github.com/arista-aristanetworks/cvprac-rb) on GitHub or
|
151
|
+
contact eosplus@arista.com. Commercial support agreements are available
|
152
|
+
through your Arista account team.
|
data/Rakefile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# Rakefile
|
2
|
+
require 'bump/tasks'
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'ci/reporter/rake/rspec'
|
5
|
+
require 'github_changelog_generator/task'
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
require 'rubocop/rake_task'
|
8
|
+
require 'yard'
|
9
|
+
|
10
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
11
|
+
require 'cvprac/version'
|
12
|
+
|
13
|
+
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
|
14
|
+
config.future_release = Cvprac::VERSION
|
15
|
+
end
|
16
|
+
|
17
|
+
RuboCop::RakeTask.new
|
18
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
19
|
+
task.rspec_opts = ['--color', '--format', 'documentation']
|
20
|
+
end
|
21
|
+
|
22
|
+
namespace :spec do
|
23
|
+
RSpec::Core::RakeTask.new(:unit) do |task|
|
24
|
+
task.pattern = 'spec/unit/**/*_spec.rb'
|
25
|
+
task.rspec_opts = ['--color', '--format', 'documentation']
|
26
|
+
end
|
27
|
+
|
28
|
+
RSpec::Core::RakeTask.new(:system) do |task|
|
29
|
+
task.pattern = 'spec/system/**/*_spec.rb'
|
30
|
+
task.rspec_opts = ['--color', '--format', 'documentation']
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
YARD::Rake::YardocTask.new do |t|
|
35
|
+
t.files = ['lib/**/*.rb']
|
36
|
+
end
|
37
|
+
|
38
|
+
desc 'Prep CI RSpec tests'
|
39
|
+
task :ci_prep do
|
40
|
+
require 'rubygems'
|
41
|
+
begin
|
42
|
+
gem 'ci_reporter'
|
43
|
+
require 'ci/reporter/rake/rspec'
|
44
|
+
ENV['CI_REPORTS'] = 'results'
|
45
|
+
rescue LoadError
|
46
|
+
puts 'Missing ci_reporter gem. You must have the ci_reporter gem ' \
|
47
|
+
'installed to run the CI spec tests'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
desc 'Run the CI RSpec tests'
|
52
|
+
task ci_spec: [:ci_prep, 'ci:setup:rspec', 'spec:unit']
|
53
|
+
|
54
|
+
task checks: %I[rubocop spec:unit yard]
|
55
|
+
task default: %I[rubocop spec:unit yard]
|
data/cvprac.gemspec
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'cvprac/version'
|
6
|
+
|
7
|
+
# rubocop:disable Style/UnneededPercentQ
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
spec.name = 'cvprac'
|
10
|
+
spec.version = Cvprac::VERSION
|
11
|
+
spec.authors = ['Arista Networks']
|
12
|
+
spec.email = ['eosplus-dev@arista.com']
|
13
|
+
spec.summary = %q(Arista REST API Client for CloudVision Portal)
|
14
|
+
spec.description = %q(Arista REST API Client for CloudVision Portal)
|
15
|
+
spec.homepage = 'https://github.com/arista-aristanetworks/cvprac-rb'
|
16
|
+
spec.license = 'BSD-3-Clause'
|
17
|
+
|
18
|
+
# NOTE: This may cause issues on Jenkins in detached head
|
19
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
20
|
+
f.match(%r{^(bin|test|spec|features)/})
|
21
|
+
end
|
22
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
23
|
+
spec.require_paths = ['lib']
|
24
|
+
|
25
|
+
spec.metadata['yard.run'] = 'yri' # use "yard" to build full HTML docs.
|
26
|
+
|
27
|
+
# spec.add_runtime_dependency 'inifile', '~> 0'
|
28
|
+
spec.add_runtime_dependency 'http-cookie'
|
29
|
+
spec.add_runtime_dependency 'require_all'
|
30
|
+
|
31
|
+
spec.add_development_dependency 'bump'
|
32
|
+
spec.add_development_dependency 'bundler'
|
33
|
+
spec.add_development_dependency 'ci_reporter'
|
34
|
+
spec.add_development_dependency 'ci_reporter_rspec'
|
35
|
+
spec.add_development_dependency 'fuubar'
|
36
|
+
spec.add_development_dependency 'github_changelog_generator'
|
37
|
+
spec.add_development_dependency 'guard'
|
38
|
+
spec.add_development_dependency 'guard-rspec'
|
39
|
+
spec.add_development_dependency 'json'
|
40
|
+
spec.add_development_dependency 'pry'
|
41
|
+
spec.add_development_dependency 'pry-remote'
|
42
|
+
spec.add_development_dependency 'pry-nav'
|
43
|
+
spec.add_development_dependency 'rake'
|
44
|
+
spec.add_development_dependency 'rb-readline'
|
45
|
+
spec.add_development_dependency 'rspec'
|
46
|
+
spec.add_development_dependency 'rspec-core'
|
47
|
+
spec.add_development_dependency 'rspec-expectations'
|
48
|
+
spec.add_development_dependency 'rspec-mocks'
|
49
|
+
spec.add_development_dependency 'rspec-nc'
|
50
|
+
spec.add_development_dependency 'rubocop'
|
51
|
+
spec.add_development_dependency 'simplecov'
|
52
|
+
spec.add_development_dependency 'simplecov-rcov'
|
53
|
+
spec.add_development_dependency 'webmock'
|
54
|
+
spec.add_development_dependency 'yard'
|
55
|
+
|
56
|
+
spec.required_ruby_version = '>= 1.9.3'
|
57
|
+
end
|
data/lib/cvprac.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# BSD 3-Clause License
|
2
|
+
#
|
3
|
+
# Copyright (c) 2016, Arista Networks EOS+
|
4
|
+
# All rights reserved.
|
5
|
+
#
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
7
|
+
# modification, are permitted provided that the following conditions are met:
|
8
|
+
#
|
9
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
10
|
+
# list of conditions and the following disclaimer.
|
11
|
+
#
|
12
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
13
|
+
# this list of conditions and the following disclaimer in the documentation
|
14
|
+
# and/or other materials provided with the distribution.
|
15
|
+
#
|
16
|
+
# * Neither the name Arista nor the names of its
|
17
|
+
# contributors may be used to endorse or promote products derived from
|
18
|
+
# this software without specific prior written permission.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
23
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
24
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
25
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
26
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
27
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
28
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
|
31
|
+
require 'cvprac/version'
|
32
|
+
require 'cvprac/client_errors'
|
33
|
+
require 'cvprac/client'
|
34
|
+
require 'cvprac/api'
|
35
|
+
|
36
|
+
# Top level definition of Cvprac
|
37
|
+
#
|
38
|
+
module Cvprac
|
39
|
+
# Your code goes here...
|
40
|
+
true
|
41
|
+
end
|
data/lib/cvprac/api.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# BSD 3-Clause License
|
4
|
+
#
|
5
|
+
# Copyright (c) 2017, Arista Networks EOS+
|
6
|
+
# All rights reserved.
|
7
|
+
#
|
8
|
+
# Redistribution and use in source and binary forms, with or without
|
9
|
+
# modification, are permitted provided that the following conditions are met:
|
10
|
+
#
|
11
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
12
|
+
# list of conditions and the following disclaimer.
|
13
|
+
#
|
14
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
15
|
+
# this list of conditions and the following disclaimer in the documentation
|
16
|
+
# and/or other materials provided with the distribution.
|
17
|
+
#
|
18
|
+
# * Neither the name Arista nor the names of its
|
19
|
+
# contributors may be used to endorse or promote products derived from
|
20
|
+
# this software without specific prior written permission.
|
21
|
+
#
|
22
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
25
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
26
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
27
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
28
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
29
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
30
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
31
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
32
|
+
#
|
33
|
+
|
34
|
+
require 'json'
|
35
|
+
require 'pp'
|
36
|
+
require 'require_all'
|
37
|
+
require_rel 'api/*.rb'
|
38
|
+
|
39
|
+
# Abstract methods for interacting with Arista CloudVision
|
40
|
+
#
|
41
|
+
# CvpApi provides high-level, convenience methods which utilize CvpClient for
|
42
|
+
# handling communications with CVP.
|
43
|
+
#
|
44
|
+
# @example Basic usage
|
45
|
+
# require 'cvprac'
|
46
|
+
# cvp = CvpClient.new
|
47
|
+
# cvp.connect(['cvp1', 'cvp2', 'cvp3'], 'cvpadmin', 'arista123')
|
48
|
+
# api = CvpApi.new(cvp)
|
49
|
+
# result = api.get_cvp_info
|
50
|
+
# print result
|
51
|
+
# {"version"=>"2016.1.1"}
|
52
|
+
#
|
53
|
+
# @author Arista EOS+ Consulting Services <eosplus-dev@arista.com>
|
54
|
+
class CvpApi
|
55
|
+
# Methods are split into modules by subject. Pull mothods back into the
|
56
|
+
# main class here. New modules in lib/cvprac/api/ must be added.
|
57
|
+
include Cvprac::Api::Info
|
58
|
+
include Cvprac::Api::Configlet
|
59
|
+
include Cvprac::Api::Provisioning
|
60
|
+
include Cvprac::Api::Inventory
|
61
|
+
include Cvprac::Api::Task
|
62
|
+
|
63
|
+
# Initialize a new CvpClient object
|
64
|
+
#
|
65
|
+
# @param [CvpClient] clnt CvpClient object
|
66
|
+
# @param opts [Hash] optional parameters
|
67
|
+
# @option opts [Fixnum] :request_timeout (30) Max seconds for a request
|
68
|
+
def initialize(clnt, **opts)
|
69
|
+
opts = { request_timeout: 30 }.merge(opts)
|
70
|
+
@clnt = clnt
|
71
|
+
@request_timeout = opts[:request_timeout]
|
72
|
+
end
|
73
|
+
|
74
|
+
# @see #CvpClient.log
|
75
|
+
def log(severity = Logger::INFO, msg = nil)
|
76
|
+
msg = yield if block_given?
|
77
|
+
@clnt.log(severity, msg)
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,309 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# BSD 3-Clause License
|
4
|
+
#
|
5
|
+
# Copyright (c) 2017, Arista Networks EOS+
|
6
|
+
# All rights reserved.
|
7
|
+
#
|
8
|
+
# Redistribution and use in source and binary forms, with or without
|
9
|
+
# modification, are permitted provided that the following conditions are met:
|
10
|
+
#
|
11
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
12
|
+
# list of conditions and the following disclaimer.
|
13
|
+
#
|
14
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
15
|
+
# this list of conditions and the following disclaimer in the documentation
|
16
|
+
# and/or other materials provided with the distribution.
|
17
|
+
#
|
18
|
+
# * Neither the name Arista nor the names of its
|
19
|
+
# contributors may be used to endorse or promote products derived from
|
20
|
+
# this software without specific prior written permission.
|
21
|
+
#
|
22
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
25
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
26
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
27
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
28
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
29
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
30
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
31
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
32
|
+
#
|
33
|
+
|
34
|
+
# @author Arista EOS+ Consulting Services <eosplus-dev@arista.com>
|
35
|
+
module Cvprac
|
36
|
+
# Cvprac::Api namespace
|
37
|
+
module Api
|
38
|
+
# CVP Configlet api methods
|
39
|
+
# rubocop:disable Metrics/ModuleLength
|
40
|
+
module Configlet
|
41
|
+
# @!group Configlet Method Summary
|
42
|
+
|
43
|
+
# Add configlet
|
44
|
+
#
|
45
|
+
# @param [String] name The name of the desired configlet
|
46
|
+
# @param [String] config Multiline string of EOS configuration
|
47
|
+
#
|
48
|
+
# @return [String, nil] The key for the new configlet. nil on failure
|
49
|
+
#
|
50
|
+
# @raise CvpApiError on failure. Common: errorCode: 132518: Data already
|
51
|
+
# exists in Database.
|
52
|
+
#
|
53
|
+
# @example
|
54
|
+
# result = api.add_configlet('api_test_3',
|
55
|
+
# "interface Ethernet1\n shutdown")
|
56
|
+
def add_configlet(name, config)
|
57
|
+
log(Logger::DEBUG) do
|
58
|
+
"add_configlet: #{name} Config: #{config.inspect}"
|
59
|
+
end
|
60
|
+
resp = @clnt.post('/configlet/addConfiglet.do',
|
61
|
+
body: { name: name, config: config.to_s }.to_json)
|
62
|
+
log(Logger::DEBUG) do
|
63
|
+
"add_configlet: #{name} Response: #{resp.inspect}"
|
64
|
+
end
|
65
|
+
resp['data']
|
66
|
+
end
|
67
|
+
|
68
|
+
# Update configlet
|
69
|
+
#
|
70
|
+
# @param [String] name The name of the desired configlet
|
71
|
+
# @param [String] key The configlet key
|
72
|
+
# @param [Hash] config The configlet definition
|
73
|
+
#
|
74
|
+
# @return [String] The key for the new configlet
|
75
|
+
#
|
76
|
+
# @example
|
77
|
+
# result = api.update_configlet('api_test_3', configlet_new['key'],
|
78
|
+
# "interface Ethernet1\n shutdown")
|
79
|
+
def update_configlet(name, key, config)
|
80
|
+
log(Logger::DEBUG) do
|
81
|
+
"update_configlet: #{name} Key: #{key} Config: #{config.inspect}"
|
82
|
+
end
|
83
|
+
data = @clnt.post('/configlet/updateConfiglet.do',
|
84
|
+
body: { name: name, key: key,
|
85
|
+
config: config }.to_json)
|
86
|
+
data['data']
|
87
|
+
end
|
88
|
+
|
89
|
+
# Delete configlet
|
90
|
+
#
|
91
|
+
# @param [String] name The name of the desired configlet
|
92
|
+
# @param [String] key The configlet key
|
93
|
+
#
|
94
|
+
# @return [String] The request result
|
95
|
+
#
|
96
|
+
# @raise CvpApiError on failure. Common when name or key is invalid:
|
97
|
+
# errorCode: 132718: Invalid input parameters.
|
98
|
+
def delete_configlet(name, key)
|
99
|
+
log(Logger::DEBUG) { "delete_configlet: #{name} Key: #{key}" }
|
100
|
+
resp = @clnt.post('/configlet/deleteConfiglet.do',
|
101
|
+
body: [{ name: name, key: key }].to_json)
|
102
|
+
resp['data']
|
103
|
+
end
|
104
|
+
|
105
|
+
# Get all configlet definitions
|
106
|
+
#
|
107
|
+
# @param [Fixnum] start_i (0) Start index of pagination
|
108
|
+
# @param [Fixnum] end_i (0) End index for pagination. 0 will get all
|
109
|
+
# @param [String] type ('Configlet') Possible types are All, Configlet,
|
110
|
+
# Builder, Draft, Builderwithoutdraft, Generated, IgnoreDraft
|
111
|
+
#
|
112
|
+
# @return [Hash] configlet definitions with keys: total and data (a list
|
113
|
+
# of definitions)
|
114
|
+
#
|
115
|
+
# @example
|
116
|
+
# configlet = api.get_configlets()
|
117
|
+
def get_configlets(start_i = 0, end_i = 0, type = 'Configlet')
|
118
|
+
log(Logger::DEBUG) do
|
119
|
+
"get_configlets: start=#{start_i}, end=#{end_i}, type=#{type}"
|
120
|
+
end
|
121
|
+
@clnt.get('/configlet/getConfiglets.do', data: { startIndex: start_i,
|
122
|
+
endIndex: end_i,
|
123
|
+
type: type })
|
124
|
+
end
|
125
|
+
|
126
|
+
# Get configlet definition by configlet name
|
127
|
+
#
|
128
|
+
# @param [String] name The name of the desired configlet
|
129
|
+
#
|
130
|
+
# @return [Hash] configlet definition
|
131
|
+
#
|
132
|
+
# @example
|
133
|
+
# configlet = api.get_configlet_by_name('api_test_3')
|
134
|
+
def get_configlet_by_name(name)
|
135
|
+
log(Logger::DEBUG) { "get_configlet_by_name: #{name}" }
|
136
|
+
@clnt.get('/configlet/getConfigletByName.do', data: { name: name })
|
137
|
+
end
|
138
|
+
|
139
|
+
# Get devices associated with a configlet name
|
140
|
+
#
|
141
|
+
# @param [String] name The name of the desired configlet
|
142
|
+
# @param opts [Hash] Optional arguments
|
143
|
+
# @option opts [String] :queryparam Search string
|
144
|
+
# @option opts [Fixnum] :start_index (0) Start index for pagination
|
145
|
+
# @option opts [Fixnum] :end_index (0) End index for pagination
|
146
|
+
#
|
147
|
+
# @return [Hash] configlet definition
|
148
|
+
#
|
149
|
+
# @example
|
150
|
+
# configlet = api.get_configlet_by_name('api_test_3')
|
151
|
+
#
|
152
|
+
def get_devices_by_configlet_name(name, **opts)
|
153
|
+
opts = { queryparam: nil,
|
154
|
+
start_index: 0,
|
155
|
+
end_index: 0 }.merge(opts)
|
156
|
+
log(Logger::DEBUG) { "get_configlet_by_name: #{name}" }
|
157
|
+
@clnt.get('/configlet/getAppliedDevices.do',
|
158
|
+
data: { configletName: name,
|
159
|
+
queryparam: opts[:queryparam],
|
160
|
+
startIndex: opts[:start_index],
|
161
|
+
endIndex: opts[:end_index] })
|
162
|
+
end
|
163
|
+
|
164
|
+
# Apply configlets to a device
|
165
|
+
#
|
166
|
+
# @param [String] app_name The name to use in the info field
|
167
|
+
# @param [Hash] device Device definition from #get_device_by_id()
|
168
|
+
# @param [Hash] new_configlets List of configlet name & key pairs
|
169
|
+
#
|
170
|
+
# @return [Hash] Hash including status and a list of task IDs created,
|
171
|
+
# if any
|
172
|
+
#
|
173
|
+
# @example
|
174
|
+
# result = api.apply_configlets_to_device('test',
|
175
|
+
# {...},
|
176
|
+
# [{'name' => 'new_configlet',
|
177
|
+
# 'key' => '...'}])
|
178
|
+
# => {"data"=>{"taskIds"=>["8"], "status"=>"success"}}
|
179
|
+
#
|
180
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
181
|
+
def apply_configlets_to_device(app_name, device, new_configlets)
|
182
|
+
log(Logger::DEBUG) { "apply_configlets_to_device: #{app_name}" }
|
183
|
+
|
184
|
+
# get the list of existing configlets
|
185
|
+
configlets = get_configlets_by_device_id(device['systemMacAddress'])
|
186
|
+
|
187
|
+
# Get a list of the configlet names and keys
|
188
|
+
cnames = []
|
189
|
+
ckeys = []
|
190
|
+
configlets.each do |configlet|
|
191
|
+
cnames << configlet['name']
|
192
|
+
ckeys << configlet['key']
|
193
|
+
end
|
194
|
+
|
195
|
+
new_configlets.each do |configlet|
|
196
|
+
cnames << configlet['name']
|
197
|
+
ckeys << configlet['key']
|
198
|
+
end
|
199
|
+
|
200
|
+
info = "#{app_name}: Configlet Assign: to Device #{device['fqdn']}"
|
201
|
+
info_preview = "<b>Configlet Assign:</b> to Device #{device['fqdn']}"
|
202
|
+
data = { data: [{ id: 1,
|
203
|
+
info: info,
|
204
|
+
infoPreview: info_preview,
|
205
|
+
note: '',
|
206
|
+
action: 'associate',
|
207
|
+
nodeType: 'configlet',
|
208
|
+
nodeId: '',
|
209
|
+
configletList: ckeys,
|
210
|
+
configletNamesList: cnames,
|
211
|
+
ignoreConfigletNamesList: [],
|
212
|
+
ignoreConfigletList: [],
|
213
|
+
configletBuilderList: [],
|
214
|
+
configletBuilderNamesList: [],
|
215
|
+
ignoreConfigletBuilderList: [],
|
216
|
+
ignoreConfigletBuilderNamesList: [],
|
217
|
+
toId: device['systemMacAddress'],
|
218
|
+
toIdType: 'netelement',
|
219
|
+
fromId: '',
|
220
|
+
nodeName: '',
|
221
|
+
fromName: '',
|
222
|
+
toName: device['fqdn'],
|
223
|
+
nodeIpAddress: device['ipAddress'],
|
224
|
+
nodeTargetIpAddress: device['ipAddress'],
|
225
|
+
childTasks: [],
|
226
|
+
parentTask: '' }] }
|
227
|
+
log(Logger::DEBUG) do
|
228
|
+
"#{__method__}: saveTopology data #{data['data']}"
|
229
|
+
end
|
230
|
+
add_temp_action(data)
|
231
|
+
save_topology_v2([])
|
232
|
+
end
|
233
|
+
|
234
|
+
# Remove configlets from a device
|
235
|
+
#
|
236
|
+
# @param [String] app_name The name to use in the info field
|
237
|
+
# @param [Hash] device Device definition from #get_device_by_id()
|
238
|
+
# @param [Hash] configlets List of configlet name & key pairs to remove
|
239
|
+
#
|
240
|
+
# @return [Hash] Hash including status and a list of task IDs created,
|
241
|
+
# if any
|
242
|
+
#
|
243
|
+
# @example
|
244
|
+
# result = api.remove_configlets_from_device('test',
|
245
|
+
# {...},
|
246
|
+
# [{'name' => 'configlet',
|
247
|
+
# 'key' => '...'}])
|
248
|
+
# => {"data"=>{"taskIds"=>["8"], "status"=>"success"}}
|
249
|
+
#
|
250
|
+
def remove_configlets_from_device(app_name, device, configlets)
|
251
|
+
log(Logger::DEBUG) { "#{__method__}: #{app_name}" }
|
252
|
+
|
253
|
+
# get the list of existing configlets
|
254
|
+
curr_cfglts = get_configlets_by_device_id(device['systemMacAddress'])
|
255
|
+
|
256
|
+
# Get a list of the configlet names and keys
|
257
|
+
keep_cnames = []
|
258
|
+
keep_ckeys = []
|
259
|
+
curr_cfglts.each do |configlet|
|
260
|
+
next if configlets.include?('name' => configlet['name'],
|
261
|
+
'key' => configlet['key'])
|
262
|
+
keep_cnames << configlet['name']
|
263
|
+
keep_ckeys << configlet['key']
|
264
|
+
end
|
265
|
+
|
266
|
+
del_cnames = []
|
267
|
+
del_ckeys = []
|
268
|
+
configlets.each do |configlet|
|
269
|
+
del_cnames << configlet['name']
|
270
|
+
del_ckeys << configlet['key']
|
271
|
+
end
|
272
|
+
|
273
|
+
info = "#{app_name}: Configlet Remove from Device #{device['fqdn']}"
|
274
|
+
info_preview = "<b>Configlet Remove:</b> from Device #{device['fqdn']}"
|
275
|
+
data = { data: [{ id: 1,
|
276
|
+
info: info,
|
277
|
+
infoPreview: info_preview,
|
278
|
+
note: '',
|
279
|
+
action: 'associate',
|
280
|
+
nodeType: 'configlet',
|
281
|
+
nodeId: '',
|
282
|
+
configletList: keep_ckeys,
|
283
|
+
configletNamesList: keep_cnames,
|
284
|
+
ignoreConfigletNamesList: del_cnames,
|
285
|
+
ignoreConfigletList: del_ckeys,
|
286
|
+
configletBuilderList: [],
|
287
|
+
configletBuilderNamesList: [],
|
288
|
+
ignoreConfigletBuilderList: [],
|
289
|
+
ignoreConfigletBuilderNamesList: [],
|
290
|
+
toId: device['systemMacAddress'],
|
291
|
+
toIdType: 'netelement',
|
292
|
+
fromId: '',
|
293
|
+
nodeName: '',
|
294
|
+
fromName: '',
|
295
|
+
toName: device['fqdn'],
|
296
|
+
nodeIpAddress: device['ipAddress'],
|
297
|
+
nodeTargetIpAddress: device['ipAddress'],
|
298
|
+
childTasks: [],
|
299
|
+
parentTask: '' }] }
|
300
|
+
log(Logger::DEBUG) do
|
301
|
+
"#{__method__}: saveTopology data #{data['data']}"
|
302
|
+
end
|
303
|
+
add_temp_action(data)
|
304
|
+
save_topology_v2([])
|
305
|
+
end
|
306
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|