jcf 0.0.12 → 0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 33389a4011279ad183dc738318b71355a50601dde4f602d867cb060b305e7a49
4
- data.tar.gz: 42f129b8aa7ab515bd51fac1f2c8f78ee6785f8750debb5778c88fa2d062dca1
3
+ metadata.gz: 65808aa6761614f5fd189ae66ffe581709eaaebe1bbca0b9833ee00ead7957be
4
+ data.tar.gz: 223665d3d2608a6a2a12d870e718fd969753c43fb73db5edad10c4bc4dfa3166
5
5
  SHA512:
6
- metadata.gz: 35548f0ce298af159e532eb6b0517594d8e990857d8c5f77aab5e0b770920758e2a11f74ca063c113342adc1a46df120ed2d4577684ae69b60db90578a4a5d8d
7
- data.tar.gz: 1fd422e325af12931d444728c4aca883eceaceab60bea50bc33e143bc62e70d783b1ed4103a2c181302fc6d5e7b44eeff70aa4ff53278cb12710e7b6ec806ee6
6
+ metadata.gz: 179b7adbe213bbc2a317fbd06407abdd1f2d3ce27e3da8e2e42495db4b9fc748d5a798f4920017d00d0039c34fa168d2dfa1ef721313853abf1202be5b5de4d7
7
+ data.tar.gz: f2e8ec3f17848da098d049ae482e8529927f77e52337023fbda07ce6f4a438cb2ac441d69095552396e913a59d2c6e52099171c6bfc0bea62f05d8a1c0785270
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## [0.0.14] - 2023-10-19
2
+
3
+ - Fix all the output I broker in the last release...I need some more extensive tests
4
+
5
+ ## [0.0.13] - 2023-10-19
6
+
7
+ - Fix a bug where I'd left in some unnecessary code
8
+
1
9
  ## [0.0.12] - 2023-10-19
2
10
 
3
11
  - 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.
data/lib/jcf/cf/base.rb CHANGED
@@ -40,7 +40,7 @@ module JCF
40
40
  class << self
41
41
  attr_accessor :endpoint
42
42
 
43
- def keys; new.keys; end
43
+ def keys = new.keys
44
44
 
45
45
  def find_by(attrs)
46
46
  objects = all
@@ -48,6 +48,7 @@ module JCF
48
48
  keys = obj.attributes.keys & attrs.keys
49
49
  keys.all? do |key|
50
50
  return true if attrs[key].nil?
51
+
51
52
  obj.attributes[key].include? attrs[key]
52
53
  end
53
54
  end
@@ -72,6 +73,15 @@ module JCF
72
73
  endpoint || name.demodulize.tableize
73
74
  end
74
75
 
76
+ def format(data)
77
+ data.each_with_object({}) do |broker, h|
78
+ broker.attributes.each do |k, v|
79
+ h[k] ||= []
80
+ h[k] << v
81
+ end
82
+ end
83
+ end
84
+
75
85
  private
76
86
 
77
87
  def resources(params: {})
@@ -107,6 +107,7 @@ module JCF
107
107
  end
108
108
 
109
109
  # values = { guid: { name: "name", space: "space" }, guid2: { name: "name2", space: "space2" } }
110
+ # output = { header1: %w[name1 name2], header2: %w[space1 space2]}
110
111
  output = Hash.new { |hash, key| hash[key] = [] }
111
112
  values.each do |guid, metrics|
112
113
  metrics.each do |k, v|
@@ -13,12 +13,12 @@ module JCF
13
13
  argument :name, required: false, desc: "Organization name"
14
14
 
15
15
  def call(name: nil, **)
16
- values = if name
17
- Organization.find_by(name: name).collect(&:values)
18
- else
19
- Organization.all.collect(&:values)
20
- end
21
- out.puts formatter.format(headers: Organization.keys, values: values)
16
+ data = if name
17
+ Organization.find_by(name: name)
18
+ else
19
+ Organization.all
20
+ end
21
+ out.puts formatter.format(data: JCF::CF::Base.format(data))
22
22
  end
23
23
  end
24
24
  end
@@ -13,11 +13,12 @@ module JCF
13
13
  option :org, aliases: ["-o", "--org", "--organization"], type: :string, desc: "Filter to an organization"
14
14
 
15
15
  def call(name: nil, **options)
16
- if name
17
- out.puts formatter.format(JCF::CF::Quota.find_by(name: name))
18
- else
19
- out.puts formatter.format(JCF::CF::Quota.all(org: options[:org]))
20
- end
16
+ data = if name
17
+ JCF::CF::Quota.find_by(name: name)
18
+ else
19
+ JCF::CF::Quota.all(org: options[:org])
20
+ end
21
+ out.puts formatter.format(data: JCF::CF::Base.format(data))
21
22
  end
22
23
  end
23
24
  end
@@ -8,19 +8,25 @@ module JCF
8
8
  module Commands
9
9
  module CF
10
10
  class ServiceBrokers < Command
11
+ include JCF::CF
12
+
11
13
  argument :name, required: false, desc: "Service Broker name"
12
14
 
13
15
  option :space, aliases: ["-s", "--space"], type: :string, desc: "Filter to a space"
14
16
 
15
17
  def call(name: nil, **options)
16
18
  if name
17
- out.puts formatter.format(JCF::CF::ServiceBroker.find_by(name: name))
19
+ out.puts formatter.format(data: JCF::CF::ServiceBroker.find_by(name: name))
18
20
  else
19
- out.puts formatter.format(
20
- JCF::CF::ServiceBroker.all(
21
- space_guids: options[:space]
22
- )
23
- )
21
+ # [
22
+ # #<ServiceBroker @name="cdn-broker", @guid="aaaa", @relationships=[]>,
23
+ # #<ServiceBroker @name="rds-broker", @guid="bbbb", @relationships=[]>
24
+ # ]
25
+ # output = { name: %w[cdn-broker rds-broker], header2: %w[aaaa bbbb]}
26
+
27
+ data = ServiceBroker.all(space_guids: options[:space])
28
+
29
+ out.puts formatter.format(data: JCF::CF::Base.format(data))
24
30
  end
25
31
  end
26
32
  end
@@ -15,21 +15,19 @@ module JCF
15
15
  option :service_plan, aliases: ["-p", "--plan", "--service-plan"], type: :string,
16
16
  desc: "Filter to a service plan"
17
17
 
18
- # rubocop:disable Metrics/MethodLength
19
18
  def call(name: nil, **options)
20
- if name
21
- out.puts formatter.format(JCF::CF::ServiceInstance.find_by(name: name))
22
- else
23
- out.puts formatter.format(
24
- JCF::CF::ServiceInstance.all(
25
- organization_guids: options[:org],
26
- space_guids: options[:space],
27
- service_plan: options[:service_plan]
28
- )
29
- )
30
- end
19
+ data = if name
20
+ JCF::CF::ServiceInstance.find_by(name: name)
21
+ else
22
+ JCF::CF::ServiceInstance.all(
23
+ organization_guids: options[:org],
24
+ space_guids: options[:space],
25
+ service_plan: options[:service_plan]
26
+ )
27
+ end
28
+
29
+ out.puts formatter.format(data: JCF::CF::Base.format(data))
31
30
  end
32
- # rubocop:enable Metrics/MethodLength
33
31
  end
34
32
  end
35
33
  end
@@ -13,11 +13,13 @@ module JCF
13
13
  option :org, aliases: ["-o", "--org", "--organization"], type: :string, desc: "Filter to an organization guid"
14
14
 
15
15
  def call(name: nil, **options)
16
- if name
17
- out.puts formatter.format(JCF::CF::ServiceOffering.find_by(name: name))
18
- else
19
- out.puts formatter.format(JCF::CF::ServiceOffering.all(organization_guids: options[:org]))
20
- end
16
+ data = if name
17
+ JCF::CF::ServiceOffering.find_by(name: name)
18
+ else
19
+ JCF::CF::ServiceOffering.all(organization_guids: options[:org])
20
+ end
21
+
22
+ out.puts formatter.format(data: JCF::CF::Base.format(data))
21
23
  end
22
24
  end
23
25
  end
@@ -13,15 +13,13 @@ module JCF
13
13
  option :org, aliases: ["-o", "--org", "--organization"], type: :string, desc: "Filter to an organization"
14
14
 
15
15
  def call(name: nil, **options)
16
- if name
17
- out.puts formatter.format(JCF::CF::ServicePlan.find_by(name: name))
18
- else
19
- out.puts formatter.format(
20
- JCF::CF::ServicePlan.all(
21
- organization_guids: options[:org]
22
- )
23
- )
24
- end
16
+ data = if name
17
+ JCF::CF::ServicePlan.find_by(name: name)
18
+ else
19
+ JCF::CF::ServicePlan.all(organization_guids: options[:org])
20
+ end
21
+
22
+ out.puts formatter.format(data: JCF::CF::Base.format(data))
25
23
  end
