지돌이의 블로그 입니다!

https://www.npmjs.com/package/asn1-stream

 

asn1-stream

ASN1 parser with a stream interface

www.npmjs.com

asn1을 stream으로 파싱하는걸 찾았는데 없네요...

infinite length 파싱은 구현은 대충 해 놓았지만 동작하지 않을겁니다...

ASN1에 대해 잘 아시는 분은 infinite length 을 사용하는 예제 Payload좀 만들어 주세요...ㅠㅠ

아님 구현하셔서 PR주시면 매우감사!

Comment +1

  • 참고로.. 최상위 객체만 next stream으로 출력하기 때문에 최상위 객체속에 여러 객체가 있고 큰 데이터가 있으면 메모리 이슈가 발생할 수 있습니다.
    asn1으로 대용량 데이터 전송 스키마를 만드신다면 최상위 객체에 데이터를 잘라서(chunk) 길게 전달해야 합니다.

ResourceHandlerRegistry의 setOrder(0)을 줬더니 이걸 먼저 타버린다...ㅠㅠ

 

덕분에 몇시간동안 삽질을..

 

 

 

Comment +0

node.js를 runtime그대로 사용하지 않고 libnode를 이용해서 C++ Project내에 embedding하여 사용하고 있습니다.

이에 대해서는 제가 만든 node-app 소스를 이용하여 쉽게 접근할 수 있습니다.

일단 일반적인 상황에서는 테스트를 해 보았고 잘 동작하는거 같습니다만...

몇가지 Issue들이 있으며, 최근 Worker를 활용하면서 몇 가지 큰 이슈 상황이 있습니다.

(필독) 일단 기본적인 embedding에 대해

* 필수적으로 tracing관련하여 Fix된 commit을 적용해야 합니다.

#PR 31217 코멘트를 참고해 주세요. 이 PR을 모티브해서 감사하게도 #PR 31245 을 올려주셨습니다.

* NODE_USE_V8_PLATFORM=1 으로 빌드된 경우 문제되는 상황이 있습니다.

NODE_USE_V8_PLATFORM=1인 경우 libnode 내부적으로 per_process::v8_platform(export되지 않아 외부에서 사용할 수 없는 객체)을 이용하는 부분이 몇군데 있습니다. 따라서 v8_platform으로 초기화하지 않은경우 Crash가 발생하게 됩니다.

* node.js Javascript 코드 종료시 Crash 발생

제가 올린 PR #31260 에 해당 내용을 적어놓았습니다. PR은 통과되지 못하였고, 사실 좋은 방법도 아니며 Test도 통과하지 못합니다.

하지만 임시 방편으로 전 사용중입니다.

DisposePlatform() 함수를 호출하면 per_process::v8_platform.Dispose()을 하는데 v8_platform을 통해 초기화 되었는지 확인하지 않고 무조건 호출하기 때문에 v8_platform을 사용하지 못하고 직접 CreateEnvironment한 경우 Crash가 발생합니다.

threads_worker관련 Issue사항들

Embedding하여 node를 사용하면서 Worker를 사용할 때 필수적인 부분이 있습니다.

구 버전의 node인 경우 위에 v8_platform과 연관된것인데 worker의 isolate를 생성하면서 v8_platform의 Platform을 사용하는 문제가 있습니다.

