Azure / azure-libraries-for-java

Azure Management Libraries for Java
https://docs.microsoft.com/en-us/java/azure/
MIT License
94 stars 98 forks source link

Frontdoor package is missing. #1297

Closed janwei25 closed 3 years ago

janwei25 commented 3 years ago

If i'm not mistaken, there is no frontdoor package available for java. https://azure.github.io/azure-sdk/releases/latest/all/#java states Python, .NET and JavaScript have frontdoor packages but Java doesn't have them. Please add them ASAP. Thanks!

weidongxu-microsoft commented 3 years ago

@janwei25 Would you let us know your use case, e.g. other Java mgmt libs you already using?

weidongxu-microsoft commented 3 years ago

@xccc-msft I didn't find a Lite package for azure frontdoor. We might need to release one if service team is OK with it.

ghost commented 3 years ago

Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc @cdnfdsuppgithub.

janwei25 commented 3 years ago

@weidongxu-microsoft I'm using a lot of Java mgmt libs for Azure. Among some of them are Network, Compute, KeyVault, Storage, Sql, etc... and many more to make queries for resources. At first, I thought Frontdoor might be within Network but it's not. It would be great if FrontDoor would be added so that we would not need to use the Rest API!

weidongxu-microsoft commented 3 years ago

@janwei25 Thanks. We'd like to know a bit whether you are using this lib (https://mvnrepository.com/artifact/com.microsoft.azure/azure-mgmt-network) or this (https://mvnrepository.com/artifact/com.microsoft.azure.network.v2020_06_01/azure-mgmt-network). Note the namespace difference.

The frontdoor java lib would likely be similar to latter.

janwei25 commented 3 years ago

@weidongxu-microsoft Oh, I'm using the stable SDK version (the former). I looked up the latter version in the github repo and could not find any frontdoor files there so I think frontdoor is not there either. Thanks for the heads up though. I'll be monitoring that repo for latest updates.

nickzhums commented 3 years ago

@janwei25 thanks for reporting the issue. If you don't mind, could you share a bit about your use cases? e.g.

Thanks much

janwei25 commented 3 years ago

@nickzhums Hi!

What are you using the management libraries for?

To query and read resource data across a variety of Azure resources across multiple services (Network, Compute, KeyVault, etc...). Long story short, our clients grant us Azure service principals in order to query their resources and we use the Java SDK to get those data. We use the Java SDK because our backend is in Java and we prefer it over directly using the REST API as the Java SDK already handle stuff like client retries and it's very robust!

Anything we can do to improve?

Generally, the SDK is very good however I have some issues with it.

weidongxu-microsoft commented 3 years ago

@janwei25 Thanks for the info. In short-term, the frontdoor lib will be like what you get as private dns / mysqldb / postgresqldb (i.e., a separate package which likely also start with beta).

@cdnfdsuppgithub Hi Max, is frontdoor service ready for Java mgmt SDK?

nickzhums commented 3 years ago

@janwei25 Thanks so much for providing the feedback. A lot of useful stuff - we will evaluate those feedback and see how we can improve those aspects. As a side-note, we just released our next generation Java SDK, which addresses some of the things you mentioned above (eg. error handling). The libraries can be found at here. Hope you will be able to use it in some of your future projects :)

weidongxu-microsoft commented 3 years ago

Next generation will have private dns in stable.

Error handling will get a ManagementException for all management operations (exclude a few data-plane operation like key/secret in vault, user/group in RBAC). Note that if resource is not found, it will have exception as well.

Fields naming is a bit hard story. We can change them to e.g. get{field} but then it will break almost all existing code.

janwei25 commented 3 years ago

@nickzhums NP. Thx for the link!

@weidongxu-microsoft Thx for the heads up on the error handling improvements in next-gen. I may upgrade it if we have more consistent error handling methods there :D

Thx for the fast response! Looking forward to it.

nickzhums commented 3 years ago

@janwei25 I talked with docs team, you can search for an API method like this:

https://docs.microsoft.com/en-us/java/api/?term=listByResourceGroup

@anmeng10101 can provide more info

weidongxu-microsoft commented 3 years ago

