persistence-providers 0.0.3.6 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,7 +2,6 @@ module DTK::State
2
2
  class Component::Attribute::Influxdb
3
3
  class Measurement
4
4
  class Attributes < self
5
-
6
5
  def write(value, params_hash = {}, timestamp)
7
6
  checked_params_hash = check_params_hash(params_hash)
8
7
  write_point(value, checked_params_hash, timestamp)
@@ -11,10 +10,9 @@ module DTK::State
11
10
  protected
12
11
 
13
12
  def required_params
14
- [:namespace, :component_name, :assembly_name, :attribute_name, :task_id]
13
+ %i[namespace component_name assembly_name attribute_name task_id]
15
14
  end
16
-
17
- end
15
+ end
18
16
  end
19
17
  end
20
18
  end
@@ -8,13 +8,18 @@ module DTK::State
8
8
  write_point(value, checked_params_hash, timestamp)
9
9
  end
10
10
 
11
+ def get_correlator_type(entrypoint)
12
+ {
13
+ correlator_type: entrypoint.split('/').last.split('.')[0]
14
+ }
15
+ end
16
+
11
17
  protected
12
18
 
13
19
  def required_params
14
- [:namespace, :component_name, :assembly_name, :task_id, :attribute_name, :task_id, :correlator_type]
20
+ %i[namespace component_name assembly_name task_id attribute_name correlator_type]
15
21
  end
16
-
17
- end
22
+ end
18
23
  end
19
24
  end
20
- end
25
+ end
@@ -8,13 +8,23 @@ module DTK::State
8
8
  write_point(value, checked_params_hash, timestamp)
9
9
  end
10
10
 
11
+ def get_required_tags(event_id, pod_name, pod_namespace, component_name, attribute_name, task_id)
12
+ {
13
+ event_id: event_id,
14
+ pod_name: pod_name,
15
+ pod_namespace: pod_namespace,
16
+ component_name: component_name,
17
+ attribute_name: attribute_name,
18
+ task_id: task_id
19
+ }
20
+ end
21
+
11
22
  protected
12
23
 
13
24
  def required_params
14
- [:event_id, :pod_name, :pod_namespace, :component_name, :attribute_name, :task_id]
25
+ %i[event_id pod_name pod_namespace component_name attribute_name task_id]
15
26
  end
16
-
17
- end
27
+ end
18
28
  end
19
29
  end
20
- end
30
+ end
@@ -8,13 +8,24 @@ module DTK::State
8
8
  write_point(value, checked_params_hash, timestamp)
9
9
  end
10
10
 
11
+ def get_required_tags(type, name, namespace, object_state, component_name, attribute_name, task_id)
12
+ {
13
+ type: type,
14
+ name: name,
15
+ namespace: namespace,
16
+ object_state: object_state,
17
+ component_name: component_name,
18
+ attribute_name: attribute_name,
19
+ task_id: task_id
20
+ }
21
+ end
22
+
11
23
  protected
12
24
 
13
25
  def required_params
14
- [:type, :name, :namespace, :object_state, :component_name, :attribute_name, :task_id]
26
+ %i[type name namespace object_state component_name attribute_name task_id]
15
27
  end
16
-
17
- end
28
+ end
18
29
  end
19
30
  end
20
- end
31
+ end
@@ -2,7 +2,8 @@ module DTK::State
2
2
  class Component::Attribute::Influxdb
3
3
  class SemanticType
4
4
  require_relative './client'
5
- attr_reader :name, :crd_content, :namespace, :client
5
+ require_relative('../../../../utils/log')
6
+ attr_reader :name, :crd_content, :namespace, :client, :expanded_semantictype_spec
6
7
  attr_accessor :content_to_write
7
8
 
8
9
  def initialize(name, namespace)
@@ -11,75 +12,103 @@ module DTK::State
11
12
  @client = Client.new
12
13
  @crd_content = get(name, namespace)
13
14
  @content_to_write = []
14
- end
15
-
16
- # no namespace because semantictype instances are going to be unique in cluster
17
- def get(name, namespace, opts = {})
18
- begin
19
- semantictype = ::DTK::CrdClient.get_kubeclient(opts).get_semantictype(name, namespace)
20
- semantictype.spec[:openAPIV3Schema]
21
- rescue => error
22
- fail "SemanticType attribute with name '#{name}' not found on the cluster!. Error: #{error}"
23
- end
15
+ @expanded_spec = ::DTK::CrdClient.get_kubeclient({}).get_semantictype(name, namespace).expandedSpec
16
+ @expanded_semantictype_spec = expand(crd_content.to_h[:properties], @expanded_spec)
24
17
  end