26
24
  end
27
25
  end
@@ -9,16 +9,11 @@ module JCF
9
9
  module Commands
10
10
  module CF
11
11
  class Services < Command
12
- argument :broker, required: false, desc: "Broker name"
12
+ argument :broker, required: true, desc: "Broker name"
13
13
 
14
- def call(broker: nil, **)
14
+ def call(broker:, **)
15
15
  # gather all service offerings and plans for a single broker
16
- if broker
17
- out.puts formatter.format(JCF::CF::Services.first(name: broker), tree: true)
18
- else
19
- # TODO: this is a stub, it should be a list of all brokers
20
- # out.puts formatter.format(JCF::CF::Organization.all)
21
- end
16
+ out.puts formatter.format(data: JCF::CF::Services.first(name: broker), tree: true)
22
17
  end
23
18
  end
24
19
  end
@@ -13,11 +13,13 @@ module JCF
13
13
  option :org, aliases: ["-o", "--org", "--organization"], type: :string, desc: "Filter to an organization"
14
14
 
15
15
  def call(name: nil, **options)
16
- if name
17
- out.puts formatter.format(JCF::CF::Space.find_by(name: name))
18
- else
19
- out.puts formatter.format(JCF::CF::Space.all(organization_guids: options[:org]))
20
- end
16
+ data = if name
17
+ JCF::CF::Space.find_by(name: name)
18
+ else
19
+ JCF::CF::Space.all(organization_guids: options[:org])
20
+ end
21
+
22
+ out.puts formatter.format(data: JCF::CF::Base.format(data))
21
23
  end
22
24
  end
23
25
  end
@@ -11,11 +11,13 @@ module JCF
11
11
  argument :name, required: false, desc: "Partial username"
12
12
 
13
13
  def call(name: nil, **_options)
14
- if name
15
- out.puts formatter.format(JCF::CF::User.all(partial_usernames: name))
16
- else
17
- out.puts formatter.format(JCF::CF::User.all)
18
- end
14
+ data = if name
15
+ JCF::CF::User.all(partial_usernames: name)
16
+ else
17
+ JCF::CF::User.all
18
+ end
19
+
20
+ out.puts formatter.format(data: JCF::CF::Base.format(data))
19
21
  end
20
22
  end
21
23
  end
@@ -10,10 +10,20 @@ module JCF
10
10
  out.puts "JCF Plugins:"
11
11
  plugin_dir = File.join(JCF.root, "jcf", "plugins", "*.rb")
12
12
  pp "plugin dir: #{plugin_dir}" if ENV["DEBUG"]
13
+ load_plugins(plugin_dir)
14
+ list_plugins
15
+ end
16
+
17
+ private
18
+
19
+ def load_plugins(plugin_dir)
13
20
  Dir[plugin_dir].each do |plugin|
14
21
  out.puts " file: #{File.basename(plugin, ".rb")}" if ENV["DEBUG"]
15
22
  JCF::Plugins.load_plugin(File.basename(plugin, ".rb").to_sym)
16
23
  end
24
+ end
25
+
26
+ def list_plugins
17
27
  JCF::Plugins.plugins.each do |plugin|
18
28
  out.puts " #{plugin}"
19
29
  end
@@ -5,6 +5,7 @@ module JCF
5
5
  module Commands
6
6
  end
7
7
 
8
+ # rubocop:disable Metrics/MethodLength
8
9
  def self.register_commands!
9
10
  register "version", Commands::Version, aliases: ["v", "-v", "--version"]
10
11
  register "plugins", Commands::Plugins
@@ -19,5 +20,6 @@ module JCF
19
20
  register "service_instances", Commands::CF::ServiceInstances, aliases: %w[si service_instance]
20
21
  register "service_plans", Commands::CF::ServicePlans, aliases: %w[sp service_plan]
21
22
  end
23
+ # rubocop:enable Metrics/MethodLength
22
24
  end
23
25
  end
@@ -5,13 +5,9 @@ module JCF
5
5
  class Error < StandardError
6
6
  end
7
7
 
8
- class NotImplementedError < Error
9
- end
10
-
11
- class NotLoggedInError < StandardError
12
- end
13
-
14
- class InvalidOptionError < StandardError
15
- end
8
+ class NotImplementedError < Error; end
9
+ class NotLoggedInError < StandardError; end
10
+ class InvalidOptionError < StandardError; end
11
+ class EmptyResultError < StandardError; end
16
12
  end
