@@ -66,6 +66,7 @@ class CmdAuth extends CmdBase implements UsageAware {
66
66
commands. add(new LoginCmd ())
67
67
commands. add(new LogoutCmd ())
68
68
commands. add(new ConfigCmd ())
69
+ commands. add(new StatusCmd ())
69
70
}
70
71
71
72
void usage () {
@@ -1019,4 +1020,172 @@ class CmdAuth extends CmdBase implements UsageAware {
1019
1020
result << ' '
1020
1021
}
1021
1022
}
1023
+
1024
+ class StatusCmd implements SubCmd {
1025
+
1026
+ @Override
1027
+ String getName () { ' status' }
1028
+
1029
+ @Override
1030
+ void apply (List<String > args ) {
1031
+ if (args. size() > 0 ) {
1032
+ throw new AbortOperationException (" Too many arguments for status command" )
1033
+ }
1034
+
1035
+ def config = readConfig()
1036
+
1037
+ println " Nextflow Seqera Platform authentication status"
1038
+ println " "
1039
+
1040
+ // API endpoint
1041
+ def endpointInfo = getConfigValue(config, ' tower.endpoint' , ' TOWER_API_ENDPOINT' , ' https://api.cloud.seqera.io' )
1042
+ println " API endpoint: ${ endpointInfo.value} (${ endpointInfo.source} )"
1043
+
1044
+ // Access token status
1045
+ def tokenInfo = getConfigValue(config, ' tower.accessToken' , ' TOWER_ACCESS_TOKEN' )
1046
+ if (tokenInfo. value) {
1047
+ println " Access token: yes (${ tokenInfo.source} )"
1048
+ } else {
1049
+ println " Access token: no"
1050
+ }
1051
+
1052
+ // Monitoring enabled
1053
+ def enabledInfo = getConfigValue(config, ' tower.enabled' , null , ' false' )
1054
+ def enabledValue = enabledInfo. value?. toString()?. toLowerCase() in [' true' , ' 1' , ' yes' ] ? ' Yes' : ' No'
1055
+ println " Local workflow monitoring enabled: ${ enabledValue} (${ enabledInfo.source ?: 'default'} )"
1056
+
1057
+ // Default workspace
1058
+ def workspaceInfo = getConfigValue(config, ' tower.workspaceId' , ' TOWER_WORKFLOW_ID' )
1059
+ if (workspaceInfo. value) {
1060
+ // Try to get workspace name from API if we have a token
1061
+ def workspaceName = null
1062
+ if (tokenInfo. value) {
1063
+ workspaceName = getWorkspaceNameFromApi(tokenInfo. value as String , endpointInfo. value as String , workspaceInfo. value as String )
1064
+ }
1065
+
1066
+ if (workspaceName) {
1067
+ println " Default workspace: ${ workspaceName} [${ workspaceInfo.value} ] (${ workspaceInfo.source} )"
1068
+ } else {
1069
+ println " Default workspace: ${ workspaceInfo.value} (${ workspaceInfo.source} )"
1070
+ }
1071
+ } else {
1072
+ println " Default workspace: Personal workspace (default)"
1073
+ }
1074
+
1075
+ println " "
1076
+ println " System health status"
1077
+
1078
+ // API connection check
1079
+ def apiConnectionOk = checkApiConnection(endpointInfo. value as String )
1080
+ println " API connection: ${ apiConnectionOk ? 'OK' : 'ERROR'} "
1081
+
1082
+ // Authentication check
1083
+ if (tokenInfo. value) {
1084
+ try {
1085
+ def userInfo = callUserInfoApi(tokenInfo. value as String , endpointInfo. value as String )
1086
+ def currentUser = userInfo. userName
1087
+ println " Authentication: OK (${ currentUser} )"
1088
+ } catch (Exception e) {
1089
+ println " Authentication: ERROR"
1090
+ }
1091
+ } else {
1092
+ println " Authentication: ERROR (no token)"
1093
+ }
1094
+ }
1095
+
1096
+ private String shortenPath (String path ) {
1097
+ def userHome = System . getProperty(' user.home' )
1098
+ if (path. startsWith(userHome)) {
1099
+ return ' ~' + path. substring(userHome. length())
1100
+ }
1101
+ return path
1102
+ }
1103
+
1104
+ private Map getConfigValue (Map config , String configKey , String envVarName , String defaultValue = null ) {
1105
+ def configValue = config[configKey]
1106
+ def envValue = System . getenv(envVarName)
1107
+ def effectiveValue = configValue ?: envValue ?: defaultValue
1108
+
1109
+ def source = null
1110
+ if (configValue) {
1111
+ source = shortenPath(getConfigFile(). toString())
1112
+ } else if (envValue) {
1113
+ source = " env var \$ ${ envVarName} "
1114
+ } else if (defaultValue) {
1115
+ source = " default"
1116
+ }
1117
+
1118
+ return [
1119
+ value : effectiveValue,
1120
+ source : source,
1121
+ fromConfig : configValue != null ,
1122
+ fromEnv : envValue != null ,
1123
+ isDefault : ! configValue && ! envValue
1124
+ ]
1125
+ }
1126
+
1127
+ private String getWorkspaceNameFromApi (String accessToken , String endpoint , String workspaceId ) {
1128
+ try {
1129
+ // Get user info to get user ID
1130
+ def userInfo = callUserInfoApi(accessToken, endpoint)
1131
+ def userId = userInfo. id as String
1132
+
1133
+ // Get workspaces for the user
1134
+ def workspacesUrl = " ${ endpoint} /user/${ userId} /workspaces"
1135
+ def connection = new URL (workspacesUrl). openConnection() as HttpURLConnection
1136
+ connection. requestMethod = ' GET'
1137
+ connection. connectTimeout = 10000 // 10 second timeout
1138
+ connection. readTimeout = 10000
1139
+ connection. setRequestProperty(' Authorization' , " Bearer ${ accessToken} " )
1140
+
1141
+ if (connection. responseCode != 200 ) {
1142
+ return null
1143
+ }
1144
+
1145
+ def response = connection. inputStream. text
1146
+ def json = new groovy.json.JsonSlurper (). parseText(response) as Map
1147
+ def orgsAndWorkspaces = json. orgsAndWorkspaces as List
1148
+
1149
+ // Find the workspace with matching ID
1150
+ def workspace = orgsAndWorkspaces. find { ((Map )it). workspaceId?. toString() == workspaceId }
1151
+ if (workspace) {
1152
+ def ws = workspace as Map
1153
+ return " ${ ws.orgName} / ${ ws.workspaceFullName} "
1154
+ }
1155
+
1156
+ return null
1157
+ } catch (Exception e) {
1158
+ return null
1159
+ }
1160
+ }
1161
+
1162
+ private boolean checkApiConnection (String endpoint ) {
1163
+ try {
1164
+ def serviceInfoUrl = " ${ endpoint} /service-info"
1165
+ def connection = new URL (serviceInfoUrl). openConnection() as HttpURLConnection
1166
+ connection. requestMethod = ' GET'
1167
+ connection. connectTimeout = 10000 // 10 second timeout
1168
+ connection. readTimeout = 10000
1169
+
1170
+ return connection. responseCode == 200
1171
+ } catch (Exception e) {
1172
+ return false
1173
+ }
1174
+ }
1175
+
1176
+
1177
+ @Override
1178
+ void usage (List<String > result ) {
1179
+ result << ' Show authentication status and configuration'
1180
+ result << " Usage: nextflow auth $name " . toString()
1181
+ result << ' '
1182
+ result << ' This command shows:'
1183
+ result << ' - Authentication status (yes/no) and source'
1184
+ result << ' - API endpoint and source'
1185
+ result << ' - Monitoring enabled status and source'
1186
+ result << ' - Default workspace and source'
1187
+ result << ' - System health status (API connection and authentication)'
1188
+ result << ' '
1189
+ }
1190
+ }
1022
1191
}
0 commit comments