oci-logging-analytics-kubernetes-discovery 1.0.2 → 1.1.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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/bin/oci-loganalytics-kubernetes-discovery +102 -25
  4. data/lib/config/oci_client_retry_config.rb +11 -8
  5. data/lib/discover/infrastructure.rb +81 -29
  6. data/lib/discover/object.rb +19 -4
  7. data/lib/dto/infra/load_balancer_payload.rb +32 -0
  8. data/lib/dto/infra/node_pool_payload.rb +28 -0
  9. data/lib/dto/infra/{node_pool_entity_payload.rb → resource_payload.rb} +6 -6
  10. data/lib/dto/infra/subnet_payload.rb +34 -0
  11. data/lib/dto/infra_objects_payload.rb +3 -3
  12. data/lib/dto/kubernetes_objects_payload.rb +19 -15
  13. data/lib/dto/state.rb +7 -3
  14. data/lib/enum/auth_type_enum.rb +1 -0
  15. data/lib/enum/infrastructure_resource_discovery.rb +1 -0
  16. data/lib/enum/object_client_mapping_enum.rb +1 -1
  17. data/lib/enum/stack_job_lifecycle_state_enum.rb +14 -0
  18. data/lib/enum/stack_job_operation_enum.rb +10 -0
  19. data/lib/infra_resources.rb +142 -41
  20. data/lib/objects_resources.rb +16 -6
  21. data/lib/oci_loganalytics_resources_discovery.rb +104 -77
  22. data/lib/util/helper.rb +15 -0
  23. data/lib/util/kube_client.rb +1 -0
  24. data/lib/util/kubectl_ops.rb +1 -1
  25. data/lib/util/log_analytics.rb +2 -2
  26. data/lib/util/oci_clients.rb +222 -103
  27. data/lib/util/service_logs.rb +559 -0
  28. data/lib/util/state_manager.rb +12 -2
  29. data/lib/util/string_utils.rb +48 -0
  30. data/lib/version.rb +1 -1
  31. data/oci-logging-analytics-kubernetes-discovery.gemspec +1 -1
  32. metadata +13 -10
  33. data/lib/dto/infra/cluster_entity_payload.rb +0 -22
  34. data/lib/dto/infra/load_balancers_entity_payload.rb +0 -22
  35. data/lib/dto/infra/subnet_entity_payload.rb +0 -22
  36. data/lib/dto/infra/vcn_entity_payload.rb +0 -22
@@ -31,9 +31,9 @@ module Dto
31
31
  {
32
32
  cluster: @cluster.to_hash,
33
33
  vcn: @vcn.to_hash,
34
- subnet: get_hash(@subnet, SUBNET.to_s),
35
- load_balancer: @load_balancer.to_hash,
36
- node_pools: get_hash(@node_pools, NODE_POOLS.to_s)
34
+ subnets: get_hash(@subnet, SUBNET.to_s),
35
+ loadbalancers: get_hash(@load_balancer, LOAD_BALANCER.to_s),
36
+ nodepools: get_hash(@node_pools, NODE_POOLS.to_s)
37
37
  }.compact
38
38
  end
39
39
  end
@@ -8,24 +8,27 @@ module Dto
8
8
  include Enum::KubernetesObjectsEnum
9
9
  extend Util::Logging
10
10
 
11
- attr_accessor :cluster, :nodes, :pods, :services, :endPointSlices, :deployments,
12
- :replicaSets, :daemonSets, :cronJobs, :jobs, :statefulSets, :events, :namespaces
11
+ attr_accessor :cluster, :nodes, :pods, :services, :endpointslices, :deployments,
12
+ :replicasets, :daemonsets, :cronjobs, :jobs, :statefulsets, :events, :namespaces,
13
+ :infra
13
14
 
14
- def initialize(cluster, nodes, pods, services, endPointSlices, deployments,
15
- replicaSets, daemonSets, cronJobs, jobs, statefulSets, events, namespaces)
15
+ def initialize(cluster, nodes, pods, services, endpointslices, deployments,
16
+ replicasets, daemonsets, cronjobs, jobs, statefulsets, events, namespaces,
17
+ infra)
16
18
  @cluster = cluster
17
19
  @nodes = nodes
18
20
  @pods = pods
19
21
  @services = services
20
- @endPointSlices = endPointSlices
22
+ @endpointslices = endpointslices
21
23
  @deployments = deployments
22
- @replicaSets = replicaSets
23
- @daemonSets = daemonSets
24
- @cronJobs = cronJobs
24
+ @replicasets = replicasets
25
+ @daemonsets = daemonsets
26
+ @cronjobs = cronjobs
25
27
  @jobs = jobs
26
- @statefulSets = statefulSets
28
+ @statefulsets = statefulsets
27
29
  @events = events
28
30
  @namespaces = namespaces
31
+ @infra = infra
29
32
  end
30
33
 
31
34
  def get_hash(obj, obj_name)
@@ -43,15 +46,16 @@ module Dto
43
46
  nodes: get_hash(@nodes, NODES.to_s),
44
47
  pods: get_hash(@pods, PODS.to_s),
45
48
  services: get_hash(@services, SERVICES.to_s),
46
- endpointslices: get_hash(@endPointSlices, ENDPOINT_SLICES.to_s),
49
+ endpointslices: get_hash(@endpointslices, ENDPOINT_SLICES.to_s),
47
50
  deployments: get_hash(@deployments, DEPLOYMENTS.to_s),
48
- replicasets: get_hash(@replicaSets, REPLICA_SETS.to_s),
49
- daemonsets: get_hash(@daemonSets, DAEMON_SETS.to_s),
50
- cronjobs: get_hash(@cronJobs, CRON_JOBS.to_s),
51
+ replicasets: get_hash(@replicasets, REPLICA_SETS.to_s),
52
+ daemonsets: get_hash(@daemonsets, DAEMON_SETS.to_s),
53
+ cronjobs: get_hash(@cronjobs, CRON_JOBS.to_s),
51
54
  jobs: get_hash(@jobs, JOBS.to_s),
52
- statefulsets: get_hash(@statefulSets, STATEFUL_SETS.to_s),
55
+ statefulsets: get_hash(@statefulsets, STATEFUL_SETS.to_s),
53
56
  events: get_hash(@events, EVENTS.to_s),
54
- namespaces: get_hash(@namespaces, NAMESPACES.to_s)
57
+ namespaces: get_hash(@namespaces, NAMESPACES.to_s),
58
+ infra: @infra.nil? ? nil : @infra.to_hash
55
59
  }.compact
56
60
  end
57
61
  end
data/lib/dto/state.rb CHANGED
@@ -3,16 +3,20 @@
3
3
 
4
4
  module Dto
5
5
  class State
6
- attr_accessor :last_timestamp
6
+ attr_accessor :last_timestamp, :retry_eligible_resources, :svc_log_stack_id
7
7
 
8
- def initialize(last_timestamp = nil)
8
+ def initialize(last_timestamp = nil, retry_eligible_resources = nil, svc_log_stack_id = nil)
9
9
  @last_timestamp = last_timestamp unless last_timestamp.nil?
10
+ @retry_eligible_resources = retry_eligible_resources unless retry_eligible_resources.nil?
11
+ @svc_log_stack_id = svc_log_stack_id unless svc_log_stack_id.nil?
10
12
  end
11
13
 
12
14
  # make sure all values are strings
13
15
  def to_hash
14
16
  {
15
- last_timestamp: @last_timestamp.to_s
17
+ last_timestamp: @last_timestamp.to_s,
18
+ retry_eligible_resources: @retry_eligible_resources.to_s,
19
+ svc_log_stack_id: @svc_log_stack_id.to_s
16
20
  }.compact
17
21
  end
18
22
  end
@@ -5,5 +5,6 @@ module Enum
5
5
  module AuthTypeEnum
6
6
  CONFIG = 'config'.freeze
7
7
  INSTANCE_PRINCIPAL = 'instance_principal'.freeze
8
+ # OKE_WORKLOAD_IDENTITY = 'oke_workload_identity'.freeze
8
9
  end
9
10
  end
@@ -5,5 +5,6 @@ module Enum
5
5
  module InfrastructureResourceDiscovery
6
6
  SUBNET = 'subnet'.freeze
7
7
  NODE_POOLS = 'node_pools'.freeze
8
+ LOAD_BALANCER = 'load_balancers'.freeze
8
9
  end
9
10
  end
@@ -2,7 +2,7 @@
2
2
  ## The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/
3
3
 
4
4
  module Enum
5
- module ObjectClientMapingEnum
5
+ module ObjectClientMappingEnum
6
6
  NODES = :core_client
7
7
  PODS = :core_client
8
8
  SERVICES = :core_client
@@ -0,0 +1,14 @@
1
+ ## Copyright (c) 2024 Oracle and/or its affiliates.
2
+ ## The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/
3
+
4
+ module Enum
5
+ module StackJobLifecycleStateEnum
6
+ # Documentation: https://docs.oracle.com/en-us/iaas/Content/ResourceManager/Tasks/jobs.htm
7
+ ACCEPTED = 'ACCEPTED'.freeze
8
+ IN_PROGRESS = 'IN_PROGRESS'.freeze
9
+ FAILED = 'FAILED'.freeze
10
+ SUCCEEDED = 'SUCCEEDED'.freeze
11
+ CANCELING = 'CANCELING'.freeze
12
+ CANCELED = 'CANCELED'.freeze
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ ## Copyright (c) 2024 Oracle and/or its affiliates.
2
+ ## The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/
3
+
4
+ module Enum
5
+ module StackJobOperationEnum
6
+ APPLY = 'APPLY'.freeze
7
+ PLAN = 'PLAN'.freeze
8
+ DESTROY = 'DESTROY'.freeze
9
+ end
10
+ end
@@ -1,6 +1,8 @@
1
1
  ## Copyright (c) 2024 Oracle and/or its affiliates.
2
2
  ## The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/
3
3
 
4
+ require 'set'
5
+
4
6
  # Infra
5
7
  require_relative './discover/infrastructure'
6
8
 
@@ -8,11 +10,10 @@ require_relative './discover/infrastructure'
8
10
  require_relative './dto/infra_objects_payload'
9
11
 
10
12
  # DTOs
11
- require_relative './dto/infra/cluster_entity_payload'
12
- require_relative './dto/infra/subnet_entity_payload'
13
- require_relative './dto/infra/vcn_entity_payload'
14
- require_relative './dto/infra/load_balancers_entity_payload'
15
- require_relative './dto/infra/node_pool_entity_payload'
13
+ require_relative './dto/infra/resource_payload'
14
+ require_relative './dto/infra/subnet_payload'
15
+ require_relative './dto/infra/node_pool_payload'
16
+ require_relative './dto/infra/load_balancer_payload'
16
17
 
17
18
  # Util
18
19
  require_relative './util/logging'
@@ -23,66 +24,166 @@ module InfraResources
23
24
 
24
25
  module_function
25
26
 
26
- def get_infra_resources(auth_object, cluster_id)
27
+ IP_Address = Struct.new(:ip, :isPublic)
28
+ Nodes = Struct.new(:id, :name, :subnetId, :privateIp, :publicIp, :lifecycleState)
29
+
30
+ def get_infra_resources(app_config, cluster_config, cluster_id, lb_ip_array)
31
+
27
32
  # Fetch cluster details using cluster OCID provided as argument during program run
28
33
  logger.debug('Fetching cluster details.')
29
- ce_response = Discover::Infrastructure.fetch_cluster_details(auth_object, cluster_id)
30
- cluster_entity_payload = Dto::Infra::ClusterEntityPayload.new(ce_response.name, ce_response.id)
34
+ ce_response = Discover::Infrastructure.fetch_cluster_details(cluster_id)
35
+ cluster_details = Dto::Infra::ResourcePayload.new(ce_response.name, ce_response.id, ce_response.compartment_id)
31
36
 
32
37
  # Fetch VCN associated with cluster
33
38
  logger.debug('Fetching virtual cloud network details.')
34
- vcn_response = Discover::Infrastructure.fetch_vcn_response(auth_object, ce_response.vcn_id)
35
- vcn_entity_payload = Dto::Infra::VcnEntityPayload.new(vcn_response.display_name, vcn_response.id)
39
+ vcn_response = Discover::Infrastructure.fetch_vcn_response(ce_response.vcn_id)
40
+ vcn_details = Dto::Infra::ResourcePayload.new(vcn_response.display_name, vcn_response.id, vcn_response.compartment_id)
36
41
 
37
- # Fetch subnets falling under same compartment as that of cluster using VCN OCID
38
- logger.debug('Fetching subnet details.')
39
- subnet_response = Discover::Infrastructure.fetch_subnet_list_response(auth_object, ce_response.compartment_id, vcn_response.id)
42
+ # Use resource search query to fetch load balancers associated with cluster OCID
43
+ logger.debug('Fetching load balancers associated with cluster.')
40
44
 
41
- # Loop subnet response to get individual subnets.
42
- subnet_entity_payload = []
43
- subnet_response.each do |subnet|
44
- next if subnet.nil?
45
+ load_balancer_details = []
45
46
 
46
- subnet_entity_payload.push(Dto::Infra::SubnetEntityPayload.new(subnet.display_name, subnet.id))
47
- end
47
+ lb_ip_array.each do |ip|
48
+ structured_query = "query loadbalancer resources matching '#{ip}'"
48
49
 
49
- # Use resource search query to fetch load balancers associated with cluster OCID
50
- logger.debug('Fetching load balancers associated with cluster.')
51
- free_text_response = Discover::Infrastructure.fetch_free_text_details(auth_object, ce_response.id)
50
+ resource_query_search_response = Discover::Infrastructure.search_with_structured_query(structured_query)
51
+
52
+ # TODO: We only expect one LB per IP address, remove looping over result ?
52
53
 
53
- load_balancer_entity_payload = nil
54
- free_text_response.items.each do |item|
55
- next if item.nil?
54
+ # Load Balancer Lifecycle State: CREATING, ACTIVE, DELETING
55
+ resource_query_search_response.items.each do |item|
56
+ lb_response = Discover::Infrastructure.fetch_load_balancer_details(item.identifier)
57
+ next if lb_response[:data].nil?
58
+ lb_ip_addresses = []
56
59
 
57
- next unless item.resource_type == 'LoadBalancer'
60
+ lb_response[:data].ip_addresses.each do |item|
61
+ lb_ip_addresses.push(IP_Address.new(item.ip_address, item.is_public))
62
+ end
58
63
 
59
- logger.info('Fetching load balancers details.')
60
- lb_response = Discover::Infrastructure.fetch_load_balancer_details(auth_object, item.identifier)
61
- lb_compartment_id = lb_response.defined_tags['Oracle-Tags']['CreatedBy']
62
- if lb_compartment_id == ce_response.id
63
- load_balancer_entity_payload = Dto::Infra::LoadBalancerEntityPayload.new(lb_response.display_name, lb_compartment_id)
64
+ subnet_ids = lb_response[:data].subnet_ids.nil? ? [] : lb_response[:data].subnet_ids
65
+
66
+ load_balancer_details.push(Dto::Infra::LoadBalancerPayload.new(lb_response[:data].display_name,
67
+ lb_response[:data].id,
68
+ lb_response[:data].compartment_id,
69
+ lb_response[:data].is_private,
70
+ lb_ip_addresses,
71
+ lb_response[:data].lifecycle_state,
72
+ subnet_ids))
73
+
74
+ logger.debug("LB detected : #{lb_response}")
64
75
  end
65
76
  end
66
77
 
78
+ logger.info("Discovered load balancer count: #{load_balancer_details.length}")
79
+
67
80
  # Iterate through all the compartments (starting from root tenancy level) and fetch node pools
