lmc 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,7 +3,6 @@
3
3
  require 'ostruct'
4
4
  module LMC
5
5
  class LMCResponse
6
-
7
6
  attr_reader :body, :code, :headers
8
7
 
9
8
  def initialize(response)
@@ -12,7 +11,7 @@ module LMC
12
11
  @body_object = JSON.parse response.body
13
12
  end
14
13
  if @body_object.class == Array
15
- @body = @body_object.map {|elem|
14
+ @body = @body_object.map { |elem|
16
15
  if elem.is_a? Hash then
17
16
  OpenStruct.new(elem)
18
17
  else
@@ -23,7 +22,7 @@ module LMC
23
22
  elsif @body_object.class == TrueClass || @body_object.class == FalseClass
24
23
  @body = @body_object
25
24
  else
26
- raise "Unknown json parse result"
25
+ raise "Unknown json parse result: #{@body_object.class}"
27
26
  end
28
27
  @code = response.code
29
28
  @headers = response.headers
@@ -59,5 +58,4 @@ module LMC
59
58
  @body_object.empty?
60
59
  end
61
60
  end
62
-
63
61
  end
@@ -3,38 +3,27 @@
3
3
  module LMC
4
4
  class Site
5
5
  attr_accessor :name
6
- attr_reader :id, :account
6
+ attr_reader :id, :account, :subnet_group_id
7
7
 
8
8
  def initialize(data, account)
9
- @cloud = Cloud.instance
10
- @id = data["id"]
11
- @name = data["name"]
12
- @subnet_group_id = data["subnetGroupId"]
9
+ @cloud = account.cloud
10
+ @cloud.auth_for_account account if account
13
11
  @account = account
12
+ data = @cloud.get ['cloud-service-devices', 'accounts', @account.id, 'sites', data] if data.is_a? UUID
13
+
14
+ @id = data['id']
15
+ @name = data['name']
16
+ @subnet_group_id = data['subnetGroupId']
14
17
 
15
- if @account
16
- @cloud.auth_for_account @account
17
- end
18
18
  end
19
19
 
20
20
  def to_s
21
21
  "#{@name}"
22
22
  end
23
23
 
24
- def account=(account)
25
- if @account == nil
26
- @account = account
27
- return true
28
- else
29
- raise "Cannot replace account for site"
30
- end
31
- end
32
-
33
24
  def configstates
34
- response = @cloud.get ["cloud-service-config", "configsubnetgroup", "accounts", @account.id, "subnetgroups", @subnet_group_id, "updatestates"]
35
- states = LMC::Configstates.new response.body
36
- return states
25
+ response = @cloud.get ['cloud-service-config', 'configsubnetgroup', 'accounts', @account.id, 'subnetgroups', @subnet_group_id, 'updatestates']
26
+ LMC::Configstates.new response.body
37
27
  end
38
28
  end
39
-
40
29
  end
@@ -2,28 +2,28 @@
2
2
 
3
3
  module LMC
4
4
  class User
5
- #todo: look into hiding password
5
+ # TODO: look into hiding password
6
6
  attr_reader :email
7
7
 
8
8
  def initialize(data)
9
- @email = data["email"]
10
- @password = data["password"]
9
+ @email = data['email']
10
+ @password = data['password']
11
11
  end
12
12
 
13
13
  # current registration process unclear and likely to have changed
14
14
  # since this code was written.
15
- #def register()
15
+ # def register()
16
16
  # # cloud instance by default authenticates.
17
17
  # # for registration specifically, no authentication is required
18
18
  # # should be possible without email and password for "admin" user
19
19
  # cloud = Cloud.instance
20
20
  # cloud.post ["cloud-service-auth", "users"], {"password" => @password, "email" => @email}
21
- #end
21
+ # end
22
22
 
23
23
  def update(old_pw)
24
24
  cloud = Cloud.instance
25
25
  begin
26
- cloud.post ["cloud-service-auth", "users", "self", "password"], {"password" => @password, 'verification' => old_pw}
26
+ cloud.post ['cloud-service-auth', 'users', 'self', 'password'], 'password' => @password, 'verification' => old_pw
27
27
  rescue RestClient::BadRequest => e
28
28
  response_body = JSON.parse(e.response)
29
29
  raise "#{e.message} - #{response_body['message']}"
@@ -32,11 +32,9 @@ module LMC
32
32
 
33
33
  def request_pw_reset
34
34
  action = AuthAction.new Cloud.instance
35
- action.type="PASSWORD_RESET"
36
- action.name=@email
35
+ action.type = 'PASSWORD_RESET'
36
+ action.name = @email
37
37
  action.post
38
38
  end
39
-
40
39
  end
41
-
42
- end
40
+ end
@@ -2,9 +2,9 @@
2
2
 
3
3
  module LMC
4
4
  class AccountManager
5
- #@options
6
- #@global_options
7
- #@errors
5
+ # @options
6
+ # @global_options
7
+ # @errors
8
8
  attr_reader :errors
9
9
 
10
10
  def initialize(options, global_options)
@@ -15,59 +15,59 @@ module LMC
15
15
 
16
16
  # returns nil if invite did not work
17
17
  def invite(lmcen, distro, line, type, authority_name)
18
- lmcen.auth_for_accounts([distro["id"]])
18
+ lmcen.auth_for_accounts([distro['id']])
19
19
  line = line.strip.downcase
20
20
  begin
21
- account = Account.get(distro["id"])
21
+ account = Account.get(distro['id'])
22
22
  account_authorities = account.authorities
23
- #puts account_authorities.inspect if @global_options[:debug]
23
+ # puts account_authorities.inspect if @global_options[:debug]
24
24
  if @global_options[:debug]
25
25
  account_authorities.each do |a|
26
- puts a["name"]
26
+ puts a['name']
27
27
  puts a.inspect
28
28
  end
29
29
  end
30
- authority = account_authorities.find {|auth| auth["name"] == authority_name}
31
- #puts "account authorities: #{account_authorities}" if @global_options[:debug]
30
+ authority = account_authorities.find { |auth| auth['name'] == authority_name }
31
+ # puts "account authorities: #{account_authorities}" if @global_options[:debug]
32
32
  puts authority if @global_options[:debug]
33
33
  if !@options[:dry]
34
- # TODO wenn der default authority nicht gibt geht das ding kaputt
35
- invited = lmcen.invite_user_to_account(line, distro["id"], type, [authority["id"]])
36
- puts "Invite response:" + invited.inspect if @global_options[:debug]
37
- puts "Invited " + invited["name"].to_s + " to account #{distro["name"]}(#{invited.code})." if @global_options[:v]
34
+ # TODO: wenn der default authority nicht gibt geht das ding kaputt
35
+ invited = lmcen.invite_user_to_account(line, distro['id'], type, [authority['id']])
36
+ puts 'Invite response:' + invited.inspect if @global_options[:debug]
37
+ puts 'Invited ' + invited['name'].to_s + " to account #{distro['name']}(#{invited.code})." if @global_options[:v]
38
38
  if invited.code != 200
39
- @errors << {:line => line, :result => invited.body}
39
+ @errors << { :line => line, :result => invited.body }
40
40
  return nil
41
41
  end
42
42
  else
43
- invited = {"name" => line}
43
+ invited = { 'name' => line }
44
44
  end
45
45
 
46
- invite_url = lmcen.build_url("#", "register", Base64.encode64(invited["name"]))
47
- if @options["show-csv"]
48
- puts "\n" + invited["name"] + ", " + invite_url
46
+ invite_url = lmcen.build_url('#', 'register', Base64.encode64(invited['name']))
47
+ if @options['show-csv']
48
+ puts "\n" + invited['name'] + ', ' + invite_url
49
49
  end
50
- if @options["send-mail"] && invited
50
+ if @options['send-mail'] && invited
51
51
  mailbody = <<END
52
52
  Hallo,
53
- auf #{lmcen.cloud_host} wurde eine Einladung zu dem Account #{distro["name"]} für den Nutzer #{invited["name"]} erstellt.
53
+ auf #{lmcen.cloud_host} wurde eine Einladung zu dem Account #{distro['name']} für den Nutzer #{invited['name']} erstellt.
54
54
 
55
55
  Falls der Account noch nicht existiert, kann dieser Link zur Registrierung genutzt werden:
56
56
  END
57
57
  mail = Mail.new do
58
- from "Philipp Erbelding <philipp.erbelding@lancom.de>"
59
- to invited["name"]
60
- subject "Einladung auf " + lmcen.cloud_host
58
+ from 'Philipp Erbelding <philipp.erbelding@lancom.de>'
59
+ to invited['name']
60
+ subject 'Einladung auf ' + lmcen.cloud_host
61
61
  body mailbody + invite_url
62
62
  end
63
63
 
64
64
  puts invite_url
65
65
  if !@options[:dry]
66
- puts "sending mail to " + invited["name"]
67
- mail.delivery_method :smtp, address: "lcs-mail"
66
+ puts 'sending mail to ' + invited['name']
67
+ mail.delivery_method :smtp, address: 'lcs-mail'
68
68
  mail.deliver
69
69
  else
70
- puts "[DRY RUN] would send mail to " + invited["name"]
70
+ puts '[DRY RUN] would send mail to ' + invited['name']
71
71
  end
72
72
  puts mail.to_s if @global_options[:v]
73
73
  end
@@ -77,9 +77,9 @@ END
77
77
  puts invited.inspect
78
78
  resp = JSON.parse(e.response)
79
79
  puts resp.inspect
80
- puts resp["message"]
80
+ puts resp['message']
81
81
  end
82
- return true
82
+ true
83
83
  end
84
84
  end
85
85
  end
@@ -14,9 +14,9 @@ module LMC
14
14
  def service_name
15
15
  'auth'
16
16
  end
17
+
17
18
  def collection_name
18
19
  'actions'
19
20
  end
20
-
21
21
  end
22
- end
22
+ end
@@ -5,6 +5,7 @@ module LMC
5
5
  attr_accessor :account, :id, :name, :visibility, :type
6
6
 
7
7
  def initialize(data, account)
8
+ # TODO: Use cloud object from account
8
9
  @cloud = Cloud.instance
9
10
  apply_data(data)
10
11
  @account = account
@@ -14,26 +15,26 @@ module LMC
14
15
  # GET /accounts/{accountId}/authorities/{authorityId}/rights
15
16
  @cloud.auth_for_account @account
16
17
  response = @cloud.get ['cloud-service-auth', 'accounts', @account.id, 'authorities', @id, 'rights']
17
- return response.body.to_s
18
+ response.body.to_s
18
19
  end
19
20
 
20
- #returns itself, allows chaining
21
+ # returns itself, allows chaining
21
22
  def save
22
23
  response = if @id.nil?
23
- Cloud.instance.post ["cloud-service-auth", 'accounts', @account.id, "authorities"], self
24
+ Cloud.instance.post ['cloud-service-auth', 'accounts', @account.id, 'authorities'], self
24
25
  else
25
- raise "editing authorities not supported"
26
- #@cloud.put ["cloud-service-auth", "principals", @id], self
26
+ raise 'editing authorities not supported'
27
+ # @cloud.put ["cloud-service-auth", "principals", @id], self
27
28
  end
28
29
  apply_data(response.body)
29
- return self
30
+ self
30
31
  end
31
32
 
32
33
  def to_json(*a)
33
34
  {
34
- "name" => @name,
35
- "type" => @type,
36
- "visibility" => @visibility
35
+ 'name' => @name,
36
+ 'type' => @type,
37
+ 'visibility' => @visibility
37
38
  }.to_json(*a)
38
39
  end
39
40
 
@@ -0,0 +1,192 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LMC
4
+ # Represents a device config in LMC
5
+ class DeviceConfig
6
+ attr_reader :state
7
+
8
+ def url_configbuilder
9
+ ['cloud-service-config', 'configbuilder', 'accounts',
10
+ @account.id, 'devices', @device.id, 'ui']
11
+ end
12
+
13
+ def url_ticket
14
+ ['cloud-service-config',
15
+ 'configbuilder',
16
+ 'accounts',
17
+ @account.id,
18
+ 'devices',
19
+ @device.id,
20
+ 'tickets',
21
+ @ticket_id]
22
+ end
23
+
24
+ def url_state
25
+ %W(cloud-service-config configdevice accounts #{@account.id} state)
26
+ end
27
+
28
+ # def url_stringtable
29
+ # ['cloud-service-config', 'configdsc', 'stringtable', dscui['stringtableId']]
30
+ # end
31
+
32
+ def initialize(cloud, account, device)
33
+ @cloud = cloud
34
+ @account = account
35
+ @device = device
36
+ @response = nil
37
+ @ticket_id = nil
38
+ # state returns an object with each requested device id pointing to a state object.
39
+ @state = @cloud.get(url_state, deviceIds: @device.id.to_s).body[@device.id]
40
+ end
41
+
42
+ def configjson
43
+ confighash.to_json
44
+ end
45
+
46
+ def confighash
47
+ items.to_h
48
+ end
49
+
50
+ ##
51
+ # Returns a hash similar to #confighash but with the OIDs replaced with more
52
+ # meaningful descriptions.
53
+
54
+ def descriptive_confighash
55
+ item_map = dscui.item_by_id_map
56
+ confighash.map { |k, v|
57
+ [item_map[k].description, v]
58
+ }.to_h
59
+ end
60
+
61
+ def items
62
+ response.items
63
+ end
64
+
65
+ def dscui
66
+ @dscui ||= DeviceDSCUi.new @device
67
+ end
68
+
69
+ def lcf
70
+ # lfc format findings:
71
+ # group headings in {} do not matter
72
+ # indentation does not matter
73
+ # table oids need to be enclosed in <>
74
+ # table cell oids need to be enclosed in () and should follow table oids
75
+
76
+ result = ''
77
+ result += lcf_header
78
+ items.each do |key, value|
79
+ if value.instance_of? String
80
+ result += "#{key} = #{value}\n"
81
+ elsif value.instance_of? Hash
82
+ rows = value['rows']
83
+ col_ids = value['colIds']
84
+ if rows.length > 0
85
+ result += "<#{key}>\n"
86
+ rows.each_with_index { |row, index|
87
+ row.each_with_index { |col, col_index|
88
+ result += "(#{key}.#{index + 1}.#{col_ids[col_index]}) = #{col}\n"}
89
+ }
90
+ end
91
+ else
92
+ raise 'Unexpected value in config items: ' + value.class.to_s
93
+ end
94
+ end
95
+ result += lcf_footer
96
+ end
97
+
98
+ def current_device_type
99
+ OpenStruct.new JSON.parse state['currentDeviceType']
100
+ end
101
+
102
+ ##
103
+ # @return [String]
104
+ def feature_mask_lower32_hex
105
+ feature_mask = 0
106
+ lower_features = current_device_type.features.select { |feature| feature < 32 }
107
+ lower_features.each do |feature_pos|
108
+ feature = 2**feature_pos
109
+ feature_mask = feature_mask | feature
110
+ end
111
+ if feature_mask == 0
112
+ '0x00000000'
113
+ else
114
+ format '%#010x', feature_mask
115
+ end
116
+ end
117
+
118
+ def lcf_device_version
119
+ v = 'v'
120
+ v += "#{@device.status['fwMajor']}."
121
+ v += "#{@device.status['fwMinor']}."
122
+ v + format('%04d', @device.status['fwBuild'])
123
+ end
124
+
125
+ ##
126
+ # Gives the feature IDs as a string like this: "IDs:2,3,f"
127
+ # @return [String]
128
+ def lcf_feature_id_string
129
+ hex_features = current_device_type.features.map { |feature| feature.to_s 16 }
130
+ "IDs:#{hex_features.join(',')}"
131
+ end
132
+
133
+ private
134
+
135
+ ##
136
+ # Produces lcf header
137
+ # @return [String]
138
+ def lcf_header
139
+ "(LMC Configuration of '#{@device.name}' at #{Time.now} via ruby-lmc #{LMC::VERSION})
140
+ (#{@device.status['fwLabel']}) (#{lcf_feature_hw_string})
141
+ [#{@device.model}] #{lcf_device_version}
142
+ [TYPE: LCF; VERSION: 1.00; HASHTYPE: none;]
143
+ "
144
+ end
145
+
146
+ ##
147
+ # Gives the feature mask, the feature IDs and the hardware mask as string for the lcf
148
+ # header like this: "0x0000c010,IDs:4,e,f//e0901447,2b;0x0c000002"
149
+ # @return [String]
150
+ def lcf_feature_hw_string
151
+ "#{feature_mask_lower32_hex},#{lcf_feature_id_string};#{@device.hwmask_hex}"
152
+ end
153
+
154
+ def lcf_footer
155
+ "[END: LCF;]\n"
156
+ end
157
+
158
+ def response
159
+ return @response unless @response.nil?
160
+ fetch_result
161
+ end
162
+
163
+ def fetch_result
164
+ response_or_ticket = @cloud.get(url_configbuilder).body
165
+ if response_or_ticket.respond_to? 'ticketId'
166
+ @ticket_id = response_or_ticket.ticketId
167
+ redeem_ticket 5
168
+ else
169
+ @response = response_or_ticket
170
+ end
171
+ @response
172
+ end
173
+
174
+ def redeem_ticket(tries)
175
+ attempts = 1
176
+ until @response
177
+ raise 'Too many attempts' if attempts > tries
178
+ attempts += 1
179
+ body = @cloud.get(url_ticket).body
180
+ unless body.respond_to? :ticketId
181
+ @ticket_id = nil
182
+ @response = body
183
+ end
184
+ sleep 0.5
185
+ end
186
+ end
187
+
188
+ # def stringtable
189
+ # @stringtable ||= @cloud.get(url_stringtable).body
190
+ # end
191
+ end
192
+ end