Azure
- [Azure Functions] Detected invalid time interval input
- Azure RBAC
- Azure ARM
- Azure Functions Java pom.xml
[Azure Functions] Detected invalid time interval input
배경
- Azure Functions Time Trigger, Golang 으로 안됨
- Java 로 하려는데
client.queryResourceWithResponse(...)
에서 계속 타임아웃 - HttpTrigger 로 하니까 테스트 코드에서 에러 발견
- 어떻게 해결?
코드
...생략
OffsetDateTime now = OffsetDateTime.now();
QueryTimeInterval timeInterval = new QueryTimeInterval(now.minusMinutes(1), now);
MetricsQueryOptions options = new MetricsQueryOptions()
.setMetricNamespace("Microsoft.DBforMySQL/flexibleServers")
.setTimeInterval(timeInterval)
.setGranularity(Duration.ofMinutes(1))
.setAggregations(Arrays.asList(AggregationType.AVERAGE));
String format = String.format("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DBforMySQL/flexibleServers/%s", subscriptionID, resourceGroupName, resourceName);
context.getLogger().info("Request sent");
Response<MetricsQueryResult> metricsQueryResultResponse = client.queryResourceWithResponse(
format,
metricName,
options,
Context.NONE);
...생략
/**
* Unit test for Function class.
*/
public class FunctionTest {
/**
* Unit test for HttpTriggerJava method.
*/
@Test
public void testHttpTriggerJava() throws Exception {
// Setup
@SuppressWarnings("unchecked")
final HttpRequestMessage<Optional<String>> req = mock(HttpRequestMessage.class);
final Map<String, String> queryParams = new HashMap<>();
queryParams.put("name", "Azure");
doReturn(queryParams).when(req).getQueryParameters();
final Optional<String> queryBody = Optional.empty();
doReturn(queryBody).when(req).getBody();
doAnswer(new Answer<HttpResponseMessage.Builder>() {
@Override
public HttpResponseMessage.Builder answer(InvocationOnMock invocation) {
HttpStatus status = (HttpStatus) invocation.getArguments()[0];
return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status);
}
}).when(req).createResponseBuilder(any(HttpStatus.class));
final ExecutionContext context = mock(ExecutionContext.class);
doReturn(Logger.getGlobal()).when(context).getLogger();
// Invoke
final HttpResponseMessage ret = new Function().run(req, context);
// Verify
assertEquals(HttpStatus.OK, ret.getStatus());
}
}
final HttpResponseMessage ret = new Function().run(req, context); 부분에서 에러 발생
com.azure.monitor.query.implementation.metrics.models.ErrorResponseException: Status code 400, "{"code":"BadRequest","message":"Detected invalid time interval input: 2024-08-26T09:06:21.940798 09:00/2024-08-26T09:07:21.940798 09:00, supported Iso 8601 time interval format: (Datetime/Datetime, Datetime/Duration, Duration/Datetime, Duration)"}"
.NET 에서 버그 이슈 발견 https://github.com/Azure/azure-sdk-for-net/issues/40047
해결
QueryTimeInterval 를 파라미터로 넣으면 안되는데 버그 같음(?)
Duration 사용
Azure RBAC
개요
- Security Principal 에 role 을 assign 할 수 있다
- Security Principal 은 4개가 있다
- User
- Group
- Service Principal
- Managed Identity
- 그룹은 role 이 전이가 가능
- Scope 가 있음
어떻게 할당?
https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#general
- Scope 를 설정
- Resource Group을 설정했다고 치자
- IAM 에서 Role 을 김연우에게 할당했다
- 그럼, Resource Group 내에서 해당 Role 을 수행할 수 있음
특정 리소스에게 권한을 할당하려면?
https://learn.microsoft.com/ko-kr/entra/identity/managed-identities-azure-resources/overview
Managed Identity
- | System-assigned managed identity | User-assigned managed identity |
---|---|---|
권한 | 해당 리소스에만 적용됨 | 권한 공유 가능 |
특징 | 리소스삭제하면 같이 삭제됨 |
할당하기 위한 Role
Owner or User Access Administrator 필요
To assign Azure roles, you must have:
Microsoft.Authorization/roleAssignments/write permissions, such as Role Based Access Control Administrator or User Access Administrator
Azure ARM
- Azure PowerShell, Azure CLI, Azure SDKs 모든 게 Azure Resource Manager 로 간다
- 따라서 일관된 결과를 얻을 수 있다
https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/overview
Azure Functions Java pom.xml
<?xml version="1.0" encoding="UTF-8" ?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.kyu</groupId>
<artifactId>forwarder</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Azure Java Functions</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>17</java.version>
<azure.functions.maven.plugin.version>1.6.0</azure.functions.maven.plugin.version>
<azure.functions.java.library.version>3.1.0</azure.functions.java.library.version>
<functionAppName>forwarder-1724717406048</functionAppName>
<stagingDirectory>${project.build.directory}/azure-functions/${functionAppName}</stagingDirectory>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-sdk-bom</artifactId>
<version>1.2.26</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-monitor-query</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.azure.functions</groupId>
<artifactId>azure-functions-java-library</artifactId>
<version>${azure.functions.java.library.version}</version>
</dependency>
<!-- Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<scope>provided</scope>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.4.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.23.4</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<shadedArtifactAttached>false</shadedArtifactAttached>
<outputFile>${project.build.directory}/azure-functions/${functionAppName}/${project.artifactId}-${project.version}.jar</outputFile>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<overwrite>true</overwrite>
<outputDirectory>${stagingDirectory}</outputDirectory>
<resources>
<resource>
<directory>${project.basedir}</directory>
<includes>
<include>host.json</include>
<include>local.settings.json</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version> <!-- 버전 추가 -->
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<plugin>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-functions-maven-plugin</artifactId>
<version>1.36.0</version>
<configuration>
<resourceGroup>io.kyu</resourceGroup>
<appName>kyu-forwarder</appName>
<region>koreancentral</region>
<runtime>
<os>linux</os>
<javaVersion>17</javaVersion>
</runtime>
<deploymentType>ZIP</deploymentType>
</configuration>
</plugin>
</plugins>
</build>
</project>