chef-licensing 0.4.43
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 +7 -0
- data/LICENSE +1 -0
- data/chef-licensing.gemspec +35 -0
- data/lib/chef-licensing/api/client.rb +39 -0
- data/lib/chef-licensing/api/describe.rb +62 -0
- data/lib/chef-licensing/api/license_feature_entitlement.rb +55 -0
- data/lib/chef-licensing/api/license_software_entitlement.rb +53 -0
- data/lib/chef-licensing/api/list_licenses.rb +30 -0
- data/lib/chef-licensing/api/parser/client.rb +100 -0
- data/lib/chef-licensing/api/parser/describe.rb +118 -0
- data/lib/chef-licensing/cli_flags/mixlib_cli.rb +28 -0
- data/lib/chef-licensing/cli_flags/thor.rb +21 -0
- data/lib/chef-licensing/config.rb +44 -0
- data/lib/chef-licensing/config_fetcher/arg_fetcher.rb +38 -0
- data/lib/chef-licensing/config_fetcher/env_fetcher.rb +21 -0
- data/lib/chef-licensing/context.rb +98 -0
- data/lib/chef-licensing/exceptions/client_error.rb +9 -0
- data/lib/chef-licensing/exceptions/describe_error.rb +9 -0
- data/lib/chef-licensing/exceptions/error.rb +4 -0
- data/lib/chef-licensing/exceptions/feature_not_entitled.rb +9 -0
- data/lib/chef-licensing/exceptions/invalid_license.rb +10 -0
- data/lib/chef-licensing/exceptions/license_generation_failed.rb +9 -0
- data/lib/chef-licensing/exceptions/license_generation_rejected.rb +7 -0
- data/lib/chef-licensing/exceptions/list_licenses_error.rb +12 -0
- data/lib/chef-licensing/exceptions/missing_api_credentials_error.rb +7 -0
- data/lib/chef-licensing/exceptions/restful_client_connection_error.rb +9 -0
- data/lib/chef-licensing/exceptions/restful_client_error.rb +9 -0
- data/lib/chef-licensing/exceptions/software_not_entitled.rb +9 -0
- data/lib/chef-licensing/license.rb +151 -0
- data/lib/chef-licensing/license_key_fetcher/base.rb +28 -0
- data/lib/chef-licensing/license_key_fetcher/chef_licensing_interactions.yaml +534 -0
- data/lib/chef-licensing/license_key_fetcher/file.rb +275 -0
- data/lib/chef-licensing/license_key_fetcher/prompt.rb +43 -0
- data/lib/chef-licensing/license_key_fetcher.rb +314 -0
- data/lib/chef-licensing/license_key_generator.rb +47 -0
- data/lib/chef-licensing/license_key_validator.rb +24 -0
- data/lib/chef-licensing/licensing_service/local.rb +29 -0
- data/lib/chef-licensing/list_license_keys.rb +142 -0
- data/lib/chef-licensing/restful_client/base.rb +139 -0
- data/lib/chef-licensing/restful_client/middleware/exceptions_handler.rb +16 -0
- data/lib/chef-licensing/restful_client/v1.rb +17 -0
- data/lib/chef-licensing/tui_engine/tui_actions.rb +238 -0
- data/lib/chef-licensing/tui_engine/tui_engine.rb +174 -0
- data/lib/chef-licensing/tui_engine/tui_engine_state.rb +62 -0
- data/lib/chef-licensing/tui_engine/tui_exceptions.rb +17 -0
- data/lib/chef-licensing/tui_engine/tui_interaction.rb +17 -0
- data/lib/chef-licensing/tui_engine/tui_prompt.rb +117 -0
- data/lib/chef-licensing/tui_engine.rb +2 -0
- data/lib/chef-licensing/version.rb +3 -0
- data/lib/chef-licensing.rb +70 -0
- metadata +191 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative "restful_client/v1"
|
2
|
+
require_relative "exceptions/invalid_license"
|
3
|
+
|
4
|
+
module ChefLicensing
|
5
|
+
class LicenseKeyValidator
|
6
|
+
attr_reader :license
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def validate!(license)
|
10
|
+
new(license).validate!
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(license, restful_client: ChefLicensing::RestfulClient::V1)
|
15
|
+
@license = license || raise(ArgumentError, "Missing Params: `license`")
|
16
|
+
@restful_client = restful_client.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def validate!
|
20
|
+
response = @restful_client.validate(license)
|
21
|
+
response.data || raise(ChefLicensing::InvalidLicense, response.message)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative "../config"
|
2
|
+
require_relative "../api/list_licenses"
|
3
|
+
require_relative "../exceptions/list_licenses_error"
|
4
|
+
|
5
|
+
module ChefLicensing
|
6
|
+
class LicensingService
|
7
|
+
class Local
|
8
|
+
attr_reader :logger
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def detected?
|
12
|
+
new.detected?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def detected?
|
17
|
+
return ChefLicensing::Config.is_local_license_service if ChefLicensing::Config.is_local_license_service
|
18
|
+
|
19
|
+
ChefLicensing::Api::ListLicenses.info
|
20
|
+
true
|
21
|
+
rescue ChefLicensing::ListLicensesError => e
|
22
|
+
# If API call returns 404, it is a global licensing service
|
23
|
+
return false if e.status_code == 404
|
24
|
+
|
25
|
+
raise(ChefLicensing::ListLicensesError.new("Error occured while fetching licenses #{e.message}", e.status_code))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require_relative "license_key_fetcher"
|
2
|
+
require_relative "api/describe"
|
3
|
+
require_relative "exceptions/describe_error"
|
4
|
+
require "pastel" unless defined?(Pastel)
|
5
|
+
require_relative "config"
|
6
|
+
|
7
|
+
module ChefLicensing
|
8
|
+
class ListLicenseKeys
|
9
|
+
def self.display(opts = {})
|
10
|
+
new(opts).display
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.display_overview(opts = {})
|
14
|
+
new(opts).display_overview
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(opts = {})
|
18
|
+
@logger = ChefLicensing::Config.logger
|
19
|
+
@output = ChefLicensing::Config.output
|
20
|
+
@pastel = Pastel.new
|
21
|
+
@license_keys = fetch_license_keys(opts)
|
22
|
+
@licenses_metadata = fetch_licenses_metadata
|
23
|
+
end
|
24
|
+
|
25
|
+
def display
|
26
|
+
output.puts "+------------ License Information ------------+"
|
27
|
+
output.puts "Total Licenses found: #{licenses_metadata.length}\n\n"
|
28
|
+
|
29
|
+
licenses_metadata.each do |license|
|
30
|
+
puts_bold "License Key : #{license.id}"
|
31
|
+
output.puts <<~LICENSE
|
32
|
+
Type : #{license.license_type}
|
33
|
+
Status : #{license.status}
|
34
|
+
Expiration Date : #{license.expiration_date}
|
35
|
+
|
36
|
+
LICENSE
|
37
|
+
|
38
|
+
iterate_attributes(license.software_entitlements, "Software Entitlements")
|
39
|
+
iterate_attributes(license.asset_entitlements, "Asset Entitlements")
|
40
|
+
iterate_attributes(license.feature_entitlements, "Feature Entitlements")
|
41
|
+
|
42
|
+
puts_bold "License Limits"
|
43
|
+
license.limits.each do |limit|
|
44
|
+
usage_limit = limit.usage_limit == -1 ? "Unlimited" : limit.usage_limit
|
45
|
+
output.puts <<~LIMIT
|
46
|
+
Usage Status : #{limit.usage_status}
|
47
|
+
Usage Limit : #{usage_limit}
|
48
|
+
Usage Measure : #{limit.usage_measure}
|
49
|
+
Used : #{limit.used}
|
50
|
+
Software : #{limit.software}
|
51
|
+
LIMIT
|
52
|
+
end
|
53
|
+
output.puts "+----------------------------------------------+"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def display_overview
|
58
|
+
output.puts "------------------------------------------------------------"
|
59
|
+
licenses_metadata.each do |license|
|
60
|
+
# Sets the validity text for a free license as "Unlimited" and displays the number of days for others.
|
61
|
+
validity = if license.license_type == "free"
|
62
|
+
"Unlimited"
|
63
|
+
else
|
64
|
+
# find the number of days left for the license to expire
|
65
|
+
days = (Date.parse(license.expiration_date) - Date.today).to_i
|
66
|
+
"#{days > 0 ? days : 0} #{"Day".pluralize(days)}"
|
67
|
+
end
|
68
|
+
num_of_units = license.limits&.first&.usage_limit || 0
|
69
|
+
num_of_units = num_of_units == -1 ? "Unlimited" : num_of_units
|
70
|
+
unit_measure = license.limits&.first&.usage_measure || "unit"
|
71
|
+
output.puts <<~LICENSE
|
72
|
+
#{pastel.bold("License Details")}
|
73
|
+
Asset Name : #{license.limits.first.software}
|
74
|
+
License ID : #{license.id}
|
75
|
+
Type : #{license.license_type.capitalize}
|
76
|
+
Status : #{license.status.capitalize}
|
77
|
+
Validity : #{validity}
|
78
|
+
No. Of Units : #{num_of_units} #{unit_measure.capitalize.pluralize(num_of_units)}
|
79
|
+
------------------------------------------------------------
|
80
|
+
LICENSE
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
attr_reader :pastel, :output, :logger, :license_keys, :licenses_metadata
|
87
|
+
|
88
|
+
def display_info(component)
|
89
|
+
output.puts <<~INFO
|
90
|
+
ID : #{component.id}
|
91
|
+
Name : #{component.name}
|
92
|
+
Status : #{component.status}
|
93
|
+
Entitled : #{component.entitled}
|
94
|
+
INFO
|
95
|
+
output.puts "\n"
|
96
|
+
end
|
97
|
+
|
98
|
+
def iterate_attributes(component, header)
|
99
|
+
puts_bold header
|
100
|
+
puts "No #{header.downcase} found.\n\n" if component.empty?
|
101
|
+
component.each do |attribute|
|
102
|
+
display_info(attribute)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def puts_bold(title)
|
107
|
+
output.puts pastel.bold(title)
|
108
|
+
end
|
109
|
+
|
110
|
+
def fetch_license_keys(opts = {})
|
111
|
+
license_keys = opts[:license_keys] || ChefLicensing::LicenseKeyFetcher.fetch({ dir: opts[:dir] })
|
112
|
+
|
113
|
+
if license_keys.empty?
|
114
|
+
logger.debug "No license keys found on disk."
|
115
|
+
output.puts "No license keys found on disk."
|
116
|
+
exit
|
117
|
+
end
|
118
|
+
logger.debug "License keys fetched from disk: #{license_keys}"
|
119
|
+
|
120
|
+
license_keys
|
121
|
+
rescue ChefLicensing::LicenseKeyFetcher::LicenseKeyNotFetchedError => e
|
122
|
+
logger.debug "Error occured while fetching license keys from disk: #{e.message}"
|
123
|
+
output.puts "Error occured while fetching license keys from disk: #{e.message}"
|
124
|
+
# TODO: Exit with a non-zero status code
|
125
|
+
exit
|
126
|
+
end
|
127
|
+
|
128
|
+
def fetch_licenses_metadata
|
129
|
+
licenses_metadata = ChefLicensing::Api::Describe.list({
|
130
|
+
license_keys: license_keys,
|
131
|
+
})
|
132
|
+
logger.debug "License metadata fetched from server: #{licenses_metadata}"
|
133
|
+
|
134
|
+
licenses_metadata
|
135
|
+
rescue ChefLicensing::DescribeError => e
|
136
|
+
logger.debug "Error occured while fetching license information: #{e.message}"
|
137
|
+
output.puts "Error occured while fetching license information: #{e.message}"
|
138
|
+
# TODO: Exit with a non-zero status code
|
139
|
+
exit
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require "faraday" unless defined?(Faraday)
|
2
|
+
require "faraday/http_cache"
|
3
|
+
require "active_support"
|
4
|
+
require "tmpdir" unless defined?(Dir.mktmpdir)
|
5
|
+
require_relative "../exceptions/restful_client_error"
|
6
|
+
require_relative "../exceptions/restful_client_connection_error"
|
7
|
+
require_relative "../exceptions/missing_api_credentials_error"
|
8
|
+
require_relative "../config"
|
9
|
+
require_relative "middleware/exceptions_handler"
|
10
|
+
|
11
|
+
module ChefLicensing
|
12
|
+
module RestfulClient
|
13
|
+
|
14
|
+
# Base class to handle all License Server endpoints
|
15
|
+
class Base
|
16
|
+
|
17
|
+
END_POINTS = {
|
18
|
+
FEATURE_BY_NAME: "license-service/featurebyname",
|
19
|
+
FEATURE_BY_ID: "license-service/featurebyid",
|
20
|
+
ENTITLEMENT_BY_NAME: "license-service/entitlementbyname",
|
21
|
+
ENTITLEMENT_BY_ID: "license-service/entitlementbyid",
|
22
|
+
}.freeze
|
23
|
+
|
24
|
+
CURRENT_ENDPOINT_VERSION = 2
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
raise MissingAPICredentialsError, "Missing credential in config: Set in block chef_license_server or use environment variable CHEF_LICENSE_SERVER or pass through argument --chef-license-server" if ChefLicensing::Config.license_server_url.nil?
|
28
|
+
|
29
|
+
@logger = ChefLicensing::Config.logger
|
30
|
+
end
|
31
|
+
|
32
|
+
def validate(license)
|
33
|
+
invoke_get_api(self.class::END_POINTS[:VALIDATE], { licenseId: license, version: CURRENT_ENDPOINT_VERSION })
|
34
|
+
end
|
35
|
+
|
36
|
+
def generate_trial_license(payload)
|
37
|
+
invoke_post_api(self.class::END_POINTS[:GENERATE_TRIAL_LICENSE], payload)
|
38
|
+
end
|
39
|
+
|
40
|
+
def generate_free_license(payload)
|
41
|
+
invoke_post_api(self.class::END_POINTS[:GENERATE_FREE_LICENSE], payload)
|
42
|
+
end
|
43
|
+
|
44
|
+
def feature_by_name(payload)
|
45
|
+
invoke_post_api(self.class::END_POINTS[:FEATURE_BY_NAME], payload)
|
46
|
+
end
|
47
|
+
|
48
|
+
def feature_by_id(payload)
|
49
|
+
invoke_post_api(self.class::END_POINTS[:FEATURE_BY_ID], payload)
|
50
|
+
end
|
51
|
+
|
52
|
+
def entitlement_by_name(payload)
|
53
|
+
invoke_post_api(self.class::END_POINTS[:ENTITLEMENT_BY_NAME], payload)
|
54
|
+
end
|
55
|
+
|
56
|
+
def entitlement_by_id(payload)
|
57
|
+
invoke_post_api(self.class::END_POINTS[:ENTITLEMENT_BY_ID], payload)
|
58
|
+
end
|
59
|
+
|
60
|
+
def client(params = {})
|
61
|
+
invoke_get_api(self.class::END_POINTS[:CLIENT], { licenseId: params[:license_keys], entitlementId: params[:entitlement_id] })
|
62
|
+
end
|
63
|
+
|
64
|
+
def describe(params = {})
|
65
|
+
invoke_get_api(self.class::END_POINTS[:DESCRIBE], { licenseId: params[:license_keys], entitlementId: params[:entitlement_id] })
|
66
|
+
end
|
67
|
+
|
68
|
+
def list_licenses(params = {})
|
69
|
+
invoke_get_api(self.class::END_POINTS[:LIST_LICENSES])
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
attr_reader :logger
|
75
|
+
|
76
|
+
# a common method to handle the get API calls
|
77
|
+
def invoke_get_api(endpoint, params = {})
|
78
|
+
handle_get_connection do |connection|
|
79
|
+
connection.get(endpoint, params).body
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# a common method to handle the post API calls
|
84
|
+
def invoke_post_api(endpoint, payload, headers = {})
|
85
|
+
handle_post_connection do |connection|
|
86
|
+
response = connection.post(endpoint) do |request|
|
87
|
+
request.body = payload.to_json
|
88
|
+
request.headers = headers
|
89
|
+
end
|
90
|
+
raise RestfulClientError, format_error_from(response) unless response.success?
|
91
|
+
|
92
|
+
response.body
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def handle_get_connection
|
97
|
+
# handle faraday errors
|
98
|
+
yield get_connection
|
99
|
+
rescue Faraday::ClientError => e
|
100
|
+
logger.debug "Restful Client Error #{e.message}"
|
101
|
+
raise RestfulClientError, e.message
|
102
|
+
end
|
103
|
+
|
104
|
+
def handle_post_connection
|
105
|
+
# handle faraday errors
|
106
|
+
yield post_connection
|
107
|
+
rescue Faraday::ClientError => e
|
108
|
+
logger.debug "Restful Client Error #{e.message}"
|
109
|
+
raise RestfulClientError, e.message
|
110
|
+
end
|
111
|
+
|
112
|
+
def get_connection
|
113
|
+
store = ::ActiveSupport::Cache.lookup_store(:file_store, Dir.tmpdir)
|
114
|
+
Faraday.new(url: ChefLicensing::Config.license_server_url) do |config|
|
115
|
+
config.request :json
|
116
|
+
config.response :json, parser_options: { object_class: OpenStruct }
|
117
|
+
config.use Faraday::HttpCache, shared_cache: false, logger: logger, store: store
|
118
|
+
config.use Middleware::ExceptionsHandler
|
119
|
+
config.adapter Faraday.default_adapter
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def post_connection
|
124
|
+
Faraday.new(url: ChefLicensing::Config.license_server_url) do |config|
|
125
|
+
config.request :json
|
126
|
+
config.response :json, parser_options: { object_class: OpenStruct }
|
127
|
+
config.use Middleware::ExceptionsHandler
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def format_error_from(response)
|
132
|
+
error_details = response.body&.data&.error
|
133
|
+
return response.reason_phrase unless error_details
|
134
|
+
|
135
|
+
error_details
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "faraday" unless defined?(Faraday)
|
2
|
+
require "faraday/middleware"
|
3
|
+
require_relative "../../../chef-licensing/exceptions/restful_client_connection_error"
|
4
|
+
|
5
|
+
module Middleware
|
6
|
+
# Middleware that handles the exception handler for chef licensing
|
7
|
+
class ExceptionsHandler < Faraday::Middleware
|
8
|
+
def call(env)
|
9
|
+
@app.call(env)
|
10
|
+
rescue Faraday::ConnectionFailed => e
|
11
|
+
ChefLicensing::Config.logger.debug("Connection failed to #{ChefLicensing::Config.license_server_url} with error: #{e.message}")
|
12
|
+
error_message = "Unable to connect to the licensing server at #{ChefLicensing::Config.license_server_url}.\nPlease check if the server is reachable and try again. #{ChefLicensing::Config.chef_product_name} requires server communication to operate."
|
13
|
+
raise ChefLicensing::RestfulClientConnectionError, error_message
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative "base"
|
2
|
+
|
3
|
+
module ChefLicensing
|
4
|
+
module RestfulClient
|
5
|
+
# Client that handles all License Server V1 endpoints
|
6
|
+
class V1 < Base
|
7
|
+
END_POINTS = END_POINTS.merge({
|
8
|
+
VALIDATE: "v1/validate",
|
9
|
+
GENERATE_TRIAL_LICENSE: "v1/trial",
|
10
|
+
GENERATE_FREE_LICENSE: "v1/free",
|
11
|
+
CLIENT: "v1/client",
|
12
|
+
DESCRIBE: "v1/desc",
|
13
|
+
LIST_LICENSES: "v1/listLicenses",
|
14
|
+
}).freeze
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,238 @@
|
|
1
|
+
require_relative "../license_key_validator"
|
2
|
+
require_relative "../license_key_generator"
|
3
|
+
require_relative "../exceptions/invalid_license"
|
4
|
+
require_relative "../exceptions/license_generation_failed"
|
5
|
+
require_relative "../exceptions/license_generation_rejected"
|
6
|
+
require_relative "../license_key_fetcher/base"
|
7
|
+
require_relative "../config"
|
8
|
+
require_relative "../context"
|
9
|
+
require_relative "../list_license_keys"
|
10
|
+
require "tty-spinner"
|
11
|
+
|
12
|
+
module ChefLicensing
|
13
|
+
class TUIEngine
|
14
|
+
class TUIActions
|
15
|
+
attr_accessor :logger, :output, :license_id, :error_msg, :rejection_msg, :invalid_license_msg, :license_type, :license
|
16
|
+
def initialize(opts = {})
|
17
|
+
@opts = opts
|
18
|
+
@logger = ChefLicensing::Config.logger
|
19
|
+
@output = ChefLicensing::Config.output
|
20
|
+
end
|
21
|
+
|
22
|
+
def is_license_with_valid_pattern?(input)
|
23
|
+
license_id = input[:ask_for_license_id]
|
24
|
+
input[:ask_for_license_id] = ChefLicensing::LicenseKeyFetcher::Base.verify_and_extract_license(license_id)
|
25
|
+
true
|
26
|
+
rescue ChefLicensing::LicenseKeyFetcher::Base::InvalidLicenseKeyFormat => e
|
27
|
+
output.puts e.message
|
28
|
+
logger.debug e.message
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
32
|
+
def is_license_valid_on_server?(input)
|
33
|
+
license_id = input[:ask_for_license_id]
|
34
|
+
spinner = TTY::Spinner.new(":spinner [Running] License validation in progress...", format: :dots, clear: true, output: output)
|
35
|
+
spinner.auto_spin # Start the spinner
|
36
|
+
is_valid = ChefLicensing::LicenseKeyValidator.validate!(license_id)
|
37
|
+
spinner.success # Stop the spinner
|
38
|
+
self.license_id = license_id
|
39
|
+
is_valid
|
40
|
+
rescue ChefLicensing::InvalidLicense => e
|
41
|
+
spinner.error # Stop the spinner
|
42
|
+
self.invalid_license_msg = e.message || "Something went wrong while validating the license"
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
46
|
+
def is_license_allowed?(input)
|
47
|
+
client_api_call(license_id)
|
48
|
+
self.license_type = get_license_type
|
49
|
+
if license_restricted?(license_type)
|
50
|
+
# Existing license keys needs to be fetcher to show details of existing license of license type which is restricted.
|
51
|
+
# However, if user is trying to add free license, and user has active trial license, we fetch the trial license key
|
52
|
+
if license_type == :free && LicenseKeyFetcher::File.user_has_active_trial_license?(@opts)
|
53
|
+
existing_license_keys_in_file = LicenseKeyFetcher::File.fetch_license_keys_based_on_type(:trial, @opts)
|
54
|
+
else
|
55
|
+
existing_license_keys_in_file = LicenseKeyFetcher::File.fetch_license_keys_based_on_type(license_type, @opts)
|
56
|
+
end
|
57
|
+
self.license_id = existing_license_keys_in_file.last
|
58
|
+
false
|
59
|
+
else
|
60
|
+
true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def license_expiration_status?(input)
|
65
|
+
get_license(license_id)
|
66
|
+
if license.expired? || license.have_grace?
|
67
|
+
ChefLicensing::Context.local_licensing_service? ? "expired_in_local_mode" : "expired"
|
68
|
+
elsif license.about_to_expire?
|
69
|
+
input[:license_expiration_date] = Date.parse(license.expiration_date).strftime("%a, %d %b %Y")
|
70
|
+
input[:number_of_days_in_expiration] = license.number_of_days_in_expiration
|
71
|
+
"about_to_expire"
|
72
|
+
else
|
73
|
+
"active"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def is_user_name_valid?(input)
|
78
|
+
user_name = input[:gather_user_last_name_for_license_generation] || input[:gather_user_first_name_for_license_generation]
|
79
|
+
(user_name =~ /\A[a-zA-Z]{1,16}\Z/) == 0
|
80
|
+
end
|
81
|
+
|
82
|
+
def is_email_valid?(input)
|
83
|
+
(input[:gather_user_email_for_license_generation] =~ URI::MailTo::EMAIL_REGEXP) == 0
|
84
|
+
end
|
85
|
+
|
86
|
+
def is_company_name_valid?(input)
|
87
|
+
(input[:gather_user_company_for_license_generation] =~ /\A[a-zA-Z0-9][a-zA-Z0-9\W_]{2,15}\z/) == 0
|
88
|
+
end
|
89
|
+
|
90
|
+
def is_phone_no_valid?(input)
|
91
|
+
# No validation
|
92
|
+
# Optional field
|
93
|
+
true
|
94
|
+
end
|
95
|
+
|
96
|
+
def generate_trial_license(input)
|
97
|
+
generate_license(input, :trial)
|
98
|
+
end
|
99
|
+
|
100
|
+
def generate_free_license(input)
|
101
|
+
generate_license(input, :free)
|
102
|
+
end
|
103
|
+
|
104
|
+
def fetch_license_id(input)
|
105
|
+
license_id
|
106
|
+
end
|
107
|
+
|
108
|
+
def fetch_license_failure_error_msg(input)
|
109
|
+
error_msg
|
110
|
+
end
|
111
|
+
|
112
|
+
def fetch_license_failure_rejection_msg(input)
|
113
|
+
rejection_msg
|
114
|
+
end
|
115
|
+
|
116
|
+
def select_license_generation_based_on_type(inputs)
|
117
|
+
if inputs.key? :free_license_selection
|
118
|
+
inputs[:license_type] = :free
|
119
|
+
"free"
|
120
|
+
elsif inputs.key? :trial_license_selection
|
121
|
+
inputs[:license_type] = :trial
|
122
|
+
"trial"
|
123
|
+
else
|
124
|
+
inputs[:license_type] = :commercial
|
125
|
+
"commercial"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def license_generation_rejected?(inputs)
|
130
|
+
!!rejection_msg
|
131
|
+
end
|
132
|
+
|
133
|
+
def fetch_invalid_license_msg(input)
|
134
|
+
invalid_license_msg
|
135
|
+
end
|
136
|
+
|
137
|
+
def display_license_info(inputs)
|
138
|
+
ChefLicensing::ListLicenseKeys.display_overview({ license_keys: [license_id] })
|
139
|
+
end
|
140
|
+
|
141
|
+
def clear_license_type_selection(inputs)
|
142
|
+
inputs.delete(:free_license_selection)
|
143
|
+
inputs.delete(:trial_license_selection)
|
144
|
+
inputs.delete(:commercial_license_selection)
|
145
|
+
end
|
146
|
+
|
147
|
+
def are_user_details_present?(inputs)
|
148
|
+
inputs.key?(:gather_user_first_name_for_license_generation) &&
|
149
|
+
inputs.key?(:gather_user_last_name_for_license_generation) &&
|
150
|
+
inputs.key?(:gather_user_email_for_license_generation) &&
|
151
|
+
inputs.key?(:gather_user_company_for_license_generation) &&
|
152
|
+
inputs.key?(:gather_user_phone_no_for_license_generation)
|
153
|
+
end
|
154
|
+
|
155
|
+
def set_license_info(input)
|
156
|
+
self.license_id = input[:license_id]
|
157
|
+
self.license_type = input[:license_type]
|
158
|
+
end
|
159
|
+
|
160
|
+
def determine_restriction_type(input)
|
161
|
+
if license_type == :free && LicenseKeyFetcher::File.user_has_active_trial_license?(@opts)
|
162
|
+
"active_trial_restriction"
|
163
|
+
else
|
164
|
+
"#{license_type}_restriction"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def fetch_license_type_restricted(inputs)
|
169
|
+
if license_restricted?(:trial) && license_restricted?(:free)
|
170
|
+
"trial_and_free"
|
171
|
+
elsif license_restricted?(:trial)
|
172
|
+
"trial"
|
173
|
+
else
|
174
|
+
"free"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def filter_license_type_options(inputs)
|
179
|
+
if (license_restricted?(:trial) && license_restricted?(:free)) || LicenseKeyFetcher::File.user_has_active_trial_license?(@opts)
|
180
|
+
"ask_for_commercial_only"
|
181
|
+
elsif license_restricted?(:trial)
|
182
|
+
"ask_for_license_except_trial"
|
183
|
+
elsif license_restricted?(:free)
|
184
|
+
"ask_for_license_except_free"
|
185
|
+
else
|
186
|
+
"ask_for_all_license_type"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
private
|
191
|
+
|
192
|
+
attr_accessor :opts
|
193
|
+
|
194
|
+
def generate_license(inputs, license_type)
|
195
|
+
spinner = TTY::Spinner.new(":spinner [Running] License generation in progress...", format: :dots, clear: true, output: output)
|
196
|
+
spinner.auto_spin # Start the spinner
|
197
|
+
self.license_id = ChefLicensing::LicenseKeyGenerator.send("generate_#{license_type}_license!",
|
198
|
+
first_name: inputs[:gather_user_first_name_for_license_generation],
|
199
|
+
last_name: inputs[:gather_user_last_name_for_license_generation],
|
200
|
+
email_id: inputs[:gather_user_email_for_license_generation],
|
201
|
+
product: ChefLicensing::Config.chef_product_name&.capitalize,
|
202
|
+
company: inputs[:gather_user_company_for_license_generation],
|
203
|
+
phone: inputs[:gather_user_phone_no_for_license_generation])
|
204
|
+
spinner.success # Stop the spinner
|
205
|
+
true
|
206
|
+
rescue ChefLicensing::LicenseGenerationFailed => e
|
207
|
+
spinner.error # Stop the spinner
|
208
|
+
self.error_msg = e.message
|
209
|
+
false
|
210
|
+
rescue ChefLicensing::LicenseGenerationRejected => e
|
211
|
+
spinner.error # Stop the spinner
|
212
|
+
self.rejection_msg = e.message
|
213
|
+
false
|
214
|
+
end
|
215
|
+
|
216
|
+
def get_license(license_key)
|
217
|
+
spinner = TTY::Spinner.new(":spinner [Running] License validation in progress...", format: :dots, clear: true, output: output)
|
218
|
+
spinner.auto_spin # Start the spinner
|
219
|
+
client_api_call(license_key)
|
220
|
+
spinner.success # Stop the spinner
|
221
|
+
end
|
222
|
+
|
223
|
+
def client_api_call(license_key)
|
224
|
+
self.license ||= ChefLicensing.client(license_keys: [license_key])
|
225
|
+
end
|
226
|
+
|
227
|
+
def get_license_type
|
228
|
+
license.license_type.downcase.to_sym
|
229
|
+
end
|
230
|
+
|
231
|
+
def license_restricted?(license_type)
|
232
|
+
file_fetcher = LicenseKeyFetcher::File.new(@opts)
|
233
|
+
allowed_license_types = file_fetcher.fetch_allowed_license_types_for_addition
|
234
|
+
!(allowed_license_types.include? license_type)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|