25
18
 
26
19
  def write_semantictype_inventory(inventory, component_id)
27
- begin
28
- get_influxdb_properties(inventory)
29
- content_to_write.each do |point|
30
- point[:tags].merge!({ component_id: component_id, attribute_name: @name })
31
- @client.write_point({
32
- name: point[:name],
33
- tags: point[:tags],
34
- fields: point[:fields],
35
- time: (Time.new.to_f * 1000).to_i
36
- })
37
- end
38
- "Inventory for attribute #{name} written to InfluxDB"
39
- rescue => error
40
- fail "#{name} inventory write failed. Error: #{error}"
20
+ get_influxdb_properties(inventory)
21
+ content_to_write.each do |point|
22
+ point[:tags].merge!({ component_id: component_id, attribute_name: @name })
23
+ @client.write_point({
24
+ name: point[:name],
25
+ tags: point[:tags],
26
+ fields: point[:fields],
27
+ time: (Time.new.to_f * 1000).to_i
28
+ })
41
29
  end
30
+ rescue => e
31
+ raise "#{name} inventory write failed. Error: #{e}"
42
32
  end
43
33
 
44
34
  def partial_write_update(component_and_attribute, path, field_name, field_value)
45
35
  parent, child = validate_parameter(path)
46
36
  component_id, attribute_name = component_and_attribute.split('/')
47
37
  # getting previous value for given parameters
48
- previous_value = { }
38
+ previous_value = {}
49
39
  begin
50
40
  flux_query = 'from(bucket:"' + @client.connection_parameters[:bucket] + '") |> range(start:-5) |> filter(fn:(r) => r._measurement == "' + attribute_name + "_" + child[:type] + '") |> filter(fn: (r) => r.parent == "' + parent[:name] + '") |> filter(fn: (r) => r.name == "' + child[:name] + '")|> last()'
51
41
  result = @client.query(query: flux_query)
52
42
  previous_value = result.values.map(&:records).flatten.map(&:values)
53
- rescue => error
54
- fail "Partial write could not be completed. Previous point for given parameters not found!"
43
+ rescue => e
44
+ raise "Partial write could not be completed. Previous point for given parameters not found!. Error: #{e}"
55
45
  end
56
46
  update_current(previous_value[0], get_path_to_object(path), field_name, field_value)
57
47
  end
58
48
 
59
49
  private
60
50
 
51
+ def expand(crd_content, expanded_spec)
52
+ if expanded_spec.nil?
53
+ expanded_spec = {}
54
+ populate_semantictypes(crd_content, expanded_spec)
55
+ ::DTK::CrdClient.get_kubeclient({}).merge_patch_semantictype(name, { expandedSpec: expanded_spec }, namespace)
56
+ end
57
+ expanded_spec
58
+ end
59
+
60
+ def get(name, namespace, opts = {})
61
+ semantictype = ::DTK::CrdClient.get_kubeclient(opts).get_semantictype(name, namespace)
62
+ semantictype.spec[:openAPIV3Schema]
63
+ rescue => e
64
+ raise "SemanticType attribute with name '#{name}' not found on the cluster!. Error: #{e.inspect}"
65
+ end
66
+
67
+ def populate_semantictypes(crd, expanded_spec, parent = nil)
68
+ crd.each_pair do |key, value|
69
+ basic, semantictype = value[:type].split(':')
70
+ if semantictype
71
+ expanded_spec[key] = get(basic.to_s, namespace).to_h[:properties]
72
+ crd[key] = get(basic.to_s, namespace).to_h[:properties]
73
+ temporary_expanded_spec = populate_semantictypes(crd[key], expanded_spec[key], basic)
74
+ end
75
+ if basic == 'array'
76
+ basic, semantictype = value[:items][:type].split(':')
77
+ if semantictype
78
+ expanded_spec[key] = get(basic.to_s, namespace).to_h[:properties]
79
+ crd[key] = get(basic.to_s, namespace).to_h[:properties]
80
+ temporary_expanded_spec = populate_semantictypes(crd[key], expanded_spec[key], basic)
81
+ end
82
+ end
83
+ temporary_expanded_spec ||= {}
84
+ unless temporary_expanded_spec.empty? || parent.nil?
85
+ ::DTK::CrdClient.get_kubeclient({}).merge_patch_semantictype(parent, { expandedSpec: { key => temporary_expanded_spec } }, namespace)
86
+ end
87
+ end
88
+ expanded_spec
89
+ end
90
+
61
91
  def update_current(previous_value, path, field_name, field_value)
