Commit 8844dd00 authored by nanahira's avatar nanahira

first

parent 21877cc6
Pipeline #244 failed with stages
in 4 minutes and 56 seconds
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
/build
/output
.git*
.dockerignore
Dockerfile
.gitlab-ci.yml
/config.yaml
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
/build
/output
/config.yaml
stages:
- build
- deploy
variables:
GIT_DEPTH: "1"
CONTAINER_TEST_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
CONTAINER_RELEASE_IMAGE: $CI_REGISTRY_IMAGE:latest
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
build:
stage: build
tags:
- docker
script:
- docker build --pull -t $CONTAINER_TEST_IMAGE .
- docker push $CONTAINER_TEST_IMAGE
deploy_latest:
stage: deploy
tags:
- docker
script:
- docker pull $CONTAINER_TEST_IMAGE
- docker tag $CONTAINER_TEST_IMAGE $CONTAINER_RELEASE_IMAGE
- docker push $CONTAINER_RELEASE_IMAGE
only:
- master
deploy_tag:
stage: deploy
tags:
- docker
variables:
CONTAINER_TAG_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
script:
- docker pull $CONTAINER_TEST_IMAGE
- docker tag $CONTAINER_TEST_IMAGE $CONTAINER_TAG_IMAGE
- docker push $CONTAINER_TAG_IMAGE
only:
- tags
FROM node:buster-slim
RUN apt update && apt -y install python3 && rm -rf /var/lib/apt/lists/*
WORKDIR /usr/src/app
COPY ./package*.json ./
RUN npm ci
COPY . ./
RUN npm run build
CMD ["npm", "run", "start"]
This diff is collapsed.
aliyun:
accessKeyId: ""
accessKeySecret: ""
endpoint: "https://alidns.aliyuncs.com"
apiVersion: "2015-01-09"
domain: yuzurisa.com
cdnRecords:
- match: '^cdn-[-a-zA-Z]+$'
port: 443
testDomains:
- ygobbs.com
- nanahira.momobako.com
timeout: 10000
cronString: "0 * * * * *"
{
"name": "cdn-node-checker",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@alicloud/pop-core": {
"version": "1.7.9",
"resolved": "https://registry.npmjs.org/@alicloud/pop-core/-/pop-core-1.7.9.tgz",
"integrity": "sha512-WKeil0O51ee1EbCcYt65vPYo6eWcDn7dfmXlCMb/GbNDq0MvVheQVS/uAeeUipRXt8jGMc58FXeQxXfsFqlRZg==",
"requires": {
"debug": "^3.1.0",
"httpx": "^2.1.2",
"json-bigint": "^0.2.3",
"kitx": "^1.2.1",
"xml2js": "^0.4.17"
}
},
"@types/cron": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/@types/cron/-/cron-1.7.2.tgz",
"integrity": "sha512-AEpNLRcsVSc5AdseJKNHpz0d4e8+ow+abTaC0fKDbAU86rF1evoFF0oC2fV9FdqtfVXkG2LKshpLTJCFOpyvTg==",
"requires": {
"@types/node": "*",
"moment": ">=2.14.0"
}
},
"@types/node": {
"version": "14.0.14",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.14.tgz",
"integrity": "sha512-syUgf67ZQpaJj01/tRTknkMNoBBLWJOBODF0Zm4NrXmiSuxjymFrxnTu1QVYRubhVkRcZLYZG8STTwJRdVm/WQ=="
},
"@types/underscore": {
"version": "1.10.3",
"resolved": "https://registry.npmjs.org/@types/underscore/-/underscore-1.10.3.tgz",
"integrity": "sha512-WgNbx0H2QO4ccIk2R1aWkteETuPxSa9OYKXoYujBgc0R4u+d2PWsb9MPpP77H+xqwbCXT+wuEBQ/6fl6s4C0OA=="
},
"@types/yaml": {
"version": "1.9.7",
"resolved": "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz",
"integrity": "sha512-8WMXRDD1D+wCohjfslHDgICd2JtMATZU8CkhH8LVJqcJs6dyYj5TGptzP8wApbmEullGBSsCEzzap73DQ1HJaA==",
"requires": {
"yaml": "*"
}
},
"axios": {
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
"requires": {
"follow-redirects": "1.5.10"
}
},
"bignumber.js": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.1.0.tgz",
"integrity": "sha512-eJzYkFYy9L4JzXsbymsFn3p54D+llV27oTQ+ziJG7WFRheJcNZilgVXMG0LoZtlQSKBsJdWtLFqOD0u+U0jZKA=="
},
"cron": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/cron/-/cron-1.8.2.tgz",
"integrity": "sha512-Gk2c4y6xKEO8FSAUTklqtfSr7oTq0CiPQeLBG5Fl0qoXpZyMcj1SG59YL+hqq04bu6/IuEA7lMkYDAplQNKkyg==",
"requires": {
"moment-timezone": "^0.5.x"
}
},
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"requires": {
"ms": "^2.1.1"
}
},
"follow-redirects": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
"requires": {
"debug": "=3.1.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"httpx": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/httpx/-/httpx-2.2.4.tgz",
"integrity": "sha512-looS7tQlnLtXCxV5s/L9hshrrFiY/8IDQ2mIt7FnK/Bll2qDEjWPLsuRmZ6ZOXJZZZ1turs5Pf0d9vzUrPkqOw==",
"requires": {
"@types/node": "^12.0.2",
"debug": "^4.1.1"
},
"dependencies": {
"@types/node": {
"version": "12.12.47",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.47.tgz",
"integrity": "sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A=="
},
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"requires": {
"ms": "^2.1.1"
}
}
}
},
"json-bigint": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.2.3.tgz",
"integrity": "sha1-EY1/b/HThlnxn5TPc+ZKdaP5iKg=",
"requires": {
"bignumber.js": "^4.0.0"
}
},
"kitx": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/kitx/-/kitx-1.3.0.tgz",
"integrity": "sha512-fhBqFlXd0GkKTB+8ayLfpzPUw+LHxZlPAukPNBD1Om7JMeInT+/PxCAf1yLagvD+VKoyWhXtJR68xQkX/a0wOQ=="
},
"moment": {
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz",
"integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ=="
},
"moment-timezone": {
"version": "0.5.31",
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.31.tgz",
"integrity": "sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==",
"requires": {
"moment": ">= 2.9.0"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"typescript": {
"version": "3.9.6",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.6.tgz",
"integrity": "sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw=="
},
"underscore": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.10.2.tgz",
"integrity": "sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg=="
},
"xml2js": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
"requires": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
}
},
"xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
},
"yaml": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz",
"integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg=="
}
}
}
{
"name": "cdn-node-checker",
"version": "1.0.0",
"description": "Check CDN nodes and update AliDNS records.",
"main": "build/run.js",
"scripts": {
"build": "./node_modules/.bin/tsc",
"start": "node build/run.js"
},
"repository": {
"type": "git",
"url": "git@git.mycard.moe:nanahira/cdn-node-checker.git"
},
"author": "Nanahira",
"license": "GPL-3.0",
"dependencies": {
"@alicloud/pop-core": "^1.7.9",
"@types/cron": "^1.7.2",
"@types/node": "^14.0.14",
"@types/underscore": "^1.10.3",
"@types/yaml": "^1.9.7",
"axios": "^0.19.2",
"cron": "^1.8.2",
"typescript": "^3.9.6",
"underscore": "^1.10.2",
"yaml": "^1.10.0"
}
}
import Aliyun from "@alicloud/pop-core";
import axios from "axios";
import _ from "underscore";
import YAML from "yaml";
import fs from "fs";
import {CronJob} from "cron";
interface CDNRecord {
match: string;
port: number;
}
interface Config {
aliyun: Aliyun.Config;
domain: string;
cdnRecords: CDNRecord[];
testDomains: string[];
timeout: number;
cronString: string;
}
interface DomainRecordObject {
Record: DomainRecord[];
}
interface DomainRecordReturnResult {
RequestId: string;
TotalCount: number;
PageNumber: number;
PageSize: number;
DomainRecords: DomainRecordObject;
}
interface DomainRecord {
DomainName: string;
RecordId: string;
RR: string;
Type: string;
Value: string;
TTL: number;
Priority: number;
Line: string;
Status: string;
Locked: boolean;
Weight: number;
Remark: string;
}
interface DomainRecordInfo {
record: DomainRecord;
port: number;
}
let config: Config;
let client: Aliyun;
let cdnRecordsRegex: RegExp[];
const requestOption = {
method: "POST"
}
async function getRecords(): Promise<DomainRecordInfo[]> {
console.log(`Fetching domain records of ${config.domain}.`)
const res: DomainRecordInfo[] = [];
for (let i = 1; ; ++i) {
const ret: DomainRecordReturnResult = await client.request("DescribeDomainRecords", {
DomainName: config.domain,
PageNumber: i,
PageSize: 500,
}, requestOption);
console.log(ret.TotalCount);
if (!ret.DomainRecords.Record.length) {
break;
}
for (let record of ret.DomainRecords.Record.filter(m => {
return m.RR && m.Type === "CNAME" && _.any(cdnRecordsRegex, r => !!m.RR.match(r)) && _.every(cdnRecordsRegex, r => {
if (!m.Value.endsWith(config.domain)) {
return true;
}
const valuePrefix = m.Value.slice(0, m.Value.length - 1 - config.domain.length);
return !valuePrefix.match(r);
});
})) {
const port = _.find(config.cdnRecords, r => record.RR.match(r.match)).port;
console.log(`Found record ${record.RR}.${config.domain} => ${record.Value}:${port}.`);
res.push({record, port});
}
}
return res;
}
async function checkNode(address: string, port: number): Promise<boolean> {
let currentTestDomain: string;
try {
for (let testDomain of config.testDomains) {
currentTestDomain = testDomain;
await axios.get(`https://${address}:${port}`, {
headers: {
Host: testDomain
},
timeout: config.timeout,
validateStatus: status => status < 500
});
}
console.log(`Node ${address} is good.`);
return true;
} catch (e) {
console.log(`Node ${address} is bad: ${currentTestDomain} => ${e.toString()}`);
return false;
}
}
async function checkRecord(recordInfo: DomainRecordInfo) {
const record = recordInfo.record;
console.log(`Checking record ${record.RR}.${config.domain} ${record.Value}:${recordInfo.port} with old status of ${record.Status}.`)
const status = record.Status;
const targetStatus = (await checkNode(record.Value, recordInfo.port)) ? "ENABLE" : "DISABLE";
if (status != targetStatus) {
console.log(`Changing record status of ${record.RR}.${config.domain} ${record.Value}:${recordInfo.port} from ${status} to ${targetStatus}.`);
await client.request("SetDomainRecordStatus", {
RecordId: record.RecordId,
Status: targetStatus
}, requestOption);
}
}
async function run() {
console.log(`Started.`);
const records = await getRecords();
await Promise.all(records.map(checkRecord));
console.log(`Finished.`);
}
async function main() {
config = YAML.parse(await fs.promises.readFile("./config.yaml", "utf8"));
client = new Aliyun(config.aliyun);
cdnRecordsRegex = config.cdnRecords.map(m => new RegExp(m.match));
//await run();
(new CronJob(config.cronString, run, null, true, "Asia/Shanghai", null, true)).start();
}
main();
{
"compilerOptions": {
"outDir": "build",
"module": "commonjs",
"target": "esnext",
"esModuleInterop": true,
"sourceMap": true
},
"compileOnSave": true,
"allowJs": true,
"include": [
"*.ts"
]
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment