lmc 0.4.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b3a6cc095210c99890c8ebb6b1c24f18fdee5ace
4
+ data.tar.gz: c32528dfb1a87d9238db2c96f23297dbdd75660f
5
+ SHA512:
6
+ metadata.gz: 32ff5ff2362f3534b20e8dab058cc0faccf9f754fa7858b89e5693f26be5c7d2adab48af988660df597242323bcb58f39f46440ba75efd938d8517f7dbaf468c
7
+ data.tar.gz: b9c2259efdb008fca13912c5066a966d66b65f25a92843413d2447bc0ee20011365869f1514f0f1c265b73f0ea64fd2176892b475bdf481e6e9115c13b9f958a
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /doc/
5
+ /pkg/
6
+ /spec/reports/
7
+ /tmp/
8
+ .idea/workspace.xml
9
+ .idea/tasks.xml
10
+ .idea/.rakeTasks
11
+ Gemfile.lock
12
+ test_credentials.yaml
13
+ lmc-*.gem
@@ -0,0 +1,13 @@
1
+ <component name="InspectionProjectProfileManager">
2
+ <profile version="1.0">
3
+ <option name="myName" value="Project Default" />
4
+ <inspection_tool class="RubyInstanceMethodNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
5
+ <scope name="Tests" level="WARNING" enabled="false" />
6
+ </inspection_tool>
7
+ <inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
8
+ <option name="processCode" value="true" />
9
+ <option name="processLiterals" value="true" />
10
+ <option name="processComments" value="true" />
11
+ </inspection_tool>
12
+ </profile>
13
+ </component>
data/.idea/lmc.iml ADDED
@@ -0,0 +1,31 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="RUBY_MODULE" version="4">
3
+ <component name="ModuleRunConfigurationManager">
4
+ <shared />
5
+ </component>
6
+ <component name="NewModuleRootManager">
7
+ <content url="file://$MODULE_DIR$" />
8
+ <orderEntry type="jdk" jdkName="rbenv: 2.4.1" jdkType="RUBY_SDK" />
9
+ <orderEntry type="sourceFolder" forTests="false" />
10
+ <orderEntry type="library" scope="PROVIDED" name="ansi (v1.5.0, rbenv: 2.4.1) [gem]" level="application" />
11
+ <orderEntry type="library" scope="PROVIDED" name="builder (v3.2.3, rbenv: 2.4.1) [gem]" level="application" />
12
+ <orderEntry type="library" scope="PROVIDED" name="bundler (v1.16.1, rbenv: 2.4.1) [gem]" level="application" />
13
+ <orderEntry type="library" scope="PROVIDED" name="docile (v1.1.5, rbenv: 2.4.1) [gem]" level="application" />
14
+ <orderEntry type="library" scope="PROVIDED" name="domain_name (v0.5.20170404, rbenv: 2.4.1) [gem]" level="application" />
15
+ <orderEntry type="library" scope="PROVIDED" name="http-cookie (v1.0.3, rbenv: 2.4.1) [gem]" level="application" />
16
+ <orderEntry type="library" scope="PROVIDED" name="json (v2.1.0, rbenv: 2.4.1) [gem]" level="application" />
17
+ <orderEntry type="library" scope="PROVIDED" name="mime-types (v3.1, rbenv: 2.4.1) [gem]" level="application" />
18
+ <orderEntry type="library" scope="PROVIDED" name="mime-types-data (v3.2016.0521, rbenv: 2.4.1) [gem]" level="application" />
19
+ <orderEntry type="library" scope="PROVIDED" name="minitest (v5.11.3, rbenv: 2.4.1) [gem]" level="application" />
20
+ <orderEntry type="library" scope="PROVIDED" name="minitest-reporters (v1.1.19, rbenv: 2.4.1) [gem]" level="application" />
21
+ <orderEntry type="library" scope="PROVIDED" name="netrc (v0.11.0, rbenv: 2.4.1) [gem]" level="application" />
22
+ <orderEntry type="library" scope="PROVIDED" name="rake (v10.5.0, rbenv: 2.4.1) [gem]" level="application" />
23
+ <orderEntry type="library" scope="PROVIDED" name="recursive-open-struct (v1.1.0, rbenv: 2.4.1) [gem]" level="application" />
24
+ <orderEntry type="library" scope="PROVIDED" name="rest-client (v2.0.2, rbenv: 2.4.1) [gem]" level="application" />
25
+ <orderEntry type="library" scope="PROVIDED" name="ruby-progressbar (v1.9.0, rbenv: 2.4.1) [gem]" level="application" />
26
+ <orderEntry type="library" scope="PROVIDED" name="simplecov (v0.15.1, rbenv: 2.4.1) [gem]" level="application" />
27
+ <orderEntry type="library" scope="PROVIDED" name="simplecov-html (v0.10.2, rbenv: 2.4.1) [gem]" level="application" />
28
+ <orderEntry type="library" scope="PROVIDED" name="unf (v0.1.4, rbenv: 2.4.1) [gem]" level="application" />
29
+ <orderEntry type="library" scope="PROVIDED" name="unf_ext (v0.0.7.5, rbenv: 2.4.1) [gem]" level="application" />
30
+ </component>
31
+ </module>
data/.idea/misc.xml ADDED
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectRootManager" version="2" project-jdk-name="rbenv: 1.9.3-p551" project-jdk-type="RUBY_SDK" />
4
+ </project>
data/.idea/modules.xml ADDED
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/lmc.iml" filepath="$PROJECT_DIR$/.idea/lmc.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
data/.idea/vcs.xml ADDED
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
+ </component>
6
+ </project>
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.4.1
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.1
5
+ before_install: gem install bundler -v 1.16.1
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in lmc.gemspec
6
+ gemspec
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # Lmc
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/lmc`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'lmc'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install lmc
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ### Tests against real LMC instances
34
+
35
+ #### credentials file
36
+ email: testuser@foocorp.example
37
+ password: Foobar1+
38
+ lmc_url: https://my.lmc.example
39
+ ## Contributing
40
+
41
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/lmc.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "lmc"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,3 @@
1
+ assets
2
+ index.html
3
+ .resultset.json*
@@ -0,0 +1,5 @@
1
+ {
2
+ "result": {
3
+ "covered_percent": 83.38
4
+ }
5
+ }
data/lib/lmc.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'json'
2
+ require 'restclient'
3
+
4
+ Dir.glob(File.expand_path("../lmc/*.rb", __FILE__)).each do |file|
5
+ require file
6
+ end
7
+
8
+ Dir.glob(File.expand_path("../lmc/exceptions/*.rb", __FILE__)).each do |file|
9
+ require file
10
+ end
11
+
12
+ module LMC
13
+ def self.useful
14
+ return true
15
+ end
16
+ end
@@ -0,0 +1,175 @@
1
+ require_relative 'account_manager.rb'
2
+ require_relative 'entity'
3
+ module LMC
4
+ class Account < Entity
5
+ ROOT_ACCOUNT_UUID = '9ec458c2-d05f-3004-96f0-ebe73fa20de8'
6
+ attr_accessor :name
7
+ attr_reader :id, :state, :type
8
+
9
+ def self.get(id)
10
+ cloud = Cloud.instance
11
+ result = cloud.get ["cloud-service-auth", "accounts", id.to_s]
12
+ return Account.new(result.body)
13
+ end
14
+
15
+ def self.get_by_uuid uuid
16
+ raise "Missing argument" if uuid.nil?
17
+ return self.get uuid
18
+ end
19
+
20
+ def self.get_by_name(name, type = nil)
21
+ raise "Missing argument" if name.nil?
22
+ accounts = Cloud.instance.get_accounts_objects.select do |a|
23
+ (name.nil? || a.name == name) && (type.nil? || a.type == type)
24
+ end
25
+ if accounts.length == 1
26
+ return accounts[0]
27
+ elsif accounts.length == 0
28
+ raise 'Did not find account'
29
+ else
30
+ raise 'Account name not unique'
31
+ end
32
+ end
33
+
34
+
35
+ def initialize(data)
36
+ @cloud = LMC::Cloud.instance
37
+ apply_data(data)
38
+ end
39
+
40
+ #returns itself, allows chaining
41
+ def save
42
+ response = if @id.nil?
43
+ @cloud.auth_for_accounts [@parent]
44
+ @cloud.post ["cloud-service-auth", "accounts"], self
45
+ else
46
+ @cloud.post path, self
47
+ end
48
+ apply_data(response.body)
49
+ return self
50
+ end
51
+
52
+ def delete
53
+ if @id != nil
54
+ @cloud.auth_for_accounts [@id]
55
+ deleted = @cloud.delete ["cloud-service-auth", "accounts", @id]
56
+ if deleted.code == 200
57
+ @id = nil
58
+ return true
59
+ else
60
+ raise "unable to delete account: #{deleted.body.message}"
61
+ end
62
+ end
63
+ end
64
+
65
+ def exists?
66
+ # noch ungelöst: woran mache ich fest, ob das objekt in der DB schon da ist.
67
+ # Bleibt wohl nix außer manuell auf @id != nil zu checken.
68
+ @id != nil
69
+ end
70
+
71
+ def members
72
+ ids = Cloud.instance.get ["cloud-service-auth", "accounts", @id, 'members'], {"select" => "id"}
73
+ puts ids.inspect if Cloud.debug
74
+ principals = ids.map do |principal_id|
75
+ response = Cloud.instance.get ["cloud-service-auth", "accounts", @id, 'members', principal_id]
76
+ if response.code == 200
77
+ principal = response.body
78
+ else
79
+ raise "ERROR: #{response.code} #{response.body.message}"
80
+ end
81
+ puts principal.inspect if Cloud.debug
82
+ principal
83
+ end
84
+ return principals
85
+ end
86
+
87
+ def find_member_by_name name
88
+ members.find {|m| m.name == name}
89
+ end
90
+
91
+ #def update_member(principal_id, data)
92
+ # response = @cloud.post ["cloud-service-auth", "accounts", id, 'members', principal_id], data
93
+ # return response
94
+ #end
95
+
96
+ def remove_membership(member_id)
97
+ response = @cloud.delete ["cloud-service-auth", "accounts", id, "members", member_id]
98
+ end
99
+
100
+ def remove_membership_self
101
+ response = @cloud.delete ["cloud-service-auth", "accounts", id, "members", "self"]
102
+ end
103
+
104
+ def authorities
105
+ response = @cloud.get ['cloud-service-auth', 'accounts', id, 'authorities']
106
+ if response.code == 200
107
+ return response.body
108
+ else
109
+ raise 'Unable to get authorities'
110
+ end
111
+ end
112
+
113
+ def children
114
+ @cloud.auth_for_account self
115
+ response = @cloud.get ['cloud-service-auth', 'accounts', id, 'children']
116
+ response.map {|child| Account.new child}
117
+ end
118
+
119
+ def logs
120
+ # https://lmctest/cloud-service-logging/accounts/6392b234-b11c-498a-a077-a5f5b23c54a0/logs?lang=DE
121
+ cloud = Cloud.instance
122
+ cloud.auth_for_accounts [id]
123
+ cloud.get(["cloud-service-logging", "accounts", id, "logs?lang=DE"]).body
124
+ end
125
+
126
+ def sites
127
+ # private clouds can not have sites
128
+ return [] if @type == "PRIVATE_CLOUD"
129
+ @cloud.auth_for_accounts([id])
130
+ response = @cloud.get ["cloud-service-devices", "accounts", id, "sites"]
131
+ if response.code == 200
132
+ return response.body.map {|data|
133
+ Site.new(data, self)
134
+ }
135
+ elsif response.code == 404
136
+ return []
137
+ end
138
+ end
139
+
140
+ def config_updatestates
141
+ @cloud.auth_for_accounts([id])
142
+ response = @cloud.get ["cloud-service-config", "configdevice", "accounts", id, "updatestates"]
143
+ return LMC::Configstates.new response.body
144
+ end
145
+
146
+ def to_json(*a)
147
+ {
148
+ "name" => @name,
149
+ "state" => @state,
150
+ "type" => @type,
151
+ "parent" => @parent
152
+ }.to_json(*a)
153
+ end
154
+
155
+ def to_s
156
+ "#{name}"
157
+ end
158
+
159
+ private
160
+
161
+ ## should be put into entity or such
162
+ def path
163
+ ["cloud-service-auth", "accounts", @id].join("/")
164
+ end
165
+
166
+ def apply_data(data)
167
+ @id = data["id"]
168
+ @parent = data["parent"]
169
+ @name = data["name"]
170
+ @state = data["state"]
171
+ @type = data["type"]
172
+ end
173
+
174
+ end
175
+ end
data/lib/lmc/Cloud.rb ADDED
@@ -0,0 +1,230 @@
1
+ require 'base64'
2
+ require 'json'
3
+ require 'restclient'
4
+
5
+ module LMC
6
+ class Cloud
7
+ #include ActionView::Helpers::DateHelper
8
+
9
+ class << self
10
+ attr_writer :cloud_host, :user, :password
11
+ attr_accessor :verbose, :debug, :verify_tls, :use_tls
12
+ Cloud.use_tls = true
13
+ Cloud.verify_tls = true
14
+ end
15
+
16
+ # def self.cloud_host=(cloud_host)
17
+ # @@cloud_host = cloud_host
18
+ # end
19
+
20
+ def self.instance(opts = {authorize: true})
21
+ @@inst ||= self.new(@cloud_host, @user, @password, opts[:authorize])
22
+ end
23
+
24
+
25
+ attr_reader :auth_ok, :cloud_host
26
+
27
+ def initialize(cloud_host, user, pass, auth=true)
28
+ @auth_ok = false
29
+ @cloud_host = cloud_host
30
+ @user = user
31
+ @password = pass
32
+ @verify_tls = Cloud.verify_tls
33
+ authorize if auth
34
+ end
35
+
36
+ # hide password from dumps
37
+ def inspect
38
+ "#<Cloud:#{object_id}, #{build_url}>"
39
+ end
40
+
41
+ def get_backstage_serviceinfos
42
+ get "cloud-service-backstage/serviceinfos"
43
+ end
44
+
45
+ def get_accounts
46
+ get "cloud-service-auth/accounts"
47
+ end
48
+
49
+ def get_accounts_objects
50
+ result = get ["cloud-service-auth", "accounts"]
51
+ if result.code == 200
52
+ accounts = result.map do |aj|
53
+ Account.new(aj)
54
+ end
55
+ else
56
+ raise "Unable to fetch accounts: #{result.body.message}"
57
+ end
58
+
59
+ return accounts
60
+ end
61
+
62
+ # functionality should be moved to Account class
63
+ #def get_account(name, type = nil)
64
+ # accounts = get_accounts_objects.select do |a|
65
+ # (name.nil? || a.name == name) && (type.nil? || a.type == type)
66
+ # end
67
+ # if accounts.length == 1
68
+ # return accounts[0]
69
+ # else
70
+ # raise "Did not specify exactly one account"
71
+ # end
72
+ #end
73
+
74
+ def invite_user_to_account(email, account_id, type, authorities = [])
75
+ body = {name: email, state: "ACTIVE", type: type}
76
+ body["authorities"] = authorities
77
+ post ["cloud-service-auth", "accounts", account_id, 'members'], body
78
+ end
79
+
80
+ def get(path, params = nil)
81
+ RestClient.log = ("stdout") if Cloud.debug
82
+ begin
83
+ prepared_headers = headers
84
+ prepared_headers[:params] = params
85
+ args = {
86
+ :method => :get,
87
+ :url => build_url(path),
88
+ :headers => prepared_headers,
89
+ }
90
+ args.merge!(rest_options)
91
+ resp = RestClient::Request.execute args
92
+ return LMCResponse.new(resp)
93
+ rescue RestClient::ExceptionWithResponse => e
94
+ puts "EXCEPTION: " + e.to_s if Cloud.debug
95
+ puts "EX.response: " + e.response.to_s if Cloud.debug
96
+ puts JSON.parse(e.response)["message"] if Cloud.debug
97
+ raise e
98
+ #return LMCResponse.new(e.response)
99
+ end
100
+ end
101
+
102
+ def put(path, body_object)
103
+ RestClient.log = ("stdout") if Cloud.debug
104
+ begin
105
+ args = {
106
+ :method => :put,
107
+ :url => build_url(path),
108
+ :payload => body_object.to_json,
109
+ :headers => headers
110
+
111
+ }
112
+ args.merge!(rest_options)
113
+ resp = RestClient::Request.execute args
114
+ return LMCResponse.new(resp)
115
+ rescue RestClient::ExceptionWithResponse => e
116
+ puts "EXCEPTION: " + e.to_s if Cloud.debug
117
+ puts "EX.response: " + e.response.to_s if Cloud.debug
118
+ puts JSON.parse(e.response)["message"] if Cloud.debug
119
+ return LMCResponse.new(e.response)
120
+ end
121
+ end
122
+
123
+ def post(path, body_object)
124
+ RestClient.log = ("stdout") if Cloud.debug
125
+ begin
126
+ args = {
127
+ :method => :post,
128
+ :url => build_url(path),
129
+ :payload => body_object.to_json,
130
+ :headers => headers
131
+
132
+ }
133
+ args.merge!(rest_options)
134
+ resp = RestClient::Request.execute args
135
+ return LMCResponse.new(resp)
136
+ rescue RestClient::ExceptionWithResponse => e
137
+ puts "EXCEPTION: " + e.to_s if Cloud.debug
138
+ puts "EX.response: " + e.response.to_s if Cloud.debug
139
+ puts JSON.parse(e.response)["message"] if Cloud.debug
140
+ raise e
141
+ end
142
+ end
143
+
144
+ def delete(path, body_object = nil)
145
+ RestClient.log = ("stdout") if Cloud.debug
146
+ begin
147
+ args = {
148
+ :method => :delete,
149
+ :url => build_url(path),
150
+ :payload => body_object.to_json,
151
+ :headers => headers
152
+ }
153
+ args.merge!(rest_options)
154
+ resp = RestClient::Request.execute args
155
+ return LMCResponse.new(resp)
156
+ rescue RestClient::ExceptionWithResponse => e
157
+ puts "EXCEPTION: " + e.to_s if Cloud.debug
158
+ puts "EX.response: " + e.response.to_s if Cloud.debug
159
+ puts JSON.parse(e.response)["message"] if Cloud.debug
160
+ return LMCResponse.new(e.response)
161
+ end
162
+ end
163
+
164
+ ##
165
+ # public accessors
166
+ ##
167
+ def session_token
168
+ @auth_token["value"]
169
+ end
170
+
171
+ def build_url(*path_components)
172
+ protocol = "https"
173
+ if !Cloud.use_tls
174
+ protocol = "http"
175
+ end
176
+ ["#{protocol}://#{@cloud_host}", path_components].flatten.compact.join("/")
177
+ end
178
+
179
+ def auth_for_accounts(account_ids)
180
+ puts "Authorizing for accounts: " + account_ids.to_s if Cloud.debug
181
+ authorize(account_ids)
182
+ end
183
+
184
+ def auth_for_account(account)
185
+ auth_for_accounts([account.id])
186
+ end
187
+
188
+ def accept_tos(tos)
189
+ authorize([], tos)
190
+ end
191
+
192
+
193
+ private
194
+ def authorize(account_ids = [], tos = [])
195
+ begin
196
+ reply = post(["cloud-service-auth", "auth"], {name: @user, password: @password, accountIds: account_ids, termsOfUse: tos})
197
+ puts "authorize reply " + reply.inspect if Cloud.debug
198
+ @auth_token = reply
199
+ @auth_ok = true
200
+ rescue ::RestClient::ExceptionWithResponse => e
201
+ response = JSON.parse(e.response.body)
202
+ if response['code'] == 100
203
+ raise LMC::OutdatedTermsOfUseException.new(response)
204
+ end
205
+ end
206
+ end
207
+
208
+ def auth_bearer
209
+ "Bearer " + session_token
210
+ end
211
+
212
+ def headers
213
+ headers = {}
214
+ headers[:content_type] = 'application/json'
215
+ if @auth_ok
216
+ headers[:Authorization] = auth_bearer
217
+ end
218
+ return headers
219
+ end
220
+
221
+ def rest_options
222
+ options = {}
223
+ if !@verify_tls
224
+ options[:verify_ssl] = false
225
+ end
226
+ return options
227
+ end
228
+ end
229
+
230
+ end
@@ -0,0 +1,14 @@
1
+ module LMC
2
+ class Configstates
3
+ attr_reader :actual, :outdated
4
+
5
+ def initialize(data)
6
+ @actual = data["ACTUAL"]
7
+ @outdated = data["OUTDATED"]
8
+ @actual ||= 0
9
+ @outdated ||= 0
10
+ end
11
+
12
+ end
13
+
14
+ end
data/lib/lmc/Device.rb ADDED
@@ -0,0 +1,72 @@
1
+ module LMC
2
+ class Device
3
+ attr_reader :id, :name, :model, :serial, :heartbeatstate
4
+
5
+ def initialize(data)
6
+ @cloud = Cloud.instance
7
+ @id = data["id"]
8
+ @comment = data["comment"]
9
+ @name = data["status"]["name"]
10
+ @serial = data["status"]["serial"]
11
+ @model = data["status"]["model"]
12
+ @heartbeatstate = data["status"]["heartbeatState"]
13
+ @status = data["status"]
14
+ @account = data["account"]
15
+ end
16
+
17
+ def get_config_for_account(account)
18
+ response = @cloud.get ["cloud-service-config", "configbuilder", "accounts", account.id, "devices", @id, "ui"]
19
+ JSON.parse(JSON.generate(response.body.to_h)) #terrible hack to get it to work for now. needs way to get more raw body_object from Response
20
+ end
21
+
22
+ def set_config_for_account(config, account)
23
+ @cloud.put ["cloud-service-config", "configbuilder", "accounts", account.id, "devices", @id, "ui"], config
24
+ end
25
+
26
+ def get_monitor_widgets(widget_item_ids)
27
+ @cloud.get ["cloud-service-monitoring", @account.id, "devices", @id, "monitordata"], {:widgetItemIds => widget_item_ids.join(",")}
28
+ end
29
+
30
+ def self.get_for_account(account)
31
+ cloud = Cloud.instance
32
+ cloud.auth_for_accounts [account.id]
33
+ list = cloud.get ["cloud-service-devices", "accounts", account.id, "devices"]
34
+ if list.code != 200
35
+ puts "Error getting devices: #{list.body.message}"
36
+ exit 1
37
+ end
38
+ devices = list.map do |data|
39
+ data["account"] = account
40
+ LMC::Device.new(data)
41
+ end
42
+ end
43
+
44
+ def self.get_for_account_id(account_id)
45
+ self.get_for_account Account.get(account_id)
46
+ end
47
+
48
+ def config_state
49
+ @config_state ||= get_config_state
50
+ end
51
+
52
+ def logs
53
+ # https://lmctest/#/project/6392b234-b11c-498a-a077-a5f5b23c54a0/devices/compact/eaafa152-62cf-48a1-be65-b222886daa6d/logging
54
+ #cloud = Cloud.instance
55
+ ##cloud.auth_for_accounts [id]
56
+ #cloud.get ["cloud-service-logging", "accounts", id, "logs?lang=DE"]
57
+ raise "device logs not supported"
58
+ end
59
+
60
+ private
61
+ def get_config_state
62
+ reply = @cloud.get ["cloud-service-config", "configdevice", "accounts", @account.id, "state"], {"deviceIds" => @id}
63
+ if reply.code == 200
64
+ # binding.pry
65
+ DeviceConfigState.new reply.body[@id]
66
+ end
67
+ end
68
+
69
+
70
+ end
71
+
72
+ end
@@ -0,0 +1,53 @@
1
+ require 'ostruct'
2
+ module LMC
3
+ class LMCResponse
4
+
5
+ attr_reader :body, :code, :headers
6
+
7
+ def initialize(response)
8
+ @body_object = {}
9
+ if response.bytesize > 0
10
+ @body_object = JSON.parse response.body
11
+ end
12
+ if @body_object.class == Array
13
+ @body = @body_object.map {|elem|
14
+ if elem.is_a? Hash then
15
+ OpenStruct.new(elem)
16
+ else
17
+ elem
18
+ end}
19
+ elsif @body_object.class == Hash
20
+ @body = OpenStruct.new(@body_object)
21
+ elsif @body_object.class == TrueClass || @body_object.class == FalseClass
22
+ @body = @body_object
23
+ else
24
+ raise "Unknown json parse result"
25
+ end
26
+ @code = response.code
27
+ @headers = response.headers
28
+ end
29
+
30
+ # body_object and these methods allow to use LMCResponse objects in place
31
+ # of the old response which was just the body parsed to a hash or array
32
+ def [](key)
33
+ @body_object[key]
34
+ end
35
+
36
+ def map(&block)
37
+ @body_object.map &block
38
+ end
39
+
40
+ def each(&block)
41
+ @body_object.each &block
42
+ end
43
+
44
+ def to_s
45
+ "Response: Code: #{@code}, Body: #{@body_object.to_s}"
46
+ end
47
+
48
+ def empty?
49
+ @body_object.empty?
50
+ end
51
+ end
52
+
53
+ end
data/lib/lmc/Site.rb ADDED
@@ -0,0 +1,37 @@
1
+ module LMC
2
+ class Site
3
+ attr_accessor :name
4
+ attr_reader :id, :account
5
+
6
+ def initialize(data, account)
7
+ @cloud = Cloud.instance
8
+ @id = data["id"]
9
+ @name = data["name"]
10
+ @subnet_group_id = data["subnetGroupId"]
11
+ @account = account
12
+
13
+ if @account
14
+ @cloud.auth_for_account @account
15
+ end
16
+ end
17
+
18
+ def to_s
19
+ "#{@name}"
20
+ end
21
+
22
+ def account=(account)
23
+ if @account == nil
24
+ @account = account
25
+ return true
26
+ else
27
+ raise "Cannot replace account for site"
28
+ end
29
+ end
30
+
31
+ def configstates
32
+ response = @cloud.get ["cloud-service-config", "configsubnetgroup", "accounts", @account.id, "subnetgroups", @subnet_group_id, "updatestates"]
33
+ states = LMC::Configstates.new response.body
34
+ end
35
+ end
36
+
37
+ end
data/lib/lmc/User.rb ADDED
@@ -0,0 +1,40 @@
1
+ module LMC
2
+ class User
3
+ #todo: look into hiding password
4
+ attr_reader :email
5
+
6
+ def initialize(data)
7
+ @email = data["email"]
8
+ @password = data["password"]
9
+ end
10
+
11
+ # current registration process unclear and likely to have changed
12
+ # since this code was written.
13
+ #def register()
14
+ # # cloud instance by default authenticates.
15
+ # # for registration specifically, no authentication is required
16
+ # # should be possible without email and password for "admin" user
17
+ # cloud = Cloud.instance
18
+ # cloud.post ["cloud-service-auth", "users"], {"password" => @password, "email" => @email}
19
+ #end
20
+
21
+ def update(old_pw)
22
+ cloud = Cloud.instance
23
+ begin
24
+ cloud.post ["cloud-service-auth", "users", "self", "password"], {"password" => @password, 'verification' => old_pw}
25
+ rescue RestClient::BadRequest => e
26
+ response_body = JSON.parse(e.response)
27
+ raise "#{e.message} - #{response_body['message']}"
28
+ end
29
+ end
30
+
31
+ def request_pw_reset
32
+ #https://beta.cloud.lancom.de/cloud-service-auth/actions
33
+ cloud = Cloud.instance
34
+ post_data = {"type" => "PASSWORD_RESET", "name" => @email}
35
+ cloud.post ["cloud-service-auth", "actions"], post_data
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,83 @@
1
+ module LMC
2
+ class AccountManager
3
+ @options
4
+ @global_options
5
+ @errors
6
+ attr_reader :errors
7
+
8
+ def initialize(options, global_options)
9
+ @options = options
10
+ @global_options = global_options
11
+ @errors = []
12
+ end
13
+
14
+ # returns nil if invite did not work
15
+ def invite(lmcen, distro, line, type, authority_name)
16
+ lmcen.auth_for_accounts([distro["id"]])
17
+ line = line.strip.downcase
18
+ begin
19
+ account = Account.get(distro["id"])
20
+ account_authorities = account.authorities
21
+ #puts account_authorities.inspect if @global_options[:debug]
22
+ if @global_options[:debug]
23
+ account_authorities.each do |a|
24
+ puts a["name"]
25
+ puts a.inspect
26
+ end
27
+ end
28
+ authority = account_authorities.find {|auth| auth["name"] == authority_name}
29
+ #puts "account authorities: #{account_authorities}" if @global_options[:debug]
30
+ puts authority if @global_options[:debug]
31
+ if !@options[:dry]
32
+ # TODO wenn der default authority nicht gibt geht das ding kaputt
33
+ invited = lmcen.invite_user_to_account(line, distro["id"], type, [authority["id"]])
34
+ puts "Invite response:" + invited.inspect if @global_options[:debug]
35
+ puts "Invited " + invited["name"].to_s + " to account #{distro["name"]}(#{invited.code})." if @global_options[:v]
36
+ if invited.code != 200
37
+ @errors << {:line => line, :result => invited.body}
38
+ return nil
39
+ end
40
+ else
41
+ invited = {"name" => line}
42
+ end
43
+
44
+ invite_url = lmcen.build_url("#", "register", Base64.encode64(invited["name"]))
45
+ if @options["show-csv"]
46
+ puts "\n" + invited["name"] + ", " + invite_url
47
+ end
48
+ if @options["send-mail"] && invited
49
+ mailbody = <<END
50
+ Hallo,
51
+ auf #{lmcen.cloud_host} wurde eine Einladung zu dem Account #{distro["name"]} für den Nutzer #{invited["name"]} erstellt.
52
+
53
+ Falls der Account noch nicht existiert, kann dieser Link zur Registrierung genutzt werden:
54
+ END
55
+ mail = Mail.new do
56
+ from "Philipp Erbelding <philipp.erbelding@lancom.de>"
57
+ to invited["name"]
58
+ subject "Einladung auf " + lmcen.cloud_host
59
+ body mailbody + invite_url
60
+ end
61
+
62
+ puts invite_url
63
+ if !@options[:dry]
64
+ puts "sending mail to " + invited["name"]
65
+ mail.delivery_method :smtp, address: "lcs-mail"
66
+ mail.deliver
67
+ else
68
+ puts "[DRY RUN] would send mail to " + invited["name"]
69
+ end
70
+ puts mail.to_s if @global_options[:v]
71
+ end
72
+
73
+ rescue RestClient::ExceptionWithResponse => e
74
+ puts e.to_s
75
+ puts invited.inspect
76
+ resp = JSON.parse(e.response)
77
+ puts resp.inspect
78
+ puts resp["message"]
79
+ end
80
+ return true
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,6 @@
1
+ require 'ostruct'
2
+ module LMC
3
+ class DeviceConfigState < OpenStruct
4
+
5
+ end
6
+ end
data/lib/lmc/entity.rb ADDED
@@ -0,0 +1,17 @@
1
+ module LMC
2
+ class Entity
3
+ def self.get_by_uuid_or_name term
4
+ raise "Missing argument" if term.nil?
5
+ begin
6
+ return self.get_by_uuid term
7
+ rescue RestClient::BadRequest, URI::InvalidURIError
8
+ return self.get_by_name term
9
+ end
10
+ end
11
+
12
+ def [] key
13
+ self.send(key)
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ module LMC
2
+ class OutdatedTermsOfUseException < Exception
3
+ def initialize(response = {})
4
+ @response = response
5
+ end
6
+
7
+ def response
8
+ r = "Terms of use must be accepted before using this LMC instance:\n"
9
+ missing.each do |tos|
10
+ r += "Name: #{tos['name']}, Date #{tos['acceptance']}\n"
11
+
12
+ end
13
+ return r
14
+ end
15
+ def missing
16
+ @response['details']['missing']
17
+ end
18
+ end
19
+
20
+
21
+ end
@@ -0,0 +1,15 @@
1
+ module LMC
2
+ class Membership
3
+ attr_accessor :name, :type, :state, :authorities
4
+
5
+ def to_json(*a)
6
+ {
7
+ "name" => @name,
8
+ "type" => @type,
9
+ "state" => @state,
10
+ "authorities" => @authorities
11
+ }.to_json(*a)
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,34 @@
1
+ module LMC
2
+ class Principal
3
+ def initialize(data)
4
+ apply_data(data)
5
+ end
6
+
7
+ #returns itself, allows chaining
8
+ def save
9
+ response = if @id.nil?
10
+ Cloud.instance.post ["cloud-service-auth", "principals"], self
11
+ else
12
+ raise "editing principals not supported"
13
+ #@cloud.put ["cloud-service-auth", "principals", @id], self
14
+ end
15
+ apply_data(response.body)
16
+ return self
17
+ end
18
+ def to_json(*a)
19
+ {
20
+ "name" => @name,
21
+ "type" => @type,
22
+ "password" => @password
23
+ }.to_json(*a)
24
+ end
25
+
26
+ private
27
+ def apply_data(data)
28
+ @id = data['id']
29
+ @name = data['name']
30
+ @password = data['password']
31
+ @type = data['type']
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ module LMC
2
+ VERSION = "0.4.0"
3
+ end
data/lmc.gemspec ADDED
@@ -0,0 +1,42 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "lmc/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "lmc"
8
+ spec.version = LMC::VERSION
9
+ spec.authors = ["erpel"]
10
+ spec.email = ["philipp@copythat.de"]
11
+
12
+ spec.summary = %q{Library for interacting with LMC cloud instances}
13
+ # spec.homepage = "https://copythat.de"
14
+ spec.license = 'BSD-3-Clause'
15
+
16
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
17
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
18
+ if spec.respond_to?(:metadata)
19
+ #spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
20
+ else
21
+ raise "RubyGems 2.0 or newer is required to protect against " \
22
+ "public gem pushes."
23
+ end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
26
+ f.match(%r{^(test|spec|features)/})
27
+ end
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+
32
+ spec.add_development_dependency 'bundler', '~> 1.16'
33
+ spec.add_development_dependency 'minitest', '~> 5.0'
34
+ spec.add_development_dependency 'minitest-reporters', '~> 1.1'
35
+ spec.add_development_dependency 'rake', '~> 10.0'
36
+ spec.add_development_dependency 'recursive-open-struct', '~> 1.1'
37
+ spec.add_development_dependency 'simplecov', '~> 0.15'
38
+ spec.add_development_dependency 'pry-nav', '~> 0.2.4'
39
+
40
+ spec.add_runtime_dependency 'json', '~> 2.0'
41
+ spec.add_runtime_dependency 'rest-client', '~> 2.0'
42
+ end
metadata ADDED
@@ -0,0 +1,201 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lmc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ platform: ruby
6
+ authors:
7
+ - erpel
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-07-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest-reporters
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: recursive-open-struct
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.1'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.15'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.15'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry-nav
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.2.4
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.2.4
111
+ - !ruby/object:Gem::Dependency
112
+ name: json
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '2.0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '2.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rest-client
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '2.0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '2.0'
139
+ description:
140
+ email:
141
+ - philipp@copythat.de
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - ".gitignore"
147
+ - ".idea/inspectionProfiles/Project_Default.xml"
148
+ - ".idea/lmc.iml"
149
+ - ".idea/misc.xml"
150
+ - ".idea/modules.xml"
151
+ - ".idea/vcs.xml"
152
+ - ".ruby-version"
153
+ - ".travis.yml"
154
+ - Gemfile
155
+ - README.md
156
+ - Rakefile
157
+ - bin/console
158
+ - bin/setup
159
+ - coverage/.gitignore
160
+ - coverage/.last_run.json
161
+ - lib/lmc.rb
162
+ - lib/lmc/Account.rb
163
+ - lib/lmc/Cloud.rb
164
+ - lib/lmc/Configstates.rb
165
+ - lib/lmc/Device.rb
166
+ - lib/lmc/Response.rb
167
+ - lib/lmc/Site.rb
168
+ - lib/lmc/User.rb
169
+ - lib/lmc/account_manager.rb
170
+ - lib/lmc/device_config_state.rb
171
+ - lib/lmc/entity.rb
172
+ - lib/lmc/exceptions/lmc_outdated_terms_of_use_exception.rb
173
+ - lib/lmc/membership.rb
174
+ - lib/lmc/principal.rb
175
+ - lib/lmc/version.rb
176
+ - lmc.gemspec
177
+ homepage:
178
+ licenses:
179
+ - BSD-3-Clause
180
+ metadata: {}
181
+ post_install_message:
182
+ rdoc_options: []
183
+ require_paths:
184
+ - lib
185
+ required_ruby_version: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - ">="
188
+ - !ruby/object:Gem::Version
189
+ version: '0'
190
+ required_rubygems_version: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ requirements: []
196
+ rubyforge_project:
197
+ rubygems_version: 2.6.11
198
+ signing_key:
199
+ specification_version: 4
200
+ summary: Library for interacting with LMC cloud instances
201
+ test_files: []