62
- tags = { }
92
+ tags = {}
63
93
  previous_value.each_pair do |key, value|
64
- tags[key] = value if key[0..0] != "_" && key != "result" && key != "table"
94
+ tags[key] = value if key[0..0] != '_' && key != 'result' && key != 'table'
65
95
  end
66
96
  fields = Hash.new
67
97
  fields[field_name.to_sym] = field_value
68
98
  validate_fields(get_partial_definition(path), fields)
69
99
  @client.write_point({
70
- name: previous_value["_measurement"],
71
- tags: tags,
72
- fields: fields,
73
- time: (Time.new.to_f * 1000).to_i
74
- })
75
- "Partial write update successful"
100
+ name: previous_value['_measurement'],
101
+ tags: tags,
102
+ fields: fields,
103
+ time: (Time.new.to_f * 1000).to_i
104
+ })
76
105
  end
77
106
 
78
107
  def get_influxdb_properties(inventory, parent_type = [:top], parent_name = nil)
79
108
  content_to_write = []
80
109
  properties = { }
81
110
  inventory.each_pair do |key, value|
82
- if value.class.to_s == "Array"
111
+ if value.class.to_s == 'Array'
83
112
  inventory[key].each do |element|
84
113
  get_influxdb_properties(element, parent_type.push(key), inventory[:name])
85
114
  end
@@ -102,12 +131,10 @@ module DTK::State
102
131
  end
103
132
 
104
133
  def validate_request(partial_definition, request)
105
- begin
106
- validate_tags(partial_definition, request[:tags])
107
- validate_fields(partial_definition, request[:fields])
108
- rescue => error
109
- fail error
110
- end
134
+ validate_tags(partial_definition, request[:tags])
135
+ validate_fields(partial_definition, request[:fields])
136
+ rescue => e
137
+ raise e
111
138
  end
112
139
 
113
140
  def get_tags_and_fields(partial_definition, properties)
@@ -115,7 +142,7 @@ module DTK::State
115
142
  fields = { }
116
143
  properties.each_pair do |key, value|
117
144
  if partial_definition[key].nil?
118
- fail "Property '#{key}' not found in the definition of attribute"
145
+ raise "Property '#{key}' not found in the definition of attribute"
119
146
  else
120
147
  if partial_definition[key][:metric].nil? || partial_definition[key][:metric] == false
121
148
  tags[key] = value
@@ -131,14 +158,12 @@ module DTK::State
131
158
  end
132
159
 
133
160
  def validate_fields(partial_definition, fields)
134
-
135
161
  partial_definition.each_pair do |key, value|
136
162
  next if key == :required || value[:metric] == (false || nil)
137
-
138
163
  if fields[key].nil?
139
- fail "Field #{key} is missing. Validation of request failed!"
164
+ raise "Field #{key} is missing. Validation of request failed!"
140
165
  elsif value[:type].capitalize != fields[key].class.to_s
141
- fail "Defined type for SemanticType attribute property '#{key}' is #{value[:type].capitalize}, #{fields[key].class} provided"
166
+ raise "Defined type for SemanticType attribute property '#{key}' is #{value[:type].capitalize}, #{fields[key].class} provided"
142
167
  end
143
168
  end
144
169
  end
@@ -146,20 +171,19 @@ module DTK::State
146
171
  def validate_tags(partial_definition, tags)
147
172
  partial_definition.each_pair do |key, value|
148
173
  next if key == :required || value[:metric] == true
149
-
150
174
  if tags[key].nil?
151
175
  if value[:default].nil?
152
- fail "Property #{key} is missing. Validation of request failed!"
153
- else
176
+ raise "Property #{key} is missing. Validation of request failed!"
177
+ else
154
178
  tags[key] = value[:default]
155
179
  end
156
- else
180
+ else
157
181
  type = tags[key].class