17
13
  end
@@ -7,6 +7,19 @@ module JCF
7
7
  module OutputFormatters
8
8
  class Text
9
9
  class << self
10
+ # @param data [Hash] the data to be formatted
11
+ # @param tree [Boolean] whether to format as a tree or a table
12
+ # @return [String] the formatted data
13
+ # @example
14
+ #
15
+ # data: { header1: %w[name1 name2], header2: %w[space1 space2]}
16
+ # output:
17
+ # ┌────────┬────────┐
18
+ # │header1 │header2 │
19
+ # ├────────┼────────┤
20
+ # │name1 │space1 │
21
+ # │name2 │space2 │
22
+ # └────────┴────────┘
10
23
  def format(data:, tree: false)
11
24
  return "" if data.nil? || data.empty?
12
25
 
@@ -19,9 +32,15 @@ module JCF
19
32
 
20
33
  private
21
34
 
35
+ # @param data [Hash] the data to be formatted
36
+ # @return [String] the formatted data
37
+ # @example
38
+ #
39
+ # data: { header1: %w[name1 name2], header2: %w[space1 space2]}
40
+ # values: [["name1", "space1"], ["name2", "space2"]]
22
41
  def render_data(data)
23
- keys = collect_keys(data)
24
- values = collect_values(data)
42
+ keys = data.keys.collect(&:to_s)
43
+ values = data.values.transpose
25
44
 
26
45
  table = TTY::Table.new(keys, values)
27
46
  table.render(:unicode, resize: true)
@@ -30,33 +49,6 @@ module JCF
30
49
  def render_tree(data)
31
50
  TTY::Tree.new(data).render
32
51
  end
33
-
34
- def collect_keys(data)
35
- return ["Empty result"] if !data || data.empty?
36
-
37
- if data.is_a?(Array)
38
- data.first.keys.collect(&:to_s)
39
- elsif data.is_a?(Hash)
40
- data.keys.collect(&:to_s) || ["Empty result"]
41
- else
42
- data.keys.collect(&:to_s)
43
- end
44
- end
45
-
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
-
52
- if data.is_a?(Array)
53
- data.map { |d| d.attributes.values.collect(&:to_s) }
54
- elsif data.is_a?(Hash)
55
- data.values.transpose
56
- else
57
- [data.attributes.values.collect(&:to_s)]
58
- end
59
- end
60
52
  end
61
53
  end
62
54
  end
data/lib/jcf/cli.rb CHANGED
@@ -25,7 +25,7 @@ module JCF
25
25
  puts "Validating plugin (#{plugin}) implementation conforms to interface" if ENV["DEBUG"]
26
26
 
27
27
  %i[metrics names values].each do |method|
28
- raise "Plugin does not conform to interface (missing method \"#{method.to_s}\")" \
28
+ raise "Plugin does not conform to interface (missing method \"#{method}\")" \
29
29
  unless plugin.new(name: nil).respond_to?(method)
30
30
  end
31
31
  rescue JCF::CLI::NotLoggedInError => e
@@ -46,6 +46,7 @@ module JCF
46
46
  puts "Loading plugin #{name}" if ENV["DEBUG"]
47
47
  require "jcf/plugins/#{name}"
48
48
  raise "Plugin didn't correctly register itself" unless @plugins[name]
49
+
49
50
  @plugins[name]
50
51
  end
51
52
 
@@ -98,8 +99,6 @@ module JCF
98
99
  require_relative "cli/output_formatters"
99
100
  require_relative "cli/commands"
100
101
  require_relative "cli/errors"
101
- # require_relative "cf.rb"
102
- require_relative "aws/cloudwatch"
103
102
 
104
103
  extend Dry::CLI::Registry
105
104
 
@@ -33,7 +33,7 @@ module JCF
33
33
  end
34
34
 
35
35
  def to_s
36
- metrics.to_s
36
+ metrics.to_s
37
37
  end
38
38
 
39
39
  private
@@ -59,8 +59,8 @@ module JCF
59
59
  def storage_allocated(name:)
60
60
  rds = Aws::RDS::Client.new
61
61
  size = rds
62
- .describe_db_instances(db_instance_identifier: name)
63
- .db_instances.first.allocated_storage
62
+ .describe_db_instances(db_instance_identifier: name)
63
+ .db_instances.first.allocated_storage
64
64
  Filesize.from("#{size} GB").to_i
65
65
  end
66
66
 
