Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """Support for Amazon Web Services (AWS)."""
2 
3 import asyncio
4 from collections import OrderedDict
5 import logging
6 
7 from aiobotocore.session import AioSession
8 import voluptuous as vol
9 
10 from homeassistant import config_entries
11 from homeassistant.config_entries import ConfigEntry
12 from homeassistant.const import (
13  ATTR_CREDENTIALS,
14  CONF_NAME,
15  CONF_PROFILE_NAME,
16  CONF_SERVICE,
17  Platform,
18 )
19 from homeassistant.core import HomeAssistant
20 from homeassistant.helpers import config_validation as cv, discovery
21 from homeassistant.helpers.typing import ConfigType
22 
23 # Loading the config flow file will register the flow
24 from .const import (
25  CONF_ACCESS_KEY_ID,
26  CONF_CONTEXT,
27  CONF_CREDENTIAL_NAME,
28  CONF_CREDENTIALS,
29  CONF_NOTIFY,
30  CONF_REGION,
31  CONF_SECRET_ACCESS_KEY,
32  CONF_VALIDATE,
33  DATA_CONFIG,
34  DATA_HASS_CONFIG,
35  DATA_SESSIONS,
36  DOMAIN,
37 )
38 
39 _LOGGER = logging.getLogger(__name__)
40 
41 AWS_CREDENTIAL_SCHEMA = vol.Schema(
42  {
43  vol.Required(CONF_NAME): cv.string,
44  vol.Inclusive(CONF_ACCESS_KEY_ID, ATTR_CREDENTIALS): cv.string,
45  vol.Inclusive(CONF_SECRET_ACCESS_KEY, ATTR_CREDENTIALS): cv.string,
46  vol.Exclusive(CONF_PROFILE_NAME, ATTR_CREDENTIALS): cv.string,
47  vol.Optional(CONF_VALIDATE, default=True): cv.boolean,
48  }
49 )
50 
51 DEFAULT_CREDENTIAL = [
52  {CONF_NAME: "default", CONF_PROFILE_NAME: "default", CONF_VALIDATE: False}
53 ]
54 
55 SUPPORTED_SERVICES = ["lambda", "sns", "sqs", "events"]
56 
57 NOTIFY_PLATFORM_SCHEMA = vol.Schema(
58  {
59  vol.Optional(CONF_NAME): cv.string,
60  vol.Required(CONF_SERVICE): vol.All(
61  cv.string, vol.Lower, vol.In(SUPPORTED_SERVICES)
62  ),
63  vol.Required(CONF_REGION): vol.All(cv.string, vol.Lower),
64  vol.Inclusive(CONF_ACCESS_KEY_ID, ATTR_CREDENTIALS): cv.string,
65  vol.Inclusive(CONF_SECRET_ACCESS_KEY, ATTR_CREDENTIALS): cv.string,
66  vol.Exclusive(CONF_PROFILE_NAME, ATTR_CREDENTIALS): cv.string,
67  vol.Exclusive(CONF_CREDENTIAL_NAME, ATTR_CREDENTIALS): cv.string,
68  vol.Optional(CONF_CONTEXT): vol.Coerce(dict),
69  }
70 )
71 
72 CONFIG_SCHEMA = vol.Schema(
73  {
74  DOMAIN: vol.Schema(
75  {
76  vol.Optional(CONF_CREDENTIALS, default=DEFAULT_CREDENTIAL): vol.All(
77  cv.ensure_list, [AWS_CREDENTIAL_SCHEMA]
78  ),
79  vol.Optional(CONF_NOTIFY, default=[]): vol.All(
80  cv.ensure_list, [NOTIFY_PLATFORM_SCHEMA]
81  ),
82  }
83  )
84  },
85  extra=vol.ALLOW_EXTRA,
86 )
87 
88 
89 async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
90  """Set up AWS component."""
91  hass.data[DATA_HASS_CONFIG] = config
92 
93  if (conf := config.get(DOMAIN)) is None:
94  # create a default conf using default profile
95  conf = CONFIG_SCHEMA({ATTR_CREDENTIALS: DEFAULT_CREDENTIAL})
96 
97  hass.data[DATA_CONFIG] = conf
98  hass.data[DATA_SESSIONS] = OrderedDict()
99 
100  hass.async_create_task(
101  hass.config_entries.flow.async_init(
102  DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data=conf
103  )
104  )
105 
106  return True
107 
108 
109 async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
110  """Load a config entry.
111 
112  Validate and save sessions per aws credential.
113  """
114  config = hass.data[DATA_HASS_CONFIG]
115  conf = hass.data[DATA_CONFIG]
116 
117  if entry.source == config_entries.SOURCE_IMPORT:
118  if conf is None:
119  # user removed config from configuration.yaml, abort setup
120  hass.async_create_task(hass.config_entries.async_remove(entry.entry_id))
121  return False
122 
123  if conf != entry.data:
124  # user changed config from configuration.yaml, use conf to setup
125  hass.config_entries.async_update_entry(entry, data=conf)
126 
127  if conf is None:
128  conf = CONFIG_SCHEMA({DOMAIN: entry.data})[DOMAIN]
129 
130  # validate credentials and create sessions
131  validation = True
132  tasks = [_validate_aws_credentials(hass, cred) for cred in conf[ATTR_CREDENTIALS]]
133  if tasks:
134  results = await asyncio.gather(*tasks, return_exceptions=True)
135  for index, result in enumerate(results):
136  name = conf[ATTR_CREDENTIALS][index][CONF_NAME]
137  if isinstance(result, Exception):
138  _LOGGER.error(
139  "Validating credential [%s] failed: %s",
140  name,
141  result,
142  exc_info=result,
143  )
144  validation = False
145  else:
146  hass.data[DATA_SESSIONS][name] = result
147 
148  # set up notify platform, no entry support for notify component yet,
149  # have to use discovery to load platform.
150  for notify_config in conf[CONF_NOTIFY]:
151  hass.async_create_task(
152  discovery.async_load_platform(
153  hass, Platform.NOTIFY, DOMAIN, notify_config, config
154  )
155  )
156 
157  return validation
158 
159 
160 async def _validate_aws_credentials(hass, credential):
161  """Validate AWS credential config."""
162  aws_config = credential.copy()
163  del aws_config[CONF_NAME]
164  del aws_config[CONF_VALIDATE]
165 
166  if (profile := aws_config.get(CONF_PROFILE_NAME)) is not None:
167  session = AioSession(profile=profile)
168  del aws_config[CONF_PROFILE_NAME]
169  if CONF_ACCESS_KEY_ID in aws_config:
170  del aws_config[CONF_ACCESS_KEY_ID]
171  if CONF_SECRET_ACCESS_KEY in aws_config:
172  del aws_config[CONF_SECRET_ACCESS_KEY]
173  else:
174  session = AioSession()
175 
176  if credential[CONF_VALIDATE]:
177  async with session.create_client("iam", **aws_config) as client:
178  await client.get_user()
179 
180  return session
def _validate_aws_credentials(hass, credential)
Definition: __init__.py:160
bool async_setup(HomeAssistant hass, ConfigType config)
Definition: __init__.py:89
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:109