jcf 0.0.11 → 0.0.12

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9479fc4468d9132f60c15f22782820798f35ae649d5bb09d575e7b051d77ddda
4
- data.tar.gz: 4090a17eb90884a706b11ea865805a4a99ada9b8bfbbfc1206fd6ddbf21e4af6
3
+ metadata.gz: 33389a4011279ad183dc738318b71355a50601dde4f602d867cb060b305e7a49
4
+ data.tar.gz: 42f129b8aa7ab515bd51fac1f2c8f78ee6785f8750debb5778c88fa2d062dca1
5
5
  SHA512:
6
- metadata.gz: 06fc37725e7ae5ad94b16e5e4a365ecd69760c45ca7e21922d81ca57e24e826cd43328d67d50e3b7bce5366a5421d09e99eb4fe03529d05562b9a6d4463ca546
7
- data.tar.gz: 2b508ca2c6441a640f13aa03fa05fb19438467f0bfa053e5cd23f37b8b861176f9648f22746cc2576a73c371e641e50684e02c0960da1e39401bfc89b676a1fc
6
+ metadata.gz: 35548f0ce298af159e532eb6b0517594d8e990857d8c5f77aab5e0b770920758e2a11f74ca063c113342adc1a46df120ed2d4577684ae69b60db90578a4a5d8d
7
+ data.tar.gz: 1fd422e325af12931d444728c4aca883eceaceab60bea50bc33e143bc62e70d783b1ed4103a2c181302fc6d5e7b44eeff70aa4ff53278cb12710e7b6ec806ee6
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [0.0.12] - 2023-10-19
2
+
3
+ - Refactored broker backend querying for metrics to use a plugin system that can be extended to support other brokers. Currently only the AWS and S3 broker is supported, but it should be easy to add others.
4
+ - Add a `jcf plugins` command to list available plugins (currently only ones in the `lib/jcf/plugins` directory)
5
+ - Refactored specs for output formatters
6
+
1
7
  ## [0.0.11] - 2023-10-12
2
8
 
3
9
  - Add a tree output for a new command `jcf services NAME` that will show all the offerings and instances for that broker. In a tree. Because trees are cool.
data/lib/jcf/cf/base.rb CHANGED
@@ -23,6 +23,14 @@ module JCF
23
23
  { name: name, guid: guid, relationships: relationships }
24
24
  end
25
25
 
26
+ def keys
27
+ attributes.keys
28
+ end
29
+
30
+ def values
31
+ attributes.values
32
+ end
33
+
26
34
  def initialize(name: nil, guid: nil, relationships: nil)
27
35
  @name = name
28
36
  @guid = guid
@@ -32,12 +40,14 @@ module JCF
32
40
  class << self
33
41
  attr_accessor :endpoint
34
42
 
43
+ def keys; new.keys; end
44
+
35
45
  def find_by(attrs)
36
46
  objects = all
37
47
  objects.find_all do |obj|
38
- # only find by attributes we have and our object has
39
48
  keys = obj.attributes.keys & attrs.keys
40
49
  keys.all? do |key|
50
+ return true if attrs[key].nil?
41
51
  obj.attributes[key].include? attrs[key]
42
52
  end
43
53
  end
@@ -51,6 +61,7 @@ module JCF
51
61
  new(guid: guid).populate!
52
62
  end
53
63
 
64
+ # TODO: make this less greedy
54
65
  def all(params = {})
55
66
  params.compact!
56
67
 
@@ -14,38 +14,51 @@ module JCF
14
14
  module Commands
15
15
  module CF
16
16
  class Metrics < Command
17
- argument :offering, required: true, values: %w[postgres mysql aws-s3-bucket],
18
- desc: "Choose a service instance offering to query"
17
+ argument :broker, required: true,
18
+ desc: "Choose a service instance offering to query. Get the broker name from the command: jcf sb"
19
+ argument :iaas_plugin, aliases: ["-m"], required: true, type: :string,
20
+ values: ::JCF::Plugins.plugins.keys.collect(&:to_s),
21
+ desc: "Select a IaaS plugin this broker is backed by"
19
22
 