따라서 6db45bf7def22eedfd95dac95713e850c366b169 커밋 이후 버전으로 빌드된 libnode.dll이 필요합니다. (PR #31217 코멘트 참고)

* Inspect초기화 문제 (Critical)

Issue #31256를 참고해 주세요.

PR #30467을 통해 해결될 수 있는데 아직 머지되지 못하였으며 코멘트들을 보면 참 많은 의견들이 있습니다..

그리고 그 사이에 또 변한 부분들이 여럿 있어서 v13 브랜치에 머지하면 현재는 다른 부분들에서 문제가 발생하기도 합니다.

저두 코드를 고쳐가며 나름 테스트를 해 보고 있습니다..

하지만 아직 Embedding환경에서 Worker사용은 시기상조인거 같습니다.

많은 분들이 관심을 가지고 nodejs측에 관심을 표현해 주심 빨리 해결되리라 생각합니다..!

참고로.. 문제가 발생하단 부분은 NodeZeroIsolateTestFixture.IsolatePlatformDelegateTest 테스트 실패인데,

(그나저나 일단 Environment Test에서 commit 1350eea23ad1da56d26bc60213734a264439aaa6 Fix가 필요하고..)

PR #30324 해당 내용 때문입니다.
PR #30467에서 FreeEnvironment할 때 DrainTasks가 추가되었는데, IsolatePlatformDelegate을 통해 Isolate를 Register했을 때 node_platform.cc의 ForNodeIsolate에서 오류가 발생합니다. shared_ptr\<PerIsolatePlatformData\>가 없기 때문에...

commit 8ab6756984c36d8b69732a71a2df5d28b03c3db5제대로된 방법일진 모르겠으나 Test는 통과합니다.

참고로 Embedding과 별개로 문제가 발생하는 경우가 있는데 PR #31215 이런 상황입니다.

그냥 제 예상으로는 worker사용시 v8 compilation cache관련하여 문제가 생기는게 아닌가 그냥 추측만 해 봅니다.

정확하게는 분석해보지 못해서 알지 못하겠구요..

암튼 코드엔 문제가 없지만 v8 engine이 잘못 해석할 수 있는 코드는 조심해야 할 것 같습니다.

저두 코드를 수정하여 해결하였습니다.

Comment +0

Error: UnsupportedEnvironment 오류

 

아마 js-crypto 라이브러리에서 오류가 날 것이다.

 

이런경우 npm install --save webcrypto-liner 를 설치하면 된다.

Comment +0

BTRFS 복구

개발 및 운영2019. 11. 22. 16:05

https://ownyourbits.com/2019/03/03/how-to-recover-a-btrfs-partition/

 

잘 설명되어있는 사이트!

 

# btrfs restore /dev/sdXY /restore/

 

마운트가 안되는 상태에서 위 명령어로 복구 가능

 

--- 아래는 번역

 

오류가 나면... 먼저 scrubing을 시도 합니다. 체크섬을 사용하여 데이터 무결성을 검사하고 손상된 데이터를 복구하려고 시도합니다. scrubing는 안전한 것으로 간주되며 일반적으로 가장 먼저 시도해야 합니다.

 

scrub 시작

# btrfs scrub start /mnt

 

scrub 상태보기

# btrfs scrub status /mnt

 

일반적으로 몇 시간이 걸립니다

이렇게 하면 가능한 한 많이 해결되지만 모든 문제를 해결하지 못할 수도 있습니다. 오류가 발생한 경우 안전을 위해 다시 복사하십시오. 아마도 우리는 많은 파일을 고쳤을 것이고 아마도 모든 파일을 고쳤을 것입니다.

 

 

... 원문을 보시길..ㅜㅜ

 

무엇보다... RAID를 쓰는 것 중요합니다. (RAID-1 이상)

그리고 RAID카드에 Backup Battrry도 꼭 다시구..

UPS는 필수입니다!

Comment +0

Kubernetes에서 사용할 Deployment/Service설정 yaml을 온라인 상에서 GUI로 만들 수 있게ㅜ도와주는걸 만들었습니다.

 

https://jc-lab.github.io/auto-generator/#/

 

kube-yaml-generator

 

jc-lab.github.io

 

github에 소스 공개되어 있으니 기능 추가 및 개선 PR주심 넘나 감사!

 

 

https://github.com/jc-lab/auto-generator/

 

jc-lab/auto-generator

Contribute to jc-lab/auto-generator development by creating an account on GitHub.

github.com

 

Comment +0

openpgp을 사용하는 프로젝트를 webpack으로 번들링하면 아래와 같은 오류가 발생한다.

Error: Cannot find module 'stream'
    at o (/bundle.js:4293:292)
    at /bundle.js:4293:449
    at Object.<anonymous> (/bundle.js:28885:38)
    at Object.76.stream (/bundle.js:28943:4)
    at o (/bundle.js:4293:398)
    at /bundle.js:4293:449
    at Object.<anonymous> (/bundle.js:28422:13)
    at Object.75../node-conversions (/bundle.js:28875:4)
    at o (/bundle.js:4293:398)
    at /bundle.js:4293:449

이런 경우 Webpack에서 openpgp패키지의 dist대신 src를 쓰게 하고

const webpack = require('webpack');
const path = require('path');

module.exports = {
    target: 'node',
    mode: 'production',
    entry: {
        main: './src/index.ts'
    },
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist'),
        libraryTarget: 'commonjs2'
    },
    devtool: 'source-map',
    resolve: {
        extensions: ['.ts', '.tsx', '.js'],
        alias: {
            '@src': path.resolve(__dirname, 'src')
        }
    },
    externals: {
        'crypto': 'commonjs crypto',
        'fs': 'commonjs fs',
        'stream': 'commonjs stream'
    },
    module: {
        rules: [
            // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader`
            { test: /\.tsx?$/, loader: "ts-loader" },

            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules\/(?!(openpgp)\/).*/,
                include: [
                    path.resolve(__dirname, "src"),
                    path.resolve(__dirname, "node_modules/openpgp")
                ],
                options: {
                    plugins: ['dynamic-import-webpack']
                }
            },
        ]
    },
    resolve: {
        modules: ['node_modules', 'src'],
        extensions: ['.js', '.json', '.jsx', '.ts'],
        alias: {
            openpgp: 'openpgp/src/index.js',
            'tweetnacl/nacl-fast-light.js': 'tweetnacl/nacl-fast.js'
        }
    },
    plugins: [
        new webpack.ContextReplacementPlugin(
            /openpgp/,
            '',
            {
                crypto: 'crypto',
                stream: 'stream',
                buffer: 'buffer',
                zlib: 'zlib',
                util: 'util'
            }
        )
    ],
    optimization: {
        minimize: false
    }
};

 