158
- type = "Boolean" if type == TrueClass || type == FalseClass
182
+ type = 'Boolean' if type == TrueClass || type == FalseClass
159
183
  if value[:type].capitalize == type.to_s
160
184
  next
161
185
  else
162
- fail "Defined type for SemanticType attribute property '#{key}' is #{value[:type].capitalize}, #{type} provided"
186
+ raise "Defined type for SemanticType attribute property '#{key}' is #{value[:type].capitalize}, #{type} provided"
163
187
  end
164
188
  end
165
189
  end
@@ -167,24 +191,25 @@ module DTK::State
167
191
 
168
192
  def get_partial_definition(path)
169
193
  i = 0
170
- definition = { }
171
- semantictype_crd = crd_content[:properties]
194
+ definition = {}
195
+ semantictype_crd = crd_content.to_h[:properties]
196
+ expanded_spec = expanded_semantictype_spec.to_h
172
197
  while i < path.length
173
198
  if path[i].to_sym == :top
174
199
  semantictype_crd.each_pair do |key, value|
175
200
  if key == :required
176
201
  definition[key] = value
177
202
  else
178
- definition[key] = value if value[:type] != "array"
203
+ basic, semantictype = value[:type].split(':')
204
+ semantictype.nil? ? definition[key] = value : definition[key] = semantictype_crd[key] if basic != 'array'
179
205
  end
180
206
  end
181
207
  else
182
208
  definition = {}
183
- definition[:required] = semantictype_crd[path[i].to_sym][:items][:required]
184
- semantictype_crd[path[i].to_sym][:items][:properties].each_pair do |key, value|
185
- definition[key] = value if value[:type] != "array"
209
+ expanded_spec[path[i].to_sym].each_pair do |key, value|
210
+ definition[key] = value unless value[:type].nil?
186
211
  end
187
- semantictype_crd = semantictype_crd[path[i].to_sym][:items][:properties]
212
+ expanded_spec = expanded_spec[path[i].to_sym]
188
213
  end
189
214
  i+=1
190
215
  end
@@ -192,7 +217,7 @@ module DTK::State
192
217
  end
193
218
 
194
219
  def get_path_to_object(parameter)
195
- path = ["top"]
220
+ path = ['top']
196
221
  array = parameter.split('/')
197
222
  array.each do |element|
198
223
  path.push(element.split(':')[1])
@@ -202,19 +227,18 @@ module DTK::State
202
227
 
203
228
  def validate_parameter(parameter)
204
229
  array_of_parameters = []
205
- begin
206
- parameter.split('/').each_with_index do |param, index|
207
- name, type = param.split(':')
208
- fail unless name && type
209
- array_of_parameters.push({
210
- name: name,
211
- type: type
212
- })
213
- end
214
- array_of_parameters
215
- rescue => error
216
- fail "Could not resolve parameter '#{parameter}'. It should be in format: 'parent:type/child:type'"
230
+ parameter.split('/').each_with_index do |param, index|
231
+ name, type = param.split(':')
232
+ raise unless name && type
233
+
234
+ array_of_parameters.push({
235
+ name: name,
236
+ type: type
237
+ })
217
238
  end
239
+ array_of_parameters
240
+ rescue => e
241
+ raise "Could not resolve parameter '#{parameter}'. It should be in format: 'parent:type/child:type'"
218
242
  end
219
243
  end
220
244
  end
@@ -2,16 +2,19 @@ module DTK::State
2
2
  class ComponentDef
3
3
  require_relative 'component_def/attribute_type_info'
4
4
 
5
+ COMPONENT_DEF_CRD_VERSION = ENV["COMPONENT_DEF_CRD_VERSION"]
6
+
5
7
  attr_reader :name, :namespace, :executable_actions, :attribute_type_info
6
8
 
7
9
  def initialize(namespace, name, content)
8
10
  @name = name
9
11
  @namespace = namespace
10
- @executable_actions = content[:spec][:actions]
12
+ @executable_actions = content[:spec][:actions] || {}
11
13
  @attribute_type_info = AttributeTypeInfo.create_from_kube_hash(content[:spec][:attributes] || {})
12
14
  end
13
15
 
14
16
  def self.get(namespace, name, opts = {})
17
+ opts[:apiVersion] = COMPONENT_DEF_CRD_VERSION
15
18
  crd_component_def = ::DTK::CrdClient.get_kubeclient(opts).get_componentdef(name, namespace)