The SDK does not have predictable naming of resource's fields. For instance, some fields are available in the .inner object but some are not and it's not clear why. This makes it harder for users to write automated scripts in order to destructure and parse large resource objects. The AWS Java SDK on the other hand handles this very well. Their resource props are always predictable and their methods to get those props are always of the template get{ResourceField}() so it's easy to write scripts to automate parsing.

If you only need all the properties, the ones in inner object will be enough (do it recursively since many will have nested objects).

Part of the difference is due to certain abstraction. E.g. StorageAccount got accountStatuses() method, which abstracts statusOfPrimary() and statusOfSecondary() from inner. Some of the abstract tries to improve the usability (e.g. certain inner will have a String with coma separated values, abstraction will convert it to List).

Also there is some operation method like getKeys() in StorageAccount.

anmeng10101 commented 3 years ago

@janwei25 , thanks a lot for the feedback about the documents.

Would like to know your normal preference to search a method please? such as find listByResourceGroup from https://docs.microsoft.com/en-us/java/api/overview/azure/?view=azure-java-stable.

Is it search from 2 highlight search boxes?

image

janwei25 commented 3 years ago

@weidongxu-microsoft Yes, I noticed that .inner usually has all the fields but while it works like...99% of the time, I think there is one instance where because I used the inner object, I got loss of field data instead. It has been a while since I have faced that issue (around 2 months ago) so I forgot all the details but IIRC, it was LocalNetworkGateway from Network service. The info I got from LocalNetworkGatewayInner had a few missing fields in some nested objects vs what I would have gotten if I had used LocalNetworkGateway instead. I forgot exactly which nested fields they were but they were not critical (prob around 4 to 5 fields). The fields were all complete and available but the SDK did not populate them. It is entirely possible that I made a mistake there though. Not sure, haha.

@anmeng10101 No, I did not use the search bar at all. Maybe Im stupid haha but I was developing for Azure via the Python SDK prior to Java and was used to the format of the documentation there. It was from the docs there that I found out that I could list by resource group.

For instance, if I wanted to search the methods available to retrieve Application Gateways, I just head here for Python https://docs.microsoft.com/en-us/python/api/azure-mgmt-network/azure.mgmt.network.v2020_06_01.operations.applicationgatewaysoperations?view=azure-python and the operations possible are listed very clearly. From this page, I know that I can call list to list by resource group. It is very intuitive and I could reach that page just via the left menu hierarchy.

So naturally, when I went on to search the docs for the stable Java SDK instead, I used the same method because I assumed it would be consistent. However, my usual navigation methods led me to some page like this https://docs.microsoft.com/en-us/java/api/com.microsoft.azure.management.network?view=azure-java-stable, which is just a large collection of class models and I'm not sure how to find list operations via navigating there at all. I searched through the whole docs and I couldn't find any listByResourceGroup type operation so I almost gave up but luckily I downloaded this github repo and did a deep term search and found the methods in the /implementation folder. Personally, I feel that docs structure should be the same across different language SDKs so that it is predictable. I feel that the way the docs on the Python SDK is structured is much better as I can see straightaway what operations are possible for a resource class. Even with the search bar there, it is hard to search for the specific listByResourceGroup method I want. Let's say I am a newbie and I have never integrated Azure before. Browsing through the Java docs, I would have never thought that there is even a listByResourceGroup method available. It is only through the Python SDK that I know that such method should be available.

weidongxu-microsoft commented 3 years ago

@janwei25 I see. Yes, it is indeed possible. Again caused by certain abstraction to improve usability (it is not common). Some object would try to take a few closely related inner objects from REST, hence this would happen (since the inner only refer to one of them).

janwei25 commented 3 years ago

@weidongxu-microsoft Hi, this is a separate subject. But is there any way of getting the object ID of a service principal via the Java SDK given an ApplicationTokenCredentials object (clientId, tenantId and clientSecret) being supplied. According to https://docs.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals#application-and-service-principal-relationship, the relation between app to service principals are 1:many in a multi-tenant app but since the tenantId is supplied here, the mapping between clientId => objectId should be 1:1. But I can't seem to find any method in the management API which does this, not even REST. I know for sure though getting the OID is possible because when I call to get an access token via logging in with the service principal credentials and after the parsing the JWT token, I do get an oid field in the object. However, I can't really get the object ID via any SDK or REST methods at all. Something like https://docs.microsoft.com/en-us/azure/healthcare-apis/find-identity-object-ids#find-service-principal-object-id for the Java SDK or any other pointers would be great

