11#!/usr/bin/env python3
2- # This script is used to create a flow from a template, run it for a couple
3- # of seconds, stop it and then query the number of queued flow files.
42
53import nipyapi
64from nipyapi .canvas import (
119 recurse_flow ,
1210)
1311from nipyapi .security import service_login
14- from nipyapi .templates import get_template , upload_template , deploy_template
15- from nipyapi .nifi .models import FlowEntity
12+ from nipyapi .nifi .api_client import ApiClient
1613
17- from typing import Union , List
14+ from typing import Union
1815from dataclasses import dataclass
1916
20- import re
2117import os
22- import sys
2318import time
24- import argparse
2519import urllib3
2620
21+ ENDPOINT = f"https://test-nifi-node-default-0.test-nifi-node-default-headless.{ os .environ ['NAMESPACE' ]} .svc.cluster.local:8443"
2722USERNAME = "admin"
28- PASSWORD = "supersecretpassword"
29- TEMPLATE_NAME = "generate-and-log-flowfiles"
30- TEMPLATE_FILE = f"{ TEMPLATE_NAME } .xml"
31- JSON_NAME = "generate-and-log-flowfiles"
32- JSON_FILE = f"{ JSON_NAME } .json"
23+ PASSWORD = "supersecretpassword" # Can we use open("/nifi-users/admin").read() here?
24+ FLOWFILE = "/tmp/generate-and-log-flowfiles.json"
3325CONNECTION_NAME = "output-connection"
3426
3527
@@ -38,170 +30,83 @@ class Error:
3830 message : str
3931
4032
41- def parse_args (args : List [str ]) -> argparse .Namespace :
42- parser = argparse .ArgumentParser (description = "Setup a flow and query the status." )
43- parser .add_argument (
44- "-e" ,
45- "--endpoint" ,
46- help = "Nifi endpoint URL (must be https). As of 2022-08-29 we cant use https://nifi:8443 here because Nifi's check for the host header validity fails. The error message looks like: <h2>The request contained an invalid host header [<code>nifi:8443</code>] in the request [<code>/nifi-api</code>]. Check for request manipulation or third-party intercept.</h2>" ,
47- required = True ,
48- )
49- parser .add_argument (
50- "-u" ,
51- "--user" ,
52- help = "Nifi login user." ,
53- )
54- parser .add_argument (
55- "-p" ,
56- "--password" ,
57- help = "Nifi login password." ,
58- )
59- subparsers = parser .add_subparsers (dest = "subcommand" , required = True )
60- run_parser = subparsers .add_parser (
61- "run" ,
62- help = "Install and run a flow." ,
63- )
64- format_parser = run_parser .add_subparsers (dest = "formatcommand" )
65- template_parser = format_parser .add_parser (
66- "template" , help = "Use the template format for the flow."
67- )
68- template_parser .add_argument (
69- "template" ,
70- help = "Nifi template file." ,
71- )
72- json_parser = format_parser .add_parser (
73- "json" , help = "Use the json format for the flow."
74- )
75- json_parser .add_argument (
76- "json" ,
77- help = "Nifi json file." ,
78- )
79- subparsers .add_parser (
80- "query" ,
81- help = "Query the flow." ,
82- )
83- return parser .parse_args (args )
84-
85-
86- def login (endpoint : str , user : str , passwd : str ) -> bool :
87- nipyapi .config .nifi_config .host = f"{ endpoint } /nifi-api"
88- nipyapi .config .nifi_config .verify_ssl = False
89- return service_login (username = user , password = passwd )
90-
91-
92- def flow_from_template (
93- pg_id : str , template_file : str , template_name : str
94- ) -> FlowEntity :
95- upload_template (pg_id , template_file )
96- template_id = get_template (template_name ).id
97- return deploy_template (pg_id , template_id , 200 , 0 )
33+ urllib3 .disable_warnings (urllib3 .exceptions .InsecureRequestWarning )
9834
9935
10036def schedule (pg_id : str , toggle : bool ) -> bool :
10137 for controller in list_all_controllers (pg_id ):
10238 schedule_controller (controller , scheduled = toggle )
39+
10340 return schedule_process_group (pg_id , scheduled = toggle )
10441
10542
10643def flow_files_queued (connection_name : str ) -> Union [str , Error ]:
10744 """Returns the current input record number for the given component"""
10845 flow = recurse_flow ()
109- c = [
110- c
111- for c in flow .process_group_flow .flow .connections
112- if c .status .name == connection_name
113- ]
114- if c :
115- return c [0 ].status .aggregate_snapshot .flow_files_queued
116- else :
117- # for nifi 2.x the flow is loaded via api into a new process group
118- # we need to look for the connection in that process group instead
119- if flow .process_group_flow .flow .process_groups :
120- inner_flow = recurse_flow (flow .process_group_flow .flow .process_groups [0 ].id )
121- inner_c = [
122- inner_c
123- for inner_c in inner_flow .process_group_flow .flow .connections
124- if inner_c .status .name == connection_name
125- ]
126- if inner_c :
127- return inner_c [0 ].status .aggregate_snapshot .flow_files_queued
128- else :
129- return Error (f"No connection named '{ connection_name } ' found." )
46+
47+ if flow .process_group_flow .flow .process_groups :
48+ inner_flow = recurse_flow (flow .process_group_flow .flow .process_groups [0 ].id )
49+ conn = [
50+ conn
51+ for conn in inner_flow .process_group_flow .flow .connections
52+ if conn .status .name == connection_name
53+ ]
54+ if conn :
55+ return conn [0 ].status .aggregate_snapshot .flow_files_queued
13056 else :
13157 return Error (f"No connection named '{ connection_name } ' found." )
58+ else :
59+ return Error (f"No connection named '{ connection_name } ' found." )
13260
13361
13462def main ():
135- # turn this on to debug Nifi api calls. Also need to import logging
136- # logging.getLogger().setLevel(logging.INFO)
137-
138- args = parse_args (sys .argv [1 :])
139-
140- urllib3 .disable_warnings (urllib3 .exceptions .InsecureRequestWarning )
141-
142- username = args .user or USERNAME
143- password = args .password or PASSWORD
144-
145- if args .subcommand == "run" :
146- login (args .endpoint , username , password )
147- pg_id = get_root_pg_id ()
148-
149- if args .formatcommand == "template" :
150- template_file = args .template or TEMPLATE_FILE
151- template_name = re .sub (r"\..+$" , "" , os .path .basename (template_file ))
152-
153- flow_from_template (pg_id , template_file , template_name )
154-
155- elif args .formatcommand == "json" :
156- json_file = args .json or JSON_FILE
157- json_name = re .sub (r"\..+$" , "" , os .path .basename (json_file ))
158-
159- if not nipyapi .config .nifi_config .api_client :
160- nipyapi .config .nifi_config .api_client = nipyapi .nifi .ApiClient ()
161-
162- header_params = {}
163- header_params ["Accept" ] = (
164- nipyapi .config .nifi_config .api_client .select_header_accept (
165- ["application/json" ]
166- )
167- )
168- header_params ["Content-Type" ] = (
169- nipyapi .config .nifi_config .api_client .select_header_content_type (
170- ["multipart/form-data" ]
171- )
172- )
173-
174- nipyapi .config .nifi_config .api_client .call_api (
175- "/process-groups/{pg_id}/process-groups/upload" ,
176- "POST" ,
177- path_params = {"pg_id" : pg_id },
178- header_params = header_params ,
179- _return_http_data_only = True ,
180- post_params = [
181- ("id" , pg_id ),
182- ("groupName" , json_name ),
183- ("positionX" , 100 ),
184- ("positionY" , 10 ),
185- ("clientId" , nipyapi .nifi .FlowApi ().generate_client_id ()),
186- ],
187- files = {"file" : json_file },
188- auth_settings = ["tokenAuth" ],
189- )
190-
191- # get the process group id of the newly created process group to pass it to the schedule() function
192- # for nifi 2.x we need to schedule the inner process group and instead of the root process group
193- flow = recurse_flow ()
194- inner_flow_id = flow .process_group_flow .flow .process_groups [0 ].id
195- pg_id = inner_flow_id
196-
197- schedule (pg_id , True ) # start
198- time .sleep (5 ) # give the flow 5 seconds to run
199- schedule (pg_id , False ) # stop
200- print (flow_files_queued (CONNECTION_NAME ))
201-
202- elif args .subcommand == "query" :
203- login (args .endpoint , username , password )
204- print (flow_files_queued (CONNECTION_NAME ))
63+ nipyapi .config .nifi_config .host = f"{ ENDPOINT } /nifi-api"
64+ nipyapi .config .nifi_config .verify_ssl = False
65+
66+ print (f"Logging in as { USERNAME } " )
67+ service_login (username = USERNAME , password = PASSWORD )
68+ print ("Logged in" )
69+
70+ pg_id = get_root_pg_id ()
71+ print (f"Got root process group id: { pg_id } " )
72+
73+ if not nipyapi .config .nifi_config .api_client :
74+ nipyapi .config .nifi_config .api_client = ApiClient ()
75+
76+ header_params = {}
77+ header_params ["Accept" ] = (
78+ nipyapi .config .nifi_config .api_client .select_header_accept (["application/json" ])
79+ )
80+ header_params ["Content-Type" ] = (
81+ nipyapi .config .nifi_config .api_client .select_header_content_type (
82+ ["multipart/form-data" ]
83+ )
84+ )
85+
86+ print ("Uploading process group" )
87+ nipyapi .config .nifi_config .api_client .call_api (
88+ "/process-groups/{pg_id}/process-groups/upload" ,
89+ "POST" ,
90+ path_params = {"pg_id" : pg_id },
91+ header_params = header_params ,
92+ _return_http_data_only = True ,
93+ post_params = [
94+ ("id" , pg_id ),
95+ ("groupName" , "Upgrade Test" ),
96+ ("positionX" , 100 ),
97+ ("positionY" , 10 ),
98+ ("clientId" , nipyapi .nifi .FlowApi ().generate_client_id ()),
99+ ],
100+ files = {"file" : FLOWFILE },
101+ auth_settings = ["tokenAuth" ],
102+ )
103+ print ("Process group uploaded" )
104+
105+ schedule (pg_id , True ) # Start the flow
106+ time .sleep (5 ) # Let the flow run for 5 seconds
107+ schedule (pg_id , False ) # Stop the flow
108+
109+ print (flow_files_queued (CONNECTION_NAME ))
205110
206111
207112if __name__ == "__main__" :
0 commit comments