Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🌱 Add Pathfinder assessment migration to CLI #507

Merged
merged 35 commits into from
Oct 30, 2023
Merged
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c510317
Add Pathfinder assessment migration to CLI
aufi Oct 6, 2023
ffa9dba
Single POST transformed assessment
aufi Oct 10, 2023
a06f7d0
Update migration assessment on-flight
aufi Oct 27, 2023
b35baa7
:bug: Fix latest analayis report. (#504)
jortel Oct 5, 2023
003362a
:ghost: Support seed build args. (#503)
jortel Oct 5, 2023
720212e
:bug: Only marshal assessment sections if not empty (#506)
mansam Oct 5, 2023
c61ea49
:bug: PrepareForArchetype should use criteria and tags (#508)
mansam Oct 6, 2023
697b502
:bug: Increment assessment counter when a new one is created (#511)
mansam Oct 10, 2023
855f10d
:bug: Protect builtin questionnaires from update/delete (#512)
mansam Oct 10, 2023
20a0875
:bug: Fix HTML analysis report. (#513)
jortel Oct 11, 2023
bf0d473
:bug: Fix business service filter of issues. (#515)
jortel Oct 11, 2023
e6678eb
:sparkles: Add `comment` string field to Section (#516)
mansam Oct 11, 2023
e8a2a4f
:bug: Static report app id needs to be a string. (#518)
jortel Oct 11, 2023
23a290c
:seedling: Fix Identity API test Maven sample (#514)
aufi Oct 12, 2023
57dbd78
:seedling: add ticket API test (#477)
khareyash05 Oct 12, 2023
de45958
:bug: Deduplicate tags on imported apps (#517)
mansam Oct 12, 2023
1b52612
:bug: Bump x/net to 0.17.0 (#519)
dymurray Oct 16, 2023
2f2a07b
:sparkles: Better pod OOM reporting. (#521)
jortel Oct 16, 2023
71b7379
:ghost: Update 0.1.2 for License. (#522)
jortel Oct 17, 2023
d4b1822
:book: Update OpenAPI spec w/ Assessment changes (#520)
mansam Oct 17, 2023
ecb7206
:bug: Bucket getdir (#525)
jortel Oct 17, 2023
ceaccd8
:seedling: Delete identity associated with tracker (#529)
mguetta1 Oct 19, 2023
d827869
:sparkles: Add `confidence` and `risk` to Application and Archetype r…
mansam Oct 19, 2023
8837c08
:sparkles: Surface latest analysis effort on Application resource (#537)
mansam Oct 24, 2023
b207a7d
:bug: Explicitly set yaml names for camelCased fields (#535)
mansam Oct 24, 2023
5f5b669
:ghost: add hack to generate jwt token. (#534)
jortel Oct 24, 2023
31807ab
:sparkles: Add Target.provider. (#541)
jortel Oct 25, 2023
efed198
:bug: Add missing Targets to ui.target.order after seeding (#536)
mansam Oct 26, 2023
565e23e
:ghost: Add As/With to v11 Setting (#546)
mansam Oct 27, 2023
b3d8435
:bug: Add `yaml:"inline"` to Resource field tags (#543)
mansam Oct 27, 2023
a8edc31
:bug: Preload assessment stakeholder relationships (#544)
mansam Oct 27, 2023
875009e
:book: Improve API documentation (#545)
mansam Oct 27, 2023
410af4d
:bug: Fix typo in AssessmentList preload (#547)
mansam Oct 27, 2023
b65f7a5
:ghost: Preload Archetype assessment stakeholder relations (#548)
mansam Oct 27, 2023
d71406d
Merge branch 'konveyor:main' into cli-migrate-assessments
aufi Oct 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 100 additions & 17 deletions hack/tool/tackle
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ parser.add_argument('-n','--no-auth', dest='noAuth', action='store_const', const
help='Skip Keycloak token creation, use empty Auth token in Tackle API calls.')
parser.add_argument('-b','--skip-buckets', dest='skipBuckets', action='store_const', const=True, default=False,
help='Skip Tackle 2 Buckets content export.')
parser.add_argument('-t','--token', type=str, help='Bearer auth token for Hub API (login/password is a fallback to create it).',
nargs='?', default='')
parser.add_argument('-p','--pathfinder-url', type=str, help='In-cluster Pathfinder endpoint URL.',
nargs='?', default='')
args = parser.parse_args()

###############################################################################
Expand Down Expand Up @@ -82,20 +86,24 @@ def debugPrint(str):
if args.verbose:
print(str)

def getHubToken(host, username, password):
print("Getting auth token via Hub from %s" % host)
url = "%s/hub/auth/login" % host
data = '{"user": "%s", "password": "%s"}' % (username, password)

r = requests.post(url, data=data, verify=False)
if r.ok:
respData = json.loads(r.text)
debugPrint("Got access token: %s" % respData['token'])
return respData['token']
def getHubToken(host, username, password, token):
if token:
print("Skipping login, using provided auth token.")
return token
else:
print("ERROR getting auth token from %s" % url)
print(data, r)
exit(1)
print("Getting auth token via Hub from %s" % host)
url = "%s/hub/auth/login" % host
data = '{"user": "%s", "password": "%s"}' % (username, password)

r = requests.post(url, data=data, verify=False)
if r.ok:
respData = json.loads(r.text)
debugPrint("Got access token: %s" % respData['token'])
return respData['token']
else:
print("ERROR getting auth token from %s" % url)
print(data, r)
exit(1)

def getKeycloakToken(host, username, password, client_id='tackle-ui', realm='tackle'):
if args.noAuth:
Expand Down Expand Up @@ -126,6 +134,9 @@ def apiJSON(url, token, data=None, method='GET', ignoreErrors=False):
elif method == 'PATCH':
debugPrint("PATCH data: %s" % json.dumps(data))
r = requests.patch(url, data=json.dumps(data), headers={"Authorization": "Bearer %s" % token, "Content-Type": "application/json"}, verify=False)
elif method == 'PUT':
debugPrint("PUT data: %s" % json.dumps(data))
r = requests.put(url, data=json.dumps(data), headers={"Authorization": "Bearer %s" % token, "Content-Type": "application/json"}, verify=False)
else: # GET
r = requests.get(url, headers={"Authorization": "Bearer %s" % token, "Content-Type": "application/json"}, verify=False)

Expand Down Expand Up @@ -722,6 +733,56 @@ class TackleTool:
# Push the updated assessment
apiJSON(self.tackle2Url + tackle2path("assessments/%d" % assmnt2['id']), self.tackle2Token, data=assmnt2, method='PATCH', ignoreErrors=ignoreErrors)

# Migrate Pathfinder Assessment to Konveyor (expecting Pathfinder hard-coded questionnaire ID=1)
def migrateAssessments(self, pathfinderUrl, ignoreErrors=False):
cnt = 0
apps = apiJSON(self.tackle2Url + "/hub/applications", self.tackle2Token)
print("There are %d Applications, looking for their Assessments.." % len(apps))
for app in apps:
# Export Pathfinder data for each Application
for passmnt in apiJSON(pathfinderUrl + "/assessments?applicationId=%d" % app['id'], self.tackle2Token):
print("# Assessment for Application %s" % passmnt["applicationId"])
appAssessmentsPath = "/hub/applications/%d/assessments" % passmnt["applicationId"]
# Skip if Assessment for given Application already exists
if len(apiJSON(self.tackle2Url + appAssessmentsPath, self.tackle2Token, data={"questionnaire": {"id": 1}})) > 0:
print(" Assessment already exists, skipping.")
continue

# Prepare new Assessment
assmnt = dict()
assmnt['questionnaire'] = {"id": 1} # Default new Questionnaire "Pathfinder Legacy"
assmnt['application'] = {"id": passmnt["applicationId"]}
assmnt['stakeholders'] = []
for sh in passmnt['stakeholders']:
assmnt['stakeholders'].append({"id": sh})
assmnt['stakeholderGroups'] = []
for shg in passmnt['stakeholderGroups']:
assmnt['stakeholderGroups'].append({"id": shg})

# Transformate Questions, Answers and related structures
for category in passmnt['questionnaire']['categories']:
del category['id']
category['name'] = category.pop('title')
for question in category["questions"]:
del question['id']
question["text"] = question.pop('question')
question["explanation"] = question.pop('description')
question["answers"] = question.pop('options')
for answer in question['answers']:
del answer['id']
answer['text'] = answer.pop('option')
answer['selected'] = answer.pop('checked')
answer['risk'] = answer['risk'].lower()
if answer['risk'] == "amber":
answer['risk'] = "yellow"
assmnt['sections'] = passmnt['questionnaire']['categories']

# Post the Assessment
apiJSON(self.tackle2Url + appAssessmentsPath, self.tackle2Token, data=assmnt, method='POST')
cnt += 1
print("Assessment submitted.")
return cnt

def preImportCheck(self):
# Compatibility checks
# TagCategories on Hub API
Expand Down Expand Up @@ -885,7 +946,7 @@ if cmdWanted(args, "export-tackle1"):
if cmdWanted(args, "export"):
cmdExecuted = True
# Gather Keycloak access tokens for Tackle2
token2 = getHubToken(c['url'], c['username'], c['password'])
token2 = getHubToken(c['url'], c['username'], c['password'], args.token)

# Setup data migration object
tool = TackleTool(args.data_dir, '', '', c['url'], token2, c['encryption_passphase'])
Expand All @@ -908,7 +969,7 @@ if cmdWanted(args, "export"):
if cmdWanted(args, "import"):
cmdExecuted = True
# Gather Keycloak access token for Tackle 2
token2 = getHubToken(c['url'], c['username'], c['password'])
token2 = getHubToken(c['url'], c['username'], c['password'], args.token)

# Setup Tackle 1.2->2.0 data migration object
tool = TackleTool(args.data_dir, '', '', c['url'], token2, c['encryption_passphase'])
Expand All @@ -930,7 +991,7 @@ if cmdWanted(args, "import"):
if cmdWanted(args, "clean"):
cmdExecuted = True
# Gather Keycloak access token for Tackle 2
token2 = getHubToken(c['url'], c['username'], c['password'])
token2 = getHubToken(c['url'], c['username'], c['password'], args.token)

# Setup Tackle 1.2->2.0 data migration object
tool = TackleTool(args.data_dir, '', '', c['url'], token2)
Expand All @@ -944,7 +1005,7 @@ if cmdWanted(args, "clean"):
if cmdWanted(args, "clean-all"):
cmdExecuted = True
# Gather Keycloak access token for Tackle 2
token2 = getHubToken(c['url'], c['username'], c['password'])
token2 = getHubToken(c['url'], c['username'], c['password'], args.token)

# Setup Tackle 1.2->2.0 data migration object
tool = TackleTool(args.data_dir, '', '', c['url'], token2)
Expand All @@ -953,6 +1014,28 @@ if cmdWanted(args, "clean-all"):
print("Cleaning ALL data in Tackle2")
tool.cleanAllTackle2()

# Migrate Pathfinder Assessments to Konveyor Assessments
if cmdWanted(args, "migrate-assessments"):
cmdExecuted = True

# Check Pathfinder URL arg
if not args.pathfinder_url:
print("Error: Pathfinder URL is required, specify it with -p or --pathfinder-url option.")
exit(1)

# Gather Keycloak access token for Tackle 2
token2 = getHubToken(c['url'], c['username'], c['password'], args.token)

# Setup Tackle data migration object
tool = TackleTool(args.data_dir, '', '', c['url'], token2)

# Run the import
print("Starting Pathfinder Assessments to Konveyor Assessment migration.")
appCnt = tool.migrateAssessments(args.pathfinder_url)

print("Done. %d new Assessment(s) for Application(s) were migrated!" % appCnt)


# Print help if action was not specified
if not cmdExecuted:
print("Unknown action, use tackle --help to see usage.")
Expand Down
Loading