-
Notifications
You must be signed in to change notification settings - Fork 115
Gangams/arc k8s metrics #413
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
2ad7181
cluster identity token
ganga1980 87904e5
wip
ganga1980 a34571f
fix exception
ganga1980 5586f70
fix exceptions
ganga1980 0fcbbc4
fix exception
ganga1980 c87f1c7
fix bug
ganga1980 9edac2b
fix bug
ganga1980 979f055
minor update
ganga1980 ba2da01
refactor the code
ganga1980 fa971c5
more refactoring
ganga1980 4a45737
fix bug
ganga1980 414f487
typo fix
ganga1980 9fddedf
fix typo
ganga1980 f8419bc
wait for 1min after token renewal request
ganga1980 c7c4c8a
Merge branch 'ci_dev' into gangams/arc-k8s-metrics
ganga1980 8dbc28a
add proxy support for arc k8s mdm endpoint
ganga1980 0d866aa
Merge branch 'ci_dev' into gangams/arc-k8s-metrics
ganga1980 d0c4c97
avoid additional get call
ganga1980 ebf9452
minor line ending fix
ganga1980 612a5a5
wip
ganga1980 5be8f2d
have separate log for arc k8s cluster identity
ganga1980 564e99a
fix bug on creating crd resource
ganga1980 776eca5
remove update permission since not required
ganga1980 58113ea
Merge branch 'ci_dev' into gangams/arc-k8s-metrics
ganga1980 bf93339
fixed some bugs
ganga1980 69543ad
fix pr feedback
ganga1980 e5b4843
remove list since its not required
ganga1980 7c50f98
Merge branch 'ci_dev' into gangams/arc-k8s-metrics
ganga1980 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
charts/azuremonitor-containers/templates/omsagent-arc-k8s-crd.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| {{- if contains "microsoft.kubernetes/connectedclusters" (.Values.omsagent.env.clusterId | lower) }} | ||
| apiVersion: clusterconfig.azure.com/v1beta1 | ||
| kind: AzureClusterIdentityRequest | ||
| metadata: | ||
| name: container-insights-clusteridentityrequest | ||
| namespace: azure-arc | ||
| spec: | ||
| audience: https://monitoring.azure.com/ | ||
| {{- end }} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,216 @@ | ||
| # frozen_string_literal: true | ||
| require "logger" | ||
| require "net/http" | ||
| require "net/https" | ||
| require "uri" | ||
| require "yajl/json_gem" | ||
| require "base64" | ||
| require "time" | ||
| require_relative "KubernetesApiClient" | ||
| require_relative "ApplicationInsightsUtility" | ||
|
|
||
| class ArcK8sClusterIdentity | ||
| # this arc k8s crd version and arc k8s uses corresponding version v1beta1 vs v1 based on the k8s version for apiextensions.k8s.io | ||
| @@cluster_config_crd_api_version = "clusterconfig.azure.com/v1beta1" | ||
| @@cluster_identity_resource_name = "container-insights-clusteridentityrequest" | ||
| @@cluster_identity_resource_namespace = "azure-arc" | ||
| @@cluster_identity_token_secret_namespace = "azure-arc" | ||
| @@crd_resource_uri_template = "%{kube_api_server_url}/apis/%{cluster_config_crd_api_version}/namespaces/%{cluster_identity_resource_namespace}/azureclusteridentityrequests/%{cluster_identity_resource_name}" | ||
| @@secret_resource_uri_template = "%{kube_api_server_url}/api/v1/namespaces/%{cluster_identity_token_secret_namespace}/secrets/%{token_secret_name}" | ||
| @@azure_monitor_custom_metrics_audience = "https://monitoring.azure.com/" | ||
| @@cluster_identity_request_kind = "AzureClusterIdentityRequest" | ||
|
|
||
| def initialize | ||
| @LogPath = "/var/opt/microsoft/docker-cimprov/log/arc_k8s_cluster_identity.log" | ||
| @log = Logger.new(@LogPath, 1, 5000000) | ||
| @log.info "initialize start @ #{Time.now.utc.iso8601}" | ||
| @token_expiry_time = Time.now | ||
| @cached_access_token = String.new | ||
| @token_file_path = "/var/run/secrets/kubernetes.io/serviceaccount/token" | ||
| @cert_file_path = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" | ||
| @kube_api_server_url = KubernetesApiClient.getKubeAPIServerUrl | ||
| if @kube_api_server_url.nil? | ||
| @log.warn "got api server url nil from KubernetesApiClient.getKubeAPIServerUrl @ #{Time.now.utc.iso8601}" | ||
| end | ||
| @http_client = get_http_client | ||
| @service_account_token = get_service_account_token | ||
| @log.info "initialize complete @ #{Time.now.utc.iso8601}" | ||
| end | ||
|
|
||
| def get_cluster_identity_token() | ||
| begin | ||
| # get the cluster msi identity token either if its empty or near expirty. Token is valid 24 hrs. | ||
| if @cached_access_token.to_s.empty? || (Time.now + 60 * 60 > @token_expiry_time) # Refresh token 1 hr from expiration | ||
| # renew the token if its near expiry | ||
| if !@cached_access_token.to_s.empty? && (Time.now + 60 * 60 > @token_expiry_time) | ||
| @log.info "renewing the token since its near expiry @ #{Time.now.utc.iso8601}" | ||
| renew_near_expiry_token | ||
| # sleep 60 seconds to get the renewed token available | ||
| sleep 60 | ||
| end | ||
| @log.info "get token reference from crd @ #{Time.now.utc.iso8601}" | ||
| tokenReference = get_token_reference_from_crd | ||
| if !tokenReference.nil? && !tokenReference.empty? | ||
| @token_expiry_time = Time.parse(tokenReference["expirationTime"]) | ||
| token_secret_name = tokenReference["secretName"] | ||
| token_secret_data_name = tokenReference["dataName"] | ||
| # get the token from secret | ||
| @log.info "get token from secret @ #{Time.now.utc.iso8601}" | ||
| token = get_token_from_secret(token_secret_name, token_secret_data_name) | ||
| if !token.nil? | ||
| @cached_access_token = token | ||
| else | ||
| @log.warn "got token nil from secret: #{@token_secret_name}" | ||
| end | ||
| else | ||
| @log.warn "got token reference either nil or empty" | ||
| end | ||
| end | ||
| rescue => err | ||
| @log.warn "get_cluster_identity_token failed: #{err}" | ||
| ApplicationInsightsUtility.sendExceptionTelemetry(err, { "FeatureArea" => "MDM" }) | ||
| end | ||
| return @cached_access_token | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def get_token_from_secret(token_secret_name, token_secret_data_name) | ||
| token = nil | ||
| begin | ||
| secret_request_uri = @@secret_resource_uri_template % { | ||
| kube_api_server_url: @kube_api_server_url, | ||
| cluster_identity_token_secret_namespace: @@cluster_identity_token_secret_namespace, | ||
| token_secret_name: token_secret_name, | ||
| } | ||
| get_request = Net::HTTP::Get.new(secret_request_uri) | ||
| get_request["Authorization"] = "Bearer #{@service_account_token}" | ||
| @log.info "Making GET request to #{secret_request_uri} @ #{Time.now.utc.iso8601}" | ||
| get_response = @http_client.request(get_request) | ||
| @log.info "Got response of #{get_response.code} for #{secret_request_uri} @ #{Time.now.utc.iso8601}" | ||
| if get_response.code.to_i == 200 | ||
| token_secret = JSON.parse(get_response.body)["data"] | ||
| cluster_identity_token = token_secret[token_secret_data_name] | ||
| token = Base64.decode64(cluster_identity_token) | ||
| end | ||
| rescue => err | ||
| @log.warn "get_token_from_secret API call failed: #{err}" | ||
ganga1980 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ApplicationInsightsUtility.sendExceptionTelemetry(err, { "FeatureArea" => "MDM" }) | ||
| end | ||
| return token | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def get_token_reference_from_crd() | ||
| tokenReference = {} | ||
| begin | ||
| crd_request_uri = @@crd_resource_uri_template % { | ||
| kube_api_server_url: @kube_api_server_url, | ||
| cluster_config_crd_api_version: @@cluster_config_crd_api_version, | ||
| cluster_identity_resource_namespace: @@cluster_identity_resource_namespace, | ||
| cluster_identity_resource_name: @@cluster_identity_resource_name, | ||
| } | ||
| get_request = Net::HTTP::Get.new(crd_request_uri) | ||
| get_request["Authorization"] = "Bearer #{@service_account_token}" | ||
| @log.info "Making GET request to #{crd_request_uri} @ #{Time.now.utc.iso8601}" | ||
| get_response = @http_client.request(get_request) | ||
| @log.info "Got response of #{get_response.code} for #{crd_request_uri} @ #{Time.now.utc.iso8601}" | ||
| if get_response.code.to_i == 200 | ||
| status = JSON.parse(get_response.body)["status"] | ||
| tokenReference["expirationTime"] = status["expirationTime"] | ||
| tokenReference["secretName"] = status["tokenReference"]["secretName"] | ||
| tokenReference["dataName"] = status["tokenReference"]["dataName"] | ||
| end | ||
| rescue => err | ||
| @log.warn "get_token_reference_from_crd call failed: #{err}" | ||
| ApplicationInsightsUtility.sendExceptionTelemetry(err, { "FeatureArea" => "MDM" }) | ||
| end | ||
| return tokenReference | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def renew_near_expiry_token() | ||
| begin | ||
| crd_request_uri = @@crd_resource_uri_template % { | ||
| kube_api_server_url: @kube_api_server_url, | ||
| cluster_config_crd_api_version: @@cluster_config_crd_api_version, | ||
| cluster_identity_resource_namespace: @@cluster_identity_resource_namespace, | ||
| cluster_identity_resource_name: @@cluster_identity_resource_name, | ||
| } | ||
| crd_request_body = get_crd_request_body | ||
| crd_request_body_json = crd_request_body.to_json | ||
| update_request = Net::HTTP::Patch.new(crd_request_uri) | ||
| update_request["Content-Type"] = "application/merge-patch+json" | ||
| update_request["Authorization"] = "Bearer #{@service_account_token}" | ||
| update_request.body = crd_request_body_json | ||
| update_response = @http_client.request(update_request) | ||
| @log.info "Got response of #{update_response.code} for PATCH #{crd_request_uri} @ #{Time.now.utc.iso8601}" | ||
| if update_response.code.to_i == 404 | ||
| @log.info "since crd resource doesnt exist since creating crd resource : #{@@cluster_identity_resource_name} @ #{Time.now.utc.iso8601}" | ||
| create_request = Net::HTTP::Post.new(crd_request_uri) | ||
| create_request["Content-Type"] = "application/json" | ||
| create_request["Authorization"] = "Bearer #{@service_account_token}" | ||
| create_request.body = crd_request_body_json | ||
| create_response = @http_client.request(create_request) | ||
| @log.info "Got response of #{create_response.code} for POST #{crd_request_uri} @ #{Time.now.utc.iso8601}" | ||
| end | ||
| rescue => err | ||
| @log.warn "renew_near_expiry_token call failed: #{err}" | ||
| ApplicationInsightsUtility.sendExceptionTelemetry(err, { "FeatureArea" => "MDM" }) | ||
| end | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def get_service_account_token() | ||
| begin | ||
| if File.exist?(@token_file_path) && File.readable?(@token_file_path) | ||
| token_str = File.read(@token_file_path).strip | ||
| return token_str | ||
| else | ||
| @log.warn "Unable to read token string from #{@token_file_path}" | ||
| return nil | ||
| end | ||
| rescue => err | ||
| @log.warn "get_service_account_token call failed: #{err}" | ||
| ApplicationInsightsUtility.sendExceptionTelemetry(err, { "FeatureArea" => "MDM" }) | ||
| end | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def get_http_client() | ||
| begin | ||
| base_api_server_url = URI.parse(@kube_api_server_url) | ||
| http = Net::HTTP.new(base_api_server_url.host, base_api_server_url.port) | ||
| http.use_ssl = true | ||
| if !File.exist?(@cert_file_path) | ||
| raise "#{@cert_file_path} doesnt exist" | ||
| else | ||
| http.ca_file = @cert_file_path | ||
| end | ||
| http.verify_mode = OpenSSL::SSL::VERIFY_PEER | ||
| return http | ||
| rescue => err | ||
| @log.warn "Unable to create http client #{err}" | ||
| ApplicationInsightsUtility.sendExceptionTelemetry(err, { "FeatureArea" => "MDM" }) | ||
| end | ||
| return nil | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def get_crd_request_body | ||
| body = {} | ||
| body["apiVersion"] = @@cluster_config_crd_api_version | ||
| body["kind"] = @@cluster_identity_request_kind | ||
| body["metadata"] = {} | ||
| body["metadata"]["name"] = @@cluster_identity_resource_name | ||
| body["metadata"]["namespace"] = @@cluster_identity_resource_namespace | ||
| body["spec"] = {} | ||
| body["spec"]["audience"] = @@azure_monitor_custom_metrics_audience | ||
| return body | ||
| end | ||
| end | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.