68
81
  # associated with the cluster OCID
69
- node_pool_entity_payload = []
70
- compartment_list_response = Discover::Infrastructure.fetch_compartment_list(auth_object, auth_object[:oci_config].tenancy)
71
- compartment_list_response.each do |compartment|
72
- next if compartment.nil?
82
+ node_pool_details = []
83
+ node_pool_subnet_ids = []
84
+ worker_node_subnet_ids = []
85
+
86
+ logger.debug('Fetching node pools associated with cluster.')
87
+
88
+ node_pool_compartment_id = nil
89
+ scoped_at_tenancy = false
90
+ if app_config[:probe_all_compartments]
91
+ # Tenancy OCID is compulsory input if probe_all_compartments flag is set
92
+ logger.info('Node pool discovery scope set at tenancy level.')
93
+
94
+ node_pool_compartment_id = app_config[:tenancy_ocid]
95
+ scoped_at_tenancy = true
96
+ else
97
+ logger.info('Node pool discovery scoped to cluster compartment.')
98
+ node_pool_compartment_id = ce_response.compartment_id
99
+ end
100
+
101
+ begin
102
+ compartment_list_response = Discover::Infrastructure.fetch_compartment_list(node_pool_compartment_id, scoped_at_tenancy)
103
+ rescue StandardError => e
104
+ logger.error("Error while fetching compartment list. Error: [#{e}]")
105
+ raise StandardError, 'Error while fetching compartment list.'
106
+ end
107
+
108
+ compartment_list = []
109
+ compartment_list_response[:data]&.each do |compartment|
110
+ compartment_list.push(compartment.id)
111
+ end
112
+
113
+ if scoped_at_tenancy
114
+ compartment_list.push(app_config[:tenancy_ocid])
115
+ else
116
+ compartment_list.push(ce_response.compartment_id)
117
+ end
118
+
119
+ compartment_list.each do |compartment|
120
+
121
+ node_pool_list_response = Discover::Infrastructure.fetch_node_pool_lists(compartment, ce_response.id)
122
+
123
+ node_pool_list_response.each do |node_pool|
124
+
125
+ subnet_ids = node_pool.subnet_ids.nil? ? [] : node_pool.subnet_ids
126
+
127
+ subnet_ids.each do |node_pool_subnet|
128
+ node_pool_subnet_ids.push(node_pool_subnet)
129
+ end
130
+
131
+ node_pool_response = Discover::Infrastructure.fetch_node_pool(node_pool.id)
132
+
133
+ nodes = []
134
+ node_pool_response&.nodes&.each do |node_instance|
135
+ nodes.push(Nodes.new(node_instance.id, node_instance.name, node_instance&.subnet_id,
136
+ node_instance&.private_ip, node_instance&.public_ip, node_instance.lifecycle_state))
137
+ end
138
+
139
+ node_pool_details.push(Dto::Infra::NodePoolPayload.new(node_pool.name, node_pool.id,
140
+ node_pool.compartment_id, subnet_ids, nodes))
141
+
142
+ # Fetch worker node subnet details from placement configurations
143
+ placement_configs_details = node_pool.node_config_details.placement_configs
144
+ placement_configs_details.each do |placement_config|
145
+ next if placement_config.nil?
146
+
147
+ worker_node_subnet_ids.push(placement_config.subnet_id)
148
+ end
149
+ end
150
+ end
151
+
152
+ # Fetch details of subnets associated with cluster
153
+ # Subnet Lifecycle State: AVAILABLE, PROVISIONING, TERMINATED, TERMINATING, UPDATING
154
+ logger.debug('Fetching subnet details associated with cluster.')
155
+
156
+ subnet_resource_details = []
157
+ cluster_subnet_ids = []
158
+
159
+ kubernetes_api_endpoint_subnet_id = ce_response.endpoint_config.subnet_id
160
+ service_loadbalancer_subnet_ids = ce_response.options.service_lb_subnet_ids
161
+
162
+ cluster_subnet_ids.push(kubernetes_api_endpoint_subnet_id)
163
+ cluster_subnet_ids += service_loadbalancer_subnet_ids
164
+ cluster_subnet_ids += node_pool_subnet_ids
165
+ cluster_subnet_ids += worker_node_subnet_ids
166
+
167
+ # Remove duplicates. The | operator is used to compute the union of two arrays
168
+ # and ensures there are no duplicates. Adding the union of an array with [] does
169
+ # not change the original array but removes the duplicates
170
+ cluster_subnet_ids = cluster_subnet_ids | []
73
171
 
