1 /*
2  * Copyright 2010-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License").
5  * You may not use this file except in compliance with the License.
6  * A copy of the License is located at
7  *
8  *  http://aws.amazon.com/apache2.0
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */

15 package com.amazonaws.monitoring;
16
17 import static com.amazonaws.SDKGlobalConfiguration.DEFAULT_AWS_CSM_CLIENT_ID;
18 import static com.amazonaws.SDKGlobalConfiguration.DEFAULT_AWS_CSM_PORT;
19 import static com.amazonaws.SDKGlobalConfiguration.DEFAULT_AWS_CSM_HOST;
20
21 import com.amazonaws.SdkClientException;
22 import com.amazonaws.annotation.ThreadSafe;
23 import com.amazonaws.auth.profile.ProfilesConfigFile;
24 import com.amazonaws.auth.profile.internal.AwsProfileNameLoader;
25 import com.amazonaws.auth.profile.internal.BasicProfile;
26 import com.amazonaws.profile.path.AwsProfileFileLocationProvider;
27
28 /**
29  * Configuration provider that sources the client side monitoring configuration
30  * parameters from the configured profile in the shared AWS config file.
31  * <p />
32  * If no profile name is given, {@link AwsProfileNameLoader} will be used to
33  * find the profile to load the configuration from.
34  */

35 @ThreadSafe
36 public final class ProfileCsmConfigurationProvider implements CsmConfigurationProvider {
37     public static final String CSM_ENABLED_PROPERTY = "csm_enabled";
38     public static final String CSM_HOST_PROPERTY = "csm_host";
39     public static final String CSM_PORT_PROPERTY = "csm_port";
40     public static final String CSM_CLIENT_ID_PROPERTY = "csm_client_id";
41
42     private final AwsProfileFileLocationProvider configFileLocationProvider;
43
44     private volatile String profileName;
45
46     private volatile ProfilesConfigFile configFile;
47
48     /**
49      * No-arg constructor.
50      * <p />
51      * {@link AwsProfileNameLoader} and {@link
52      * AwsProfileFileLocationProvider#DEFAULT_CONFIG_LOCATION_PROVIDER} will be
53      * used to find locate the profile name and config file respectively.
54      */

55     public ProfileCsmConfigurationProvider() {
56         this(null, AwsProfileFileLocationProvider.DEFAULT_CONFIG_LOCATION_PROVIDER);
57     }
58
59     /**
60      * Create an instance that loads the configuration from the given profile
61      * name.
62      * <p />
63      * {@link AwsProfileFileLocationProvider#DEFAULT_CONFIG_LOCATION_PROVIDER}
64      * will be used to find locate the config file.
65      *
66      * @param profileName The name of the profile.
67      */

68     public ProfileCsmConfigurationProvider(String profileName) {
69         this(profileName, AwsProfileFileLocationProvider.DEFAULT_CONFIG_LOCATION_PROVIDER);
70     }
71
72     /**
73      * Create an instance that loads the configuration from the given profile
74      * name and config file location.
75      *
76      * @param profileName The name of the profile.
77      * @param configFileLocationProvider The provider to use to locate the
78      * config file.
79      */

80     public ProfileCsmConfigurationProvider(String profileName,
81             AwsProfileFileLocationProvider configFileLocationProvider) {
82         this.profileName = profileName;
83         this.configFileLocationProvider = configFileLocationProvider;
84     }
85
86     @Override
87     public CsmConfiguration getConfiguration() {
88         String profileName = getProfileName();
89
90         BasicProfile profile = getProfile(profileName);
91         if (profile == null) {
92             throw new SdkClientException(String.format("Could not find the '%s' profile!",
93                         profileName));
94         }
95
96         String enabled = profile.getPropertyValue(CSM_ENABLED_PROPERTY);
97
98         if (enabled == null) {
99             throw new SdkClientException(String.format("The '%s' profile does not define all the"
100                                                        + " required properties!", profileName));
101         }
102
103         String host = profile.getPropertyValue(CSM_HOST_PROPERTY);
104         host = host == null ? DEFAULT_AWS_CSM_HOST : host;
105         String port = profile.getPropertyValue(CSM_PORT_PROPERTY);
106         String clientId = profile.getPropertyValue(CSM_CLIENT_ID_PROPERTY);
107         clientId = clientId == null ? DEFAULT_AWS_CSM_CLIENT_ID : clientId;
108
109         try {
110             int portNumber = port == null ? DEFAULT_AWS_CSM_PORT : Integer.parseInt(port);
111
112             return CsmConfiguration.builder()
113                     .withEnabled(Boolean.parseBoolean(enabled))
114                     .withHost(host)
115                     .withPort(portNumber)
116                     .withClientId(clientId)
117                     .build();
118         } catch (Exception e) {
119             throw new SdkClientException(String.format("Unable to load configuration from the '%s'"
120                         + " profile!", profileName), e);
121         }
122     }
123
124     private String getProfileName() {
125         if (profileName == null) {
126             synchronized (this) {
127                 if (profileName == null) {
128                     profileName = AwsProfileNameLoader.INSTANCE.loadProfileName();
129                 }
130             }
131         }
132         return profileName;
133     }
134
135     private synchronized BasicProfile getProfile(String profileName) {
136         return getProfilesConfigFile().getAllBasicProfiles().get(profileName);
137     }
138
139     // ProfilesConfigFile immediately loads the profiles at construction time
140     private ProfilesConfigFile getProfilesConfigFile() {
141         if (configFile == null) {
142             synchronized (this) {
143                 if (configFile == null) {
144                     try {
145                         configFile = new ProfilesConfigFile(configFileLocationProvider.getLocation());
146                     } catch (Exception e) {
147                         throw new SdkClientException("Unable to load config file", e);
148                     }
149                 }
150             }
151         }
152         return configFile;
153     }
154 }
155