chef-licensing 0.4.43
Sign up to get free protection for your applications and to get access to all the features.
- 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
|