20
23
  option :template, aliases: ["-t"], required: true, type: :string,
21
- desc: "Template for backend service instance names e.g. \"rdsbroker-{guid}-{name}\""
24
+ desc: "Template for backend service instance names e.g. \"rdsbroker-{guid}-{name}\""
22
25
  option :values, aliases: ["-v"], required: false, type: :string, default: "",
23
- desc: "Values for the template. 'guid' is the service instance guid e.g. \"name=test\""
26
+ desc: "Values for the template. 'guid' is the service instance guid e.g. \"name=test\""
24
27
  option :org, aliases: ["-o"], required: true, type: :string,
25
- desc: "Choose an organization (can be multiple comma-separated)"
28
+ desc: "Choose an organization (can be multiple comma-separated)"
26
29
  option :name, aliases: ["-n"], type: :string, desc: "Choose a service instance name"
27
30
 
28
31
  def call(*_args, **options)
29
32
  validate_options(options)
33
+ JCF.plugin options[:iaas_plugin].to_sym
34
+ plugin = JCF::Plugins.plugins[options[:iaas_plugin].to_sym]
35
+
30
36
  orgs = options[:org].include?(",") ? options[:org].split(",") : [options[:org]]
31
37
 
38
+ brokers = service_brokers.select { |b| b.name == options[:broker] }
39
+ # find the offerings for those brokers
40
+ offerings = service_offerings.select do |o|
41
+ brokers.find { |b| b.guid == o.relationships.service_broker.guid }
42
+ end
43
+ if offerings && offerings.empty?
44
+ err.puts "No offerings found for broker #{options[:broker]}"
45
+ exit(1)
46
+ end
47
+ err.puts "Found #{offerings.count} offerings"
48
+
32
49
  orgs.each do |org|
33
50
  org_guid = organizations.find { |o| o.name == org }.guid
34
51
  err.puts "Found org guid: #{org_guid}"
35
52
 
36
- offering_guid = service_offerings.find { |s| s.name == options[:offering] }&.guid
37
- err.puts "Found offering guid: #{offering_guid}"
38
-
39
- unless offering_guid
40
- err.puts "No offerings found for type #{options[:offering]}"
41
- exit(1)
42
- end
43
-
44
- # find the plans for those gatherings
53
+ # find the plans for those offerings
45
54
  plan_guids = service_plans.find_all do |plan|
46
- plan.relationships.service_offering.guid == offering_guid
55
+ offerings.collect(&:guid).include? plan.relationships.service_offering.guid
47
56
  end.collect(&:guid)
48
57
  err.puts "Found plan guids: #{plan_guids.count}"
58
+ if plan_guids.empty?
59
+ err.puts "No plans found for offerings"
60
+ exit(1)
61
+ end
49
62
 
50
63
  # look up the instances that match the plans and org
51
64
  # "/v3/service_instances?organization_guids=${org_guids}&service_plan_guids=${plan_guids}"
@@ -56,11 +69,9 @@ module JCF
56
69
  instances.select! { |i| i.name.include? options[:name] } if options[:name]
57
70
  err.puts "Found instances: #{instances.count}"
58
71
 
59
- cw = JCF::AWS::CloudWatch.new
60
- values = []
72
+ values = {}
61
73
 
62
74
  Thread.abort_on_exception = true
63
- # use a the number of processors as the number of threads
64
75
  instances.each_slice(Concurrent.processor_count) do |slice|
65
76
  slice.collect do |instance|
66
77
  service_plan = instance.relationships.service_plan.populate!
@@ -68,42 +79,42 @@ module JCF
68
79
  service_broker = service_offering.relationships.service_broker.populate!
69
80
 
70
81
  Thread.new do
71
- m = JCF::CF::Metric.new
72
- m.name = (instance.name || "")
73
- err.puts "Getting metrics for #{m.name}"
74
- m.region = ENV["AWS_REGION"]
75
- m.deploy_env = options[:env]
76
- m.organization = org
77
- m.organization_guid = org_guid
82
+ metrics = {}
83
+ metrics[:name] = (instance.name || "")
84
+ metrics[:instance_guid] = instance.guid
85
+ err.puts "Getting metrics for #{instance.name}"
86
+ metrics[:region] = ENV["AWS_REGION"]
87
+ metrics[:organization] = org
88
+ metrics[:organization_guid] = org_guid
78
89
  space = spaces.find { |s| s.guid == instance.relationships.space.guid }
79
- m.space = space.name
80
- m.space_guid = space.guid
81
- m.service_broker_name = service_broker.name
82
- m.service_broker_guid = service_broker.guid
83
- m.service_offering = service_offering.name
84
- m.service_plan = service_plan.name
90
+ metrics[:space] = space.name
91
+ metrics[:space_guid] = space.guid
92
+ metrics[:service_broker_name] = service_broker.name
93
+ metrics[:service_broker_guid] = service_broker.guid
94
+ metrics[:service_offering] = service_offering.name
95
+ metrics[:service_plan] = service_plan.name
85
96
 
86
97
  template = options[:template]
87
98
  t_values = parse_values(options[:values], instance.guid)
88
99
 
89
- if service_offering.name == "postgres"
90
- m.storage_used = to_gb(cw.rds_storage_used(name: JCF::CLI.template_parser(template, t_values)) || "")
91
- m.storage_allocated = to_gb(cw.storage_allocated(name: JCF::CLI.template_parser(template, t_values)) || "")
92
- m.storage_free = to_gb(cw.storage_free(name: JCF::CLI.template_parser(template, t_values)) || "")
93
- m.iops = (cw.iops(name: JCF::CLI.template_parser(template, t_values)).to_fs(:rounded, precision: 0) || "")
94
- m.cpu = (cw.cpu(name: JCF::CLI.template_parser(template, t_values)).to_fs(:rounded, precision: 0) || "")
95
- end
96
-
97
- if service_offering.name == "aws-s3-bucket"
98
- m.storage_used = to_gb(cw.s3_storage_used(name: JCF::CLI.template_parser(template, t_values)) || "")
100
+ t = JCF::CLI.template_parser(template, t_values)
101
+ plugin.new(name: t).metrics.each do |k, v|
102
+ metrics[k] = v
99
103
  end
100
- values << m
104
+ values[instance.guid] = metrics
101
105
  end
102
- end.map(&:value)
106
+ end.each(&:join)
103
107
  end
104
108
 
105
- values << JCF::CF::Metric.new if values.empty?
106
- out.puts formatter.format(values)
109
+ # values = { guid: { name: "name", space: "space" }, guid2: { name: "name2", space: "space2" } }
110
+ output = Hash.new { |hash, key| hash[key] = [] }
111
+ values.each do |guid, metrics|
112
+ metrics.each do |k, v|
113
+ output[k] << v
114
+ end
115
+ end
116
+
117
+ out.puts formatter.format(data: output)
107
118
  err.puts "Done."
108
119
  end
109
120
  end
@@ -141,13 +152,7 @@ module JCF
141
152
  end
142
153
 
143
154
  def service_brokers
144
- JCF::CF::ServiceBroker.all
145
- end
146
-
147
- def to_gb(bytes)
148
- Filesize.from("#{bytes} b").to("GB").to_fs(:rounded, precision: 2)
149
- rescue ArgumentError
150
- 0
155
+ @service_brokers ||= JCF::CF::ServiceBroker.all
151
156
  end
152
157
  end
153
158
  end
@@ -8,14 +8,17 @@ module JCF
8
8
  module Commands
9
9
  module CF
10
10
  class Organizations < Command
11
+ include JCF::CF
12
+
11
13
  argument :name, required: false, desc: "Organization name"
12
14
 
13
15
  def call(name: nil, **)
14
- if name
15
- out.puts formatter.format(JCF::CF::Organization.find_by(name: name))
16
+ values = if name
17
+ Organization.find_by(name: name).collect(&:values)
16
18
  else
17
- out.puts formatter.format(JCF::CF::Organization.all)
19
+ Organization.all.collect(&:values)
18
20
  end
21
+ out.puts formatter.format(headers: Organization.keys, values: values)
19
22
  end
20
23
  end