weidongxu-microsoft commented 3 years ago

@janwei25

You can do this

String objectId = azure.accessManagement().servicePrincipals().getByName(credentials.clientId()).id();

Note that listing (with filter) the service principals will require certain AAD permission.

PS: for frontdoor Java SDK, still taking with service on which api-version to release.

weidongxu-microsoft commented 3 years ago

@ChenTanyi Please update when package is released.

weidongxu-microsoft commented 3 years ago

Sample code (might not be exactly same)

        String backendAddress;

        String frontendName = "frontend1";
        String loadBalancingName = "loadbalancing1";
        String healthProbeName = "healthprobe1";
        String routingRuleName = "rule1";
        String backendPoolName = "backend1";

        String frontendEndpointsId = getResourceId("frontendEndpoints", frontendName);
        String loadBalancingSettingsId = getResourceId("loadBalancingSettings", loadBalancingName);
        String healthProbeSettingsId = getResourceId("healthProbeSettings", healthProbeName);
        String backendPoolsId = getResourceId("backendPools", backendPoolName);

        FrontDoor frontDoor = frontDoorManager.frontDoors().define(fdName)
                .withRegion("global")
                .withExistingResourceGroup(rgName)
                .withFrontendEndpoints(Collections.singletonList(
                        new FrontendEndpointInner()
                                .withName(frontendName)
                                .withHostname(fdName + ".azurefd.net")
                                .withSessionAffinityEnabledState(SessionAffinityEnabledState.DISABLED)
                ))
                .withBackendPools(Collections.singletonList(
                        new BackendPool().withName(backendPoolName).withBackends(Collections.singletonList(
                                new Backend()
                                        .withAddress(backendAddress)
                                        .withEnabledState(BackendEnabledState.ENABLED)
                                        .withBackendHostHeader(backendAddress)
                                        .withHttpPort(80)
                                        .withHttpsPort(443)
                                        .withPriority(1)
                                        .withWeight(50)
                        ))
                        .withLoadBalancingSettings(new SubResource().withId(loadBalancingSettingsId))
                        .withHealthProbeSettings(new SubResource().withId(healthProbeSettingsId))
                ))
                .withLoadBalancingSettings(Collections.singletonList(
                        new LoadBalancingSettingsModel()
                            .withName(loadBalancingName)
                            .withSampleSize(4)
                            .withSuccessfulSamplesRequired(2)
                            .withAdditionalLatencyMilliseconds(0)
                ))
                .withHealthProbeSettings(Collections.singletonList(
                        new HealthProbeSettingsModel()
                                .withName(healthProbeName)
                                .withEnabledState(HealthProbeEnabled.ENABLED)
                                .withPath("/")
                                .withProtocol(FrontDoorProtocol.HTTPS)
                                .withHealthProbeMethod(FrontDoorHealthProbeMethod.HEAD)
                                .withIntervalInSeconds(30)
                ))
                .withRoutingRules(Collections.singletonList(
                        new RoutingRule()
                                .withName(routingRuleName)
                                .withEnabledState(RoutingRuleEnabledState.ENABLED)
                                .withFrontendEndpoints(Collections.singletonList(new SubResource().withId(frontendEndpointsId)))
                                .withAcceptedProtocols(Arrays.asList(FrontDoorProtocol.HTTP, FrontDoorProtocol.HTTPS))
                                .withPatternsToMatch(Collections.singletonList("/*"))
                                .withRouteConfiguration(new ForwardingConfiguration()
                                        .withForwardingProtocol(FrontDoorForwardingProtocol.HTTPS_ONLY)
                                        .withBackendPool(new SubResource().withId(backendPoolsId)))
                ))
                .create();

    private String getResourceId(String type, String name) {
        return String.format("/subscriptions/%1$s/resourceGroups/%2$s/providers/Microsoft.Network/frontdoors/%3$s/%4$s/%5$s",
                subscriptionId, rgName, fdName, type, name);
    }
ChenTanyi commented 3 years ago

https://search.maven.org/artifact/com.microsoft.azure.frontdoor.v2020_05_01/azure-mgmt-network/1.0.0-beta/jar

janwei25 commented 3 years ago

Thanks guys for the fast response. I tested and it worked with my use case! :+1: