mirror of
https://github.com/google/nomulus
synced 2026-08-15 11:46:08 +00:00
Compare commits
26
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abc1a0ef3d | ||
|
|
7b47ecb1f1 | ||
|
|
469d62703a | ||
|
|
009fda67b7 | ||
|
|
e492936cec | ||
|
|
d1d59c1afd | ||
|
|
7b786eaf1f | ||
|
|
45c5d12743 | ||
|
|
73ab95bd9d | ||
|
|
f85cf57e36 | ||
|
|
5e36cf30c3 | ||
|
|
829be0777b | ||
|
|
c0ac9bdba4 | ||
|
|
58ec0f826d | ||
|
|
f9e0908022 | ||
|
|
b21e1a1935 | ||
|
|
0112b3ae06 | ||
|
|
a4903c27b9 | ||
|
|
2166c28d6d | ||
|
|
891e7c0174 | ||
|
|
64f5971275 | ||
|
|
818944317f | ||
|
|
ea96ed300f | ||
|
|
8415c8bbe4 | ||
|
|
dc48c257b5 | ||
|
|
2bf3867532 |
@@ -33,7 +33,7 @@ jobs:
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '11'
|
||||
java-version: '17'
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
||||
+38
-15
@@ -211,6 +211,30 @@ allprojects {
|
||||
options.fork = true
|
||||
options.forkOptions.executable =
|
||||
file("${System.env.JAVA_HOME}/bin/javac")
|
||||
options.compilerArgs = ["--add-exports",
|
||||
"jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
|
||||
"--add-exports",
|
||||
"jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED",
|
||||
"--add-exports",
|
||||
"jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
|
||||
"--add-exports",
|
||||
"jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
|
||||
"--add-exports",
|
||||
"jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
|
||||
"--add-exports",
|
||||
"jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED",
|
||||
"--add-exports",
|
||||
"jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED",
|
||||
"--add-exports",
|
||||
"jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED"]
|
||||
options.forkOptions.jvmArgs = ["-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
|
||||
"-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
|
||||
"-J--add-exports=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED",
|
||||
"-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
|
||||
"-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
|
||||
"-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED",
|
||||
"-J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED",
|
||||
"-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -358,16 +382,11 @@ subprojects {
|
||||
|
||||
apply from: "${rootDir.path}/java_common.gradle"
|
||||
|
||||
if (!rootProject.enableCrossReferencing.toBoolean()) {
|
||||
compileJava {
|
||||
// TODO: Remove this once we migrate off of AppEngine.
|
||||
options.release = 8
|
||||
}
|
||||
compileTestJava {
|
||||
// TODO: Remove this once we migrate off of AppEngine.
|
||||
options.release = 8
|
||||
}
|
||||
}
|
||||
// When changing Java version here, be sure to update BEAM Java runtime:
|
||||
// in core/build.gradle, search for `flex-template-base-image` and update
|
||||
// the parameter value.
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
|
||||
project.tasks.test.dependsOn runPresubmits
|
||||
|
||||
@@ -479,10 +498,14 @@ def createGetBuildSrcDirectDepsTask(outputFileName) {
|
||||
|
||||
rootProject.ext {
|
||||
invokeJavaDiffFormatScript = { action ->
|
||||
println("JAVA_HOME=${System.env.JAVA_HOME}")
|
||||
println("PATH=${System.env.PATH}")
|
||||
println(ext.execInBash("type java", "${rootDir}"))
|
||||
println(ext.execInBash("java -version", "${rootDir}"))
|
||||
def javaHome = project.findProperty('org.gradle.java.home')
|
||||
def javaBin
|
||||
if (javaHome != null) {
|
||||
javaBin = "$javaHome/bin/java"
|
||||
} else {
|
||||
javaBin = ext.execInBash("which java", rootDir)
|
||||
}
|
||||
println("Running the formatting tool with $javaBin")
|
||||
def scriptDir = rootDir.path.endsWith('buildSrc')
|
||||
? "${rootDir}/../java-format"
|
||||
: "${rootDir}/java-format"
|
||||
@@ -493,7 +516,7 @@ rootProject.ext {
|
||||
def pythonExe = getPythonExecutable()
|
||||
|
||||
return ext.execInBash(
|
||||
"PYTHON=${pythonExe} ${formatDiffScript} ${action}", "${workingDir}")
|
||||
"JAVA=${javaBin} PYTHON=${pythonExe} ${formatDiffScript} ${action}", "${workingDir}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ PRESUBMITS = {
|
||||
PresubmitCheck(
|
||||
r".*Copyright 20\d{2} The Nomulus Authors\. All Rights Reserved\.",
|
||||
("java", "js", "soy", "sql", "py", "sh", "gradle", "ts"), {
|
||||
".git", "/build/", "/generated/", "/generated_tests/",
|
||||
".git", "/build/", "/bin/generated-sources/", "/bin/generated-test-sources/",
|
||||
"node_modules/", "LoggerConfig.java", "registrar_bin.",
|
||||
"registrar_dbg.", "google-java-format-diff.py",
|
||||
"nomulus.golden.sql", "soyutils_usegoog.js", "javascript/checks.js"
|
||||
|
||||
Generated
+2310
-15168
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { AfterViewInit, Component, ViewChild } from '@angular/core';
|
||||
import { AfterViewInit, Component, ViewChild, effect } from '@angular/core';
|
||||
import { RegistrarService } from './registrar/registrar.service';
|
||||
import { UserDataService } from './shared/services/userData.service';
|
||||
import { GlobalLoaderService } from './shared/services/globalLoader.service';
|
||||
@@ -36,11 +36,13 @@ export class AppComponent implements AfterViewInit {
|
||||
protected globalLoader: GlobalLoaderService,
|
||||
protected router: Router
|
||||
) {
|
||||
registrarService.activeRegistrarIdChange.subscribe(() => {
|
||||
this.renderRouter = false;
|
||||
setTimeout(() => {
|
||||
this.renderRouter = true;
|
||||
}, 400);
|
||||
effect(() => {
|
||||
if (registrarService.registrarId()) {
|
||||
this.renderRouter = false;
|
||||
setTimeout(() => {
|
||||
this.renderRouter = true;
|
||||
}, 400);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ export class DomainListService {
|
||||
) {
|
||||
return this.backendService
|
||||
.getDomains(
|
||||
this.registrarService.activeRegistrarId,
|
||||
this.registrarService.registrarId(),
|
||||
this.checkpointTime,
|
||||
pageNumber,
|
||||
resultsPerPage,
|
||||
|
||||
@@ -23,8 +23,10 @@ export class BillingWidgetComponent {
|
||||
constructor(public registrarService: RegistrarService) {}
|
||||
|
||||
public get driveFolderUrl(): string {
|
||||
if (this.registrarService?.registrar.driveFolderId) {
|
||||
return `https://drive.google.com/drive/folders/${this.registrarService?.registrar.driveFolderId}`;
|
||||
if (this.registrarService.registrar()?.driveFolderId) {
|
||||
return `https://drive.google.com/drive/folders/${
|
||||
this.registrarService.registrar()?.driveFolderId
|
||||
}`;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -12,9 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, effect } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import { RegistrarService } from './registrar.service';
|
||||
|
||||
@@ -24,22 +23,15 @@ import { RegistrarService } from './registrar.service';
|
||||
styleUrls: ['./emptyRegistrar.component.scss'],
|
||||
})
|
||||
export class EmptyRegistrar {
|
||||
private registrarIdChangeSubscription?: Subscription;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
protected registrarService: RegistrarService,
|
||||
private router: Router
|
||||
) {
|
||||
this.registrarIdChangeSubscription =
|
||||
registrarService.activeRegistrarIdChange.subscribe((newRegistrarId) => {
|
||||
if (newRegistrarId) {
|
||||
this.router.navigate([this.route.snapshot.paramMap.get('nextUrl')]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.registrarIdChangeSubscription?.unsubscribe();
|
||||
effect(() => {
|
||||
if (registrarService.registrarId()) {
|
||||
this.router.navigate([this.route.snapshot.paramMap.get('nextUrl')]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ export class RegistrarGuard {
|
||||
_: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot
|
||||
): Promise<boolean> | boolean {
|
||||
if (this.registrarService.activeRegistrarId) {
|
||||
if (this.registrarService.registrarId()) {
|
||||
return true;
|
||||
}
|
||||
return this.router.navigate([
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, Subject, tap } from 'rxjs';
|
||||
import { Injectable, computed, signal } from '@angular/core';
|
||||
import { Observable, tap } from 'rxjs';
|
||||
|
||||
import { BackendService } from '../shared/services/backend.service';
|
||||
import {
|
||||
@@ -52,9 +52,11 @@ export interface Registrar {
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class RegistrarService implements GlobalLoader {
|
||||
activeRegistrarId: string = '';
|
||||
registrars: Registrar[] = [];
|
||||
activeRegistrarIdChange: Subject<string> = new Subject<string>();
|
||||
registrarId = signal<string>('');
|
||||
registrars = signal<Registrar[]>([]);
|
||||
registrar = computed<Registrar | undefined>(() =>
|
||||
this.registrars().find((r) => r.registrarId === this.registrarId())
|
||||
);
|
||||
|
||||
constructor(
|
||||
private backend: BackendService,
|
||||
@@ -67,22 +69,15 @@ export class RegistrarService implements GlobalLoader {
|
||||
this.globalLoader.startGlobalLoader(this);
|
||||
}
|
||||
|
||||
public get registrar(): Registrar {
|
||||
return this.registrars.filter(
|
||||
(r) => r.registrarId === this.activeRegistrarId
|
||||
)[0];
|
||||
}
|
||||
|
||||
public updateSelectedRegistrar(registrarId: string) {
|
||||
this.activeRegistrarId = registrarId;
|
||||
this.activeRegistrarIdChange.next(registrarId);
|
||||
this.registrarId.set(registrarId);
|
||||
}
|
||||
|
||||
public loadRegistrars(): Observable<Registrar[]> {
|
||||
return this.backend.getRegistrars().pipe(
|
||||
tap((registrars) => {
|
||||
if (registrars) {
|
||||
this.registrars = registrars;
|
||||
this.registrars.set(registrars);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
@@ -5,20 +5,20 @@
|
||||
routerLinkActive="active"
|
||||
*ngIf="isMobile; else desktop"
|
||||
>
|
||||
{{ registrarService.activeRegistrarId || "Select registrar" }}
|
||||
{{ registrarService.registrarId() || "Select registrar" }}
|
||||
<mat-icon>open_in_new</mat-icon>
|
||||
</button>
|
||||
<ng-template #desktop>
|
||||
<mat-form-field class="mat-form-field-density-5" appearance="fill">
|
||||
<mat-label>Registrar</mat-label>
|
||||
<mat-select
|
||||
[ngModel]="registrarService.activeRegistrarId"
|
||||
[ngModel]="registrarService.registrarId()"
|
||||
(selectionChange)="
|
||||
registrarService.updateSelectedRegistrar($event.value)
|
||||
"
|
||||
>
|
||||
<mat-option
|
||||
*ngFor="let registrar of registrarService.registrars"
|
||||
*ngFor="let registrar of registrarService.registrars()"
|
||||
[value]="registrar.registrarId"
|
||||
>
|
||||
{{ registrar.registrarId }}
|
||||
|
||||
@@ -87,7 +87,7 @@ export class RegistrarComponent {
|
||||
|
||||
constructor(protected registrarService: RegistrarService) {
|
||||
this.dataSource = new MatTableDataSource<Registrar>(
|
||||
registrarService.registrars
|
||||
registrarService.registrars()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
<div *ngIf="loading" class="contact__loading">
|
||||
@if (loading) {
|
||||
<div class="contact__loading">
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
<div *ngIf="!loading">
|
||||
<div
|
||||
class="contact__empty-contacts"
|
||||
*ngIf="contactService.contacts.length === 0"
|
||||
>
|
||||
} @else {
|
||||
<div>
|
||||
@if (contactService.contacts().length === 0) {
|
||||
<div class="contact__empty-contacts">
|
||||
<mat-icon class="contact__empty-contacts-icon secondary-text"
|
||||
>apps_outage</mat-icon
|
||||
>
|
||||
<h1>No contacts found</h1>
|
||||
</div>
|
||||
<div *ngFor="let group of groupedData">
|
||||
<div class="contact__cards-wrapper" *ngIf="group.contacts.length">
|
||||
<h3>{{ group.label }}s</h3>
|
||||
<mat-divider></mat-divider>
|
||||
<div class="contact__cards">
|
||||
<mat-card class="contact__card" *ngFor="let contact of group.contacts">
|
||||
<mat-card-title>{{ contact.name }}</mat-card-title>
|
||||
<p *ngIf="contact.phoneNumber">{{ contact.phoneNumber }}</p>
|
||||
<p *ngIf="contact.emailAddress">{{ contact.emailAddress }}</p>
|
||||
<mat-card-actions class="contact__card-actions">
|
||||
<button
|
||||
mat-button
|
||||
color="primary"
|
||||
(click)="openDetails($event, contact)"
|
||||
>
|
||||
<mat-icon>edit</mat-icon>Edit
|
||||
</button>
|
||||
<button mat-button color="accent" (click)="deleteContact(contact)">
|
||||
<mat-icon>delete</mat-icon>Delete
|
||||
</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</div>
|
||||
} @else { @for (group of groupedContacts(); track group.emailAddress) {
|
||||
<div class="contact__cards-wrapper">
|
||||
<h3>{{ group.label }}s</h3>
|
||||
<mat-divider></mat-divider>
|
||||
<div class="contact__cards">
|
||||
<mat-card class="contact__card" *ngFor="let contact of group.contacts">
|
||||
<mat-card-title>{{ contact.name }}</mat-card-title>
|
||||
<p *ngIf="contact.phoneNumber">{{ contact.phoneNumber }}</p>
|
||||
<p *ngIf="contact.emailAddress">{{ contact.emailAddress }}</p>
|
||||
<mat-card-actions class="contact__card-actions">
|
||||
<button
|
||||
mat-button
|
||||
color="primary"
|
||||
(click)="openDetails($event, contact)"
|
||||
>
|
||||
<mat-icon>edit</mat-icon>Edit
|
||||
</button>
|
||||
<button mat-button color="accent" (click)="deleteContact(contact)">
|
||||
<mat-icon>delete</mat-icon>Delete
|
||||
</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
} }
|
||||
<div class="contact__actions">
|
||||
<button mat-raised-button color="primary" (click)="openCreateNew($event)">
|
||||
<mat-icon>add</mat-icon>Create a Contact
|
||||
@@ -45,3 +45,4 @@
|
||||
#contactDetailsWrapper
|
||||
></app-dialog-bottom-sheet-wrapper>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, ViewChild } from '@angular/core';
|
||||
import { Component, ViewChild, computed } from '@angular/core';
|
||||
import { Contact, ContactService } from './contact.service';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
@@ -70,9 +70,9 @@ export class ContactDetailsDialogComponent implements DialogBottomSheetContent {
|
||||
|
||||
init(params: ContactDetailsParams) {
|
||||
this.params = params;
|
||||
this.contactIndex = this.contactService.contacts.findIndex(
|
||||
(c) => c === params.data.contact
|
||||
);
|
||||
this.contactIndex = this.contactService
|
||||
.contacts()
|
||||
.findIndex((c) => c === params.data.contact);
|
||||
this.contact = JSON.parse(JSON.stringify(params.data.contact));
|
||||
}
|
||||
|
||||
@@ -115,6 +115,16 @@ export class ContactDetailsDialogComponent implements DialogBottomSheetContent {
|
||||
})
|
||||
export default class ContactComponent {
|
||||
public static PATH = 'contact';
|
||||
public groupedContacts = computed(() => {
|
||||
return this.contactService.contacts().reduce((acc, contact) => {
|
||||
contact.types.forEach((contactType) => {
|
||||
acc
|
||||
.find((group: GroupedContacts) => group.value === contactType)
|
||||
?.contacts.push(contact);
|
||||
});
|
||||
return acc;
|
||||
}, JSON.parse(JSON.stringify(contactTypes)));
|
||||
});
|
||||
|
||||
@ViewChild('contactDetailsWrapper')
|
||||
detailsComponentWrapper!: DialogBottomSheetWrapper;
|
||||
@@ -131,17 +141,6 @@ export default class ContactComponent {
|
||||
});
|
||||
}
|
||||
|
||||
public get groupedData() {
|
||||
return this.contactService.contacts?.reduce((acc, contact) => {
|
||||
contact.types.forEach((type) => {
|
||||
acc
|
||||
.find((group: GroupedContacts) => group.value === type)
|
||||
?.contacts.push(contact);
|
||||
});
|
||||
return acc;
|
||||
}, JSON.parse(JSON.stringify(contactTypes)));
|
||||
}
|
||||
|
||||
deleteContact(contact: Contact) {
|
||||
if (confirm(`Please confirm contact ${contact.name} delete`)) {
|
||||
this.contactService.deleteContact(contact).subscribe({
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Injectable, signal } from '@angular/core';
|
||||
import { Observable, tap } from 'rxjs';
|
||||
import { RegistrarService } from 'src/app/registrar/registrar.service';
|
||||
import { BackendService } from 'src/app/shared/services/backend.service';
|
||||
@@ -33,7 +33,7 @@ export interface Contact {
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ContactService {
|
||||
contacts: Contact[] = [];
|
||||
contacts = signal<Contact[]>([]);
|
||||
|
||||
constructor(
|
||||
private backend: BackendService,
|
||||
@@ -42,39 +42,37 @@ export class ContactService {
|
||||
|
||||
// TODO: Come up with a better handling for registrarId
|
||||
fetchContacts(): Observable<Contact[]> {
|
||||
return this.backend
|
||||
.getContacts(this.registrarService.activeRegistrarId)
|
||||
.pipe(
|
||||
tap((contacts = []) => {
|
||||
this.contacts = contacts;
|
||||
})
|
||||
);
|
||||
return this.backend.getContacts(this.registrarService.registrarId()).pipe(
|
||||
tap((contacts = []) => {
|
||||
this.contacts.set(contacts);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
saveContacts(contacts: Contact[]): Observable<Contact[]> {
|
||||
return this.backend
|
||||
.postContacts(this.registrarService.activeRegistrarId, contacts)
|
||||
.postContacts(this.registrarService.registrarId(), contacts)
|
||||
.pipe(
|
||||
tap((_) => {
|
||||
this.contacts = contacts;
|
||||
this.contacts.set(contacts);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
updateContact(index: number, contact: Contact) {
|
||||
const newContacts = this.contacts.map((c, i) =>
|
||||
const newContacts = this.contacts().map((c, i) =>
|
||||
i === index ? contact : c
|
||||
);
|
||||
return this.saveContacts(newContacts);
|
||||
}
|
||||
|
||||
addContact(contact: Contact) {
|
||||
const newContacts = this.contacts.concat([contact]);
|
||||
const newContacts = this.contacts().concat([contact]);
|
||||
return this.saveContacts(newContacts);
|
||||
}
|
||||
|
||||
deleteContact(contact: Contact) {
|
||||
const newContacts = this.contacts.filter((c) => c !== contact);
|
||||
const newContacts = this.contacts().filter((c) => c !== contact);
|
||||
return this.saveContacts(newContacts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ export default class SecurityComponent {
|
||||
private _snackBar: MatSnackBar,
|
||||
public registrarService: RegistrarService
|
||||
) {
|
||||
this.dataSource = apiToUiConverter(this.registrarService.registrar);
|
||||
this.dataSource = apiToUiConverter(this.registrarService.registrar());
|
||||
}
|
||||
|
||||
enableEdit() {
|
||||
@@ -76,6 +76,6 @@ export default class SecurityComponent {
|
||||
}
|
||||
|
||||
resetDataSource() {
|
||||
this.dataSource = apiToUiConverter(this.registrarService.registrar);
|
||||
this.dataSource = apiToUiConverter(this.registrarService.registrar());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ export class SecurityService {
|
||||
saveChanges(newSecuritySettings: SecuritySettings) {
|
||||
return this.backend
|
||||
.postSecuritySettings(
|
||||
this.registrarService.activeRegistrarId,
|
||||
this.registrarService.registrarId(),
|
||||
uiToApiConverter(newSecuritySettings)
|
||||
)
|
||||
.pipe(
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
FROM gcr.io/distroless/java:debug
|
||||
FROM gcr.io/distroless/java17-debian11:debug
|
||||
ADD build/libs/nomulus.jar /nomulus.jar
|
||||
ENTRYPOINT ["/usr/bin/java", "-jar", "/nomulus.jar"]
|
||||
|
||||
+1
-1
@@ -776,7 +776,7 @@ if (environment == 'alpha') {
|
||||
gs://${gcpProject}-deploy/live/beam/${metaDataBaseName} \
|
||||
--image-gcr-path ${imageName}:live \
|
||||
--sdk-language JAVA \
|
||||
--flex-template-base-image JAVA11 \
|
||||
--flex-template-base-image JAVA17 \
|
||||
--metadata-file ${projectDir}/src/main/resources/${metaData} \
|
||||
--jar ${uberJarName} \
|
||||
--env FLEX_TEMPLATE_JAVA_MAIN_CLASS=${mainClass} \
|
||||
|
||||
@@ -163,7 +163,12 @@ public class InvoicingPipeline implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/** Saves the billing events to a single overall invoice CSV file. */
|
||||
/**
|
||||
* Saves the billing events to a single overall invoice CSV file. TextIO always produces the file
|
||||
* of type text/plain, which we then update to desired text/csv before sending an email to billing
|
||||
* team {@link google.registry.reporting.billing.BillingEmailUtils#emailOverallInvoice()
|
||||
* emailOverallInvoice}
|
||||
*/
|
||||
static void saveInvoiceCsv(
|
||||
PCollection<google.registry.beam.billing.BillingEvent> billingEvents,
|
||||
InvoicingPipelineOptions options) {
|
||||
|
||||
@@ -209,10 +209,18 @@ public final class RegistryJpaIO {
|
||||
|
||||
@ProcessElement
|
||||
public void processElement(OutputReceiver<T> outputReceiver) {
|
||||
tm().transact(
|
||||
// Note the use of no-retry transaction here. The results from the query are streamed to the
|
||||
// output receiver inside the transaction, which cannot be rolled back in case of a retry,
|
||||
// which in turn results in duplicate elements. If we try to pass the results to the output
|
||||
// receiver outside the transaction, they have to be materialized into a list containing all
|
||||
// the elements (without resorting to manual pagination) and greatly decrease the
|
||||
// parallelism of the pipeline.
|
||||
tm().transactNoRetry(
|
||||
() -> {
|
||||
query.stream().map(resultMapper::apply).forEach(outputReceiver::output);
|
||||
});
|
||||
return null;
|
||||
},
|
||||
null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,13 +117,12 @@ public class BsaRefreshAction implements Runnable {
|
||||
case CHECK_FOR_CHANGES:
|
||||
ImmutableList<UnblockableDomainChange> blockabilityChanges =
|
||||
refresher.checkForBlockabilityChanges();
|
||||
// Always write even if no change. Easier for manual inspection of GCS bucket.
|
||||
gcsClient.writeRefreshChanges(schedule.jobName(), blockabilityChanges.stream());
|
||||
if (blockabilityChanges.isEmpty()) {
|
||||
logger.atInfo().log("No change to Unblockable domains found.");
|
||||
schedule.updateJobStage(RefreshStage.DONE);
|
||||
return null;
|
||||
}
|
||||
gcsClient.writeRefreshChanges(schedule.jobName(), blockabilityChanges.stream());
|
||||
schedule.updateJobStage(RefreshStage.APPLY_CHANGES);
|
||||
// Fall through
|
||||
case APPLY_CHANGES:
|
||||
@@ -162,7 +161,7 @@ public class BsaRefreshAction implements Runnable {
|
||||
.filter(UnblockableDomainChange::isNewOrChange)
|
||||
.map(UnblockableDomainChange::newValue));
|
||||
if (report.isPresent()) {
|
||||
gcsClient.logRemovedUnblockableDomainsReport(
|
||||
gcsClient.logAddedUnblockableDomainsReport(
|
||||
schedule.jobName(), LINE_SPLITTER.splitToStream(report.get()));
|
||||
bsaReportSender.addUnblockableDomainsUpdates(report.get());
|
||||
} else {
|
||||
|
||||
@@ -48,7 +48,8 @@ public final class BsaTransactions {
|
||||
@CanIgnoreReturnValue
|
||||
public static <T> T bsaQuery(Callable<T> work) {
|
||||
verify(!isInTransaction(), "May only be used for top-level transactions.");
|
||||
return replicaTm().transact(work, TRANSACTION_REPEATABLE_READ);
|
||||
// TRANSACTION_REPEATABLE_READ is default on replica.
|
||||
return replicaTm().transact(work);
|
||||
}
|
||||
|
||||
private BsaTransactions() {}
|
||||
|
||||
@@ -80,7 +80,7 @@ public class UploadBsaUnavailableDomainsAction implements Runnable {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private static final int BATCH_SIZE = 50000;
|
||||
private static final int BATCH_SIZE = 40000;
|
||||
|
||||
Clock clock;
|
||||
|
||||
|
||||
@@ -721,6 +721,17 @@ public final class RegistryConfig {
|
||||
return "gs://" + billingBucket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns origin part of the URL of the billing invoice file
|
||||
*
|
||||
* @see google.registry.beam.billing.InvoicingPipeline
|
||||
*/
|
||||
@Provides
|
||||
@Config("billingInvoiceOriginUrl")
|
||||
public static String provideBillingInvoiceOriginUrl(RegistryConfigSettings config) {
|
||||
return config.billing.billingInvoiceOriginUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not we should publish invoices to partners automatically by default.
|
||||
*
|
||||
|
||||
@@ -173,6 +173,7 @@ public class RegistryConfigSettings {
|
||||
public List<String> invoiceEmailRecipients;
|
||||
public String invoiceReplyToEmailAddress;
|
||||
public String invoiceFilePrefix;
|
||||
public String billingInvoiceOriginUrl;
|
||||
}
|
||||
|
||||
/** Configuration for Registry Data Escrow (RDE). */
|
||||
|
||||
@@ -381,6 +381,7 @@ billing:
|
||||
# Optional return address that overrides the default.
|
||||
invoiceReplyToEmailAddress: null
|
||||
invoiceFilePrefix: REG-INV
|
||||
billingInvoiceOriginUrl: https://billing-origin-url/
|
||||
|
||||
rde:
|
||||
# URL prefix of ICANN's server to upload RDE reports to. Nomulus adds /TLD/ID
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# Example of a TLD configuration file. TLD configuration files are stored in
|
||||
# the internal repository and synced regularly to the database using the
|
||||
# release/cloudbuild-tld-sync.yaml job. The file can be created using the exact
|
||||
# output from the getTldCommand of an existing TLD.
|
||||
|
||||
addGracePeriodLength: "PT432000S"
|
||||
allowedFullyQualifiedHostNames: []
|
||||
allowedRegistrantContactIds: []
|
||||
anchorTenantAddGracePeriodLength: "PT2592000S"
|
||||
autoRenewGracePeriodLength: "PT3888000S"
|
||||
automaticTransferLength: "PT432000S"
|
||||
claimsPeriodEnd: "294247-01-10T04:00:54.775Z"
|
||||
createBillingCost:
|
||||
currency: "USD"
|
||||
amount: 8.00
|
||||
creationTime: "2017-01-03T19:52:47.770Z"
|
||||
currency: "USD"
|
||||
defaultPromoTokens: []
|
||||
dnsAPlusAaaaTtl: null
|
||||
dnsDsTtl: null
|
||||
dnsNsTtl: null
|
||||
dnsPaused: true
|
||||
dnsWriters:
|
||||
- "VoidDnsWriter"
|
||||
driveFolderId: null
|
||||
eapFeeSchedule:
|
||||
"1970-01-01T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 0.00
|
||||
escrowEnabled: false
|
||||
idnTables: []
|
||||
invoicingEnabled: false
|
||||
lordnUsername: null
|
||||
numDnsPublishLocks: 1
|
||||
pendingDeleteLength: "PT432000S"
|
||||
premiumListName: null
|
||||
pricingEngineClassName: "google.registry.model.pricing.StaticPremiumListPricingEngine"
|
||||
redemptionGracePeriodLength: "PT2592000S"
|
||||
registryLockOrUnlockBillingCost:
|
||||
currency: "USD"
|
||||
amount: 0.00
|
||||
renewBillingCostTransitions:
|
||||
"1970-01-01T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 8.00
|
||||
renewGracePeriodLength: "PT432000S"
|
||||
reservedListNames: []
|
||||
restoreBillingCost:
|
||||
currency: "USD"
|
||||
amount: 50.00
|
||||
roidSuffix: "EXAMPLE"
|
||||
serverStatusChangeBillingCost:
|
||||
currency: "USD"
|
||||
amount: 0.00
|
||||
tldStateTransitions:
|
||||
"1970-01-01T00:00:00.000Z": "GENERAL_AVAILABILITY"
|
||||
tldStr: "example"
|
||||
tldType: "TEST"
|
||||
tldUnicode: "example"
|
||||
transferGracePeriodLength: "PT432000S"
|
||||
+2
-3
@@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
|
||||
|
||||
<runtime>java8</runtime>
|
||||
<runtime>java17</runtime>
|
||||
<service>backend</service>
|
||||
<!--app-engine-apis>true</app-engine-apis-->
|
||||
<threadsafe>true</threadsafe>
|
||||
<app-engine-apis>true</app-engine-apis>
|
||||
<sessions-enabled>true</sessions-enabled>
|
||||
<instance-class>B4_1G</instance-class>
|
||||
<basic-scaling>
|
||||
|
||||
+2
-3
@@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
|
||||
|
||||
<runtime>java8</runtime>
|
||||
<runtime>java17</runtime>
|
||||
<service>bsa</service>
|
||||
<!--app-engine-apis>true</app-engine-apis-->
|
||||
<threadsafe>true</threadsafe>
|
||||
<app-engine-apis>true</app-engine-apis>
|
||||
<sessions-enabled>true</sessions-enabled>
|
||||
<instance-class>B4_1G</instance-class>
|
||||
<basic-scaling>
|
||||
|
||||
+2
-3
@@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
|
||||
|
||||
<runtime>java8</runtime>
|
||||
<runtime>java17</runtime>
|
||||
<service>default</service>
|
||||
<!--app-engine-apis>true</app-engine-apis-->
|
||||
<threadsafe>true</threadsafe>
|
||||
<app-engine-apis>true</app-engine-apis>
|
||||
<sessions-enabled>true</sessions-enabled>
|
||||
<instance-class>B4_1G</instance-class>
|
||||
<manual-scaling>
|
||||
|
||||
+2
-3
@@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
|
||||
|
||||
<runtime>java8</runtime>
|
||||
<runtime>java17</runtime>
|
||||
<service>pubapi</service>
|
||||
<!--app-engine-apis>true</app-engine-apis-->
|
||||
<threadsafe>true</threadsafe>
|
||||
<app-engine-apis>true</app-engine-apis>
|
||||
<sessions-enabled>true</sessions-enabled>
|
||||
<instance-class>B4_1G</instance-class>
|
||||
<manual-scaling>
|
||||
|
||||
+2
-3
@@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
|
||||
|
||||
<runtime>java8</runtime>
|
||||
<runtime>java17</runtime>
|
||||
<service>tools</service>
|
||||
<!--app-engine-apis>true</app-engine-apis-->
|
||||
<threadsafe>true</threadsafe>
|
||||
<app-engine-apis>true</app-engine-apis>
|
||||
<sessions-enabled>true</sessions-enabled>
|
||||
<instance-class>B4_1G</instance-class>
|
||||
<basic-scaling>
|
||||
|
||||
+2
-3
@@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
|
||||
|
||||
<runtime>java8</runtime>
|
||||
<runtime>java17</runtime>
|
||||
<service>backend</service>
|
||||
<!--app-engine-apis>true</app-engine-apis-->
|
||||
<threadsafe>true</threadsafe>
|
||||
<app-engine-apis>true</app-engine-apis>
|
||||
<sessions-enabled>true</sessions-enabled>
|
||||
<instance-class>B4</instance-class>
|
||||
<basic-scaling>
|
||||
|
||||
+2
-3
@@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
|
||||
|
||||
<runtime>java8</runtime>
|
||||
<runtime>java17</runtime>
|
||||
<service>bsa</service>
|
||||
<!--app-engine-apis>true</app-engine-apis-->
|
||||
<threadsafe>true</threadsafe>
|
||||
<app-engine-apis>true</app-engine-apis>
|
||||
<sessions-enabled>true</sessions-enabled>
|
||||
<instance-class>B4</instance-class>
|
||||
<basic-scaling>
|
||||
|
||||
+2
-3
@@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
|
||||
|
||||
<runtime>java8</runtime>
|
||||
<runtime>java17</runtime>
|
||||
<service>default</service>
|
||||
<!--app-engine-apis>true</app-engine-apis-->
|
||||
<threadsafe>true</threadsafe>
|
||||
<app-engine-apis>true</app-engine-apis>
|
||||
<sessions-enabled>true</sessions-enabled>
|
||||
<instance-class>B4_1G</instance-class>
|
||||
<manual-scaling>
|
||||
|
||||
+2
-3
@@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
|
||||
|
||||
<runtime>java8</runtime>
|
||||
<runtime>java17</runtime>
|
||||
<service>pubapi</service>
|
||||
<!--app-engine-apis>true</app-engine-apis-->
|
||||
<threadsafe>true</threadsafe>
|
||||
<app-engine-apis>true</app-engine-apis>
|
||||
<sessions-enabled>true</sessions-enabled>
|
||||
<instance-class>B4_1G</instance-class>
|
||||
<manual-scaling>
|
||||
|
||||
+2
-3
@@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
|
||||
|
||||
<runtime>java8</runtime>
|
||||
<runtime>java17</runtime>
|
||||
<service>tools</service>
|
||||
<!--app-engine-apis>true</app-engine-apis-->
|
||||
<threadsafe>true</threadsafe>
|
||||
<app-engine-apis>true</app-engine-apis>
|
||||
<sessions-enabled>true</sessions-enabled>
|
||||
<instance-class>B4</instance-class>
|
||||
<basic-scaling>
|
||||
|
||||
@@ -26,6 +26,7 @@ import static google.registry.flows.domain.DomainFlowUtils.checkHasBillingAccoun
|
||||
import static google.registry.flows.domain.DomainFlowUtils.getReservationTypes;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.handleFeeRequest;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.isAnchorTenant;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.isRegisterBsaCreate;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.isReserved;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.isValidReservedCreate;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.validateDomainName;
|
||||
@@ -269,13 +270,13 @@ public final class DomainCheckFlow implements TransactionalFlow {
|
||||
if (tokenResult.isPresent()) {
|
||||
return tokenResult;
|
||||
}
|
||||
if (bsaBlockedDomains.contains(domainName)) {
|
||||
// TODO(weiminyu): extract to a constant for here and CheckApiAction.
|
||||
// Excerpt from BSA's custom message. Max len 32 chars by EPP XML schema.
|
||||
return Optional.of("Blocked by a GlobalBlock service");
|
||||
} else {
|
||||
if (isRegisterBsaCreate(domainName, allocationToken)
|
||||
|| !bsaBlockedDomains.contains(domainName)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
// TODO(weiminyu): extract to a constant for here and CheckApiAction.
|
||||
// Excerpt from BSA's custom message. Max len 32 chars by EPP XML schema.
|
||||
return Optional.of("Blocked by a GlobalBlock service");
|
||||
}
|
||||
|
||||
/** Handle the fee check extension. */
|
||||
|
||||
@@ -330,7 +330,7 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
.verifySignedMarks(launchCreate.get().getSignedMarks(), domainLabel, now)
|
||||
.getId();
|
||||
}
|
||||
verifyNotBlockedByBsa(domainLabel, tld, now);
|
||||
verifyNotBlockedByBsa(domainName, tld, now, allocationToken);
|
||||
flowCustomLogic.afterValidation(
|
||||
DomainCreateFlowCustomLogic.AfterValidationParameters.newBuilder()
|
||||
.setDomainName(domainName)
|
||||
@@ -421,8 +421,7 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
createNameCollisionOneTimePollMessage(targetId, domainHistory, registrarId, now));
|
||||
}
|
||||
entitiesToSave.add(domain, domainHistory);
|
||||
if (allocationToken.isPresent()
|
||||
&& TokenType.SINGLE_USE.equals(allocationToken.get().getTokenType())) {
|
||||
if (allocationToken.isPresent() && allocationToken.get().getTokenType().isOneTimeUse()) {
|
||||
entitiesToSave.add(
|
||||
allocationTokenFlowUtils.redeemToken(
|
||||
allocationToken.get(), domainHistory.getHistoryEntryId()));
|
||||
|
||||
@@ -27,6 +27,7 @@ import static com.google.common.collect.Sets.intersection;
|
||||
import static com.google.common.collect.Sets.union;
|
||||
import static google.registry.bsa.persistence.BsaLabelUtils.isLabelBlocked;
|
||||
import static google.registry.model.domain.Domain.MAX_REGISTRATION_YEARS;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.REGISTER_BSA;
|
||||
import static google.registry.model.tld.Tld.TldState.GENERAL_AVAILABILITY;
|
||||
import static google.registry.model.tld.Tld.TldState.PREDELEGATION;
|
||||
import static google.registry.model.tld.Tld.TldState.QUIET_PERIOD;
|
||||
@@ -265,9 +266,14 @@ public class DomainFlowUtils {
|
||||
* Verifies that the {@code domainLabel} is not blocked by any BSA block label for the given
|
||||
* {@code tld} at the specified time.
|
||||
*/
|
||||
public static void verifyNotBlockedByBsa(String domainLabel, Tld tld, DateTime now)
|
||||
public static void verifyNotBlockedByBsa(
|
||||
InternetDomainName domainName,
|
||||
Tld tld,
|
||||
DateTime now,
|
||||
Optional<AllocationToken> allocationToken)
|
||||
throws DomainLabelBlockedByBsaException {
|
||||
if (isBlockedByBsa(domainLabel, tld, now)) {
|
||||
if (!isRegisterBsaCreate(domainName, allocationToken)
|
||||
&& isBlockedByBsa(domainName.parts().get(0), tld, now)) {
|
||||
throw new DomainLabelBlockedByBsaException();
|
||||
}
|
||||
}
|
||||
@@ -311,6 +317,15 @@ public class DomainFlowUtils {
|
||||
&& token.get().getDomainName().get().equals(domainName.toString());
|
||||
}
|
||||
|
||||
/** Returns whether a given domain create request may bypass the BSA block check. */
|
||||
public static boolean isRegisterBsaCreate(
|
||||
InternetDomainName domainName, Optional<AllocationToken> token) {
|
||||
return token.isPresent()
|
||||
&& token.get().getTokenType().equals(REGISTER_BSA)
|
||||
&& token.get().getDomainName().isPresent()
|
||||
&& token.get().getDomainName().get().equals(domainName.toString());
|
||||
}
|
||||
|
||||
/** Check if the registrar running the flow has access to the TLD in question. */
|
||||
public static void checkAllowedAccessToTld(String registrarId, String tld) throws EppException {
|
||||
if (!Registrar.loadByRegistrarIdCached(registrarId).get().getAllowedTlds().contains(tld)) {
|
||||
|
||||
@@ -73,7 +73,6 @@ import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
import google.registry.model.domain.rgp.GracePeriodStatus;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.domain.token.AllocationToken.TokenType;
|
||||
import google.registry.model.domain.token.AllocationTokenExtension;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
@@ -258,8 +257,7 @@ public final class DomainRenewFlow implements MutatingFlow {
|
||||
ImmutableSet.Builder<ImmutableObject> entitiesToSave = new ImmutableSet.Builder<>();
|
||||
entitiesToSave.add(
|
||||
newDomain, domainHistory, explicitRenewEvent, newAutorenewEvent, newAutorenewPollMessage);
|
||||
if (allocationToken.isPresent()
|
||||
&& TokenType.SINGLE_USE.equals(allocationToken.get().getTokenType())) {
|
||||
if (allocationToken.isPresent() && allocationToken.get().getTokenType().isOneTimeUse()) {
|
||||
entitiesToSave.add(
|
||||
allocationTokenFlowUtils.redeemToken(
|
||||
allocationToken.get(), domainHistory.getHistoryEntryId()));
|
||||
|
||||
@@ -36,7 +36,6 @@ import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.domain.token.AllocationToken.TokenBehavior;
|
||||
import google.registry.model.domain.token.AllocationToken.TokenStatus;
|
||||
import google.registry.model.domain.token.AllocationToken.TokenType;
|
||||
import google.registry.model.domain.token.AllocationTokenExtension;
|
||||
import google.registry.model.reporting.HistoryEntry.HistoryEntryId;
|
||||
import google.registry.model.tld.Tld;
|
||||
@@ -105,8 +104,7 @@ public class AllocationTokenFlowUtils {
|
||||
/** Redeems a SINGLE_USE {@link AllocationToken}, returning the redeemed copy. */
|
||||
public AllocationToken redeemToken(AllocationToken token, HistoryEntryId redemptionHistoryId) {
|
||||
checkArgument(
|
||||
TokenType.SINGLE_USE.equals(token.getTokenType()),
|
||||
"Only SINGLE_USE tokens can be marked as redeemed");
|
||||
token.getTokenType().isOneTimeUse(), "Only SINGLE_USE tokens can be marked as redeemed");
|
||||
return token.asBuilder().setRedemptionHistoryId(redemptionHistoryId).build();
|
||||
}
|
||||
|
||||
|
||||
@@ -118,6 +118,14 @@ public class GcsUtils implements Serializable {
|
||||
storage().delete(blobId);
|
||||
}
|
||||
|
||||
/** Update file content type on existing GCS file */
|
||||
public void updateContentType(BlobId blobId, String contentType) throws StorageException {
|
||||
if (existsAndNotEmpty(blobId)) {
|
||||
Blob blob = storage().get(blobId);
|
||||
blob.toBuilder().setContentType(contentType).build().update();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all object names within a bucket for a given prefix.
|
||||
*
|
||||
|
||||
@@ -22,6 +22,7 @@ import static google.registry.model.domain.token.AllocationToken.TokenStatus.CAN
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenStatus.ENDED;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenStatus.NOT_STARTED;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenStatus.VALID;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.REGISTER_BSA;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.CollectionUtils.forceEmptyToNull;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
@@ -120,18 +121,37 @@ public class AllocationToken extends UpdateAutoTimestampEntity implements Builda
|
||||
/** Type of the token that indicates how and where it should be used. */
|
||||
public enum TokenType {
|
||||
/** Token used for bulk pricing */
|
||||
BULK_PRICING,
|
||||
BULK_PRICING(/* isOneTimeUse= */ false),
|
||||
/** Token saved on a TLD to use if no other token is passed from the client */
|
||||
DEFAULT_PROMO,
|
||||
DEFAULT_PROMO(/* isOneTimeUse= */ false),
|
||||
/** This is the old name for what is now BULK_PRICING. */
|
||||
// TODO(sarahbot@): Remove this type once all tokens of this type have been scrubbed from the
|
||||
// database
|
||||
@Deprecated
|
||||
PACKAGE,
|
||||
PACKAGE(/* isOneTimeUse= */ false),
|
||||
/** Invalid after use */
|
||||
SINGLE_USE,
|
||||
SINGLE_USE(/* isOneTimeUse= */ true),
|
||||
/** Do not expire after use */
|
||||
UNLIMITED_USE,
|
||||
UNLIMITED_USE(/* isOneTimeUse= */ false),
|
||||
/**
|
||||
* Allows bypassing the BSA check during domain creation, otherwise has the same semantics as
|
||||
* {@link #SINGLE_USE}.
|
||||
*
|
||||
* <p>This token applies to a single domain only. If the domain is not blocked by BSA at the
|
||||
* redemption time this token is processed like {@code SINGLE_USE}, as mentioned above.
|
||||
*/
|
||||
REGISTER_BSA(/* isOneTimeUse= */ true);
|
||||
|
||||
private final boolean isOneTimeUse;
|
||||
|
||||
private TokenType(boolean isOneTimeUse) {
|
||||
this.isOneTimeUse = isOneTimeUse;
|
||||
}
|
||||
|
||||
/** Returns true if token should be invalidated after use. */
|
||||
public boolean isOneTimeUse() {
|
||||
return this.isOneTimeUse;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -361,12 +381,11 @@ public class AllocationToken extends UpdateAutoTimestampEntity implements Builda
|
||||
|| !getInstance().discountPremiums,
|
||||
"Bulk tokens cannot discount premium names");
|
||||
checkArgument(
|
||||
getInstance().domainName == null || TokenType.SINGLE_USE.equals(getInstance().tokenType),
|
||||
"Domain name can only be specified for SINGLE_USE tokens");
|
||||
getInstance().domainName == null || getInstance().tokenType.isOneTimeUse(),
|
||||
"Domain name can only be specified for SINGLE_USE or REGISTER_BSA tokens");
|
||||
checkArgument(
|
||||
getInstance().redemptionHistoryId == null
|
||||
|| TokenType.SINGLE_USE.equals(getInstance().tokenType),
|
||||
"Redemption history entry can only be specified for SINGLE_USE tokens");
|
||||
getInstance().redemptionHistoryId == null || getInstance().tokenType.isOneTimeUse(),
|
||||
"Redemption history entry can only be specified for SINGLE_USE or REGISTER_BSA tokens");
|
||||
checkArgument(
|
||||
getInstance().tokenType != TokenType.BULK_PRICING
|
||||
|| (getInstance().allowedClientIds != null
|
||||
@@ -378,6 +397,10 @@ public class AllocationToken extends UpdateAutoTimestampEntity implements Builda
|
||||
checkArgument(
|
||||
getInstance().discountFraction > 0 || getInstance().discountYears == 1,
|
||||
"Discount years can only be specified along with a discount fraction");
|
||||
if (getInstance().getTokenType().equals(REGISTER_BSA)) {
|
||||
checkArgumentNotNull(
|
||||
getInstance().domainName, "REGISTER_BSA tokens must be tied to a domain");
|
||||
}
|
||||
if (getInstance().registrationBehavior.equals(RegistrationBehavior.ANCHOR_TENANT)) {
|
||||
checkArgumentNotNull(
|
||||
getInstance().domainName, "ANCHOR_TENANT tokens must be tied to a domain");
|
||||
|
||||
@@ -74,6 +74,7 @@ import google.registry.tldconfig.idn.IdnTableEnum;
|
||||
import google.registry.util.Idn;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
@@ -458,6 +459,8 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl
|
||||
@JsonDeserialize(using = CurrencyDeserializer.class)
|
||||
CurrencyUnit currency = DEFAULT_CURRENCY;
|
||||
|
||||
// TODO(sarahbot@): Remove this field and make createBillingCostTransitions not-null once all TLDs
|
||||
// are populated with a create cost transition map
|
||||
/** The per-year billing cost for registering a new domain name. */
|
||||
@Type(type = JodaMoneyType.TYPE_NAME)
|
||||
@Columns(
|
||||
@@ -467,6 +470,12 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl
|
||||
})
|
||||
Money createBillingCost = DEFAULT_CREATE_BILLING_COST;
|
||||
|
||||
// TODO(sarahbot@): Make this field not null and add a default value once field is populated on
|
||||
// all existing TLDs
|
||||
/** A property that transitions to different create billing costs at different times. */
|
||||
@JsonDeserialize(using = TimedTransitionPropertyMoneyDeserializer.class)
|
||||
TimedTransitionProperty<Money> createBillingCostTransitions;
|
||||
|
||||
/** The one-time billing cost for restoring a domain name from the redemption grace period. */
|
||||
@Type(type = JodaMoneyType.TYPE_NAME)
|
||||
@Columns(
|
||||
@@ -676,6 +685,13 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl
|
||||
return createBillingCost;
|
||||
}
|
||||
|
||||
public ImmutableSortedMap<DateTime, Money> getCreateBillingCostTransitions() {
|
||||
return Objects.requireNonNullElseGet(
|
||||
createBillingCostTransitions,
|
||||
() -> TimedTransitionProperty.withInitialValue(getCreateBillingCost()))
|
||||
.toValueMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the add-on cost of a domain restore (the flat tld-wide fee charged in addition to one
|
||||
* year of renewal for that name).
|
||||
@@ -959,6 +975,17 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setCreateBillingCostTransitions(
|
||||
ImmutableSortedMap<DateTime, Money> createCostsMap) {
|
||||
checkArgumentNotNull(createCostsMap, "Create billing costs map cannot be null");
|
||||
checkArgument(
|
||||
createCostsMap.values().stream().allMatch(Money::isPositiveOrZero),
|
||||
"Create billing cost cannot be negative");
|
||||
getInstance().createBillingCostTransitions =
|
||||
TimedTransitionProperty.fromValueMap(createCostsMap);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setReservedListsByName(Set<String> reservedListNames) {
|
||||
// TODO(b/309175133): forbid if enrolled with BSA
|
||||
checkArgument(reservedListNames != null, "reservedListNames must not be null");
|
||||
@@ -1131,6 +1158,10 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl
|
||||
// here to catch cases where we loaded an invalid TimedTransitionProperty from the database
|
||||
// and cloned it into a new builder, to block re-building a Tld in an invalid state.
|
||||
instance.tldStateTransitions.checkValidity();
|
||||
// TODO(sarahbot@): Remove null check when createBillingCostTransitions field is made not-null
|
||||
if (instance.createBillingCostTransitions != null) {
|
||||
instance.createBillingCostTransitions.checkValidity();
|
||||
}
|
||||
instance.renewBillingCostTransitions.checkValidity();
|
||||
instance.eapFeeSchedule.checkValidity();
|
||||
// All costs must be in the expected currency.
|
||||
|
||||
+1
@@ -203,6 +203,7 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||
return transact(work, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T transactNoRetry(
|
||||
Callable<T> work, @Nullable TransactionIsolationLevel isolationLevel) {
|
||||
if (inTransaction()) {
|
||||
|
||||
@@ -63,6 +63,18 @@ public interface TransactionManager {
|
||||
*/
|
||||
<T> T transact(Callable<T> work, TransactionIsolationLevel isolationLevel);
|
||||
|
||||
/**
|
||||
* Executes the work in a transaction at the given {@link TransactionIsolationLevel} and returns
|
||||
* the result, without retrying upon retryable exceptions.
|
||||
*
|
||||
* <p>This method should only be used when the transaction contains side effects that are not
|
||||
* rolled back by the transaction manager, for example in {@link
|
||||
* google.registry.beam.common.RegistryJpaIO} where the results from a query are streamed to the
|
||||
* next transformation inside a transaction, as the result stream has to materialize to a list
|
||||
* outside a transaction and doing so would greatly affect the parallelism of the pipeline.
|
||||
*/
|
||||
<T> T transactNoRetry(Callable<T> work, TransactionIsolationLevel isolationLevel);
|
||||
|
||||
/**
|
||||
* Executes the work in a (potentially wrapped) transaction and returns the result.
|
||||
*
|
||||
|
||||
@@ -15,20 +15,17 @@
|
||||
package google.registry.reporting.billing;
|
||||
|
||||
import static com.google.common.base.Throwables.getRootCause;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.cloud.storage.BlobId;
|
||||
import com.google.cloud.storage.StorageException;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.io.CharStreams;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.gcs.GcsUtils;
|
||||
import google.registry.groups.GmailClient;
|
||||
import google.registry.reporting.billing.BillingModule.InvoiceDirectoryPrefix;
|
||||
import google.registry.util.EmailMessage;
|
||||
import google.registry.util.EmailMessage.Attachment;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
@@ -37,6 +34,7 @@ import org.joda.time.YearMonth;
|
||||
/** Utility functions for sending emails involving monthly invoices. */
|
||||
public class BillingEmailUtils {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
private final GmailClient gmailClient;
|
||||
private final YearMonth yearMonth;
|
||||
private final InternetAddress outgoingEmailAddress;
|
||||
@@ -46,6 +44,7 @@ public class BillingEmailUtils {
|
||||
private final String billingBucket;
|
||||
private final String invoiceFilePrefix;
|
||||
private final String invoiceDirectoryPrefix;
|
||||
private final String billingInvoiceOriginUrl;
|
||||
private final GcsUtils gcsUtils;
|
||||
|
||||
@Inject
|
||||
@@ -58,6 +57,7 @@ public class BillingEmailUtils {
|
||||
@Config("invoiceReplyToEmailAddress") Optional<InternetAddress> replyToEmailAddress,
|
||||
@Config("billingBucket") String billingBucket,
|
||||
@Config("invoiceFilePrefix") String invoiceFilePrefix,
|
||||
@Config("billingInvoiceOriginUrl") String billingInvoiceOriginUrl,
|
||||
@InvoiceDirectoryPrefix String invoiceDirectoryPrefix,
|
||||
GcsUtils gcsUtils) {
|
||||
this.gmailClient = gmailClient;
|
||||
@@ -69,31 +69,36 @@ public class BillingEmailUtils {
|
||||
this.billingBucket = billingBucket;
|
||||
this.invoiceFilePrefix = invoiceFilePrefix;
|
||||
this.invoiceDirectoryPrefix = invoiceDirectoryPrefix;
|
||||
this.billingInvoiceOriginUrl = billingInvoiceOriginUrl;
|
||||
this.gcsUtils = gcsUtils;
|
||||
}
|
||||
|
||||
/** Sends an e-mail to all expected recipients with an attached overall invoice from GCS. */
|
||||
void emailOverallInvoice() {
|
||||
public void emailOverallInvoice() {
|
||||
try {
|
||||
String invoiceFile = String.format("%s-%s.csv", invoiceFilePrefix, yearMonth);
|
||||
String fileUrl = billingInvoiceOriginUrl + invoiceDirectoryPrefix + invoiceFile;
|
||||
BlobId invoiceFilename = BlobId.of(billingBucket, invoiceDirectoryPrefix + invoiceFile);
|
||||
try (InputStream in = gcsUtils.openInputStream(invoiceFilename)) {
|
||||
gmailClient.sendEmail(
|
||||
EmailMessage.newBuilder()
|
||||
.setSubject(String.format("Domain Registry invoice data %s", yearMonth))
|
||||
.setBody(
|
||||
String.format("Attached is the %s invoice for the domain registry.", yearMonth))
|
||||
.setFrom(outgoingEmailAddress)
|
||||
.setRecipients(invoiceEmailRecipients)
|
||||
.setReplyToEmailAddress(replyToEmailAddress)
|
||||
.setAttachment(
|
||||
Attachment.newBuilder()
|
||||
.setContent(CharStreams.toString(new InputStreamReader(in, UTF_8)))
|
||||
.setContentType(MediaType.CSV_UTF_8)
|
||||
.setFilename(invoiceFile)
|
||||
.build())
|
||||
.build());
|
||||
try {
|
||||
gcsUtils.updateContentType(invoiceFilename, "text/csv");
|
||||
} catch (StorageException e) {
|
||||
// We want to continue with email anyway, it just will be less convenient for billing team
|
||||
// to process the file.
|
||||
logger.atWarning().withCause(e).log("Failed to update invoice file type");
|
||||
}
|
||||
gmailClient.sendEmail(
|
||||
EmailMessage.newBuilder()
|
||||
.setSubject(String.format("Domain Registry invoice data %s", yearMonth))
|
||||
.setBody(
|
||||
String.format(
|
||||
"<p>Use the following link to download %s invoice for the domain registry -"
|
||||
+ " <a href=\"%s\">invoice</a>.</p>",
|
||||
yearMonth, fileUrl))
|
||||
.setFrom(outgoingEmailAddress)
|
||||
.setRecipients(invoiceEmailRecipients)
|
||||
.setReplyToEmailAddress(replyToEmailAddress)
|
||||
.setContentType(MediaType.HTML_UTF_8)
|
||||
.build());
|
||||
} catch (Throwable e) {
|
||||
// Strip one layer, because callWithRetry wraps in a RuntimeException
|
||||
sendAlertEmail(
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.model.tld.Tld.Builder.ROID_SUFFIX_PATTERN;
|
||||
import static google.registry.model.tld.Tlds.getTlds;
|
||||
import static google.registry.util.ListNamingUtils.convertFilePathToName;
|
||||
@@ -28,10 +29,12 @@ import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Sets.SetView;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.model.common.TimedTransitionProperty;
|
||||
import google.registry.model.tld.Tld;
|
||||
import google.registry.model.tld.label.PremiumList;
|
||||
import google.registry.model.tld.label.PremiumListDao;
|
||||
import google.registry.tools.params.PathParameter;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.Idn;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
@@ -40,9 +43,11 @@ import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
@@ -90,6 +95,8 @@ public class ConfigureTldCommand extends MutatingCommand {
|
||||
|
||||
@Inject ObjectMapper mapper;
|
||||
|
||||
@Inject Clock clock;
|
||||
|
||||
@Inject
|
||||
@Named("dnsWriterNames")
|
||||
Set<String> validDnsWriterNames;
|
||||
@@ -105,11 +112,20 @@ public class ConfigureTldCommand extends MutatingCommand {
|
||||
|
||||
@Override
|
||||
protected void init() throws Exception {
|
||||
if (RegistryToolEnvironment.get().equals(RegistryToolEnvironment.PRODUCTION)) {
|
||||
checkArgument(
|
||||
buildEnv || breakGlass != null,
|
||||
"Either the --break_glass or --build_environment flag must be used when"
|
||||
+ " running the configure_tld command on Production");
|
||||
}
|
||||
String name = convertFilePathToName(inputFile);
|
||||
Map<String, Object> tldData = new Yaml().load(Files.newBufferedReader(inputFile));
|
||||
checkName(name, tldData);
|
||||
checkForMissingFields(tldData);
|
||||
Tld oldTld = getTlds().contains(name) ? Tld.get(name) : null;
|
||||
|
||||
checkForMissingFields(
|
||||
Stream.concat(tldData.keySet().stream(), Stream.of("createBillingCostTransitions"))
|
||||
.collect(toImmutableSet()));
|
||||
Tld newTld = mapper.readValue(inputFile.toFile(), Tld.class);
|
||||
if (oldTld != null) {
|
||||
oldTldInBreakGlass = oldTld.getBreakglassMode();
|
||||
@@ -140,6 +156,14 @@ public class ConfigureTldCommand extends MutatingCommand {
|
||||
checkPremiumList(newTld);
|
||||
checkDnsWriters(newTld);
|
||||
checkCurrency(newTld);
|
||||
// TODO(sarahbot@): Remove this once the createBillingCost field is removed
|
||||
checkArgument(
|
||||
Objects.equals(
|
||||
TimedTransitionProperty.fromValueMap(newTld.getCreateBillingCostTransitions())
|
||||
.getValueAtTime(clock.nowUtc()),
|
||||
newTld.getCreateBillingCost()),
|
||||
"The createBillingCostTransitions map must have the same current cost as the"
|
||||
+ " createBillingCost field");
|
||||
// bsaEnrollStartTime only exists in DB. Need to carry it over to the updated copy. See Tld.java
|
||||
// for more information.
|
||||
Optional<DateTime> bsaEnrollTime =
|
||||
@@ -192,7 +216,7 @@ public class ConfigureTldCommand extends MutatingCommand {
|
||||
ROID_SUFFIX_PATTERN.pattern());
|
||||
}
|
||||
|
||||
private void checkForMissingFields(Map<String, Object> tldData) {
|
||||
private void checkForMissingFields(ImmutableSet<String> keySet) {
|
||||
Set<String> tldFields =
|
||||
Arrays.stream(Tld.class.getDeclaredFields())
|
||||
.filter(field -> !Modifier.isStatic(field.getModifiers()))
|
||||
@@ -201,7 +225,7 @@ public class ConfigureTldCommand extends MutatingCommand {
|
||||
.collect(Collectors.toSet());
|
||||
Set<String> missingFields = new HashSet<>();
|
||||
for (String field : tldFields) {
|
||||
if (!tldData.containsKey(field)) {
|
||||
if (!keySet.contains(field)) {
|
||||
missingFields.add(field);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,8 +292,8 @@ abstract class CreateOrUpdateRegistrarCommand extends MutatingCommand {
|
||||
}
|
||||
if (!isNullOrEmpty(email)) {
|
||||
builder.setEmailAddress(email);
|
||||
} else if (!isNullOrEmpty(
|
||||
icannReferralEmail)) { // fall back to ICANN referral email if present
|
||||
} else if (!isNullOrEmpty(icannReferralEmail) && oldRegistrar == null) {
|
||||
// On creates, fall back to ICANN referral email (if present).
|
||||
builder.setEmailAddress(icannReferralEmail);
|
||||
}
|
||||
if (url != null) {
|
||||
|
||||
@@ -18,7 +18,6 @@ import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.Iterables.partition;
|
||||
import static com.google.common.collect.Streams.stream;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
@@ -78,7 +77,7 @@ final class DeleteAllocationTokensCommand extends UpdateOrDeleteAllocationTokens
|
||||
ImmutableSet<VKey<AllocationToken>> tokensToDelete =
|
||||
tm().loadByKeys(batch).values().stream()
|
||||
.filter(t -> withDomains || !t.getDomainName().isPresent())
|
||||
.filter(t -> SINGLE_USE.equals(t.getTokenType()))
|
||||
.filter(t -> t.getTokenType().isOneTimeUse())
|
||||
.filter(t -> !t.isRedeemed())
|
||||
.map(AllocationToken::createVKey)
|
||||
.collect(toImmutableSet());
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.ParameterException;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.beust.jcommander.ParametersDelegate;
|
||||
import com.google.common.base.Ascii;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
@@ -218,12 +219,21 @@ final class RegistryCli implements CommandRunner {
|
||||
|
||||
// Reset the JPA transaction manager after every command to avoid a situation where a test can
|
||||
// interfere with other tests
|
||||
JpaTransactionManager cachedJpaTm = tm();
|
||||
TransactionManagerFactory.setJpaTm(() -> component.nomulusToolJpaTransactionManager().get());
|
||||
TransactionManagerFactory.setReplicaJpaTm(
|
||||
() -> component.nomulusToolReplicaJpaTransactionManager().get());
|
||||
command.run();
|
||||
TransactionManagerFactory.setJpaTm(() -> cachedJpaTm);
|
||||
try {
|
||||
JpaTransactionManager cachedJpaTm = tm();
|
||||
TransactionManagerFactory.setJpaTm(() -> component.nomulusToolJpaTransactionManager().get());
|
||||
TransactionManagerFactory.setReplicaJpaTm(
|
||||
() -> component.nomulusToolReplicaJpaTransactionManager().get());
|
||||
command.run();
|
||||
TransactionManagerFactory.setJpaTm(() -> cachedJpaTm);
|
||||
} catch (Exception e) {
|
||||
String env = Ascii.toLowerCase(environment.name());
|
||||
System.err.printf(
|
||||
"Could not get tool transaction manager; try running nomulus -e %s logout "
|
||||
+ "and then nomulus -e %s login.\n",
|
||||
env, env);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
void setEnvironment(RegistryToolEnvironment environment) {
|
||||
|
||||
@@ -35,11 +35,22 @@ class UpdatePremiumListCommand extends CreateOrUpdatePremiumListCommand {
|
||||
description = "Does not execute the entity mutation")
|
||||
boolean dryRun;
|
||||
|
||||
// indicates if there is a new change made by this command
|
||||
@Parameter(
|
||||
names = {"--build_environment"},
|
||||
description =
|
||||
"DO NOT USE THIS FLAG ON THE COMMAND LINE! This flag indicates the command is being run"
|
||||
+ " by the build environment tools. This flag should never be used by a human user"
|
||||
+ " from the command line.")
|
||||
boolean buildEnv;
|
||||
|
||||
// Indicates if there is a new change made by this command
|
||||
private boolean newChange = false;
|
||||
|
||||
@Override
|
||||
protected String prompt() throws Exception {
|
||||
checkArgument(
|
||||
!RegistryToolEnvironment.get().equals(RegistryToolEnvironment.PRODUCTION) || buildEnv,
|
||||
"The --build_environment flag must be used when running update_premium_list in production");
|
||||
name = Strings.isNullOrEmpty(name) ? convertFilePathToName(inputFile) : name;
|
||||
PremiumList existingList =
|
||||
PremiumListDao.getLatestRevision(name)
|
||||
|
||||
@@ -14,10 +14,12 @@
|
||||
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.util.DiffUtils.prettyPrintEntityDeepDiff;
|
||||
import static google.registry.util.ListNamingUtils.convertFilePathToName;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.google.common.base.Strings;
|
||||
import google.registry.model.tld.label.ReservedList;
|
||||
@@ -28,8 +30,28 @@ import java.util.List;
|
||||
@Parameters(separators = " =", commandDescription = "Update a ReservedList.")
|
||||
final class UpdateReservedListCommand extends CreateOrUpdateReservedListCommand {
|
||||
|
||||
@Parameter(
|
||||
names = {"-d", "--dry_run"},
|
||||
description = "Does not execute the entity mutation")
|
||||
boolean dryRun;
|
||||
|
||||
@Parameter(
|
||||
names = {"--build_environment"},
|
||||
description =
|
||||
"DO NOT USE THIS FLAG ON THE COMMAND LINE! This flag indicates the command is being run"
|
||||
+ " by the build environment tools. This flag should never be used by a human user"
|
||||
+ " from the command line.")
|
||||
boolean buildEnv;
|
||||
|
||||
// indicates if there is a new change made by this command
|
||||
private boolean newChange = true;
|
||||
|
||||
@Override
|
||||
protected String prompt() throws Exception {
|
||||
checkArgument(
|
||||
!RegistryToolEnvironment.get().equals(RegistryToolEnvironment.PRODUCTION) || buildEnv,
|
||||
"The --build_environment flag must be used when running update_reserved_list in"
|
||||
+ " production");
|
||||
name = Strings.isNullOrEmpty(name) ? convertFilePathToName(input) : name;
|
||||
ReservedList existingReservedList =
|
||||
ReservedList.get(name)
|
||||
@@ -54,6 +76,7 @@ final class UpdateReservedListCommand extends CreateOrUpdateReservedListCommand
|
||||
.getReservedListEntries()
|
||||
.equals(reservedList.getReservedListEntries());
|
||||
if (!shouldPublishChanged && !reservedListEntriesChanged) {
|
||||
newChange = false;
|
||||
return "No entity changes to apply.";
|
||||
}
|
||||
String result = String.format("Update reserved list for %s?\n", name);
|
||||
@@ -70,4 +93,9 @@ final class UpdateReservedListCommand extends CreateOrUpdateReservedListCommand
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean dontRunCommand() {
|
||||
return dryRun || !newChange;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import static google.registry.testing.DatabaseHelper.deleteTestDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
@@ -54,6 +55,7 @@ import google.registry.request.Response;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeLockHandler;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
@@ -293,7 +295,12 @@ class BsaRefreshFunctionalTest {
|
||||
action.run();
|
||||
assertThat(queryUnblockableDomains())
|
||||
.containsExactly(UnblockableDomain.of("blocked1.app", Reason.REGISTERED));
|
||||
assertThat(gcsClient.readRefreshChanges(jobName)).isEmpty();
|
||||
// Verify that refresh change file does not exist (404 error) since there is no change.
|
||||
assertThat(
|
||||
assertThrows(
|
||||
UncheckedIOException.class, () -> gcsClient.readRefreshChanges(jobName).findAny()))
|
||||
.hasMessageThat()
|
||||
.contains("404");
|
||||
verifyNoInteractions(bsaReportSender);
|
||||
}
|
||||
|
||||
@@ -313,7 +320,12 @@ class BsaRefreshFunctionalTest {
|
||||
action.run();
|
||||
assertThat(queryUnblockableDomains())
|
||||
.containsExactly(UnblockableDomain.of("blocked1.app", Reason.REGISTERED));
|
||||
assertThat(gcsClient.readRefreshChanges(jobName)).isEmpty();
|
||||
// Verify that refresh change file does not exist (404 error) since there is no change.
|
||||
assertThat(
|
||||
assertThrows(
|
||||
UncheckedIOException.class, () -> gcsClient.readRefreshChanges(jobName).findAny()))
|
||||
.hasMessageThat()
|
||||
.contains("404");
|
||||
verifyNoInteractions(bsaReportSender);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,10 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class UploadBsaUnavailableDomainsActionTest {
|
||||
|
||||
private static final String BUCKET = "domain-registry-bsa";
|
||||
|
||||
private static final String API_URL = "https://upload.test/bsa";
|
||||
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("2024-02-02T02:02:02Z"));
|
||||
|
||||
@RegisterExtension
|
||||
@@ -62,10 +66,6 @@ public class UploadBsaUnavailableDomainsActionTest {
|
||||
|
||||
private final GcsUtils gcsUtils = new GcsUtils(LocalStorageHelper.getOptions());
|
||||
|
||||
private final String BUCKET = "domain-registry-bsa";
|
||||
|
||||
private final String API_URL = "https://upload.test/bsa";
|
||||
|
||||
private final FakeResponse response = new FakeResponse();
|
||||
|
||||
@BeforeEach
|
||||
|
||||
@@ -19,6 +19,7 @@ import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.DEF
|
||||
import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.NONPREMIUM;
|
||||
import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.SPECIFIED;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.DEFAULT_PROMO;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.REGISTER_BSA;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE;
|
||||
import static google.registry.model.eppoutput.CheckData.DomainCheck.create;
|
||||
@@ -189,6 +190,40 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
create(true, "example3.tld", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_bsaBlocked_createAllowedWithToken() throws Exception {
|
||||
persistBsaLabel("example1");
|
||||
setEppInput("domain_check_allocationtoken.xml");
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(REGISTER_BSA)
|
||||
.setDomainName("example1.tld")
|
||||
.build());
|
||||
doCheckTest(
|
||||
create(true, "example1.tld", null),
|
||||
create(false, "example2.tld", "Alloc token invalid for domain"),
|
||||
create(false, "reserved.tld", "Reserved"),
|
||||
create(false, "specificuse.tld", "Reserved; alloc. token required"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_bsaBlocked_withIrrelevantTokenType() throws Exception {
|
||||
persistBsaLabel("example1");
|
||||
setEppInput("domain_check_allocationtoken.xml");
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("example1.tld")
|
||||
.build());
|
||||
doCheckTest(
|
||||
create(false, "example1.tld", "Blocked by a GlobalBlock service"),
|
||||
create(false, "example2.tld", "Alloc token invalid for domain"),
|
||||
create(false, "reserved.tld", "Reserved"),
|
||||
create(false, "specificuse.tld", "Reserved; alloc. token required"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_clTridNotSpecified() throws Exception {
|
||||
setEppInput("domain_check_no_cltrid.xml");
|
||||
|
||||
@@ -29,6 +29,7 @@ import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.SPE
|
||||
import static google.registry.model.domain.fee.Fee.FEE_EXTENSION_URIS;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.BULK_PRICING;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.DEFAULT_PROMO;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.REGISTER_BSA;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE;
|
||||
import static google.registry.model.eppcommon.EppXmlTransformer.marshal;
|
||||
@@ -255,6 +256,14 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
persistClaimsList(ImmutableMap.of("example-one", CLAIMS_KEY, "test-validate", CLAIMS_KEY));
|
||||
}
|
||||
|
||||
private void enrollTldInBsa() {
|
||||
persistResource(
|
||||
Tld.get("tld")
|
||||
.asBuilder()
|
||||
.setBsaEnrollStartTime(Optional.of(clock.nowUtc().minusSeconds(1)))
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create host and contact entries for testing.
|
||||
*
|
||||
@@ -2593,12 +2602,92 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_blockedByBsa() throws Exception {
|
||||
void testSuccess_blockedByBsa_hasRegisterBsaToken() throws Exception {
|
||||
enrollTldInBsa();
|
||||
allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(REGISTER_BSA)
|
||||
.setDomainName("example.tld")
|
||||
.build());
|
||||
persistBsaLabel("example");
|
||||
persistContactsAndHosts();
|
||||
setEppInput(
|
||||
"domain_create_allocationtoken.xml",
|
||||
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
|
||||
runFlow();
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(), allocationToken);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_blockedByBsa_reservedDomain_viaAllocationTokenExtension() throws Exception {
|
||||
enrollTldInBsa();
|
||||
allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(REGISTER_BSA)
|
||||
.setDomainName("resdom.tld")
|
||||
.build());
|
||||
persistBsaLabel("resdom");
|
||||
setEppInput(
|
||||
"domain_create_allocationtoken.xml", ImmutableMap.of("DOMAIN", "resdom.tld", "YEARS", "2"));
|
||||
persistContactsAndHosts();
|
||||
runFlowAssertResponse(
|
||||
loadFile("domain_create_response.xml", ImmutableMap.of("DOMAIN", "resdom.tld")));
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(RESERVED), allocationToken);
|
||||
assertNoLordn();
|
||||
assertAllocationTokenWasRedeemed("abc123");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_blockedByBsa_quietPeriod_skipTldStateCheckWithToken() throws Exception {
|
||||
enrollTldInBsa();
|
||||
AllocationToken token =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(REGISTER_BSA)
|
||||
.setRegistrationBehavior(RegistrationBehavior.BYPASS_TLD_STATE)
|
||||
.setDomainName("example.tld")
|
||||
.build());
|
||||
persistContactsAndHosts();
|
||||
persistBsaLabel("example");
|
||||
setEppInput(
|
||||
"domain_create_allocationtoken.xml",
|
||||
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
|
||||
persistResource(
|
||||
Tld.get("tld")
|
||||
.asBuilder()
|
||||
.setBsaEnrollStartTime(Optional.of(clock.nowUtc().minusSeconds(1)))
|
||||
.setTldStateTransitions(ImmutableSortedMap.of(START_OF_TIME, QUIET_PERIOD))
|
||||
.build());
|
||||
runFlow();
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(), token);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_blockedByBsa_anchorTenant() throws Exception {
|
||||
enrollTldInBsa();
|
||||
allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abcDEF23456")
|
||||
.setTokenType(REGISTER_BSA)
|
||||
.setDomainName("anchor.tld")
|
||||
.build());
|
||||
setEppInput("domain_create_anchor_allocationtoken.xml");
|
||||
persistContactsAndHosts();
|
||||
persistBsaLabel("anchor");
|
||||
runFlowAssertResponse(loadFile("domain_create_anchor_response.xml"));
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT), allocationToken);
|
||||
assertNoLordn();
|
||||
assertAllocationTokenWasRedeemed("abcDEF23456");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_blockedByBsa() throws Exception {
|
||||
enrollTldInBsa();
|
||||
persistBsaLabel("example");
|
||||
persistContactsAndHosts();
|
||||
EppException thrown = assertThrows(DomainLabelBlockedByBsaException.class, this::runFlow);
|
||||
@@ -2619,6 +2708,41 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
.isEqualTo(loadFile("domain_create_blocked_by_bsa.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_blockedByBsa_hasWrongToken() throws Exception {
|
||||
enrollTldInBsa();
|
||||
allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setRegistrationBehavior(RegistrationBehavior.BYPASS_TLD_STATE)
|
||||
.setDomainName("example.tld")
|
||||
.build());
|
||||
persistBsaLabel("example");
|
||||
persistContactsAndHosts();
|
||||
setEppInput(
|
||||
"domain_create_allocationtoken.xml",
|
||||
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
|
||||
EppException thrown = assertThrows(DomainLabelBlockedByBsaException.class, this::runFlow);
|
||||
assertAboutEppExceptions()
|
||||
.that(thrown)
|
||||
.marshalsToXml()
|
||||
.and()
|
||||
.hasMessage("Domain label is blocked by the Brand Safety Alliance");
|
||||
byte[] responseXmlBytes =
|
||||
marshal(
|
||||
EppOutput.create(
|
||||
new EppResponse.Builder()
|
||||
.setTrid(Trid.create(null, "server-trid"))
|
||||
.setResult(thrown.getResult())
|
||||
.build()),
|
||||
ValidationMode.STRICT);
|
||||
assertThat(new String(responseXmlBytes, StandardCharsets.UTF_8))
|
||||
.isEqualTo(loadFile("domain_create_blocked_by_bsa.xml"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testFailure_uppercase() {
|
||||
doFailingDomainNameTest("Example.tld", BadDomainNameCharacterException.class);
|
||||
|
||||
@@ -21,6 +21,7 @@ import static google.registry.model.domain.token.AllocationToken.TokenStatus.END
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenStatus.NOT_STARTED;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenStatus.VALID;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.BULK_PRICING;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.REGISTER_BSA;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
@@ -245,6 +246,18 @@ public class AllocationTokenTest extends EntityTestCase {
|
||||
.isEqualTo("Bulk tokens may only be valid for CREATE actions");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuild_registerBsa_missingDomain() {
|
||||
createTld("tld");
|
||||
// REGISTER_BSA requires a domain
|
||||
AllocationToken.Builder token =
|
||||
new AllocationToken.Builder().setToken("abc").setTokenType(REGISTER_BSA);
|
||||
assertThat(assertThrows(IllegalArgumentException.class, () -> token.build()))
|
||||
.hasMessageThat()
|
||||
.isEqualTo("REGISTER_BSA tokens must be tied to a domain");
|
||||
token.setDomainName("example.tld").build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFail_bulkTokenNullEppActions() {
|
||||
AllocationToken.Builder builder =
|
||||
@@ -317,7 +330,7 @@ public class AllocationTokenTest extends EntityTestCase {
|
||||
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, builder::build);
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo("Domain name can only be specified for SINGLE_USE tokens");
|
||||
.isEqualTo("Domain name can only be specified for SINGLE_USE or REGISTER_BSA tokens");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -347,7 +360,8 @@ public class AllocationTokenTest extends EntityTestCase {
|
||||
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, builder::build);
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo("Redemption history entry can only be specified for SINGLE_USE tokens");
|
||||
.isEqualTo(
|
||||
"Redemption history entry can only be specified for SINGLE_USE or REGISTER_BSA tokens");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import google.registry.dns.writer.VoidDnsWriter;
|
||||
import google.registry.model.EntityTestCase;
|
||||
import google.registry.model.common.TimedTransitionProperty;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.tld.Tld.TldNotFoundException;
|
||||
import google.registry.model.tld.Tld.TldState;
|
||||
@@ -149,6 +150,8 @@ public final class TldTest extends EntityTestCase {
|
||||
.asBuilder()
|
||||
.setDnsAPlusAaaaTtl(Duration.standardHours(1))
|
||||
.setDnsWriters(ImmutableSet.of("baz", "bang"))
|
||||
.setCreateBillingCostTransitions(
|
||||
TimedTransitionProperty.withInitialValue(Money.of(USD, 13)).toValueMap())
|
||||
.setEapFeeSchedule(
|
||||
ImmutableSortedMap.of(
|
||||
START_OF_TIME,
|
||||
@@ -170,7 +173,12 @@ public final class TldTest extends EntityTestCase {
|
||||
|
||||
@Test
|
||||
void testSuccess_tldYamlRoundtrip() throws Exception {
|
||||
Tld testTld = createTld("test");
|
||||
Tld testTld =
|
||||
createTld("test")
|
||||
.asBuilder()
|
||||
.setCreateBillingCostTransitions(
|
||||
TimedTransitionProperty.withInitialValue(Money.of(USD, 8)).toValueMap())
|
||||
.build();
|
||||
ObjectMapper mapper = createObjectMapper();
|
||||
String yaml = mapper.writeValueAsString(testTld);
|
||||
Tld constructedTld = mapper.readValue(yaml, Tld.class);
|
||||
@@ -224,6 +232,46 @@ public final class TldTest extends EntityTestCase {
|
||||
assertThat(registry.getRestoreBillingCost()).isEqualTo(Money.of(USD, 17));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetCreateBillingCostTransitions() {
|
||||
ImmutableSortedMap<DateTime, Money> createCostTransitions =
|
||||
ImmutableSortedMap.of(
|
||||
START_OF_TIME,
|
||||
Money.of(USD, 8),
|
||||
fakeClock.nowUtc(),
|
||||
Money.of(USD, 1),
|
||||
fakeClock.nowUtc().plusMonths(1),
|
||||
Money.of(USD, 2),
|
||||
fakeClock.nowUtc().plusMonths(2),
|
||||
Money.of(USD, 3));
|
||||
Tld registry =
|
||||
Tld.get("tld").asBuilder().setCreateBillingCostTransitions(createCostTransitions).build();
|
||||
assertThat(registry.getCreateBillingCostTransitions()).isEqualTo(createCostTransitions);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetCreateBillingCostTransitionsNegativeCost() throws Exception {
|
||||
ImmutableSortedMap<DateTime, Money> createCostTransitions =
|
||||
ImmutableSortedMap.of(
|
||||
START_OF_TIME,
|
||||
Money.of(USD, 8),
|
||||
fakeClock.nowUtc(),
|
||||
Money.of(USD, 1),
|
||||
fakeClock.nowUtc().plusMonths(1),
|
||||
Money.of(USD, -2),
|
||||
fakeClock.nowUtc().plusMonths(2),
|
||||
Money.of(USD, 3));
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
Tld.get("tld")
|
||||
.asBuilder()
|
||||
.setCreateBillingCostTransitions(createCostTransitions)
|
||||
.build());
|
||||
assertThat(thrown.getMessage()).isEqualTo("Create billing cost cannot be negative");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSettingRestoreBillingCost() {
|
||||
Tld registry = Tld.get("tld").asBuilder().setRestoreBillingCost(Money.of(USD, 42)).build();
|
||||
|
||||
@@ -21,17 +21,12 @@ import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.cloud.storage.BlobId;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.gcs.GcsUtils;
|
||||
import google.registry.groups.GmailClient;
|
||||
import google.registry.util.EmailMessage;
|
||||
import google.registry.util.EmailMessage.Attachment;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Optional;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
@@ -45,18 +40,14 @@ class BillingEmailUtilsTest {
|
||||
|
||||
private GmailClient gmailClient;
|
||||
private BillingEmailUtils emailUtils;
|
||||
private GcsUtils gcsUtils;
|
||||
private ArgumentCaptor<EmailMessage> contentCaptor;
|
||||
private GcsUtils gcsUtils;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws Exception {
|
||||
gmailClient = mock(GmailClient.class);
|
||||
gcsUtils = mock(GcsUtils.class);
|
||||
when(gcsUtils.openInputStream(BlobId.of("test-bucket", "results/REG-INV-2017-10.csv")))
|
||||
.thenReturn(
|
||||
new ByteArrayInputStream("test,data\nhello,world".getBytes(StandardCharsets.UTF_8)));
|
||||
contentCaptor = ArgumentCaptor.forClass(EmailMessage.class);
|
||||
|
||||
gcsUtils = mock(GcsUtils.class);
|
||||
emailUtils = getEmailUtils(Optional.of(new InternetAddress("reply-to@test.com")));
|
||||
}
|
||||
|
||||
@@ -72,6 +63,7 @@ class BillingEmailUtilsTest {
|
||||
replyToAddress,
|
||||
"test-bucket",
|
||||
"REG-INV",
|
||||
"www.google.com/",
|
||||
"results/",
|
||||
gcsUtils);
|
||||
}
|
||||
@@ -89,14 +81,11 @@ class BillingEmailUtilsTest {
|
||||
ImmutableList.of(
|
||||
new InternetAddress("hello@world.com"), new InternetAddress("hola@mundo.com")))
|
||||
.setSubject("Domain Registry invoice data 2017-10")
|
||||
.setBody("Attached is the 2017-10 invoice for the domain registry.")
|
||||
.setBody(
|
||||
"<p>Use the following link to download 2017-10 invoice for the domain registry -"
|
||||
+ " <a href=\"www.google.com/results/REG-INV-2017-10.csv\">invoice</a>.</p>")
|
||||
.setReplyToEmailAddress(new InternetAddress("reply-to@test.com"))
|
||||
.setAttachment(
|
||||
Attachment.newBuilder()
|
||||
.setContent("test,data\nhello,world")
|
||||
.setContentType(MediaType.CSV_UTF_8)
|
||||
.setFilename("REG-INV-2017-10.csv")
|
||||
.build())
|
||||
.setContentType(MediaType.HTML_UTF_8)
|
||||
.build();
|
||||
assertThat(emailMessage).isEqualTo(expectedContent);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import static google.registry.testing.TestDataHelper.loadFile;
|
||||
import static google.registry.tldconfig.idn.IdnTableEnum.EXTENDED_LATIN;
|
||||
import static google.registry.tldconfig.idn.IdnTableEnum.JA;
|
||||
import static google.registry.tldconfig.idn.IdnTableEnum.UNCONFUSABLE_LATIN;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static org.joda.money.CurrencyUnit.JPY;
|
||||
@@ -39,6 +40,7 @@ import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
|
||||
import com.google.common.base.Ascii;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.common.testing.TestLogHandler;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
@@ -70,6 +72,7 @@ public class ConfigureTldCommandTest extends CommandTestCase<ConfigureTldCommand
|
||||
command.mapper = objectMapper;
|
||||
premiumList = persistPremiumList("test", USD, "silver,USD 50", "gold,USD 80");
|
||||
command.validDnsWriterNames = ImmutableSet.of("VoidDnsWriter", "FooDnsWriter");
|
||||
command.clock = fakeClock;
|
||||
logger.addHandler(logHandler);
|
||||
}
|
||||
|
||||
@@ -173,6 +176,57 @@ public class ConfigureTldCommandTest extends CommandTestCase<ConfigureTldCommand
|
||||
assertThat(updatedTld.getCreateBillingCost()).isEqualTo(Money.of(USD, 25));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_fileMissingCreateBillingCostTransitions() throws Exception {
|
||||
createTld("nocreatecostmap");
|
||||
File tldFile = tmpDir.resolve("nocreatecostmap.yaml").toFile();
|
||||
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "nocreatecostmap.yaml"));
|
||||
runCommandForced("--input=" + tldFile);
|
||||
Tld updatedTld = Tld.get("nocreatecostmap");
|
||||
assertThat(updatedTld.getCreateBillingCostTransitions())
|
||||
.isEqualTo(ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 25)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_fileMissingCreateBillingCostTransitionsRevertsToBasicConstructedMap()
|
||||
throws Exception {
|
||||
ImmutableSortedMap<DateTime, Money> createCostTransitions =
|
||||
ImmutableSortedMap.of(
|
||||
START_OF_TIME,
|
||||
Money.of(USD, 8),
|
||||
fakeClock.nowUtc(),
|
||||
Money.of(USD, 1),
|
||||
fakeClock.nowUtc().plusMonths(1),
|
||||
Money.of(USD, 2),
|
||||
fakeClock.nowUtc().plusMonths(2),
|
||||
Money.of(USD, 3));
|
||||
Tld tld =
|
||||
createTld("nocreatecostmap")
|
||||
.asBuilder()
|
||||
.setCreateBillingCostTransitions(createCostTransitions)
|
||||
.build();
|
||||
assertThat(tld.getCreateBillingCostTransitions().size()).isEqualTo(4);
|
||||
File tldFile = tmpDir.resolve("nocreatecostmap.yaml").toFile();
|
||||
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "nocreatecostmap.yaml"));
|
||||
runCommandForced("--input=" + tldFile);
|
||||
Tld updatedTld = Tld.get("nocreatecostmap");
|
||||
assertThat(updatedTld.getCreateBillingCostTransitions())
|
||||
.isEqualTo(ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 25)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_billingCostTransitionsDoesNotMatchCreateCost() throws Exception {
|
||||
createTld("diffcostmap");
|
||||
File tldFile = tmpDir.resolve("diffcostmap.yaml").toFile();
|
||||
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "diffcostmap.yaml"));
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile));
|
||||
assertThat(thrown.getMessage())
|
||||
.isEqualTo(
|
||||
"The createBillingCostTransitions map must have the same current cost as the"
|
||||
+ " createBillingCost field");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_fileMissingNullableFieldsOnCreate() throws Exception {
|
||||
File tldFile = tmpDir.resolve("missingnullablefields.yaml").toFile();
|
||||
@@ -185,6 +239,20 @@ public class ConfigureTldCommandTest extends CommandTestCase<ConfigureTldCommand
|
||||
+ " premiumListName, currency, numDnsPublishLocks]");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_addCreateBillingCostTransitions() throws Exception {
|
||||
createTld("costmap");
|
||||
File tldFile = tmpDir.resolve("costmap.yaml").toFile();
|
||||
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "costmap.yaml"));
|
||||
runCommandForced("--input=" + tldFile);
|
||||
Tld updatedTld = Tld.get("costmap");
|
||||
ImmutableSortedMap<DateTime, Money> costTransitions =
|
||||
updatedTld.getCreateBillingCostTransitions();
|
||||
assertThat(costTransitions.size()).isEqualTo(3);
|
||||
assertThat(costTransitions.get(START_OF_TIME)).isEqualTo(Money.of(USD, 13));
|
||||
assertThat(costTransitions.get(START_OF_TIME.plusYears(26))).isEqualTo(Money.of(USD, 14));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_fileMissingNullableFieldOnUpdate() throws Exception {
|
||||
Tld tld = createTld("missingnullablefields");
|
||||
@@ -671,4 +739,46 @@ public class ConfigureTldCommandTest extends CommandTestCase<ConfigureTldCommand
|
||||
Tld notUpdatedTld = Tld.get("tld");
|
||||
assertThat(notUpdatedTld.getCreateBillingCost()).isEqualTo(Money.of(USD, 13));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_runCommandOnProduction_noFlag() throws Exception {
|
||||
createTld("tld");
|
||||
File tldFile = tmpDir.resolve("tld.yaml").toFile();
|
||||
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "tld.yaml"));
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
runCommandInEnvironment(RegistryToolEnvironment.PRODUCTION, "--input=" + tldFile));
|
||||
assertThat(thrown.getMessage())
|
||||
.isEqualTo(
|
||||
"Either the --break_glass or --build_environment flag must be used when running the"
|
||||
+ " configure_tld command on Production");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_runCommandOnProduction_breakGlassFlag() throws Exception {
|
||||
createTld("tld");
|
||||
File tldFile = tmpDir.resolve("tld.yaml").toFile();
|
||||
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "tld.yaml"));
|
||||
runCommandInEnvironment(
|
||||
RegistryToolEnvironment.PRODUCTION, "--input=" + tldFile, "--break_glass=true", "-f");
|
||||
Tld updatedTld = Tld.get("tld");
|
||||
assertThat(updatedTld.getCreateBillingCost()).isEqualTo(Money.of(USD, 25));
|
||||
testTldConfiguredSuccessfully(updatedTld, "tld.yaml");
|
||||
assertThat(updatedTld.getBreakglassMode()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_runCommandOnProduction_buildEnvFlag() throws Exception {
|
||||
createTld("tld");
|
||||
File tldFile = tmpDir.resolve("tld.yaml").toFile();
|
||||
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "tld.yaml"));
|
||||
runCommandInEnvironment(
|
||||
RegistryToolEnvironment.PRODUCTION, "--input=" + tldFile, "--build_environment", "-f");
|
||||
Tld updatedTld = Tld.get("tld");
|
||||
assertThat(updatedTld.getCreateBillingCost()).isEqualTo(Money.of(USD, 25));
|
||||
testTldConfiguredSuccessfully(updatedTld, "tld.yaml");
|
||||
assertThat(updatedTld.getBreakglassMode()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,7 +380,7 @@ class GenerateAllocationTokensCommandTest extends CommandTestCase<GenerateAlloca
|
||||
.hasMessageThat()
|
||||
.isEqualTo(
|
||||
"Invalid value for -t parameter. Allowed values:[BULK_PRICING, DEFAULT_PROMO, PACKAGE,"
|
||||
+ " SINGLE_USE, UNLIMITED_USE]");
|
||||
+ " SINGLE_USE, UNLIMITED_USE, REGISTER_BSA]");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -19,14 +19,17 @@ import static google.registry.testing.DatabaseHelper.createTlds;
|
||||
import static google.registry.testing.DatabaseHelper.persistPremiumList;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.TestDataHelper.loadFile;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.beust.jcommander.ParameterException;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import google.registry.model.EntityYamlUtils;
|
||||
import google.registry.model.tld.Tld;
|
||||
import google.registry.model.tld.label.PremiumList;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -48,6 +51,12 @@ class GetTldCommandTest extends CommandTestCase<GetTldCommand> {
|
||||
.setDnsAPlusAaaaTtl(Duration.standardMinutes(15))
|
||||
.setDriveFolderId("driveFolder")
|
||||
.setCreateBillingCost(Money.of(USD, 25))
|
||||
.setCreateBillingCostTransitions(
|
||||
ImmutableSortedMap.of(
|
||||
START_OF_TIME,
|
||||
Money.of(USD, 8),
|
||||
DateTime.parse("2020-01-01T00:00:00Z"),
|
||||
Money.of(USD, 25)))
|
||||
.setPremiumList(premiumList)
|
||||
.build());
|
||||
runCommand("tld");
|
||||
|
||||
@@ -205,4 +205,39 @@ class UpdatePremiumListCommandTest<C extends UpdatePremiumListCommand>
|
||||
.comparingElementsUsing(immutableObjectCorrespondence("revisionId"))
|
||||
.containsExactly(PremiumEntry.create(0L, new BigDecimal("9090.00"), "doge"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_runCommandOnProduction_noFlag() throws Exception {
|
||||
File tmpFile = tmpDir.resolve(String.format("%s.txt", TLD_TEST)).toFile();
|
||||
String newPremiumListData = "eth,USD 9999";
|
||||
Files.asCharSink(tmpFile, UTF_8).write(newPremiumListData);
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
runCommandInEnvironment(
|
||||
RegistryToolEnvironment.PRODUCTION,
|
||||
"--name=" + TLD_TEST,
|
||||
"--input=" + Paths.get(tmpFile.getPath())));
|
||||
assertThat(thrown.getMessage())
|
||||
.isEqualTo(
|
||||
"The --build_environment flag must be used when running update_premium_list in"
|
||||
+ " production");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_runCommandOnProduction_buildEnvFlag() throws Exception {
|
||||
File tmpFile = tmpDir.resolve(String.format("%s.txt", TLD_TEST)).toFile();
|
||||
String newPremiumListData = "eth,USD 9999";
|
||||
Files.asCharSink(tmpFile, UTF_8).write(newPremiumListData);
|
||||
runCommandInEnvironment(
|
||||
RegistryToolEnvironment.PRODUCTION,
|
||||
"--name=" + TLD_TEST,
|
||||
"--input=" + Paths.get(tmpFile.getPath()),
|
||||
"--build_environment",
|
||||
"-f");
|
||||
assertThat(PremiumListDao.loadAllPremiumEntries(TLD_TEST))
|
||||
.comparingElementsUsing(immutableObjectCorrespondence("revisionId"))
|
||||
.containsExactly(PremiumEntry.create(0L, new BigDecimal("9999.00"), "eth"));
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Tests for {@link UpdateRecurrenceCommand}. */
|
||||
public class UpdateBillingRecurrenceCommandTest extends CommandTestCase<UpdateRecurrenceCommand> {
|
||||
public class UpdateRecurrenceCommandTest extends CommandTestCase<UpdateRecurrenceCommand> {
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
@@ -637,10 +637,12 @@ class UpdateRegistrarCommandTest extends CommandTestCase<UpdateRegistrarCommand>
|
||||
|
||||
@Test
|
||||
void testSuccess_setIcannEmail() throws Exception {
|
||||
runCommand("--icann_referral_email=foo@bar.test", "--force", "TheRegistrar");
|
||||
Registrar registrar = loadRegistrar("TheRegistrar");
|
||||
assertThat(registrar.getIcannReferralEmail()).isEqualTo("foo@bar.test");
|
||||
assertThat(registrar.getEmailAddress()).isEqualTo("foo@bar.test");
|
||||
assertThat(registrar.getEmailAddress()).isEqualTo("the.registrar@example.com");
|
||||
runCommand("--icann_referral_email=foo@bar.test", "--force", "TheRegistrar");
|
||||
Registrar updatedRegistrar = loadRegistrar("TheRegistrar");
|
||||
assertThat(updatedRegistrar.getIcannReferralEmail()).isEqualTo("foo@bar.test");
|
||||
assertThat(updatedRegistrar.getEmailAddress()).isEqualTo("the.registrar@example.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -142,4 +142,50 @@ class UpdateReservedListCommandTest
|
||||
assertThat(command.prompt()).contains("baddies: null -> baddies,FULLY_BLOCKED");
|
||||
assertThat(command.prompt()).contains("ford: null -> ford,FULLY_BLOCKED # random comment");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_dryRun() throws Exception {
|
||||
runCommandForced("--input=" + reservedTermsPath, "--dry_run");
|
||||
assertThat(command.prompt()).contains("Update reserved list for xn--q9jyb4c_common-reserved?");
|
||||
assertThat(ReservedList.get("xn--q9jyb4c_common-reserved")).isPresent();
|
||||
ReservedList reservedList = ReservedList.get("xn--q9jyb4c_common-reserved").get();
|
||||
assertThat(reservedList.getReservedListEntries()).hasSize(1);
|
||||
assertThat(reservedList.getReservationInList("helicopter")).hasValue(FULLY_BLOCKED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_runCommandOnProduction_noFlag() throws Exception {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
runCommandInEnvironment(
|
||||
RegistryToolEnvironment.PRODUCTION,
|
||||
"--name=xn--q9jyb4c_common-reserved",
|
||||
"--input=" + reservedTermsPath));
|
||||
assertThat(thrown.getMessage())
|
||||
.isEqualTo(
|
||||
"The --build_environment flag must be used when running update_reserved_list in"
|
||||
+ " production");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_runCommandOnProduction_buildEnvFlag() throws Exception {
|
||||
runCommandInEnvironment(
|
||||
RegistryToolEnvironment.PRODUCTION,
|
||||
"--name=xn--q9jyb4c_common-reserved",
|
||||
"--input=" + reservedTermsPath,
|
||||
"--build_environment",
|
||||
"-f");
|
||||
assertThat(ReservedList.get("xn--q9jyb4c_common-reserved")).isPresent();
|
||||
ReservedList reservedList = ReservedList.get("xn--q9jyb4c_common-reserved").get();
|
||||
assertThat(reservedList.getReservedListEntries()).hasSize(2);
|
||||
assertThat(reservedList.getReservationInList("baddies")).hasValue(FULLY_BLOCKED);
|
||||
assertThat(reservedList.getReservationInList("ford")).hasValue(FULLY_BLOCKED);
|
||||
assertThat(reservedList.getReservationInList("helicopter")).isEmpty();
|
||||
assertInStdout("Update reserved list for xn--q9jyb4c_common-reserved?");
|
||||
assertInStdout("helicopter: helicopter,FULLY_BLOCKED -> null");
|
||||
assertInStdout("baddies: null -> baddies,FULLY_BLOCKED");
|
||||
assertInStdout("ford: null -> ford,FULLY_BLOCKED # random comment");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,10 @@ claimsPeriodEnd: "294247-01-10T04:00:54.775Z"
|
||||
createBillingCost:
|
||||
currency: "USD"
|
||||
amount: 13.00
|
||||
createBillingCostTransitions:
|
||||
"1970-01-01T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 13.00
|
||||
creationTime: "1970-01-01T00:00:00.000Z"
|
||||
currency: "USD"
|
||||
defaultPromoTokens:
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
addGracePeriodLength: "PT432000S"
|
||||
allowedFullyQualifiedHostNames:
|
||||
- "foo"
|
||||
allowedRegistrantContactIds: []
|
||||
anchorTenantAddGracePeriodLength: "PT2592000S"
|
||||
autoRenewGracePeriodLength: "PT3888000S"
|
||||
automaticTransferLength: "PT432000S"
|
||||
claimsPeriodEnd: "294247-01-10T04:00:54.775Z"
|
||||
createBillingCost:
|
||||
currency: "USD"
|
||||
amount: 14.00
|
||||
createBillingCostTransitions:
|
||||
"1970-01-01T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 13.00
|
||||
"1996-01-01T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 14.00
|
||||
"2050-01-01T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 15.00
|
||||
creationTime: "1970-01-01T00:00:00.000Z"
|
||||
currency: "USD"
|
||||
defaultPromoTokens:
|
||||
- "bbbbb"
|
||||
dnsAPlusAaaaTtl: "PT3600S"
|
||||
dnsDsTtl: null
|
||||
dnsNsTtl: null
|
||||
dnsPaused: false
|
||||
dnsWriters:
|
||||
- "VoidDnsWriter"
|
||||
driveFolderId: null
|
||||
eapFeeSchedule:
|
||||
"1970-01-01T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 0.00
|
||||
"2000-06-01T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 100.00
|
||||
"2000-06-02T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 0.00
|
||||
escrowEnabled: false
|
||||
idnTables:
|
||||
- "EXTENDED_LATIN"
|
||||
- "JA"
|
||||
invoicingEnabled: false
|
||||
lordnUsername: null
|
||||
numDnsPublishLocks: 1
|
||||
pendingDeleteLength: "PT432000S"
|
||||
premiumListName: "test"
|
||||
pricingEngineClassName: "google.registry.model.pricing.StaticPremiumListPricingEngine"
|
||||
redemptionGracePeriodLength: "PT2592000S"
|
||||
registryLockOrUnlockBillingCost:
|
||||
currency: "USD"
|
||||
amount: 0.00
|
||||
renewBillingCostTransitions:
|
||||
"1970-01-01T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 11.00
|
||||
renewGracePeriodLength: "PT432000S"
|
||||
reservedListNames: []
|
||||
restoreBillingCost:
|
||||
currency: "USD"
|
||||
amount: 17.00
|
||||
roidSuffix: "COSTMAP"
|
||||
serverStatusChangeBillingCost:
|
||||
currency: "USD"
|
||||
amount: 19.00
|
||||
tldStateTransitions:
|
||||
"1970-01-01T00:00:00.000Z": "GENERAL_AVAILABILITY"
|
||||
tldStr: "costmap"
|
||||
tldType: "REAL"
|
||||
tldUnicode: "costmap"
|
||||
transferGracePeriodLength: "PT432000S"
|
||||
@@ -0,0 +1,59 @@
|
||||
addGracePeriodLength: "PT432000S"
|
||||
allowedFullyQualifiedHostNames: []
|
||||
allowedRegistrantContactIds: []
|
||||
anchorTenantAddGracePeriodLength: "PT2592000S"
|
||||
autoRenewGracePeriodLength: "PT3888000S"
|
||||
automaticTransferLength: "PT432000S"
|
||||
claimsPeriodEnd: "294247-01-10T04:00:54.775Z"
|
||||
createBillingCost:
|
||||
currency: "USD"
|
||||
amount: 25.00
|
||||
createBillingCostTransitions:
|
||||
"1970-01-01T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 12.00
|
||||
creationTime: "2022-09-01T00:00:00.000Z"
|
||||
currency: "USD"
|
||||
defaultPromoTokens: []
|
||||
dnsAPlusAaaaTtl: "PT900S"
|
||||
dnsDsTtl: null
|
||||
dnsNsTtl: null
|
||||
dnsPaused: false
|
||||
dnsWriters:
|
||||
- "VoidDnsWriter"
|
||||
driveFolderId: "driveFolder"
|
||||
eapFeeSchedule:
|
||||
"1970-01-01T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 0.00
|
||||
escrowEnabled: false
|
||||
idnTables: []
|
||||
invoicingEnabled: false
|
||||
lordnUsername: null
|
||||
numDnsPublishLocks: 1
|
||||
pendingDeleteLength: "PT432000S"
|
||||
premiumListName: "test"
|
||||
pricingEngineClassName: "google.registry.model.pricing.StaticPremiumListPricingEngine"
|
||||
redemptionGracePeriodLength: "PT2592000S"
|
||||
registryLockOrUnlockBillingCost:
|
||||
currency: "USD"
|
||||
amount: 0.00
|
||||
renewBillingCostTransitions:
|
||||
"1970-01-01T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 11.00
|
||||
renewGracePeriodLength: "PT432000S"
|
||||
reservedListNames: []
|
||||
restoreBillingCost:
|
||||
currency: "USD"
|
||||
amount: 17.00
|
||||
roidSuffix: "DIFFMAP"
|
||||
serverStatusChangeBillingCost:
|
||||
currency: "USD"
|
||||
amount: 19.00
|
||||
tldStateTransitions:
|
||||
"1970-01-01T00:00:00.000Z": "GENERAL_AVAILABILITY"
|
||||
tldStr: "diffcostmap"
|
||||
tldType: "REAL"
|
||||
tldUnicode: "diffcostmap"
|
||||
transferGracePeriodLength: "PT432000S"
|
||||
@@ -12,6 +12,10 @@ claimsPeriodEnd: "294247-01-10T04:00:54.775Z"
|
||||
createBillingCost:
|
||||
currency: "USD"
|
||||
amount: 13.00
|
||||
createBillingCostTransitions:
|
||||
"1970-01-01T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 13.00
|
||||
creationTime: "2022-09-01T00:00:00.000Z"
|
||||
currency: "USD"
|
||||
defaultPromoTokens: []
|
||||
|
||||
@@ -8,6 +8,10 @@ claimsPeriodEnd: "294247-01-10T04:00:54.775Z"
|
||||
createBillingCost:
|
||||
currency: "JPY"
|
||||
amount: 250
|
||||
createBillingCostTransitions:
|
||||
"1970-01-01T00:00:00.000Z":
|
||||
currency: "JPY"
|
||||
amount: 250
|
||||
creationTime: "2022-09-01T00:00:00.000Z"
|
||||
currency: "JPY"
|
||||
defaultPromoTokens: []
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
addGracePeriodLength: "PT432000S"
|
||||
allowedFullyQualifiedHostNames: []
|
||||
allowedRegistrantContactIds: []
|
||||
anchorTenantAddGracePeriodLength: "PT2592000S"
|
||||
autoRenewGracePeriodLength: "PT3888000S"
|
||||
automaticTransferLength: "PT432000S"
|
||||
claimsPeriodEnd: "294247-01-10T04:00:54.775Z"
|
||||
createBillingCost:
|
||||
currency: "USD"
|
||||
amount: 25.00
|
||||
creationTime: "2022-09-01T00:00:00.000Z"
|
||||
currency: "USD"
|
||||
defaultPromoTokens: []
|
||||
dnsAPlusAaaaTtl: "PT900S"
|
||||
dnsDsTtl: null
|
||||
dnsNsTtl: null
|
||||
dnsPaused: false
|
||||
dnsWriters:
|
||||
- "VoidDnsWriter"
|
||||
driveFolderId: "driveFolder"
|
||||
eapFeeSchedule:
|
||||
"1970-01-01T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 0.00
|
||||
escrowEnabled: false
|
||||
idnTables: []
|
||||
invoicingEnabled: false
|
||||
lordnUsername: null
|
||||
numDnsPublishLocks: 1
|
||||
pendingDeleteLength: "PT432000S"
|
||||
premiumListName: "test"
|
||||
pricingEngineClassName: "google.registry.model.pricing.StaticPremiumListPricingEngine"
|
||||
redemptionGracePeriodLength: "PT2592000S"
|
||||
registryLockOrUnlockBillingCost:
|
||||
currency: "USD"
|
||||
amount: 0.00
|
||||
renewBillingCostTransitions:
|
||||
"1970-01-01T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 11.00
|
||||
renewGracePeriodLength: "PT432000S"
|
||||
reservedListNames: []
|
||||
restoreBillingCost:
|
||||
currency: "USD"
|
||||
amount: 17.00
|
||||
roidSuffix: "NOCREATE"
|
||||
serverStatusChangeBillingCost:
|
||||
currency: "USD"
|
||||
amount: 19.00
|
||||
tldStateTransitions:
|
||||
"1970-01-01T00:00:00.000Z": "GENERAL_AVAILABILITY"
|
||||
tldStr: "nocreatecostmap"
|
||||
tldType: "REAL"
|
||||
tldUnicode: "nocreatecostmap"
|
||||
transferGracePeriodLength: "PT432000S"
|
||||
@@ -8,6 +8,13 @@ claimsPeriodEnd: "294247-01-10T04:00:54.775Z"
|
||||
createBillingCost:
|
||||
currency: "USD"
|
||||
amount: 25.00
|
||||
createBillingCostTransitions:
|
||||
"1970-01-01T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 8.00
|
||||
"2020-01-01T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 25.00
|
||||
creationTime: "2022-09-01T00:00:00.000Z"
|
||||
currency: "USD"
|
||||
defaultPromoTokens: []
|
||||
|
||||
@@ -8,6 +8,10 @@ claimsPeriodEnd: "294247-01-10T04:00:54.775Z"
|
||||
createBillingCost:
|
||||
currency: "USD"
|
||||
amount: 25.00
|
||||
createBillingCostTransitions:
|
||||
"1970-01-01T00:00:00.000Z":
|
||||
currency: "USD"
|
||||
amount: 25.00
|
||||
creationTime: "2022-09-01T00:00:00.000Z"
|
||||
currency: "USD"
|
||||
defaultPromoTokens: []
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -150,3 +150,5 @@ V149__add_bsa_domain_in_use_table.sql
|
||||
V150__add_tld_bsa_enroll_date.sql
|
||||
V151__add_bsa_unblockable_domain_table.sql
|
||||
V152__add_bsa_domain_refresh_table.sql
|
||||
V153__drop_bsa_domain_in_use_table.sql
|
||||
V154__add_create_billing_cost_transitions_to_tld.sql
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
-- Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||
--
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License");
|
||||
-- you may not use this file except in compliance with the License.
|
||||
-- You may obtain a copy of the License at
|
||||
--
|
||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
||||
--
|
||||
-- Unless required by applicable law or agreed to in writing, software
|
||||
-- distributed under the License is distributed on an "AS IS" BASIS,
|
||||
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
-- See the License for the specific language governing permissions and
|
||||
-- limitations under the License.
|
||||
|
||||
DROP TABLE IF EXISTS "BsaDomainInUse";
|
||||
@@ -0,0 +1,15 @@
|
||||
-- Copyright 2024 The Nomulus Authors. All Rights Reserved.
|
||||
--
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License");
|
||||
-- you may not use this file except in compliance with the License.
|
||||
-- You may obtain a copy of the License at
|
||||
--
|
||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
||||
--
|
||||
-- Unless required by applicable law or agreed to in writing, software
|
||||
-- distributed under the License is distributed on an "AS IS" BASIS,
|
||||
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
-- See the License for the specific language governing permissions and
|
||||
-- limitations under the License.
|
||||
|
||||
ALTER TABLE "Tld" ADD COLUMN create_billing_cost_transitions hstore;
|
||||
@@ -740,6 +740,7 @@
|
||||
claims_period_end timestamptz not null,
|
||||
create_billing_cost_amount numeric(19, 2),
|
||||
create_billing_cost_currency text,
|
||||
create_billing_cost_transitions hstore,
|
||||
creation_time timestamptz not null,
|
||||
currency text not null,
|
||||
default_promo_tokens text[],
|
||||
|
||||
@@ -123,18 +123,6 @@ CREATE TABLE public."BillingRecurrence" (
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: BsaDomainInUse; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public."BsaDomainInUse" (
|
||||
label text NOT NULL,
|
||||
tld text NOT NULL,
|
||||
creation_time timestamp with time zone NOT NULL,
|
||||
reason text NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: BsaDomainRefresh; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
@@ -1190,7 +1178,8 @@ CREATE TABLE public."Tld" (
|
||||
dns_ns_ttl interval,
|
||||
idn_tables text[],
|
||||
breakglass_mode boolean DEFAULT false NOT NULL,
|
||||
bsa_enroll_start_time timestamp with time zone
|
||||
bsa_enroll_start_time timestamp with time zone,
|
||||
create_billing_cost_transitions public.hstore
|
||||
);
|
||||
|
||||
|
||||
@@ -1369,14 +1358,6 @@ ALTER TABLE ONLY public."BillingRecurrence"
|
||||
ADD CONSTRAINT "BillingRecurrence_pkey" PRIMARY KEY (billing_recurrence_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: BsaDomainInUse BsaDomainInUse_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public."BsaDomainInUse"
|
||||
ADD CONSTRAINT "BsaDomainInUse_pkey" PRIMARY KEY (label, tld);
|
||||
|
||||
|
||||
--
|
||||
-- Name: BsaDomainRefresh BsaDomainRefresh_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
@@ -2781,14 +2762,6 @@ ALTER TABLE ONLY public."DomainHistoryHost"
|
||||
ADD CONSTRAINT fka9woh3hu8gx5x0vly6bai327n FOREIGN KEY (domain_history_domain_repo_id, domain_history_history_revision_id) REFERENCES public."DomainHistory"(domain_repo_id, history_revision_id) DEFERRABLE INITIALLY DEFERRED;
|
||||
|
||||
|
||||
--
|
||||
-- Name: BsaDomainInUse fkbsadomaininuse2label; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public."BsaDomainInUse"
|
||||
ADD CONSTRAINT fkbsadomaininuse2label FOREIGN KEY (label) REFERENCES public."BsaLabel"(label) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: BsaUnblockableDomain fkbsaunblockabledomainlabel; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -40,37 +40,22 @@ where:
|
||||
show show the effect of the formatting as unified diff"
|
||||
|
||||
SCRIPT_DIR="$(realpath $(dirname $0))"
|
||||
JAR_NAME="google-java-format-1.8-all-deps.jar"
|
||||
JAR_NAME="google-java-format-1.19.2-all-deps.jar"
|
||||
|
||||
# Make sure we have a valid python interpreter.
|
||||
if [ -z "$PYTHON" ]; then
|
||||
echo "You must specify the name of a python3 interpreter in the PYTHON" \
|
||||
echo "You must specify the name of a Python interpreter in the PYTHON" \
|
||||
"environment variable."
|
||||
exit 1
|
||||
elif ! "$PYTHON" -c ''; then
|
||||
echo "Invalid python interpreter: $PYTHON"
|
||||
echo "Invalid Python interpreter: $PYTHON"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Locate the java binary.
|
||||
if [ -n "$JAVA_HOME" ]; then
|
||||
JAVA_BIN="$JAVA_HOME/bin/java"
|
||||
if [ ! -x "$JAVA_BIN" ]; then
|
||||
echo "No java binary found in JAVA_HOME (JAVA_HOME is $JAVA_HOME)"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# Use java from the path.
|
||||
JAVA_BIN="$(which java)" || JAVA_BIN=""
|
||||
if [ -z "$JAVA_BIN" ]; then
|
||||
echo "JAVA_HOME is not defined and java was not found on the path"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! "$JAVA_BIN" -version 2>&1 | grep 'version "11\.' >/dev/null; then
|
||||
echo "Bad java version. Requires java 11, got:"
|
||||
"$JAVA_BIN" -version
|
||||
# Make sure we have a valid JRE binary
|
||||
if [ -z "$JAVA" ]; then
|
||||
echo "You must specify the name of a JRE binary in the JAVA" \
|
||||
"environment variable."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -80,7 +65,7 @@ function runGoogleJavaFormatAgainstDiffs() {
|
||||
|
||||
git diff -U0 "$forkPoint" | \
|
||||
"${PYTHON}" "${SCRIPT_DIR}/google-java-format-diff.py" \
|
||||
--java-binary "$JAVA_BIN" \
|
||||
--java-binary "$JAVA" \
|
||||
--google-java-format-jar "${SCRIPT_DIR}/${JAR_NAME}" \
|
||||
-p1 "$@" | \
|
||||
tee gjf.out
|
||||
|
||||
@@ -50,7 +50,7 @@ import javax.persistence.Converter;
|
||||
|
||||
/** Processor to generate {@link AttributeConverter} for {@code VKey} type. */
|
||||
@SupportedAnnotationTypes("google.registry.persistence.WithVKey")
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_17)
|
||||
public class VKeyProcessor extends AbstractProcessor {
|
||||
|
||||
private static final String CONVERTER_CLASS_NAME_TEMP = "VKeyConverter_%s";
|
||||
|
||||
@@ -29,6 +29,12 @@ steps:
|
||||
mv $${JAVA_HOME}/bin/javac $${JAVA_HOME}/bin/javac.real
|
||||
cp ./kythe/extractors/javac-wrapper.sh $${JAVA_HOME}/bin/javac
|
||||
export JAVAC_EXTRACTOR_JAR="$${PWD}/kythe/extractors/javac_extractor.jar"
|
||||
jvmopts="--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED"
|
||||
jvmopts="$${jvmopts} --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED"
|
||||
jvmopts="$${jvmopts} --add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED"
|
||||
jvmopts="$${jvmopts} --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED"
|
||||
jvmopts="$${jvmopts} --add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED"
|
||||
export KYTHE_JAVA_RUNTIME_OPTIONS=$${jvmopts}
|
||||
export KYTHE_VNAMES="$${PWD}/vnames.json"
|
||||
export KYTHE_ROOT_DIRECTORY="$${PWD}"
|
||||
export KYTHE_OUTPUT_DIRECTORY="$${PWD}/kythe_output"
|
||||
|
||||
@@ -91,7 +91,7 @@ steps:
|
||||
--format="get(digest)" --filter="tags = ${TAG_NAME}")
|
||||
sed -i s/'prober_cert_updater:latest'/prober_cert_updater@$digest/g \
|
||||
release/cloudbuild-renew-prober-certs-*.yaml
|
||||
# Build the tld_updater image and upload it to GCR. This image extends
|
||||
# Build the db_object_updater image and upload it to GCR. This image extends
|
||||
# from the `builder` and the nomulus.jar built earlier.
|
||||
- name: 'gcr.io/cloud-builders/docker'
|
||||
entrypoint: /bin/bash
|
||||
@@ -101,14 +101,14 @@ steps:
|
||||
set -e
|
||||
# The nomulus jar is not under the working dir. Must be copied over.
|
||||
cp ../../output/nomulus.jar .
|
||||
docker build -t gcr.io/${PROJECT_ID}/tld_updater:${TAG_NAME} \
|
||||
docker build -t gcr.io/${PROJECT_ID}/db_object_updater:${TAG_NAME} \
|
||||
--build-arg TAG_NAME=${TAG_NAME} --build-arg PROJECT_ID=${PROJECT_ID} .
|
||||
docker tag gcr.io/${PROJECT_ID}/tld_updater:${TAG_NAME} \
|
||||
gcr.io/${PROJECT_ID}/tld_updater:latest
|
||||
docker push gcr.io/${PROJECT_ID}/tld_updater:latest
|
||||
docker push gcr.io/${PROJECT_ID}/tld_updater:${TAG_NAME}
|
||||
dir: 'release/tld-updater/'
|
||||
# Update the tld_updater image digest in relevant GCB files.
|
||||
docker tag gcr.io/${PROJECT_ID}/db_object_updater:${TAG_NAME} \
|
||||
gcr.io/${PROJECT_ID}/db_object_updater:latest
|
||||
docker push gcr.io/${PROJECT_ID}/db_object_updater:latest
|
||||
docker push gcr.io/${PROJECT_ID}/db_object_updater:${TAG_NAME}
|
||||
dir: 'release/db-object-updater/'
|
||||
# Update the db_object_updater image digest in relevant GCB files.
|
||||
- name: 'gcr.io/${PROJECT_ID}/builder:latest'
|
||||
entrypoint: /bin/bash
|
||||
args:
|
||||
@@ -116,10 +116,10 @@ steps:
|
||||
- |
|
||||
set -e
|
||||
digest=$(gcloud container images list-tags \
|
||||
gcr.io/${PROJECT_ID}/tld_updater \
|
||||
gcr.io/${PROJECT_ID}/db_object_updater \
|
||||
--format="get(digest)" --filter="tags = ${TAG_NAME}")
|
||||
sed -i s/'tld_updater:latest'/tld_updater@$digest/g \
|
||||
release/cloudbuild-tld-sync-*.yaml
|
||||
sed -i s/'db_object_updater:latest'/db_object_updater@$digest/g \
|
||||
release/cloudbuild-sync-db-objects-*.yaml
|
||||
# Build and stage Dataflow Flex templates.
|
||||
- name: 'gcr.io/${PROJECT_ID}/builder:latest'
|
||||
entrypoint: /bin/bash
|
||||
@@ -190,7 +190,7 @@ artifacts:
|
||||
- 'release/cloudbuild-renew-prober-certs-*.yaml'
|
||||
- 'release/cloudbuild-schema-deploy-*.yaml'
|
||||
- 'release/cloudbuild-schema-verify-*.yaml'
|
||||
- 'release/cloudbuild-tld-sync-*.yaml'
|
||||
- 'release/cloudbuild-sync-db-objects-*.yaml'
|
||||
|
||||
timeout: 7200s
|
||||
options:
|
||||
|
||||
@@ -139,9 +139,9 @@ steps:
|
||||
gcloud container images list-tags \
|
||||
gcr.io/${PROJECT_ID}/prober_cert_updater \
|
||||
--format='get(digest)' --filter='tags = ${TAG_NAME}')
|
||||
tld_updater_digest=$( \
|
||||
db_object_updater_digest=$( \
|
||||
gcloud container images list-tags \
|
||||
gcr.io/${PROJECT_ID}/tld_updater \
|
||||
gcr.io/${PROJECT_ID}/db_object_updater \
|
||||
--format='get(digest)' --filter='tags = ${TAG_NAME}')
|
||||
sed -i s/builder:latest/builder@$builder_digest/g \
|
||||
release/cloudbuild-schema-deploy.yaml
|
||||
@@ -150,7 +150,7 @@ steps:
|
||||
sed -i s/builder:latest/builder@$builder_digest/g \
|
||||
release/cloudbuild-renew-prober-certs.yaml
|
||||
sed -i s/builder:latest/builder@$builder_digest/g \
|
||||
release/cloudbuild-tld-sync.yaml
|
||||
release/cloudbuild-sync-db-objects.yaml
|
||||
sed -i s/schema_deployer:latest/schema_deployer@$schema_deployer_digest/g \
|
||||
release/cloudbuild-schema-deploy.yaml
|
||||
sed -i s/schema_verifier:latest/schema_verifier@$schema_verifier_digest/g \
|
||||
@@ -163,8 +163,8 @@ steps:
|
||||
> release/cloudbuild-schema-verify-${environment}.yaml
|
||||
sed s/'$${_ENV}'/${environment}/g release/cloudbuild-renew-prober-certs.yaml \
|
||||
> release/cloudbuild-renew-prober-certs-${environment}.yaml
|
||||
sed s/'$${_ENV}'/${environment}/g release/cloudbuild-tld-sync.yaml \
|
||||
> release/cloudbuild-tld-sync-${environment}.yaml
|
||||
sed s/'$${_ENV}'/${environment}/g release/cloudbuild-sync-db-objects.yaml \
|
||||
> release/cloudbuild-sync-db-objects-${environment}.yaml
|
||||
done
|
||||
# Upload the gradle binary to GCS if it does not exist and point URL in gradle wrapper to it.
|
||||
- name: 'gcr.io/cloud-builders/gsutil'
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# This will sync the Tld configurations in the internal repo with the Tld objects in the database.
|
||||
# This will sync the configuration files in the internal repo with their
|
||||
# corresponding objects in the database.
|
||||
#
|
||||
# To manually trigger a build on GCB, run:
|
||||
# gcloud builds submit --config cloudbuild-tld-sync.yaml --substitutions \
|
||||
# gcloud builds submit --config cloudbuild-sync-db-objects.yaml --substitutions \
|
||||
# _INTERNAL_REPO_URL=[URL] ..
|
||||
#
|
||||
# To trigger a build automatically, follow the instructions below and add a trigger:
|
||||
@@ -34,11 +35,26 @@ steps:
|
||||
--secret nomulus-tool-cloudbuild-credential \
|
||||
> nomulus_tool_credential.json
|
||||
# Configure the TLDs using the stored configuration files in the internal repo
|
||||
- name: 'gcr.io/$PROJECT_ID/tld_updater:latest'
|
||||
- name: 'gcr.io/$PROJECT_ID/db_object_updater:latest'
|
||||
args:
|
||||
- ${_ENV}
|
||||
- ./nomulus_tool_credential.json
|
||||
- configure_tld
|
||||
- nomulus-internal/core/src/main/java/google/registry/config/files/tld/
|
||||
# Configure the premium lists using the stored configuration files in the internal repo
|
||||
- name: 'gcr.io/$PROJECT_ID/db_object_updater:latest'
|
||||
args:
|
||||
- ${_ENV}
|
||||
- ./nomulus_tool_credential.json
|
||||
- update_premium_list
|
||||
- nomulus-internal/core/src/main/java/google/registry/config/files/premium/
|
||||
# Configure the reserved lists using the stored configuration files in the internal repo
|
||||
- name: 'gcr.io/$PROJECT_ID/db_object_updater:latest'
|
||||
args:
|
||||
- ${_ENV}
|
||||
- ./nomulus_tool_credential.json
|
||||
- update_reserved_list
|
||||
- nomulus-internal/core/src/main/java/google/registry/config/files/reserved/
|
||||
|
||||
timeout: 7200s
|
||||
options:
|
||||
@@ -17,6 +17,6 @@ ARG TAG_NAME
|
||||
FROM gcr.io/${PROJECT_ID}/builder:${TAG_NAME}
|
||||
|
||||
COPY nomulus.jar /
|
||||
COPY sync_tlds.sh /usr/local/bin
|
||||
COPY sync_db_objects.sh /usr/local/bin
|
||||
|
||||
ENTRYPOINT [ "bash", "sync_tlds.sh" ]
|
||||
ENTRYPOINT [ "bash", "sync_db_objects.sh" ]
|
||||
@@ -13,23 +13,25 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Sync the TLD configuration files from the internal repo with the Tld object
|
||||
# in the database. Loops through the Tld configuration files and runs the configure_tld command
|
||||
# with the file.
|
||||
# Sync the configuration files in the internal repo with the objects in the
|
||||
# database. Loops through the configuration files in the inputted directory and
|
||||
# runs the passed in nomulus update command with the file.
|
||||
|
||||
# - env: The Nomulus environment, production, sandbox, etc.
|
||||
# - tools_credential: The credential (.json) needed to run the nomulus command.
|
||||
# - nomulus_command: The nomulus command to run.
|
||||
# - config_file_directory: The internal directory storing the TLD config files.
|
||||
|
||||
set -e
|
||||
if [ "$#" -ne 3 ]; then
|
||||
echo "Expecting three parameters in order: env tools_credential config_file_directory"
|
||||
if [ "$#" -ne 4 ]; then
|
||||
echo "Expecting four parameters in order: env tools_credential nomulus_command config_file_directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
nomulus_env="${1}"
|
||||
tools_credential="${2}"
|
||||
config_file_directory="${3}"
|
||||
nomulus_command="${3}"
|
||||
config_file_directory="${4}"
|
||||
|
||||
echo ${config_file_directory}
|
||||
|
||||
@@ -37,5 +39,5 @@ for FILE in ${config_file_directory}/${nomulus_env}/*; do
|
||||
echo $FILE
|
||||
java -jar /nomulus.jar -e "${nomulus_env}" \
|
||||
--credential "${tools_credential}" \
|
||||
configure_tld -i $FILE --force
|
||||
"${nomulus_command}" -i $FILE --force --build_environment
|
||||
done
|
||||
Reference in New Issue
Block a user