@@ -78,18 +78,18 @@ module JCF
78
78
  cloudwatch(name: name, metric: :cpu)
79
79
  end
80
80
 
81
- # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
81
+ # rubocop:disable Metrics/MethodLength
82
82
  def cloudwatch(name:, metric:)
83
83
  cloudwatch = Aws::CloudWatch::Client.new
84
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
- })
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
93
 
94
94
  pp res if ENV["DEBUG"]
95
95
 
@@ -97,7 +97,7 @@ module JCF
97
97
  rescue Aws::Errors::MissingCredentialsError
98
98
  puts "You are not logged in to an AWS shell. 'gds aws <ACCOUNT> -s'"
99
99
  end
100
- # rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
100
+ # rubocop:enable Metrics/MethodLength
101
101
 
102
102
  def to_gb(bytes)
103
103
  Filesize.from("#{bytes} b").to("GB").to_fs(:rounded, precision: 2)
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.12"
4
+ VERSION = "0.1.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jcf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.12
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamie van Dyke
@@ -275,7 +275,6 @@ files:
275
275
  - lib/.DS_Store
276
276
  - lib/jcf.rb
277
277
  - lib/jcf/.DS_Store
278
- - lib/jcf/aws/cloudwatch.rb
279
278
  - lib/jcf/cf.rb
280
279
  - lib/jcf/cf/.DS_Store
281
280
  - lib/jcf/cf/base.rb
@@ -1,90 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "aws-sdk-cloudwatch"
4
- require "aws-sdk-rds"
5
- require "aws-sdk-s3"
6
- require "active_support/core_ext/integer/time"
7
- require "active_support/isolated_execution_state"
8
- require "filesize"
9
-
10
- module JCF
11
- module AWS
12
- class CloudWatch
13
- NAMESPACES = {
14
- rds: "AWS/RDS",
15
- s3: "AWS/S3"
16
- }.freeze
17
- METRICS = {
18
- free_storage: "FreeStorageSpace",
19
- allocated_storage: "AllocatedStorage",
20
- iops: "WriteIOPS",
21
- cpu: "CPUUtilization"
22
- }.freeze
23
-
24
- def storage_free(name:)
25
- storage_free = rds(name: name, metric: :free_storage)
26
- storage_free.to_i
27
- end
28
-
29
- def storage_allocated(name:)
30
- rds = Aws::RDS::Client.new
31
- size = rds
32
- .describe_db_instances(db_instance_identifier: name)
33
- .db_instances.first.allocated_storage
34
- Filesize.from("#{size} GB").to_i
35
- end
36
-
37
- def rds_storage_used(name:)
38
- free = storage_free(name: name)
39
- allocated = storage_allocated(name: name)
40
- allocated - free
41
- end
42
-
43
- def s3_storage_used(name:)
44
- s3 = Aws::S3::Client.new
45
- total_size = 0
46
- response = s3.list_objects_v2(bucket: name)
47
- response.contents.each do |object|
48
- total_size += object.size
49
- end
50
- total_size
51
- end
52
-
53
- def iops(name:)
54
- rds(name: name, metric: :iops)
55
- end
56
-
57
- def cpu(name:)
58
- rds(name: name, metric: :cpu)
59
- end
60
-
61
- private
62
-
63
- def rds(name:, metric:)
64
- dimensions = { name: "DBInstanceIdentifier", value: name }
65
- aws(namespace: NAMESPACES[:rds], metric: METRICS[metric], dimensions: dimensions)
66
- end
67
-
68
- # rubocop:disable Metrics/ParameterLists, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
69
- def aws(namespace:, metric:, dimensions:, start_time: nil, end_time: nil, period: nil, statistic: nil)
70
- cloudwatch = Aws::CloudWatch::Client.new
71
- res = cloudwatch.get_metric_statistics({
72
- namespace: namespace,
73
- metric_name: metric,
74
- dimensions: [dimensions],
75
- start_time: (start_time || 1.day.ago),
76
- end_time: (end_time || Time.now),
77
- period: (period || 86_400),
78
- statistics: [(statistic || "Average")]
79
- })
80
-
81
- pp res if ENV["DEBUG"]
82
-
83
- res.datapoints.first&.average || 0
84
- rescue Aws::Errors::MissingCredentialsError
85
- puts "You are not logged in to an AWS shell. 'gds aws <ACCOUNT> -s'"
86
- end
87
- # rubocop:enable Metrics/ParameterLists, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
88
- end
89
- end
90
- end