74
- node_pool_response = Discover::Infrastructure.fetch_node_pool_lists(auth_object, compartment.id, ce_response.id)
172
+ cluster_subnet_ids.each do |subnet_id|
75
173
 
76
- node_pool_response.each do |node_pool|
77
- next if node_pool.nil?
174
+ subnet_details = Discover::Infrastructure.fetch_subnet_details(subnet_id)
78
175
 
79
- node_pool_entity_payload.push(Dto::Infra::NodePoolEntityPayload.new(node_pool.node_image_name, node_pool.node_image_id, node_pool.compartment_id))
176
+ if !subnet_details[:data].nil? && subnet_details[:status] == 200
177
+ subnet = subnet_details[:data]
178
+ subnet_resource_details.push(Dto::Infra::SubnetPayload.new(subnet.display_name, subnet.id, subnet.compartment_id,
179
+ subnet.prohibit_internet_ingress, subnet.prohibit_public_ip_on_vnic,
180
+ subnet.cidr_block, subnet.lifecycle_state))
80
181
  end
81
182
  end
82
183
 
83
184
  Dto::InfraObjectsPayLoad.new(
84
- cluster_entity_payload, vcn_entity_payload, subnet_entity_payload,
85
- load_balancer_entity_payload, node_pool_entity_payload
185
+ cluster_details, vcn_details, subnet_resource_details,
186
+ load_balancer_details, node_pool_details
86
187
  )
87
188
  rescue StandardError => e
88
189
  logger.error("Error in getting infrastructure resources: #{e}")
@@ -56,7 +56,7 @@ module ObjectsResources
56
56
 
57
57
  begin
58
58
  payload_executors = Enum::KubernetesObjectsEnum.constants(false).map do |object_type|
59
- if Enum::ObjectClientMapingEnum.const_defined? object_type
59
+ if Enum::ObjectClientMappingEnum.const_defined? object_type
60
60
  if enable_threading == true
61
61
  Concurrent::Future.execute({ executor: thread_pool }) do
62
62
  get_objects_resources(object_type)
@@ -80,11 +80,21 @@ module ObjectsResources
80
80
  end_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
81
81
  logger.debug("Time elapsed in collecting objects: #{(end_time - start_time).round(2)} seconds.")
82
82
 
83
- kubernetes_objects_processed = Dto::KubernetesObjectsPayLoad.new(
84
- cluster, @nodes[:processed], @pods[:processed], @services[:processed], @endpoint_slices[:processed],
85
- @deployments[:processed], @replica_sets[:processed], @daemon_sets[:processed], @cron_jobs[:processed],
86
- @jobs[:processed], @stateful_sets[:processed], @events[:processed], @namespaces[:processed]
87
- )
83
+ kubernetes_objects_processed = {
84
+ cluster: cluster,
85
+ nodes: @nodes[:processed],
86
+ pods: @pods[:processed],
87
+ services: @services[:processed],
88
+ endpoint_slices: @endpoint_slices[:processed],
89
+ deployments: @deployments[:processed],
90
+ replica_sets: @replica_sets[:processed],
91
+ daemon_sets: @daemon_sets[:processed],
92
+ cron_jobs: @cron_jobs[:processed],
93
+ jobs: @jobs[:processed],
94
+ stateful_sets: @stateful_sets[:processed],
95
+ events: @events[:processed],
96
+ namespaces: @namespaces[:processed]
97
+ }
88
98
 
89
99
  kubernetes_objects_raw_responses = {
90
100
  nodes: @nodes[:raw],