21
24
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JCF
4
+ module CLI
5
+ module Commands
6
+ class Plugins < Command
7
+ desc "Show JCF plugins"
8
+
9
+ def call(*)
10
+ out.puts "JCF Plugins:"
11
+ plugin_dir = File.join(JCF.root, "jcf", "plugins", "*.rb")
12
+ pp "plugin dir: #{plugin_dir}" if ENV["DEBUG"]
13
+ Dir[plugin_dir].each do |plugin|
14
+ out.puts " file: #{File.basename(plugin, ".rb")}" if ENV["DEBUG"]
15
+ JCF::Plugins.load_plugin(File.basename(plugin, ".rb").to_sym)
16
+ end
17
+ JCF::Plugins.plugins.each do |plugin|
18
+ out.puts " #{plugin}"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -7,6 +7,7 @@ module JCF
7
7
 
8
8
  def self.register_commands!
9
9
  register "version", Commands::Version, aliases: ["v", "-v", "--version"]
10
+ register "plugins", Commands::Plugins
10
11
  register "metrics", Commands::CF::Metrics, aliases: ["m"]
11
12
 
12
13
  register "organizations", Commands::CF::Organizations, aliases: %w[o orgs organization]
@@ -7,24 +7,12 @@ module JCF
7
7
  module OutputFormatters
8
8
  class CSV
9
9
  class << self
10
- def format(data)
11
- case data
12
- in Array
13
- array = data.collect(&:serializable_hash)
14
- generate_csv(headers: array.first&.keys, values: array)
15
- in Hash
16
- generate_csv(headers: data.keys.sort, values: [data.serializable_hash])
17
- else
18
- generate_csv(headers: [], values: [])
19
- end
20
- end
21
-
22
- private
10
+ def format(data:)
11
+ return "" if data.nil? || data.empty?
23
12
 
24
- def generate_csv(headers:, values:)
25
- ::CSV.generate(headers: headers, write_headers: true) do |csv|
26
- values.each do |hash|
27
- csv << hash.values
13
+ ::CSV.generate(headers: data.keys, write_headers: true) do |csv|
14
+ data.values.transpose.each do |value|
15
+ csv << value
28
16
  end
29
17
  end
30
18
  end
@@ -6,12 +6,10 @@ module JCF
6
6
  module CLI
7
7
  module OutputFormatters
8
8
  class JSON
9
- def self.format(data)
10
- if data.is_a?(Enumerable)
11
- ::JSON.generate data.collect(&:serializable_hash)
12
- else
13
- ::JSON.generate data.serializable_hash
14
- end
9
+ def self.format(data:)
10
+ return "{}" if data.nil? || data.empty?
11
+
12
+ data.to_json
15
13
  end
16
14
  end
17
15
  end
@@ -7,8 +7,8 @@ module JCF
7
7
  module OutputFormatters
8
8
  class Text
9
9
  class << self
10
- def format(data, tree: false)
11
- return "" if data.nil?
10
+ def format(data:, tree: false)
11
+ return "" if data.nil? || data.empty?
12
12
 
13
13
  if tree
14
14
  render_tree(data)
@@ -17,6 +17,8 @@ module JCF
17
17
  end
18
18
  end
19
19
 
20
+ private
21
+
20
22
  def render_data(data)
21
23
  keys = collect_keys(data)
22
24
  values = collect_values(data)
@@ -29,19 +31,30 @@ module JCF
29
31
  TTY::Tree.new(data).render
30
32
  end
31
33
 
32
- def collect_values(data)
34
+ def collect_keys(data)
35
+ return ["Empty result"] if !data || data.empty?
36
+
33
37
  if data.is_a?(Array)
34
- data.map { |d| d.attributes.values.collect(&:to_s) }
38
+ data.first.keys.collect(&:to_s)
39
+ elsif data.is_a?(Hash)
40
+ data.keys.collect(&:to_s) || ["Empty result"]
35
41
  else
36
- [data.attributes.values.collect(&:to_s)]
42
+ data.keys.collect(&:to_s)
37
43
  end
38
44
  end
39
45
 
40
- def collect_keys(data)
46
+ # Hash:
47
+ # values: [["name1", "name2"], ["space1", "space2"]]
48
+ # output: [["name1", "space1"], ["name2", "space2"]]
49
+ def collect_values(data)
50
+ return [["Empty result"]] if !data || data.empty?
51
+
41
52
  if data.is_a?(Array)
42
- data.first&.attributes&.keys || ["Empty result"]
53
+ data.map { |d| d.attributes.values.collect(&:to_s) }
54
+ elsif data.is_a?(Hash)
55
+ data.values.transpose
43
56
  else
44
- data.attributes.keys
57
+ [data.attributes.values.collect(&:to_s)]
45
58
  end
46
59
  end
47
60
  end
data/lib/jcf/cli.rb CHANGED
@@ -14,6 +14,50 @@ module JCF
14
14
  @cache ||= MiniCache::Store.new
15
15
  end
16
16
 
17
+ def self.plugin(plugin)
18
+ plugin = JCF::Plugins.load_plugin(plugin) if plugin.is_a?(Symbol)
19
+ validate_plugin!(plugin)
20
+ plugin.load_dependencies(self, *args, &block) if plugin.respond_to?(:load_dependencies)
21
+ plugin.configure(self, *args, &block) if plugin.respond_to?(:configure)
22
+ end
23
+
24
+ def self.validate_plugin!(plugin)
25
+ puts "Validating plugin (#{plugin}) implementation conforms to interface" if ENV["DEBUG"]
26
+
27
+ %i[metrics names values].each do |method|
28
+ raise "Plugin does not conform to interface (missing method \"#{method.to_s}\")" \
29
+ unless plugin.new(name: nil).respond_to?(method)
30
+ end
31
+ rescue JCF::CLI::NotLoggedInError => e
32
+ puts e.message
33
+ exit 1
34
+ end
35
+
36
+ module Plugins
37
+ @plugins = {}
38
+
39
+ def self.plugins
40
+ @plugins
41
+ end
42
+
43
+ def self.load_plugin(name)
44
+ return @plugins[name] if @plugins[name]
45
+
46
+ puts "Loading plugin #{name}" if ENV["DEBUG"]
47
+ require "jcf/plugins/#{name}"
48
+ raise "Plugin didn't correctly register itself" unless @plugins[name]
49
+ @plugins[name]
50
+ end
51
+
52
+ # Plugins need to call this method to register themselves:
53
+ #
54
+ # JCF::Plugins.register_plugin :render, Render
55
+ def self.register_plugin(name, mod)
56
+ puts "Registering plugin #{name}" if ENV["DEBUG"]
57
+ @plugins[name] = mod
58
+ end
59
+ end
60
+
17
61
  module CLI
18
62
  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
19
63
  def self.loader
@@ -59,7 +103,9 @@ module JCF
59
103
 
60
104
  extend Dry::CLI::Registry
61
105
 
106
+ puts "Loading formatters..." if ENV["DEBUG"]
62
107
  register_formatters!
108
+ puts "Loading commands..." if ENV["DEBUG"]
63
109
  register_commands!
64
110
  end
65
111
  end
data/lib/jcf/metric.rb ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module JCF
6
+ class Metric
7
+ attr_accessor :name, :value
8
+
9
+ def to_s
10
+ "#{name}: #{value}"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "aws-sdk-cloudwatch"
4
+ require "aws-sdk-rds"
5
+ require "active_support/core_ext/integer/time"
6
+ require "active_support/isolated_execution_state"
7
+ require "filesize"
8
+
9
+ module JCF
10
+ module Plugins
11
+ class AwsRds
12
+ def initialize(name:)
13
+ @name = name
14
+ @metrics = {}
15
+ check_token!
16
+ end
17
+
18
+ def names
19
+ %w[storage_used storage_allocated storage_free iops cpu]
20
+ end
21
+
22
+ def values
23
+ names.map { |name| send(name.to_sym) }
24
+ end
25
+
26
+ def metrics
27
+ @metrics[:storage_used] = to_gb(storage_used(name: @name || ""))
28
+ @metrics[:storage_allocated] = to_gb(storage_allocated(name: @name) || "")
29
+ @metrics[:storage_free] = to_gb(storage_free(name: @name) || "")
30
+ @metrics[:iops] = (iops(name: @name).to_fs(:rounded, precision: 0) || "")
31
+ @metrics[:cpu] = (cpu(name: @name).to_fs(:rounded, precision: 0) || "")
32
+ @metrics
33
+ end
34
+
35
+ def to_s
36
+ metrics.to_s
37
+ end
38
+
39
+ private
40
+
41
+ def check_token!
42
+ Aws::STS::Client.new.get_caller_identity({})
43
+ rescue Aws::Errors::MissingCredentialsError
44
+ raise JCF::CLI::NotLoggedInError, "Your AWS token has expired. Please log in again."
45
+ end
46
+
47
+ METRICS = {
48
+ free_storage: "FreeStorageSpace",
49
+ allocated_storage: "AllocatedStorage",
50
+ iops: "WriteIOPS",
51
+ cpu: "CPUUtilization"
52
+ }.freeze
53
+
54
+ def storage_free(name:)
55
+ storage_free = cloudwatch(name: name, metric: "FreeStorageSpace")
56
+ storage_free.to_i
57
+ end
58
+
59
+ def storage_allocated(name:)
60
+ rds = Aws::RDS::Client.new
61
+ size = rds
62
+ .describe_db_instances(db_instance_identifier: name)
63
+ .db_instances.first.allocated_storage
64
+ Filesize.from("#{size} GB").to_i
65
+ end
66
+
67
+ def storage_used(name:)
68
+ free = storage_free(name: name)
69
+ allocated = storage_allocated(name: name)
70
+ allocated - free
71
+ end
72
+
73
+ def iops(name:)
74
+ cloudwatch(name: name, metric: :iops)
75
+ end
76
+
77
+ def cpu(name:)
78
+ cloudwatch(name: name, metric: :cpu)
79
+ end
80
+
81
+ # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
82
+ def cloudwatch(name:, metric:)
83
+ cloudwatch = Aws::CloudWatch::Client.new
84
+ res = cloudwatch.get_metric_statistics({
85
+ namespace: "AWS/RDS",
86
+ metric_name: metric,
87
+ dimensions: [{ name: "DBInstanceIdentifier", value: name }],
88
+ start_time: 1.day.ago,
89
+ end_time: Time.now,
90
+ period: 86_400,
91
+ statistics: ["Average"]
92
+ })
93
+
94
+ pp res if ENV["DEBUG"]
95
+
96
+ res.datapoints.first&.average || 0
97
+ rescue Aws::Errors::MissingCredentialsError
98
+ puts "You are not logged in to an AWS shell. 'gds aws <ACCOUNT> -s'"
99
+ end
100
+ # rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
101
+
102
+ def to_gb(bytes)
103
+ Filesize.from("#{bytes} b").to("GB").to_fs(:rounded, precision: 2)
104
+ rescue ArgumentError
105
+ 0
106
+ end
107
+ end
108
+
109
+ register_plugin :aws_rds, AwsRds
110
+ end
111
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "aws-sdk-s3"
4
+ require "active_support/core_ext/integer/time"
5
+ require "active_support/isolated_execution_state"
6
+ require "filesize"
7
+
8
+ module JCF
9
+ module Plugins
10
+ class AwsS3
11
+ def initialize(name:)
12
+ @name = name
13
+ @metrics = {}
14
+ check_token!
15
+ end
16
+
17
+ def names
18
+ %w[storage_used]
19
+ end
20
+
21
+ def values
22
+ names.map { |name| send(name.to_sym) }
23
+ end
24
+
25
+ def metrics
26
+ @metrics[:storage_used] = to_gb(s3_storage_used(name: @name || ""))
27
+ @metrics
28
+ end
29
+
30
+ def to_s
31
+ metrics.to_s
32
+ end
33
+
34
+ private
35
+
36
+ def s3_storage_used(name:)
37
+ s3 = Aws::S3::Client.new
38
+ total_size = 0
39
+ response = s3.list_objects_v2(bucket: name)
40
+ response.contents.each do |object|
41
+ total_size += object.size
42
+ end
43
+ total_size
44
+ end
45
+
46
+ def check_token!
47
+ Aws::STS::Client.new.get_caller_identity({})
48
+ rescue Aws::Errors::MissingCredentialsError
49
+ raise JCF::CLI::NotLoggedInError, "Your AWS token has expired. Please log in again."
50
+ end
51
+
52
+ def to_gb(bytes)
53
+ Filesize.from("#{bytes} b").to("GB").to_fs(:rounded, precision: 2)
54
+ rescue ArgumentError
55
+ 0
56
+ end
57
+ end
58
+
59
+ register_plugin :aws_s3, AwsS3
60
+ end
61
+ end
data/lib/jcf/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JCF
4
- VERSION = "0.0.11"
4
+ VERSION = "0.0.12"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jcf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.11
4
+ version: 0.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamie van Dyke
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-10-12 00:00:00.000000000 Z
11
+ date: 2023-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -279,7 +279,6 @@ files:
279
279
  - lib/jcf/cf.rb
280
280
  - lib/jcf/cf/.DS_Store
281
281
  - lib/jcf/cf/base.rb
282
- - lib/jcf/cf/metric.rb
283
282
  - lib/jcf/cf/organization.rb
284
283
  - lib/jcf/cf/quota.rb
285
284
  - lib/jcf/cf/relationships.rb
@@ -304,12 +303,16 @@ files:
304
303
  - lib/jcf/cli/commands/cf/services.rb
305
304
  - lib/jcf/cli/commands/cf/spaces.rb
306
305
  - lib/jcf/cli/commands/cf/users.rb
306
+ - lib/jcf/cli/commands/plugins.rb
307
307
  - lib/jcf/cli/commands/version.rb
308
308
  - lib/jcf/cli/errors.rb
309
309
  - lib/jcf/cli/output_formatters.rb
310
310
  - lib/jcf/cli/output_formatters/csv.rb
311
311
  - lib/jcf/cli/output_formatters/json.rb
312
312
  - lib/jcf/cli/output_formatters/text.rb
313
+ - lib/jcf/metric.rb
314
+ - lib/jcf/plugins/aws_rds.rb
315
+ - lib/jcf/plugins/aws_s3.rb
313
316
  - lib/jcf/version.rb
314
317
  - sig/jcf.rbs
315
318
  homepage: https://github.com/fearoffish/paas-org-metric-gathering-gem
@@ -336,7 +339,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
336
339
  - !ruby/object:Gem::Version
337
340
  version: '0'
338
341
  requirements: []
339
- rubygems_version: 3.4.19
342
+ rubygems_version: 3.4.20
340
343
  signing_key:
341
344
  specification_version: 4
342
345
  summary: Gather metrics from AWS for CloudFoundry installations
data/lib/jcf/cf/metric.rb DELETED
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "base"
4
-
5
- module JCF
6
- module CF
7
- class Metric < Base
8
- attr_accessor :name, :region, :deploy_env, :organization, :organization_guid, :space, :space_guid,
9
- :service_broker_name, :service_broker_guid, :service_offering, :service_plan,
10
- :storage_allocated, :storage_used, :storage_free, :iops, :cpu
11
-
12
- # rubocop:disable Metrics/MethodLength
13
- def attributes
14
- {
15
- name: name,
16
- region: region,
17
- organization: organization,
18
- organization_guid: organization_guid,
19
- space: space,
20
- space_guid: space_guid,
21
- service_broker_name: service_broker_name,
22
- service_broker_guid: service_broker_guid,
23
- service_offering: service_offering,
24
- service_plan: service_plan,
25
- storage_used: storage_used,
26
- storage_allocated: storage_allocated,
27
- storage_free: storage_free,
28
- iops: iops,
29
- cpu: cpu
30
- }
31
- end
32
- # rubocop:enable Metrics/MethodLength
33
-
34
- def to_s
35
- "#{name}: used(#{storage_used}) allocated(#{storage_allocated}) free(#{storage_free}) iops(#{iops}) cpu(#{cpu})"
36
- end
37
- end
38
- end
39
- end