persistence-providers 0.0.3.6 → 0.0.5

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.
@@ -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)