ms-azure-api 0.2.0.1 → 0.3.0.0
raw patch · 10 files changed
+361/−37 lines, 10 filesdep +conduitPVP ok
version bump matches the API change (PVP)
Dependencies added: conduit
API changes (from Hackage documentation)
- MSAzureAPI.Internal.Common: (==:) :: Text -> Text -> Option 'Https
- MSAzureAPI.Internal.Common: APData :: Text -> APIPlane
- MSAzureAPI.Internal.Common: APManagement :: APIPlane
- MSAzureAPI.Internal.Common: aesonOptions :: String -> Options
- MSAzureAPI.Internal.Common: data APIPlane
- MSAzureAPI.Internal.Common: data Collection a
- MSAzureAPI.Internal.Common: get :: FromJSON b => APIPlane -> [Text] -> Option 'Https -> AccessToken -> Req b
- MSAzureAPI.Internal.Common: getBs :: APIPlane -> [Text] -> Option 'Https -> AccessToken -> Req ByteString
- MSAzureAPI.Internal.Common: getLbs :: APIPlane -> [Text] -> Option 'Https -> AccessToken -> Req ByteString
- MSAzureAPI.Internal.Common: instance Data.Aeson.Types.FromJSON.FromJSON a => Data.Aeson.Types.FromJSON.FromJSON (MSAzureAPI.Internal.Common.Collection a)
- MSAzureAPI.Internal.Common: instance GHC.Classes.Eq a => GHC.Classes.Eq (MSAzureAPI.Internal.Common.Collection a)
- MSAzureAPI.Internal.Common: instance GHC.Generics.Generic (MSAzureAPI.Internal.Common.Collection a)
- MSAzureAPI.Internal.Common: instance GHC.Show.Show a => GHC.Show.Show (MSAzureAPI.Internal.Common.Collection a)
- MSAzureAPI.Internal.Common: post :: (FromJSON b, ToJSON a) => APIPlane -> [Text] -> Option 'Https -> a -> AccessToken -> Req b
- MSAzureAPI.Internal.Common: tryReq :: Req a -> Req (Either HttpException a)
+ MSAzureAPI: LNorthEU :: Location
+ MSAzureAPI: LWestEU :: Location
+ MSAzureAPI: collectionNextLink :: Collection a -> Maybe Text
+ MSAzureAPI: collectionValue :: Collection a -> [a]
+ MSAzureAPI: data Collection a
+ MSAzureAPI: data Location
+ MSAzureAPI: showLocation :: Location -> Text
+ MSAzureAPI: tryReq :: Req a -> Req (Either HttpException a)
+ MSAzureAPI.MachineLearning.Compute: AKS :: ComputeType
+ MSAzureAPI.MachineLearning.Compute: Compute :: Text -> Text -> Text -> Text -> ComputeProperties -> Compute
+ MSAzureAPI.MachineLearning.Compute: ComputeProperties :: ZonedTime -> ZonedTime -> Text -> ComputeType -> ProvisioningState -> ComputeProperties
+ MSAzureAPI.MachineLearning.Compute: Succeeded :: ProvisioningState
+ MSAzureAPI.MachineLearning.Compute: [cmpId] :: Compute -> Text
+ MSAzureAPI.MachineLearning.Compute: [cmpLocation] :: Compute -> Text
+ MSAzureAPI.MachineLearning.Compute: [cmpName] :: Compute -> Text
+ MSAzureAPI.MachineLearning.Compute: [cmpProperties] :: Compute -> ComputeProperties
+ MSAzureAPI.MachineLearning.Compute: [cmpType] :: Compute -> Text
+ MSAzureAPI.MachineLearning.Compute: [cmppComputeType] :: ComputeProperties -> ComputeType
+ MSAzureAPI.MachineLearning.Compute: [cmppCreatedOn] :: ComputeProperties -> ZonedTime
+ MSAzureAPI.MachineLearning.Compute: [cmppModifiedOn] :: ComputeProperties -> ZonedTime
+ MSAzureAPI.MachineLearning.Compute: [cmppProvisioningState] :: ComputeProperties -> ProvisioningState
+ MSAzureAPI.MachineLearning.Compute: [cmppResourceId] :: ComputeProperties -> Text
+ MSAzureAPI.MachineLearning.Compute: data Compute
+ MSAzureAPI.MachineLearning.Compute: data ComputeProperties
+ MSAzureAPI.MachineLearning.Compute: data ComputeType
+ MSAzureAPI.MachineLearning.Compute: data ProvisioningState
+ MSAzureAPI.MachineLearning.Compute: instance Data.Aeson.Types.FromJSON.FromJSON MSAzureAPI.MachineLearning.Compute.Compute
+ MSAzureAPI.MachineLearning.Compute: instance Data.Aeson.Types.FromJSON.FromJSON MSAzureAPI.MachineLearning.Compute.ComputeProperties
+ MSAzureAPI.MachineLearning.Compute: instance Data.Aeson.Types.FromJSON.FromJSON MSAzureAPI.MachineLearning.Compute.ComputeType
+ MSAzureAPI.MachineLearning.Compute: instance Data.Aeson.Types.FromJSON.FromJSON MSAzureAPI.MachineLearning.Compute.ProvisioningState
+ MSAzureAPI.MachineLearning.Compute: instance Data.Aeson.Types.ToJSON.ToJSON MSAzureAPI.MachineLearning.Compute.Compute
+ MSAzureAPI.MachineLearning.Compute: instance Data.Aeson.Types.ToJSON.ToJSON MSAzureAPI.MachineLearning.Compute.ComputeProperties
+ MSAzureAPI.MachineLearning.Compute: instance Data.Aeson.Types.ToJSON.ToJSON MSAzureAPI.MachineLearning.Compute.ComputeType
+ MSAzureAPI.MachineLearning.Compute: instance Data.Aeson.Types.ToJSON.ToJSON MSAzureAPI.MachineLearning.Compute.ProvisioningState
+ MSAzureAPI.MachineLearning.Compute: instance GHC.Classes.Eq MSAzureAPI.MachineLearning.Compute.ComputeType
+ MSAzureAPI.MachineLearning.Compute: instance GHC.Classes.Eq MSAzureAPI.MachineLearning.Compute.ProvisioningState
+ MSAzureAPI.MachineLearning.Compute: instance GHC.Generics.Generic MSAzureAPI.MachineLearning.Compute.Compute
+ MSAzureAPI.MachineLearning.Compute: instance GHC.Generics.Generic MSAzureAPI.MachineLearning.Compute.ComputeProperties
+ MSAzureAPI.MachineLearning.Compute: instance GHC.Generics.Generic MSAzureAPI.MachineLearning.Compute.ComputeType
+ MSAzureAPI.MachineLearning.Compute: instance GHC.Generics.Generic MSAzureAPI.MachineLearning.Compute.ProvisioningState
+ MSAzureAPI.MachineLearning.Compute: instance GHC.Show.Show MSAzureAPI.MachineLearning.Compute.Compute
+ MSAzureAPI.MachineLearning.Compute: instance GHC.Show.Show MSAzureAPI.MachineLearning.Compute.ComputeProperties
+ MSAzureAPI.MachineLearning.Compute: instance GHC.Show.Show MSAzureAPI.MachineLearning.Compute.ComputeType
+ MSAzureAPI.MachineLearning.Compute: instance GHC.Show.Show MSAzureAPI.MachineLearning.Compute.ProvisioningState
+ MSAzureAPI.MachineLearning.Compute: listComputes :: Text -> Text -> Text -> AccessToken -> Req (Collection Compute)
+ MSAzureAPI.MachineLearning.Jobs: JBAutoMLJob :: JobBase
+ MSAzureAPI.MachineLearning.Jobs: JBCommandJob :: JobBase
+ MSAzureAPI.MachineLearning.Jobs: JBPipelineJob :: JobBase
+ MSAzureAPI.MachineLearning.Jobs: JBSweepJob :: JobBase
+ MSAzureAPI.MachineLearning.Jobs: createJob :: FromJSON b => Text -> Text -> Text -> Text -> JobBase -> AccessToken -> Req b
+ MSAzureAPI.MachineLearning.Jobs: data JobBase
+ MSAzureAPI.MachineLearning.Jobs: instance Data.Aeson.Types.ToJSON.ToJSON MSAzureAPI.MachineLearning.Jobs.JobBase
+ MSAzureAPI.MachineLearning.Jobs: instance GHC.Classes.Eq MSAzureAPI.MachineLearning.Jobs.JobBase
+ MSAzureAPI.MachineLearning.Jobs: instance GHC.Generics.Generic MSAzureAPI.MachineLearning.Jobs.JobBase
+ MSAzureAPI.MachineLearning.Jobs: instance GHC.Show.Show MSAzureAPI.MachineLearning.Jobs.JobBase
+ MSAzureAPI.MachineLearning.Usages: Usage :: Int -> Int -> Text -> UsageName -> Usage
+ MSAzureAPI.MachineLearning.Usages: UsageName :: Text -> Text -> UsageName
+ MSAzureAPI.MachineLearning.Usages: [uCurrentValue] :: Usage -> Int
+ MSAzureAPI.MachineLearning.Usages: [uLimit] :: Usage -> Int
+ MSAzureAPI.MachineLearning.Usages: [uName] :: Usage -> UsageName
+ MSAzureAPI.MachineLearning.Usages: [uType] :: Usage -> Text
+ MSAzureAPI.MachineLearning.Usages: [unLocalizedValue] :: UsageName -> Text
+ MSAzureAPI.MachineLearning.Usages: [unValue] :: UsageName -> Text
+ MSAzureAPI.MachineLearning.Usages: data Usage
+ MSAzureAPI.MachineLearning.Usages: data UsageName
+ MSAzureAPI.MachineLearning.Usages: getUsages :: Text -> Location -> AccessToken -> Req (Collection Usage)
+ MSAzureAPI.MachineLearning.Usages: instance Data.Aeson.Types.FromJSON.FromJSON MSAzureAPI.MachineLearning.Usages.Usage
+ MSAzureAPI.MachineLearning.Usages: instance Data.Aeson.Types.FromJSON.FromJSON MSAzureAPI.MachineLearning.Usages.UsageName
+ MSAzureAPI.MachineLearning.Usages: instance GHC.Classes.Eq MSAzureAPI.MachineLearning.Usages.Usage
+ MSAzureAPI.MachineLearning.Usages: instance GHC.Classes.Eq MSAzureAPI.MachineLearning.Usages.UsageName
+ MSAzureAPI.MachineLearning.Usages: instance GHC.Classes.Ord MSAzureAPI.MachineLearning.Usages.Usage
+ MSAzureAPI.MachineLearning.Usages: instance GHC.Classes.Ord MSAzureAPI.MachineLearning.Usages.UsageName
+ MSAzureAPI.MachineLearning.Usages: instance GHC.Generics.Generic MSAzureAPI.MachineLearning.Usages.Usage
+ MSAzureAPI.MachineLearning.Usages: instance GHC.Generics.Generic MSAzureAPI.MachineLearning.Usages.UsageName
+ MSAzureAPI.MachineLearning.Usages: instance GHC.Show.Show MSAzureAPI.MachineLearning.Usages.Usage
+ MSAzureAPI.MachineLearning.Usages: instance GHC.Show.Show MSAzureAPI.MachineLearning.Usages.UsageName
+ MSAzureAPI.StorageServices.FileService: DirItems :: [DirItem] -> Maybe Text -> DirItems
+ MSAzureAPI.StorageServices.FileService: [disItems] :: DirItems -> [DirItem]
+ MSAzureAPI.StorageServices.FileService: [disResponseMarker] :: DirItems -> Maybe Text
+ MSAzureAPI.StorageServices.FileService: data DirItems
- MSAzureAPI.StorageServices.FileService: listDirectoriesAndFiles :: Text -> Text -> Text -> AccessToken -> Req (Either String [DirItem])
+ MSAzureAPI.StorageServices.FileService: listDirectoriesAndFiles :: Text -> Text -> Text -> Maybe Text -> AccessToken -> Req (Either String DirItems)
Files
- CHANGELOG.md +15/−2
- README.md +4/−3
- ms-azure-api.cabal +8/−3
- src/MSAzureAPI.hs +13/−0
- src/MSAzureAPI/Internal/Common.hs +46/−3
- src/MSAzureAPI/MachineLearning/Compute.hs +80/−0
- src/MSAzureAPI/MachineLearning/Jobs.hs +67/−0
- src/MSAzureAPI/MachineLearning/Usages.hs +58/−0
- src/MSAzureAPI/StorageServices.hs +6/−10
- src/MSAzureAPI/StorageServices/FileService.hs +64/−16
CHANGELOG.md view
@@ -8,9 +8,22 @@ ## Unreleased -## 0.2+MSAzureAPI.StorageServices.FileService : add listDirectoriesAndFilesC (stream all response pages from listDirectoriesAndFiles) -MSAzureAPI.StorageServices.FileService. listDirectoriesAndFiles+## 0.3.0.0++add 'conduit' as a dependency++MSAzureAPI.MachineLearning.Compute+MSAzureAPI.MachineLearning.Jobs+MSAzureAPI.MachineLearning.Usages++* breaking changes:+MSAzureAPI.StorageServices.FileService. listDirectoriesAndFiles now has an extra parameter to support paginated results, as well as a more informative return type.++## 0.2.0.0++MSAzureAPI.StorageServices.FileService : add listDirectoriesAndFiles Add XML support via `xeno` and `xmlbf` to parse `listDirectoriesAndFiles` response bodies
README.md view
@@ -1,6 +1,6 @@ # ms-azure-api -Haskell client bindings to the [Microsoft Azure API]().+Haskell client bindings to the [Microsoft Azure API](https://learn.microsoft.com/en-us/rest/api/azure/). [](https://hackage.haskell.org/package/ms-azure-api) @@ -9,7 +9,7 @@ ## Introduction -This library provides the client interface (under the `MSAzureAPI` namespace).+This library provides the client interface to the MS Azure API (under the `MSAzureAPI` namespace). Authentication can be implemented with the `ms-auth` library. @@ -24,8 +24,9 @@ Some breaking changes might also be introduced as the library matures. -We adhere to a simplified version of the [Package Versioning Policy](https://pvp.haskell.org/): breaking changes are signaled by increasing the major version number (e.g. 0.x -> 1.x ).+We adhere to the [Package Versioning Policy](https://pvp.haskell.org/): major breaking changes or API refactors are signaled by increasing the first major version number (i.e. 0.0.0.0 -> 1.0.0.0 ) whereas less significant ones are indicated by increasing the second one (0.0.0.0 -> 0.1.0.0). +Significant changes in the SDK will be documented in the respective CHANGELOG. ## Copyright
ms-azure-api.cabal view
@@ -1,5 +1,5 @@ name: ms-azure-api-version: 0.2.0.1+version: 0.3.0.0 synopsis: Microsoft Azure API description: Bindings to the Microsoft Azure API homepage: https://github.com/unfoldml/ms-graph-api@@ -13,17 +13,22 @@ extra-source-files: README.md CHANGELOG.md cabal-version: >=1.10-tested-with: GHC == 7.10.2+tested-with: GHC == 9.2.8 library default-language: Haskell2010 hs-source-dirs: src- exposed-modules: MSAzureAPI.Internal.Common+ exposed-modules: MSAzureAPI+ MSAzureAPI.MachineLearning.Compute+ MSAzureAPI.MachineLearning.Jobs+ MSAzureAPI.MachineLearning.Usages MSAzureAPI.StorageServices MSAzureAPI.StorageServices.FileService+ other-modules: MSAzureAPI.Internal.Common build-depends: base >= 4.7 && < 5 , aeson , bytestring+ , conduit , containers , hoauth2 == 2.6.0 , http-types
+ src/MSAzureAPI.hs view
@@ -0,0 +1,13 @@+module MSAzureAPI (+ -- ** HTTP request helpers+ tryReq+ -- ** Common types+ , Collection+ , collectionValue+ , collectionNextLink+ -- *** Location+ , Location(..)+ , showLocation+ ) where++import MSAzureAPI.Internal.Common
src/MSAzureAPI/Internal/Common.hs view
@@ -4,6 +4,7 @@ -- module MSAzureAPI.Internal.Common ( APIPlane(..)+ , put , get , getBs , getLbs@@ -12,8 +13,14 @@ , (==:) -- ** Helpers , tryReq- -- ** JSON+ -- ** Common types , Collection+ , collectionValue+ , collectionNextLink+ -- *** Location+ , Location(..)+ , showLocation+ -- ** JSON co\/dec , aesonOptions ) where @@ -83,11 +90,23 @@ data APIPlane = APManagement -- ^ Management plane (@management.azure.com@ endpoints) | APData Text -- ^ Data plane e.g. FileREST API ++-- | @PUT@+put :: (A.FromJSON b, A.ToJSON a) =>+ APIPlane+ -> [Text] -- ^ URI path segments+ -> Option 'Https -- ^ request parameters etc.+ -> a -> AccessToken -> Req b+put apiplane paths params bdy tok = responseBody <$> req POST url (ReqBodyJson bdy) jsonResponse opts+ where+ opts = auth <> params+ (url, auth) = msAzureReqConfig apiplane paths tok+ -- | @POST@ post :: (A.FromJSON b, A.ToJSON a) => APIPlane -> [Text] -- ^ URI path segments- -> Option 'Https+ -> Option 'Https -- ^ request parameters etc. -> a -- ^ request body -> AccessToken -> Req b post apiplane paths params bdy tok = responseBody <$> req POST url (ReqBodyJson bdy) jsonResponse opts@@ -123,14 +142,38 @@ (//:) = foldl (/:) --- * aeson+-- * common types +showLocation :: Location -> Text+showLocation = pack . show++-- | Azure regions+data Location =+ LNorthEU -- ^ "North Europe"+ | LWestEU -- ^ "West Europe"+ deriving (Eq)+instance Show Location where+ show = \case+ LNorthEU -> "northeu"+ LWestEU -> "westeu"+ -- | a collection of items with key @value@+--+-- NB : results are paginated, and subsequent chunks can be accessed by following the @nextLink@ field data Collection a = Collection { cValue :: [a]+ , cNextLink :: Maybe Text -- ^ The URI to fetch the next page of results } deriving (Eq, Show, Generic) instance A.FromJSON a => A.FromJSON (Collection a) where parseJSON = A.genericParseJSON (aesonOptions "c")+-- | Get the collection items+collectionValue :: Collection a -> [a]+collectionValue = cValue+-- | Get the next link for a 'Collection' of paginated results+collectionNextLink :: Collection a -> Maybe Text+collectionNextLink = cNextLink++-- * aeson -- | drop the prefix and lowercase first character --
+ src/MSAzureAPI/MachineLearning/Compute.hs view
@@ -0,0 +1,80 @@+-- |+--+-- auth: needs @user_impersonation@ scope+module MSAzureAPI.MachineLearning.Compute where++import Control.Applicative (Alternative(..))+import Control.Monad.IO.Class (MonadIO(..))+import Data.Foldable (asum)+import Data.Functor (void)+-- import Data.Maybe (listToMaybe)+import GHC.Generics (Generic(..))++-- aeson+import qualified Data.Aeson as A (ToJSON(..), genericToEncoding, FromJSON(..), genericParseJSON, defaultOptions, Options(..), withObject, withText, (.:), (.:?), object, (.=), Key, Value, camelTo2)+-- bytestring+import qualified Data.ByteString as BS (ByteString)+import qualified Data.ByteString.Char8 as BS8 (pack, unpack)+import qualified Data.ByteString.Lazy as LBS (ByteString)+-- hoauth2+import Network.OAuth.OAuth2.Internal (AccessToken(..))+-- req+import Network.HTTP.Req (Req, Url, Option, Scheme(..))+-- text+import Data.Text (Text, pack, unpack)+import qualified Data.Text.Lazy as TL (Text, pack, unpack, toStrict)+-- time+import Data.Time (UTCTime, getCurrentTime)+import Data.Time.Format (FormatTime, formatTime, defaultTimeLocale)+import Data.Time.LocalTime (ZonedTime, getZonedTime)++import qualified MSAzureAPI.Internal.Common as MSA (Collection, APIPlane(..), (==:), put, get, getBs, post, getLbs, aesonOptions)++-- | list computes in a workspace+--+-- docs : https://learn.microsoft.com/en-us/rest/api/azureml/2023-04-01/compute/list?tabs=HTTP+--+-- @GET https:\/\/management.azure.com\/subscriptions\/{subscriptionId}\/resourceGroups\/{resourceGroupName}\/providers\/Microsoft.MachineLearningServices\/workspaces\/{workspaceName}\/computes?api-version=2023-04-01@+listComputes :: Text -- ^ subscription id+ -> Text -- ^ res group id+ -> Text -- ^ ML workspace id+ -> AccessToken -> Req (MSA.Collection Compute)+listComputes sid rgid wsid = MSA.get MSA.APManagement [+ "subscriptions", sid,+ "resourceGroups", rgid,+ "providers", "Microsoft.MachineLearningServices",+ "workspaces", wsid,+ "computes"+ ] ("api-version" MSA.==: "2023-04-01")++data Compute = Compute {+ cmpId :: Text+ , cmpType :: Text+ , cmpName :: Text+ , cmpLocation :: Text+ , cmpProperties :: ComputeProperties+ } deriving (Show, Generic)+instance A.FromJSON Compute where+ parseJSON = A.genericParseJSON (MSA.aesonOptions "cmp")+instance A.ToJSON Compute where+ toEncoding = A.genericToEncoding (MSA.aesonOptions "cmp")++data ComputeProperties = ComputeProperties {+ cmppCreatedOn :: ZonedTime+ , cmppModifiedOn :: ZonedTime+ , cmppResourceId :: Text+ , cmppComputeType :: ComputeType+ , cmppProvisioningState :: ProvisioningState+ } deriving (Show, Generic)+instance A.ToJSON ComputeProperties where+ toEncoding = A.genericToEncoding (MSA.aesonOptions "cmpp")+instance A.FromJSON ComputeProperties where+ parseJSON = A.genericParseJSON (MSA.aesonOptions "cmpp")++data ComputeType = AKS deriving (Eq, Show, Generic)+instance A.ToJSON ComputeType+instance A.FromJSON ComputeType++data ProvisioningState = Succeeded deriving (Eq, Show, Generic)+instance A.ToJSON ProvisioningState+instance A.FromJSON ProvisioningState
+ src/MSAzureAPI/MachineLearning/Jobs.hs view
@@ -0,0 +1,67 @@+module MSAzureAPI.MachineLearning.Jobs where++import Control.Applicative (Alternative(..))+import Control.Monad.IO.Class (MonadIO(..))+import Data.Foldable (asum)+import Data.Functor (void)+-- import Data.Maybe (listToMaybe)+import GHC.Generics (Generic(..))++-- aeson+import qualified Data.Aeson as A (ToJSON(..), genericToEncoding, FromJSON(..), genericParseJSON, defaultOptions, Options(..), withObject, withText, (.:), (.:?), object, (.=), Key, Value, camelTo2)+-- bytestring+import qualified Data.ByteString as BS (ByteString)+import qualified Data.ByteString.Char8 as BS8 (pack, unpack)+import qualified Data.ByteString.Lazy as LBS (ByteString)+-- hoauth2+-- import Network.OAuth.OAuth2 (OAuth2Token(..))+import Network.OAuth.OAuth2.Internal (AccessToken(..))+-- req+import Network.HTTP.Req (Req, Url, Option, Scheme(..), header, (=:))+-- text+import Data.Text (Text, pack, unpack)+import qualified Data.Text.Lazy as TL (Text, pack, unpack, toStrict)+-- -- time+-- import Data.Time (UTCTime, getCurrentTime)+-- import Data.Time.Format (FormatTime, formatTime, defaultTimeLocale)+-- import Data.Time.LocalTime (getZonedTime)+-- -- xeno+-- import qualified Xeno.DOM.Robust as X (Node, Content(..), name, contents, children)+-- -- xmlbf-xeno+-- import qualified Xmlbf.Xeno as XB (fromRawXml)+-- xmlbf+-- import qualified Xmlbf as XB (Parser, runParser, pElement, pText)++import qualified MSAzureAPI.Internal.Common as MSA (APIPlane(..), (==:), put, get, getBs, post, getLbs, aesonOptions)++++-- | create a job+--+-- docs: <https://learn.microsoft.com/en-us/rest/api/azureml/2023-04-01/jobs/create-or-update?tabs=HTTP>+--+-- @PUT https:\/\/management.azure.com\/subscriptions\/{subscriptionId}\/resourceGroups\/{resourceGroupName}\/providers\/Microsoft.MachineLearningServices\/workspaces\/{workspaceName}\/jobs\/{id}?api-version=2023-04-01@+createJob :: (A.FromJSON b) =>+ Text -- ^ subscription id+ -> Text -- ^ res group id+ -> Text -- ^ ML workspace id+ -> Text -- ^ job id+ -> JobBase+ -> AccessToken -> Req b+createJob sid rgid wsid jid =+ MSA.put MSA.APManagement ["subscriptions", sid,+ "resourceGroups", rgid,+ "providers", "Microsoft.MachineLearningServices",+ "workspaces", wsid,+ "jobs", jid] ("api-version" MSA.==: "2023-04-JobBase")++-- | 01 type+--+-- https://learn.microsoft.com/en-us/rest/api/azureml/2023-04-01/jobs/create-or-update?tabs=HTTP+data JobBase = JBAutoMLJob -- ^ https://learn.microsoft.com/en-us/rest/api/azureml/2023-04-01/jobs/list?tabs=HTTP#automljob+ | JBCommandJob+ | JBPipelineJob+ | JBSweepJob+ deriving (Eq, Show, Generic)+instance A.ToJSON JobBase where+ toEncoding = A.genericToEncoding (MSA.aesonOptions "jb")
+ src/MSAzureAPI/MachineLearning/Usages.hs view
@@ -0,0 +1,58 @@+module MSAzureAPI.MachineLearning.Usages where++import Control.Applicative (Alternative(..))+import Control.Monad.IO.Class (MonadIO(..))+import Data.Foldable (asum)+import Data.Functor (void)+-- import Data.Maybe (listToMaybe)+import GHC.Generics (Generic(..))++-- aeson+import qualified Data.Aeson as A (ToJSON(..), genericToEncoding, FromJSON(..), genericParseJSON, defaultOptions, Options(..), withObject, withText, (.:), (.:?), object, (.=), Key, Value, camelTo2)+-- bytestring+import qualified Data.ByteString as BS (ByteString)+import qualified Data.ByteString.Char8 as BS8 (pack, unpack)+import qualified Data.ByteString.Lazy as LBS (ByteString)+-- hoauth2+-- import Network.OAuth.OAuth2 (OAuth2Token(..))+import Network.OAuth.OAuth2.Internal (AccessToken(..))+-- req+import Network.HTTP.Req (Req, Url, Option, Scheme(..), header, (=:))+-- text+import Data.Text (Text, pack, unpack)+import qualified Data.Text.Lazy as TL (Text, pack, unpack, toStrict)++import qualified MSAzureAPI.Internal.Common as MSA (APIPlane(..), (==:), put, get, getBs, post, getLbs, Collection, Location, showLocation, aesonOptions)++-- | Gets the current usage information as well as limits for AML resources for given subscription and location.+--+-- docs : <https://learn.microsoft.com/en-us/rest/api/azureml/2023-04-01/usages/list?tabs=HTTP>+--+-- @GET https:\/\/management.azure.com\/subscriptions\/{subscriptionId}\/providers\/Microsoft.MachineLearningServices\/locations\/{location}\/usages?api-version=2023-04-01@+getUsages :: Text -- ^ subscription ID+ -> MSA.Location -- ^ location+ -> AccessToken -> Req (MSA.Collection Usage)+getUsages sid loc = MSA.get MSA.APManagement [+ "subscriptions", sid,+ "providers", "Microsoft.MachineLearningServices",+ "locations", MSA.showLocation loc,+ "usages"+ ] ("api-version" MSA.==: "2023-04-01")++data Usage = Usage {+ uCurrentValue :: Int+ , uLimit :: Int+ , uType :: Text+ , uName :: UsageName+ } deriving (Eq, Show, Ord, Generic)+instance A.FromJSON Usage where+ parseJSON = A.genericParseJSON (MSA.aesonOptions "u")++data UsageName = UsageName {+ unLocalizedValue :: Text+ , unValue :: Text+ } deriving (Eq, Show, Ord, Generic)+instance A.FromJSON UsageName where+ parseJSON = A.genericParseJSON (MSA.aesonOptions "un")++
src/MSAzureAPI/StorageServices.hs view
@@ -1,11 +1,7 @@+-- | Storage Services API: https://learn.microsoft.com/en-us/rest/api/storageservices/+--+--+-- Permissions that an Azure AD entity (user or service principal) needs to perform file service operations:+--+-- <https://learn.microsoft.com/en-us/rest/api/storageservices/authorize-with-azure-active-directory#permissions-for-calling-data-operations> module MSAzureAPI.StorageServices where--{- Permissions that an Azure AD entity (user or service principal) needs to perform file service operations:---https://learn.microsoft.com/en-us/rest/api/storageservices/authorize-with-azure-active-directory#permissions-for-calling-data-operations--}----
src/MSAzureAPI/StorageServices/FileService.hs view
@@ -8,25 +8,31 @@ getFile -- * Directories , listDirectoriesAndFiles+ -- , listDirectoriesAndFilesC+ , DirItems(..) , DirItem(..) ) where -import Control.Applicative (Alternative(..))+import Control.Applicative (Alternative(..), optional)+import Control.Monad (when) import Control.Monad.IO.Class (MonadIO(..)) import Data.Foldable (asum) import Data.Functor (void)-import Data.Maybe (listToMaybe)+import Data.Maybe (listToMaybe, isJust) import qualified Text.ParserCombinators.ReadP as RP (ReadP, readP_to_S, choice, many, between, char, string, satisfy) -- bytestring import qualified Data.ByteString as BS (ByteString) import qualified Data.ByteString.Char8 as BS8 (pack, unpack) import qualified Data.ByteString.Lazy as LBS (ByteString)+-- conduit+import qualified Data.Conduit as C (ConduitT, yield, runConduitRes)+import Data.Conduit ((.|)) -- hoauth2 -- import Network.OAuth.OAuth2 (OAuth2Token(..)) import Network.OAuth.OAuth2.Internal (AccessToken(..)) -- req-import Network.HTTP.Req (Req, Url, Option, Scheme(..), header, (=:))+import Network.HTTP.Req (HttpException, runReq, defaultHttpConfig, Req, Url, Option, Scheme(..), header, (=:)) -- text import Data.Text (Text, pack, unpack) import qualified Data.Text.Lazy as TL (Text, pack, unpack, toStrict)@@ -41,7 +47,7 @@ -- xmlbf import qualified Xmlbf as XB (Parser, runParser, pElement, pText) -import MSAzureAPI.Internal.Common (APIPlane(..), (==:), get, getBs, post, getLbs)+import MSAzureAPI.Internal.Common (APIPlane(..), (==:), get, getBs, post, getLbs, tryReq) @@ -113,39 +119,78 @@ domain = acct <> ".file.core.windows.net" pth = [fshare, fpath] --- | list directories and files https://learn.microsoft.com/en-us/rest/api/storageservices/list-directories-and-files#request +-- | list directories and files https://learn.microsoft.com/en-us/rest/api/storageservices/list-directories-and-files#request --+-- NB the the response list contains at most 5000 elements+-- -- @GET https:\/\/myaccount.file.core.windows.net\/myshare\/mydirectorypath?restype=directory&comp=list@+--+-- === Paginated results+--+-- NB : The Marker, ShareSnapshot, and MaxResults elements are present only if you specify them on the request URI.+--+-- If the @<NextMarker> element in the @XML body has a value, it means that the result list is not complete. In that case listDirectoriesAndFiles :: Text -- ^ storage account -> Text -- ^ file share -> Text -- ^ directory path, including directories+ -> Maybe Text -- ^ next page marker. Use 'Nothing' to retrieve first page of results -> AccessToken- -> Req (Either String [DirItem])-listDirectoriesAndFiles acct fshare fpath atok = do+ -> Req (Either String DirItems)+listDirectoriesAndFiles acct fshare fpath mm atok = do os <- msStorageReqHeaders- bs <- getBs (APData domain) pth (os <> "restype" ==: "directory" <> "comp" ==: "list") atok+ bs <- getBs (APData domain) pth (os <> "restype" ==: "directory" <> "comp" ==: "list" <> mMarker mm) atok pure $ parseXML listDirectoriesP bs where domain = acct <> ".file.core.windows.net" pth = [fshare, fpath]+ mMarker = \case+ Just m -> ("marker" ==: m)+ _ -> mempty +-- -- | Repeated call of 'listDirectoriesAndFiles' supporting multi-page results+-- listDirectoriesAndFilesC :: MonadIO m =>+-- Text -- ^ storage account+-- -> Text -- ^ file share+-- -> Text -- ^ directory path, including directories+-- -> AccessToken -> C.ConduitT i [DirItem] m ()+-- listDirectoriesAndFilesC acct fshare fpath atok = go Nothing+-- where+-- go mm = do+-- eres <- runReq defaultHttpConfig $ tryReq $ listDirectoriesAndFiles acct fshare fpath mm atok+-- case eres of+-- Left _ -> undefined -- FIXME http exception+-- Right xe -> case xe of+-- Left _ -> undefined -- FIXME xml parsing error+-- Right (DirItems xs nMarker) -> do+-- C.yield xs+-- when (isJust nMarker) (go nMarker)+ -- | Directory item, as returned by 'listDirectoriesAndFiles'-data DirItem = DIFile {diId :: Text, diName :: Text}- | DIDirectory {diId :: Text, diName :: Text}+data DirItem = DIFile {diId :: Text, diName :: Text} -- ^ file+ | DIDirectory {diId :: Text, diName :: Text} -- ^ directory deriving (Show) +-- | Items in the 'listDirectoriesAndFiles' response+data DirItems = DirItems {+ disItems :: [DirItem]+ , disResponseMarker :: Maybe Text -- ^ marker to request next page of results+ }+ -- | XML parser for the response body format shown here: https://learn.microsoft.com/en-us/rest/api/storageservices/list-directories-and-files#response-body-listDirectoriesP :: XB.Parser [DirItem]+listDirectoriesP :: XB.Parser DirItems listDirectoriesP = do tag "EnumerationResults" $ do enumResultsIgnore es <- entries- selfClosing "NextMarker"- pure es+ nm <- nextMarker+ pure (DirItems es nm) enumResultsIgnore :: XB.Parser ()-enumResultsIgnore = ignoreList ["Marker", "Prefix", "MaxResults", "DirectoryId"]+enumResultsIgnore = ignoreList ["Marker", "Prefix", "MaxResults", "DirectoryId"] +-- marker :: XB.Parser (Maybe Text)+-- marker = optional (TL.toStrict <$> tag "Marker" anystring)+ entries :: XB.Parser [DirItem] entries = tag "Entries" $ many (file <|> directory) @@ -183,8 +228,11 @@ ignoreList :: [Text] -> XB.Parser () ignoreList ns = void $ many (asum (map (`XB.pElement` XB.pText) ns)) -selfClosing :: Text -> XB.Parser ()-selfClosing t = tag t (pure ())+nextMarker :: XB.Parser (Maybe Text)+nextMarker = optional (TL.toStrict <$> tag "NextMarker" anystring)++-- selfClosing :: Text -> XB.Parser ()+-- selfClosing t = tag t (pure ()) anystring :: XB.Parser TL.Text