필요한 dependency들을 추가해주면 된다.

package.json의 dependencies에

    "asmcrypto.js": "github:openpgpjs/asmcrypto#6e4e407b9b8ae317925a9e677cc7b4de3e447e83",
    "elliptic": "github:openpgpjs/elliptic#6b7801573b8940a49e7b8253176ece2725841efd",
    "email-addresses": "github:openpgpjs/email-addresses#686743c6452b44bafcd06d47db7f36ddf3f3f118",

추가한다.

(주의할점은 그냥 npm install 으로 설치하면 안되고 openpgpjs의 github 리포지터리에서 가져와야 한다. 기존의 패키지를 openpgp에서 수정해서 쓰는것이기 때문)

그리고

$ npm update

$ npm install --save web-stream-tools tweetnacl text-encoding-utf-8 @mattiasbuelens/web-streams-polyfill

Comment +0

 INFO  Launching Electron...
internal/modules/cjs/loader.js:630
    throw err;
    ^
Error: Cannot find module 'electron'
Require stack:
- ...\electron-output\index.js
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:627:15)
    at Function.Module._load (internal/modules/cjs/loader.js:531:27)
    at Module.require (internal/modules/cjs/loader.js:685:19)
    at require (internal/modules/cjs/helpers.js:16:16)
    at eval (webpack:///external_%22electron%22?:1:18)
    at Object.electron (...\electron-output\index.js:2146:1)
    at __webpack_require__ (...\electron-output\index.js:20:30)
    at eval (webpack:///./background/background.ts?:3:66)
    at Module../background/background.ts (...\electron-output\index.js:133:1)
    at __webpack_require__ (...\electron-output\index.js:20:30) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    ...\\electron-output\\index.js'
  ]
}
Done in 26.02s.

ELECTRON_RUN_AS_NODE 환경변수를 확인해 보아야 한다.

(Windows 환경임)

> set ELECTRON_RUN_AS_NODE=0

이건 node로 실행하지 않겠다는 뜻이지만...

> set ELECTRON_RUN_AS_NODE=0

이게 있으면 위와 같은 문제가 발생한다...ㅠㅠ 겁나 삽질함....

Comment +0

https://gist.github.com/jc-lab/b80aa4183c0f8c3971260ac2ee49443d

 

AWS NAT Instance configure-pat.sh for Keep source ip

AWS NAT Instance configure-pat.sh for Keep source ip - configure-pat.sh

gist.github.com

기존에는 configure-pat.sh에

 

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

으로 되어있는데 이러면 내/외부 모든 패킷에 MASQUERADE가 적용되어 DNAT를 이용한 Port Forwarding시 Source IP가 NAT Instance의 IP으로 변하게 됩니다.

따라서 MySQL의 User에 IP Rule이 적용되어있으면 로그인 할 수 없게 되죠..

이를 해결하기 위해서는 외부망으로 다시 나가는 패킷에만 MASQUERADE를 해야 하는데

iptables -t nat -A POSTROUTING -o eth0 ! -d 내부망 MASQUERADE 으로 바꿔야 합니다.

Cloud 환경은 친절하게도 metadata url을 지원해서 내부망 IP를 자동으로 가져올 수 있습니다.

자동으로 위 처리를 해주는 스크립트로 변경하였습니다.

 

AWS에서 이렇게 진즉에 적용해주었음 참 고마웠을텐데요...

 

(그나저나 여담으로.. 뉴스는 안나왔지만 어제 밤 8시쯤 넘어서 언젠가.. 잠깐 AWS Console에 장애가 있었네요..

로그인도 안되고 창도 엄청 늦게 뜨거나 안나오고.. EC2/Lambda등 서비스에서는 문제없고 AWS Console에만 문제가 있었습니다. Console만져야 하는데 긴장좀 탔네요..ㅠㅠ)

Comment +0

요즘 AWS Lambda를 써보는데 기본적인 걸로 삽질을 했다..ㅋㅋ

1. VPC의 Subnet는 기본적으로 서로 통신이 가능하다.

삽질한 내용은 아니지만 기본적인 내용인데 인터넷을 보면 잘못 설명한 글이 몇몇 있었다.

한 VPC내의 모든 Subnet들은 라우터로 연결된 것으로 묘사되는데 서로 통신이 가능하단 뜻이다.

2. API Gateway이랑 연동할 때 Lambda에서 Timeout발생시 502 Bad Gateway가 뜬다.

3. Security Group는 Rule이 없으면 기본적으로 모든 Inbound를 거부한다.

4. Lambda를 VPC로 연결했을 때 기본적으로 AWS Service에 연결할 수 없다.

따라서 VPC에 Endpoint를 만들어서 외부 endpoint가 아닌 VPC 내부의 endpoint를 타도록 해야 한다.

여기서 VPC에 Endpoint만들 때 Security Group선택하는데 443포트에 대한 Inbound를 허용해야 한다.

그리고 DNS가 활성화되기 때문에 lambda 소스에서 따로 endpoint를 지정해줄 필요는 없다. ({service}.{region}.amazonaws.com 이 자동으로 VPC Endpoint IP로 Resolve된다)

5. UnrecognizedClientException: The security token included in the request is invalid. 오류시...

    await new Promise((resolve, reject) => {
        AWS.config.getCredentials(function(err) {
            if (err)
                reject(err);
            else {
                resolve();
            }
        });
    });
    const kms = new AWS.KMS({
        credentials: AWS.config.credentials // 필요!
    }));

6. Private Subnet에서 실행중인 Lambda는 다른 Lambda를 호출할 수 없다.

4번과 같은 문제인데 진짜 문제는 AWS PrivateLink에 Lambda 서비스 (lambda.{region}.amazonaws.com)가 없다는 것이다.

따라서 Private Subnet에서 돌아가는 Lambda에서 다른 Lambda를 Invoke하려면 NAT이 필수적이다.

이참에.. KMS도 써야하고 Lambda도 써야하는데 PrivateLink는 비싸서(시간당 0.01달라인가.. 여러개면...ㅠㅠ) NAT Instance를 구축했다. (NAT Gateway는 비싸다...ㅠㅠ)

AWS때문에 지갑이 얇아진다... 아니 지네 서비스안에서 지네 서비스 연결하는데도 돈이 든다니... 인터넷 통신비용도 또 따로 책정하면서... 이런...

7. NodeJs에서 exports = require(...) 이런 형식의 handler는 안된다.

무슨 말이냐면...

index.js

exports = require('./dist/main.js')

dist/main.js

const server = JsExpressServer.createServer();
exports.handler = server.lambdaHandler;

이렇게 했는데 안되었다.

웃긴건 index.js에서 exports.handler를 출력해보면 자알 존재하는데 딱히 실행하면 오류도 안나고 그저 502 Bad Gateway (Timeout)가 떠버린다..

이유는 lambdaHandler가 Promise로 작동하는거 때문인거 같은데 쨋든 웃기다기보단 내가 아직 node.js를 잘 몰라서 그렇다..ㅎㅎ

this 참조때문인가 했는데 그건 아니었다. lambdaHandler안에서 this객체들은 너무도 잘 참조되었다.

지금은 dist/main.js를 직접 실행하고 (WebPack을 쓰고있다. 용량도 확 줄고 alias도 쓸 수 있고 좋다~)

const server = JsExpressServer.createServer();
exports.handler = (event, context) => server.lambdaHandler(event, context);

이렇게 하니 잘 된다!

Comment +0