Azure

[Azure Functions] Detected invalid time interval input

배경

코드

       ...생략

       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

개요

어떻게 할당?

https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#general

  1. Scope 를 설정
  2. Resource Group을 설정했다고 치자
  3. IAM 에서 Role 을 김연우에게 할당했다
  4. 그럼, 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

https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#role-based-access-control-administrator

Azure ARM

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>