16
19
  ComponentDef.new(namespace, name, crd_component_def)
17
20
  end
@@ -19,6 +19,19 @@ module DTK::State
19
19
  end
20
20
  end
21
21
 
22
+ def to_hash
23
+ type_info = {}
24
+
25
+ type_info.merge!(name: @name) if @name
26
+ type_info.merge!(type: @type) if @type
27
+ type_info.merge!(required: @required) if @required
28
+ type_info.merge!(dynamic: @dynamic) if @dynamic
29
+ type_info.merge!(temporal: @temporal) if @temporal
30
+ type_info.merge!(encrypted: @encrypted) if @encrypted
31
+
32
+ type_info
33
+ end
34
+
22
35
  end
23
36
  end
24
37
  end
@@ -1,17 +1,24 @@
1
1
  module DTK::State
2
2
  class CrdAssembly
3
- attr_reader :name, :namespace, :crd_content, :components, :references
3
+ ASSEMBLY_CRD_VERSION = ENV["ASSEMBLY_CRD_VERSION"]
4
+
5
+ attr_reader :name, :namespace, :crd_content, :references, :component_objs
6
+ attr_accessor :components
4
7
 
5
8
  def initialize(namespace, name, crd_content)
6
- @name = name
7
- @namespace = namespace
8
- @crd_content = crd_content
9
- @references = crd_content.references
10
- @components = crd_content[:spec][:components]
9
+ @name = name
10
+ @namespace = namespace
11
+ @api_version = crd_content.apiVersion
12
+ @kind = crd_content.kind
13
+ @metadata = crd_content.metadata
14
+ # @crd_content = crd_content
15
+ @references = crd_content.references
16
+ @components = crd_content[:spec][:components] || []
17
+ # @component_objs = Component.create_from_kube_array(@components, self)
11
18
  end
12
19
 
13
20
  def self.get(namespace, name, opts = {})
14
- # crd_component = ::DTK::CrdClient.instance.kubeclient.get_component(name, namespace)
21
+ opts[:apiVersion] = ASSEMBLY_CRD_VERSION
15
22
  crd_assembly = ::DTK::CrdClient.get_kubeclient(opts).get_assembly(name, namespace)
16
23
  CrdAssembly.new(namespace, name, crd_assembly)
17
24
  end
@@ -50,6 +57,51 @@ module DTK::State
50
57
  output
51
58
  end
52
59
 
60
+ # TODO: this is a temporal solution to avoid breaking backward compatibility; will change this soon
61
+ def self.get_with_influx_data(namespace, assembly_name, opts = {})
62
+ assembly = get(namespace, assembly_name, opts)
63
+
64
+ components_hash = {}
65
+ assembly.components.each do |assembly_component|
66
+ cmp_name = assembly_component.to_hash.keys.first
67
+ components_hash[cmp_name] = assembly_component[cmp_name].to_hash
68
+ end
69
+
70
+ component_objs = Component.create_from_kube_array(assembly.components, assembly)
71
+
72
+ component_objs.each do |component_obj|
73
+ component_name = component_obj.name
74
+ attr_type_info = component_obj.component_def.attribute_type_info
75
+ attr_type_info.each do |attr_info|
76
+ if attr_info.temporal
77
+ attribute_name = attr_info.name
78
+ influxdb = ::DTK::State::Component::Attribute::Influxdb.new(:attributes)
79
+ influxdb_attribute = influxdb.get(namespace, component_name, assembly_name, attribute_name, opts)
80
+ if valid_attribute = influxdb_attribute.first
81
+ value = valid_attribute['_value']
82
+ if components_hash[component_name][:attributes][attribute_name].is_a?(String)
83
+ components_hash[component_name][:attributes][attribute_name] = value
84
+ else
85
+ components_hash[component_name][:attributes][attribute_name][:value] = value
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ assembly.components = components_hash
92
+ assembly
93
+ end
94
+
95
+ def to_hash
96
+ {
97
+ apiVersion: @api_version,
98
+ kind: @kind,
99
+ metadata: @metadata.to_hash,
100
+ references: @references.to_hash,
101
+ spec: { components: @components.to_hash }
102
+ }
103
+ end
104
+
53
105
  private
54
106
 
55
107
  def self.check_for_missing_components(crd_components, requested_components)